Commit 26902be0 authored by Qu Wenruo's avatar Qu Wenruo Committed by David Sterba
Browse files

btrfs: remove the old btrfs_compress_folios() infrastructure



Since it's been replaced by btrfs_compress_bio(), remove all involved
functions.

Reviewed-by: default avatarBoris Burkov <boris@bur.io>
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 6f706f34
Loading
Loading
Loading
Loading
+0 −70
Original line number Diff line number Diff line
@@ -86,37 +86,6 @@ bool btrfs_compress_is_valid_type(const char *str, size_t len)
	return false;
}

static int compression_compress_pages(int type, struct list_head *ws,
				      struct btrfs_inode *inode, u64 start,
				      struct folio **folios, unsigned long *out_folios,
				      unsigned long *total_in, unsigned long *total_out)
{
	switch (type) {
	case BTRFS_COMPRESS_ZLIB:
		return zlib_compress_folios(ws, inode, start, folios,
					    out_folios, total_in, total_out);
	case BTRFS_COMPRESS_LZO:
		return lzo_compress_folios(ws, inode, start, folios,
					   out_folios, total_in, total_out);
	case BTRFS_COMPRESS_ZSTD:
		return zstd_compress_folios(ws, inode, start, folios,
					    out_folios, total_in, total_out);
	case BTRFS_COMPRESS_NONE:
	default:
		/*
		 * This can happen when compression races with remount setting
		 * it to 'no compress', while caller doesn't call
		 * inode_need_compress() to check if we really need to
		 * compress.
		 *
		 * Not a big deal, just need to inform caller that we
		 * haven't allocated any pages yet.
		 */
		*out_folios = 0;
		return -E2BIG;
	}
}

static int compression_decompress_bio(struct list_head *ws,
				      struct compressed_bio *cb)
{
@@ -1023,45 +992,6 @@ int btrfs_compress_filemap_get_folio(struct address_space *mapping, u64 start,
	return 0;
}

/*
 * Given an address space and start and length, compress the bytes into @pages
 * that are allocated on demand.
 *
 * @type_level is encoded algorithm and level, where level 0 means whatever
 * default the algorithm chooses and is opaque here;
 * - compression algo are 0-3
 * - the level are bits 4-7
 *
 * @out_folios is an in/out parameter, holds maximum number of folios to allocate
 * and returns number of actually allocated folios
 *
 * @total_in is used to return the number of bytes actually read.  It
 * may be smaller than the input length if we had to exit early because we
 * ran out of room in the folios array or because we cross the
 * max_out threshold.
 *
 * @total_out is an in/out parameter, must be set to the input length and will
 * be also used to return the total number of compressed bytes
 */
int btrfs_compress_folios(unsigned int type, int level, struct btrfs_inode *inode,
			 u64 start, struct folio **folios, unsigned long *out_folios,
			 unsigned long *total_in, unsigned long *total_out)
{
	struct btrfs_fs_info *fs_info = inode->root->fs_info;
	const unsigned long orig_len = *total_out;
	struct list_head *workspace;
	int ret;

	level = btrfs_compress_set_level(type, level);
	workspace = get_workspace(fs_info, type, level);
	ret = compression_compress_pages(type, workspace, inode, start, folios,
					 out_folios, total_in, total_out);
	/* The total read-in bytes should be no larger than the input. */
	ASSERT(*total_in <= orig_len);
	put_workspace(fs_info, type, workspace);
	return ret;
}

/*
 * Given an address space and start and length, compress the page cache
 * contents into @cb.
+0 −12
Original line number Diff line number Diff line
@@ -91,9 +91,6 @@ int __init btrfs_init_compress(void);
void __cold btrfs_exit_compress(void);

bool btrfs_compress_level_valid(unsigned int type, int level);
int btrfs_compress_folios(unsigned int type, int level, struct btrfs_inode *inode,
			  u64 start, struct folio **folios, unsigned long *out_folios,
			 unsigned long *total_in, unsigned long *total_out);
int btrfs_decompress(int type, const u8 *data_in, struct folio *dest_folio,
		     unsigned long dest_pgoff, size_t srclen, size_t destlen);
int btrfs_decompress_buf2page(const char *buf, u32 buf_len,
@@ -160,9 +157,6 @@ static inline void cleanup_compressed_bio(struct compressed_bio *cb)
	bio_put(bio);
}

int zlib_compress_folios(struct list_head *ws, struct btrfs_inode *inode,
			 u64 start, struct folio **folios, unsigned long *out_folios,
		unsigned long *total_in, unsigned long *total_out);
int zlib_compress_bio(struct list_head *ws, struct compressed_bio *cb);
int zlib_decompress_bio(struct list_head *ws, struct compressed_bio *cb);
int zlib_decompress(struct list_head *ws, const u8 *data_in,
@@ -172,9 +166,6 @@ struct list_head *zlib_alloc_workspace(struct btrfs_fs_info *fs_info, unsigned i
void zlib_free_workspace(struct list_head *ws);
struct list_head *zlib_get_workspace(struct btrfs_fs_info *fs_info, unsigned int level);

int lzo_compress_folios(struct list_head *ws, struct btrfs_inode *inode,
			u64 start, struct folio **folios, unsigned long *out_folios,
		unsigned long *total_in, unsigned long *total_out);
int lzo_compress_bio(struct list_head *ws, struct compressed_bio *cb);
int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb);
int lzo_decompress(struct list_head *ws, const u8 *data_in,
@@ -183,9 +174,6 @@ int lzo_decompress(struct list_head *ws, const u8 *data_in,
struct list_head *lzo_alloc_workspace(struct btrfs_fs_info *fs_info);
void lzo_free_workspace(struct list_head *ws);

int zstd_compress_folios(struct list_head *ws, struct btrfs_inode *inode,
			 u64 start, struct folio **folios, unsigned long *out_folios,
		unsigned long *total_in, unsigned long *total_out);
int zstd_compress_bio(struct list_head *ws, struct compressed_bio *cb);
int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb);
int zstd_decompress(struct list_head *ws, const u8 *data_in,
+1 −1
Original line number Diff line number Diff line
@@ -966,7 +966,7 @@ static void compress_file_range(struct btrfs_work *work)
	/*
	 * All the folios should have been locked thus no failure.
	 *
	 * And even if some folios are missing, btrfs_compress_folios()
	 * And even if some folios are missing, btrfs_compress_bio()
	 * would handle them correctly, so here just do an ASSERT() check for
	 * early logic errors.
	 */
+0 −188
Original line number Diff line number Diff line
@@ -122,98 +122,6 @@ static inline size_t read_compress_length(const char *buf)
	return le32_to_cpu(dlen);
}

