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: Boris Burkov <boris@bur.io>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Qu Wenruo 2026-01-29 13:53:41 +10:30 committed by David Sterba
parent 3d74a7556f
commit c51173271d
2 changed files with 81 additions and 0 deletions

View File

@ -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);

View File

@ -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,