Commit 4fd188a4 authored by Qu Wenruo's avatar Qu Wenruo Committed by David Sterba
Browse files

btrfs: prepare lzo to support bs > ps cases



This involves converting the following functions to use correct folio
sizes/shifts:

- copy_compress_data_to_page()
- lzo_compress_folios()
- lzo_decompress_bio()

Just like zstd, lzo has some extra incorrect usage of kmap_local_folio()
that the offset is always 0.

This will not handle HIGHMEM large folios correctly, but those cases are
already rejected explicitly so it should not cause problems when bs > ps
support is enabled.

Signed-off-by: default avatarQu Wenruo <wqu@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent a6452b85
Loading
Loading
Loading
Loading
+22 −19
Original line number Diff line number Diff line
@@ -140,12 +140,13 @@ static int copy_compressed_data_to_page(struct btrfs_fs_info *fs_info,
					u32 *cur_out)
{
	const u32 sectorsize = fs_info->sectorsize;
	const u32 min_folio_shift = PAGE_SHIFT + fs_info->block_min_order;
	u32 sector_bytes_left;
	u32 orig_out;
	struct folio *cur_folio;
	char *kaddr;

	if ((*cur_out / PAGE_SIZE) >= max_nr_folio)
	if ((*cur_out >> min_folio_shift) >= max_nr_folio)
		return -E2BIG;

	/*
@@ -154,18 +155,17 @@ static int copy_compressed_data_to_page(struct btrfs_fs_info *fs_info,
	 */
	ASSERT((*cur_out / sectorsize) == (*cur_out + LZO_LEN - 1) / sectorsize);

	cur_folio = out_folios[*cur_out / PAGE_SIZE];
	cur_folio = out_folios[*cur_out >> min_folio_shift];
	/* Allocate a new page */
	if (!cur_folio) {
		cur_folio = btrfs_alloc_compr_folio(fs_info);
		if (!cur_folio)
			return -ENOMEM;
		out_folios[*cur_out / PAGE_SIZE] = cur_folio;
		out_folios[*cur_out >> min_folio_shift] = cur_folio;
	}

	kaddr = kmap_local_folio(cur_folio, 0);
	write_compress_length(kaddr + offset_in_page(*cur_out),
			      compressed_size);
	kaddr = kmap_local_folio(cur_folio, offset_in_folio(cur_folio, *cur_out));
	write_compress_length(kaddr, compressed_size);
	*cur_out += LZO_LEN;

	orig_out = *cur_out;
@@ -177,20 +177,20 @@ static int copy_compressed_data_to_page(struct btrfs_fs_info *fs_info,

		kunmap_local(kaddr);

		if ((*cur_out / PAGE_SIZE) >= max_nr_folio)
		if ((*cur_out >> min_folio_shift) >= max_nr_folio)
			return -E2BIG;

		cur_folio = out_folios[*cur_out / PAGE_SIZE];
		cur_folio = out_folios[*cur_out >> min_folio_shift];
		/* Allocate a new page */
		if (!cur_folio) {
			cur_folio = btrfs_alloc_compr_folio(fs_info);
			if (!cur_folio)
				return -ENOMEM;
			out_folios[*cur_out / PAGE_SIZE] = cur_folio;
			out_folios[*cur_out >> min_folio_shift] = cur_folio;
		}
		kaddr = kmap_local_folio(cur_folio, 0);

		memcpy(kaddr + offset_in_page(*cur_out),
		memcpy(kaddr + offset_in_folio(cur_folio, *cur_out),
		       compressed_data + *cur_out - orig_out, copy_len);

		*cur_out += copy_len;
@@ -221,6 +221,7 @@ int lzo_compress_folios(struct list_head *ws, struct btrfs_inode *inode,
	struct btrfs_fs_info *fs_info = inode->root->fs_info;
	struct workspace *workspace = list_entry(ws, struct workspace, list);
	const u32 sectorsize = fs_info->sectorsize;
	const u32 min_folio_size = btrfs_min_folio_size(fs_info);
	struct address_space *mapping = inode->vfs_inode.i_mapping;
	struct folio *folio_in = NULL;
	char *sizes_ptr;
@@ -287,8 +288,8 @@ int lzo_compress_folios(struct list_head *ws, struct btrfs_inode *inode,
			goto out;
		}

		/* Check if we have reached page boundary */
		if (PAGE_ALIGNED(cur_in)) {
		/* Check if we have reached folio boundary. */
		if (IS_ALIGNED(cur_in, min_folio_size)) {
			folio_put(folio_in);
			folio_in = NULL;
		}
@@ -305,7 +306,7 @@ int lzo_compress_folios(struct list_head *ws, struct btrfs_inode *inode,
out:
	if (folio_in)
		folio_put(folio_in);
	*out_folios = DIV_ROUND_UP(cur_out, PAGE_SIZE);
	*out_folios = DIV_ROUND_UP(cur_out, min_folio_size);
	return ret;
}

@@ -317,15 +318,16 @@ int lzo_compress_folios(struct list_head *ws, struct btrfs_inode *inode,
static void copy_compressed_segment(struct compressed_bio *cb,
				    char *dest, u32 len, u32 *cur_in)
{
	struct btrfs_fs_info *fs_info = cb_to_fs_info(cb);
	const u32 min_folio_shift = PAGE_SHIFT + fs_info->block_min_order;
	u32 orig_in = *cur_in;

	while (*cur_in < orig_in + len) {
		struct folio *cur_folio;
		u32 copy_len = min_t(u32, PAGE_SIZE - offset_in_page(*cur_in),
					  orig_in + len - *cur_in);
		struct folio *cur_folio = cb->compressed_folios[*cur_in >> min_folio_shift];
		u32 copy_len = min_t(u32, orig_in + len - *cur_in,
				     folio_size(cur_folio) - offset_in_folio(cur_folio, *cur_in));

		ASSERT(copy_len);
		cur_folio = cb->compressed_folios[*cur_in / PAGE_SIZE];

		memcpy_from_folio(dest + *cur_in - orig_in, cur_folio,
				  offset_in_folio(cur_folio, *cur_in), copy_len);
@@ -339,6 +341,7 @@ int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
	struct workspace *workspace = list_entry(ws, struct workspace, list);
	const struct btrfs_fs_info *fs_info = cb->bbio.inode->root->fs_info;
	const u32 sectorsize = fs_info->sectorsize;
	const u32 min_folio_shift = PAGE_SHIFT + fs_info->block_min_order;
	char *kaddr;
	int ret;
	/* Compressed data length, can be unaligned */
@@ -385,10 +388,10 @@ int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
		 */
		ASSERT(cur_in / sectorsize ==
		       (cur_in + LZO_LEN - 1) / sectorsize);
		cur_folio = cb->compressed_folios[cur_in / PAGE_SIZE];
		cur_folio = cb->compressed_folios[cur_in >> min_folio_shift];
		ASSERT(cur_folio);
		kaddr = kmap_local_folio(cur_folio, 0);
		seg_len = read_compress_length(kaddr + offset_in_page(cur_in));
		seg_len = read_compress_length(kaddr + offset_in_folio(cur_folio, cur_in));
		kunmap_local(kaddr);
		cur_in += LZO_LEN;