From: Daniel Vacek Date: Thu, 6 Mar 2025 13:15:35 +0000 (+0100) Subject: btrfs: defrag: extend ioctl to accept compression levels X-Git-Tag: v6.15-rc1~152^2~36 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fc5c0c5825874859069ac44c367c724acd7190fb;p=thirdparty%2Flinux.git btrfs: defrag: extend ioctl to accept compression levels The zstd and zlib compression types support setting compression levels. Enhance the defrag interface to specify the levels as well. For zstd the negative (realtime) levels are also accepted. Reviewed-by: Qu Wenruo Signed-off-by: Daniel Vacek Reviewed-by: David Sterba Signed-off-by: David Sterba --- diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index ca1cd600f5d21..cd5c8b595ebb6 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h @@ -145,6 +145,7 @@ struct btrfs_inode { * different from prop_compress and takes precedence if set. */ u8 defrag_compress; + s8 defrag_compress_level; /* * Lock for counters and all fields used to determine if the inode is in diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index 1fe154e7cc028..e7f8ee5d48a4f 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -980,6 +980,16 @@ static int btrfs_compress_set_level(unsigned int type, int level) return level; } +/* + * Check whether the @level is within the valid range for the given type. + */ +bool btrfs_compress_level_valid(unsigned int type, int level) +{ + const struct btrfs_compress_op *ops = btrfs_compress_op[type]; + + return ops->min_level <= level && level <= ops->max_level; +} + /* Wrapper around find_get_page(), with extra error message. */ int btrfs_compress_filemap_get_folio(struct address_space *mapping, u64 start, struct folio **in_folio_ret) diff --git a/fs/btrfs/compression.h b/fs/btrfs/compression.h index 933178f03d8f8..df198623cc084 100644 --- a/fs/btrfs/compression.h +++ b/fs/btrfs/compression.h @@ -83,6 +83,7 @@ static inline u32 btrfs_calc_input_length(u64 range_end, u64 cur) 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 address_space *mapping, u64 start, struct folio **folios, unsigned long *out_folios, unsigned long *total_in, unsigned long *total_out); diff --git a/fs/btrfs/defrag.c b/fs/btrfs/defrag.c index 18f0704263f32..ae0b92b963456 100644 --- a/fs/btrfs/defrag.c +++ b/fs/btrfs/defrag.c @@ -1363,6 +1363,7 @@ int btrfs_defrag_file(struct btrfs_inode *inode, struct file_ra_state *ra, u64 last_byte; bool do_compress = (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS); int compress_type = BTRFS_COMPRESS_ZLIB; + int compress_level = 0; int ret = 0; u32 extent_thresh = range->extent_thresh; pgoff_t start_index; @@ -1376,10 +1377,21 @@ int btrfs_defrag_file(struct btrfs_inode *inode, struct file_ra_state *ra, return -EINVAL; if (do_compress) { - if (range->compress_type >= BTRFS_NR_COMPRESS_TYPES) - return -EINVAL; - if (range->compress_type) - compress_type = range->compress_type; + if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS_LEVEL) { + if (range->compress.type >= BTRFS_NR_COMPRESS_TYPES) + return -EINVAL; + if (range->compress.type) { + compress_type = range->compress.type; + compress_level = range->compress.level; + if (!btrfs_compress_level_valid(compress_type, compress_level)) + return -EINVAL; + } + } else { + if (range->compress_type >= BTRFS_NR_COMPRESS_TYPES) + return -EINVAL; + if (range->compress_type) + compress_type = range->compress_type; + } } if (extent_thresh == 0) @@ -1430,8 +1442,10 @@ int btrfs_defrag_file(struct btrfs_inode *inode, struct file_ra_state *ra, btrfs_inode_unlock(inode, 0); break; } - if (do_compress) + if (do_compress) { inode->defrag_compress = compress_type; + inode->defrag_compress_level = compress_level; + } ret = defrag_one_cluster(inode, ra, cur, cluster_end + 1 - cur, extent_thresh, newer_than, do_compress, §ors_defragged, diff --git a/fs/btrfs/fs.h b/fs/btrfs/fs.h index 6710da812a380..c76d432168447 100644 --- a/fs/btrfs/fs.h +++ b/fs/btrfs/fs.h @@ -497,7 +497,7 @@ struct btrfs_fs_info { u64 last_trans_log_full_commit; unsigned long long mount_opt; - unsigned long compress_type:4; + int compress_type; int compress_level; u32 commit_interval; /* diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 84a6f764f28bc..3a8e0858803c1 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -877,6 +877,7 @@ static void compress_file_range(struct btrfs_work *work) unsigned int poff; int i; int compress_type = fs_info->compress_type; + int compress_level = fs_info->compress_level; inode_should_defrag(inode, start, end, end - start + 1, SZ_16K); @@ -959,13 +960,15 @@ again: goto cleanup_and_bail_uncompressed; } - if (inode->defrag_compress) + if (inode->defrag_compress) { compress_type = inode->defrag_compress; - else if (inode->prop_compress) + compress_level = inode->defrag_compress_level; + } else if (inode->prop_compress) { compress_type = inode->prop_compress; + } /* Compression level is applied here. */ - ret = btrfs_compress_folios(compress_type, fs_info->compress_level, + ret = btrfs_compress_folios(compress_type, compress_level, mapping, start, folios, &nr_folios, &total_in, &total_compressed); if (ret) diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h index d3b222d7af240..dd02160015b2b 100644 --- a/include/uapi/linux/btrfs.h +++ b/include/uapi/linux/btrfs.h @@ -615,7 +615,9 @@ struct btrfs_ioctl_clone_range_args { */ #define BTRFS_DEFRAG_RANGE_COMPRESS 1 #define BTRFS_DEFRAG_RANGE_START_IO 2 +#define BTRFS_DEFRAG_RANGE_COMPRESS_LEVEL 4 #define BTRFS_DEFRAG_RANGE_FLAGS_SUPP (BTRFS_DEFRAG_RANGE_COMPRESS | \ + BTRFS_DEFRAG_RANGE_COMPRESS_LEVEL | \ BTRFS_DEFRAG_RANGE_START_IO) struct btrfs_ioctl_defrag_range_args { @@ -640,10 +642,18 @@ struct btrfs_ioctl_defrag_range_args { /* * which compression method to use if turning on compression - * for this defrag operation. If unspecified, zlib will - * be used + * for this defrag operation. If unspecified, zlib will be + * used. If compression level is also being specified, set the + * BTRFS_DEFRAG_RANGE_COMPRESS_LEVEL flag and fill the compress + * member structure instead of the compress_type field. */ - __u32 compress_type; + union { + __u32 compress_type; + struct { + __u8 type; + __s8 level; + } compress; + }; /* spare for later */ __u32 unused[4];