/*
 * Will do:
 *
 * - Write a segment header into the destination
 * - Copy the compressed buffer into the destination
 * - Make sure we have enough space in the last sector to fit a segment header
 *   If not, we will pad at most (LZO_LEN (4)) - 1 bytes of zeros.
 *
 * Will allocate new pages when needed.
 */
static int copy_compressed_data_to_page(struct btrfs_fs_info *fs_info,
					char *compressed_data,
					size_t compressed_size,
					struct folio **out_folios,
					unsigned long max_nr_folio,
					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 >> min_folio_shift) >= max_nr_folio)
		return -E2BIG;

	/*
	 * We never allow a segment header crossing sector boundary, previous
	 * run should ensure we have enough space left inside the sector.
	 */
	ASSERT((*cur_out / sectorsize) == (*cur_out + LZO_LEN - 1) / sectorsize);

	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 >> min_folio_shift] = cur_folio;
	}

	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;

	/* Copy compressed data */
	while (*cur_out - orig_out < compressed_size) {
		u32 copy_len = min_t(u32, sectorsize - *cur_out % sectorsize,
				     orig_out + compressed_size - *cur_out);

		kunmap_local(kaddr);

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

		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 >> min_folio_shift] = cur_folio;
		}
		kaddr = kmap_local_folio(cur_folio, 0);

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

		*cur_out += copy_len;
	}

	/*
	 * Check if we can fit the next segment header into the remaining space
	 * of the sector.
	 */
	sector_bytes_left = round_up(*cur_out, sectorsize) - *cur_out;
	if (sector_bytes_left >= LZO_LEN || sector_bytes_left == 0)
		goto out;

	/* The remaining size is not enough, pad it with zeros */
	memset(kaddr + offset_in_page(*cur_out), 0,
	       sector_bytes_left);
	*cur_out += sector_bytes_left;

out:
	kunmap_local(kaddr);
	return 0;
}

