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

btrfs: introduce btrfs_compress_bio() helper



The helper will allocate a new compressed_bio, do the compression, and
return it to the caller.

This greatly simplifies the compression path, as we no longer need to
allocate a folio array thus no extra error path, furthermore the
compressed bio structure can be utilized for submission with very minor
modifications (like rounding up the bi_size and populate the bi_sector).

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 3d74a755
Loading
Loading
Loading
Loading
+68 −0
Original line number Diff line number Diff line
@@ -1064,6 +1064,74 @@ int btrfs_compress_folios(unsigned int type, int level, struct btrfs_inode *inod
	return ret;
}

/*
 * Given an address space and start and length, compress the page cache
 * contents into @cb.
 *
 * @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
 *
 * @cb->bbio.bio.bi_iter.bi_size will indicate the compressed data size.
 * The bi_size may not be sectorsize aligned, thus the caller still need
 * to do the round up before submission.
 *
 * This function will allocate compressed folios with btrfs_alloc_compr_folio(),
 * thus callers must make sure the endio function and error handling are using
 * btrfs_free_compr_folio() to release those folios.
 * This is already done in end_bbio_compressed_write() and cleanup_compressed_bio().
 */
struct compressed_bio *btrfs_compress_bio(struct btrfs_inode *inode,
					  u64 start, u32 len, unsigned int type,
					  int level, blk_opf_t write_flags)
{
	struct btrfs_fs_info *fs_info = inode->root->fs_info;
	struct list_head *workspace;
	struct compressed_bio *cb;
	int ret;

	cb = alloc_compressed_bio(inode, start, REQ_OP_WRITE | write_flags,
				  end_bbio_compressed_write);
	cb->start = start;
	cb->len = len;
	cb->writeback = true;
	cb->compress_type = type;

	level = btrfs_compress_set_level(type, level);
	workspace = get_workspace(fs_info, type, level);
	switch (type) {
	case BTRFS_COMPRESS_ZLIB:
		ret = zlib_compress_bio(workspace, cb);
		break;
	case BTRFS_COMPRESS_LZO:
		ret = lzo_compress_bio(workspace, cb);
		break;
	case BTRFS_COMPRESS_ZSTD:
		ret = zstd_compress_bio(workspace, cb);
		break;
	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.
		 */
		ret = -E2BIG;
	}

	put_workspace(fs_info, type, workspace);
	if (ret < 0) {
		cleanup_compressed_bio(cb);
		return ERR_PTR(ret);
	}
	return cb;
}

static int btrfs_decompress_bio(struct compressed_bio *cb)
{
	struct btrfs_fs_info *fs_info = cb_to_fs_info(cb);
+13 −0
Original line number Diff line number Diff line
@@ -146,6 +146,19 @@ int btrfs_compress_heuristic(struct btrfs_inode *inode, u64 start, u64 end);

int btrfs_compress_filemap_get_folio(struct address_space *mapping, u64 start,
				     struct folio **in_folio_ret);
struct compressed_bio *btrfs_compress_bio(struct btrfs_inode *inode,
					  u64 start, u32 len, unsigned int type,
					  int level, blk_opf_t write_flags);

static inline void cleanup_compressed_bio(struct compressed_bio *cb)
{
	struct bio *bio = &cb->bbio.bio;
	struct folio_iter fi;

	bio_for_each_folio_all(fi, bio)
		btrfs_free_compr_folio(fi.folio);
	bio_put(bio);
}

int zlib_compress_folios(struct list_head *ws, struct btrfs_inode *inode,
			 u64 start, struct folio **folios, unsigned long *out_folios,