/*
 * Write data into @out_folio and queue it into @out_bio.
 *
@@ -365,102 +273,6 @@ static int copy_compressed_data_to_bio(struct btrfs_fs_info *fs_info,
	return write_and_queue_folio(out_bio, out_folio, total_out, sector_bytes_left);
}

int lzo_compress_folios(struct list_head *ws, struct btrfs_inode *inode,
			u64 start, struct folio **folios, unsigned long *out_folios,
			unsigned long *total_in, unsigned long *total_out)
{
	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;
	const unsigned long max_nr_folio = *out_folios;
	int ret = 0;
	/* Points to the file offset of input data */
	u64 cur_in = start;
	/* Points to the current output byte */
	u32 cur_out = 0;
	u32 len = *total_out;

	ASSERT(max_nr_folio > 0);
	*out_folios = 0;
	*total_out = 0;
	*total_in = 0;

	/*
	 * Skip the header for now, we will later come back and write the total
	 * compressed size
	 */
	cur_out += LZO_LEN;
	while (cur_in < start + len) {
		char *data_in;
		const u32 sectorsize_mask = sectorsize - 1;
		u32 sector_off = (cur_in - start) & sectorsize_mask;
		u32 in_len;
		size_t out_len;

		/* Get the input page first */
		if (!folio_in) {
			ret = btrfs_compress_filemap_get_folio(mapping, cur_in, &folio_in);
			if (ret < 0)
				goto out;
		}

		/* Compress at most one sector of data each time */
		in_len = min_t(u32, start + len - cur_in, sectorsize - sector_off);
		ASSERT(in_len);
		data_in = kmap_local_folio(folio_in, offset_in_folio(folio_in, cur_in));
		ret = lzo1x_1_compress(data_in, in_len,
				       workspace->cbuf, &out_len,
				       workspace->mem);
		kunmap_local(data_in);
		if (unlikely(ret < 0)) {
			/* lzo1x_1_compress never fails. */
			ret = -EIO;
			goto out;
		}

		ret = copy_compressed_data_to_page(fs_info, workspace->cbuf, out_len,
						   folios, max_nr_folio,
						   &cur_out);
		if (ret < 0)
			goto out;

		cur_in += in_len;

		/*
		 * Check if we're making it bigger after two sectors.  And if
		 * it is so, give up.
		 */
		if (cur_in - start > sectorsize * 2 && cur_in - start < cur_out) {
			ret = -E2BIG;
			goto out;
		}

		/* Check if we have reached folio boundary. */
		if (IS_ALIGNED(cur_in, min_folio_size)) {
			folio_put(folio_in);
			folio_in = NULL;
		}
	}

	/* Store the size of all chunks of compressed data */
	sizes_ptr = kmap_local_folio(folios[0], 0);
	write_compress_length(sizes_ptr, cur_out);
	kunmap_local(sizes_ptr);

	ret = 0;
	*total_out = cur_out;
	*total_in = cur_in - start;
out:
	if (folio_in)
		folio_put(folio_in);
	*out_folios = DIV_ROUND_UP(cur_out, min_folio_size);
	return ret;
}

int lzo_compress_bio(struct list_head *ws, struct compressed_bio *cb)
{
	struct btrfs_inode *inode = cb->bbio.inode;
+0 −189
Original line number Diff line number Diff line
@@ -145,195 +145,6 @@ static int copy_data_into_buffer(struct address_space *mapping,
	return 0;
}

int zlib_compress_folios(struct list_head *ws, struct btrfs_inode *inode,
			 u64 start, struct folio **folios, unsigned long *out_folios,
			 unsigned long *total_in, unsigned long *total_out)
{
	struct btrfs_fs_info *fs_info = inode->root->fs_info;
	struct workspace *workspace = list_entry(ws, struct workspace, list);
	struct address_space *mapping = inode->vfs_inode.i_mapping;
	const u32 min_folio_shift = PAGE_SHIFT + fs_info->block_min_order;
	const u32 min_folio_size = btrfs_min_folio_size(fs_info);
	int ret;
	char *data_in = NULL;
	char *cfolio_out;
	int nr_folios = 0;
	struct folio *in_folio = NULL;
	struct folio *out_folio = NULL;
	unsigned long len = *total_out;
	unsigned long nr_dest_folios = *out_folios;
	const unsigned long max_out = nr_dest_folios << min_folio_shift;
	const u32 blocksize = fs_info->sectorsize;
	const u64 orig_end = start + len;

	*out_folios = 0;
	*total_out = 0;
	*total_in = 0;

	ret = zlib_deflateInit(&workspace->strm, workspace->level);
	if (unlikely(ret != Z_OK)) {
		btrfs_err(fs_info,
	"zlib compression init failed, error %d root %llu inode %llu offset %llu",
			  ret, btrfs_root_id(inode->root), btrfs_ino(inode), start);
		ret = -EIO;
		goto out;
	}

	workspace->strm.total_in = 0;
	workspace->strm.total_out = 0;

	out_folio = btrfs_alloc_compr_folio(fs_info);
	if (out_folio == NULL) {
		ret = -ENOMEM;
		goto out;
	}
	cfolio_out = folio_address(out_folio);
	folios[0] = out_folio;
	nr_folios = 1;

	workspace->strm.next_in = workspace->buf;
	workspace->strm.avail_in = 0;
	workspace->strm.next_out = cfolio_out;
	workspace->strm.avail_out = min_folio_size;

	while (workspace->strm.total_in < len) {
		/*
		 * Get next input pages and copy the contents to
		 * the workspace buffer if required.
		 */
		if (workspace->strm.avail_in == 0) {
			unsigned long bytes_left = len - workspace->strm.total_in;
			unsigned int copy_length = min(bytes_left, workspace->buf_size);

			/*
			 * For s390 hardware accelerated zlib, and our folio is smaller
			 * than the copy_length, we need to fill the buffer so that
			 * we can take full advantage of hardware acceleration.
			 */
			if (need_special_buffer(fs_info)) {
				ret = copy_data_into_buffer(mapping, workspace,
							    start, copy_length);
				if (ret < 0)
					goto out;
				start += copy_length;
				workspace->strm.next_in = workspace->buf;
				workspace->strm.avail_in = copy_length;
			} else {
				unsigned int cur_len;

				if (data_in) {
					kunmap_local(data_in);
					folio_put(in_folio);
					data_in = NULL;
				}
				ret = btrfs_compress_filemap_get_folio(mapping,
						start, &in_folio);
				if (ret < 0)
					goto out;
				cur_len = btrfs_calc_input_length(in_folio, orig_end, start);
				data_in = kmap_local_folio(in_folio,
							   offset_in_folio(in_folio, start));
				start += cur_len;
				workspace->strm.next_in = data_in;
				workspace->strm.avail_in = cur_len;
			}
		}

		ret = zlib_deflate(&workspace->strm, Z_SYNC_FLUSH);
		if (unlikely(ret != Z_OK)) {
			btrfs_warn(fs_info,
		"zlib compression failed, error %d root %llu inode %llu offset %llu",
				   ret, btrfs_root_id(inode->root), btrfs_ino(inode),
				   start);
			zlib_deflateEnd(&workspace->strm);
			ret = -EIO;
			goto out;
		}

		/* we're making it bigger, give up */
		if (workspace->strm.total_in > blocksize * 2 &&
		    workspace->strm.total_in <
		    workspace->strm.total_out) {
			ret = -E2BIG;
			goto out;
		}
		/* we need another page for writing out.  Test this
		 * before the total_in so we will pull in a new page for
		 * the stream end if required
		 */
		if (workspace->strm.avail_out == 0) {
			if (nr_folios == nr_dest_folios) {
				ret = -E2BIG;
				goto out;
			}
			out_folio = btrfs_alloc_compr_folio(fs_info);
			if (out_folio == NULL) {
				ret = -ENOMEM;
				goto out;
			}
			cfolio_out = folio_address(out_folio);
			folios[nr_folios] = out_folio;
			nr_folios++;
			workspace->strm.avail_out = min_folio_size;
			workspace->strm.next_out = cfolio_out;
		}
		/* we're all done */
		if (workspace->strm.total_in >= len)
			break;
		if (workspace->strm.total_out > max_out)
			break;
	}
	workspace->strm.avail_in = 0;
	/*
	 * Call deflate with Z_FINISH flush parameter providing more output
	 * space but no more input data, until it returns with Z_STREAM_END.
	 */
	while (ret != Z_STREAM_END) {
		ret = zlib_deflate(&workspace->strm, Z_FINISH);
		if (ret == Z_STREAM_END)
			break;
		if (unlikely(ret != Z_OK && ret != Z_BUF_ERROR)) {
			zlib_deflateEnd(&workspace->strm);
			ret = -EIO;
			goto out;
		} else if (workspace->strm.avail_out == 0) {
			/* Get another folio for the stream end. */
			if (nr_folios == nr_dest_folios) {
				ret = -E2BIG;
				goto out;
			}
			out_folio = btrfs_alloc_compr_folio(fs_info);
			if (out_folio == NULL) {
				ret = -ENOMEM;
				goto out;
			}
			cfolio_out = folio_address(out_folio);
			folios[nr_folios] = out_folio;
			nr_folios++;
			workspace->strm.avail_out = min_folio_size;
			workspace->strm.next_out = cfolio_out;
		}
	}
	zlib_deflateEnd(&workspace->strm);

	if (workspace->strm.total_out >= workspace->strm.total_in) {
		ret = -E2BIG;
		goto out;
	}

	ret = 0;
	*total_out = workspace->strm.total_out;
	*total_in = workspace->strm.total_in;
out:
	*out_folios = nr_folios;
	if (data_in) {
		kunmap_local(data_in);
		folio_put(in_folio);
	}

	return ret;
}

int zlib_compress_bio(struct list_head *ws, struct compressed_bio *cb)
{
	struct btrfs_inode *inode = cb->bbio.inode;
Loading