btrfs-progs: defrag: allow passing compression levels

The zlib and zstd compression methods support using compression levels.
Enable defrag to pass them to kernel.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Daniel Vacek <neelx@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Daniel Vacek 2025-03-04 18:27:12 +01:00 committed by David Sterba
parent 6be1d80a64
commit 0cfc20b374
4 changed files with 57 additions and 14 deletions

View File

@ -25,8 +25,10 @@ LZO
* good backward compatibility
ZSTD
* compression comparable to ZLIB with higher compression/decompression speeds and different ratio
* levels: 1 to 15, mapped directly (higher levels are not available)
* since 4.14, levels since 5.1
* levels: -15..15, mapped directly, default is 3
* support since 4.14
* levels 1..15 supported since 5.1
* levels -15..-1 supported since 6.15
The differences depend on the actual data set and cannot be expressed by a
single number or recommendation. Higher levels consume more CPU time and may
@ -78,7 +80,7 @@ Compression levels
The level support of ZLIB has been added in v4.14, LZO does not support levels
(the kernel implementation provides only one), ZSTD level support has been added
in v5.1.
in v5.1 and the negative levels in v6.15.
There are 9 levels of ZLIB supported (1 to 9), mapping 1:1 from the mount option
to the algorithm defined level. The default is level 3, which provides the
@ -86,9 +88,12 @@ reasonably good compression ratio and is still reasonably fast. The difference
in compression gain of levels 7, 8 and 9 is comparable but the higher levels
take longer.
The ZSTD support includes levels 1 to 15, a subset of full range of what ZSTD
provides. Levels 1-3 are real-time, 4-8 slower with improved compression and
9-15 try even harder though the resulting size may not be significantly improved.
The ZSTD support includes levels -15..15, a subset of full range of what ZSTD
provides. Levels -15..-1 are real-time with worse compression ratio, levels
1..3 are near real-time with good compression, 4..8 are slower with improved
compression and 9..15 try even harder though the resulting size may not be
significantly improved. Higher levels also require more memory and as they need
more CPU the system performance is affected.
Level 0 always maps to the default. The compression level does not affect
compatibility.

View File

@ -962,6 +962,7 @@ static const char * const cmd_filesystem_defrag_usage[] = {
"",
OPTLINE("-r", "defragment files recursively"),
OPTLINE("-c[zlib,lzo,zstd]", "compress the file while defragmenting, optional parameter (no space in between)"),
OPTLINE("-L|--level level", "use given compression level if enabled (zlib: 1..9, zstd: -15..15, and 0 selects the default level)"),
OPTLINE("-f", "flush data to disk immediately after defragmenting"),
OPTLINE("-s start", "defragment only from byte onward"),
OPTLINE("-l len", "defragment only up to len bytes"),
@ -1066,6 +1067,7 @@ static int cmd_filesystem_defrag(const struct cmd_struct *cmd,
bool recursive = false;
int ret = 0;
int compress_type = BTRFS_COMPRESS_NONE;
int compress_level = 0;
/*
* Kernel 4.19+ supports defragmention of files open read-only,
@ -1095,18 +1097,18 @@ static int cmd_filesystem_defrag(const struct cmd_struct *cmd,
if (bconf.verbose != BTRFS_BCONF_UNSET)
bconf.verbose++;
defrag_global_errors = 0;
defrag_global_errors = 0;
optind = 0;
while(1) {
enum { GETOPT_VAL_STEP = GETOPT_VAL_FIRST };
static const struct option long_options[] = {
{ "level", required_argument, NULL, 'L' },
{ "step", required_argument, NULL, GETOPT_VAL_STEP },
{ NULL, 0, NULL, 0 }
};
int c;
c = getopt_long(argc, argv, "vrc::fs:l:t:", long_options, NULL);
c = getopt_long(argc, argv, "vrc::L:fs:l:t:", long_options, NULL);
if (c < 0)
break;
@ -1116,6 +1118,18 @@ static int cmd_filesystem_defrag(const struct cmd_struct *cmd,
if (optarg)
compress_type = parse_compress_type_arg(optarg);
break;
case 'L':
/*
* Do not enforce any limits here, kernel will do itself
* based on what's supported by the running version.
* Just clip to the s8 type of the API.
*/
compress_level = atoi(optarg);
if (compress_level < -128)
compress_level = -128;
else if (compress_level > 127)
compress_level = 127;
break;
case 'f':
flush = true;
break;
@ -1165,7 +1179,12 @@ static int cmd_filesystem_defrag(const struct cmd_struct *cmd,
defrag_global_range.extent_thresh = (u32)thresh;
if (compress_type) {
defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_COMPRESS;
defrag_global_range.compress_type = compress_type;
if (compress_level) {
defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_COMPRESS_LEVEL;
defrag_global_range.compress.type = compress_type;
defrag_global_range.compress.level= compress_level;
} else
defrag_global_range.compress_type = compress_type;
}
if (flush)
defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_START_IO;

View File

@ -645,7 +645,9 @@ _static_assert(sizeof(struct btrfs_ioctl_clone_range_args) == 32);
*/
#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 {
@ -669,11 +671,20 @@ struct btrfs_ioctl_defrag_range_args {
__u32 extent_thresh;
/*
* which compression method to use if turning on compression
* for this defrag operation. If unspecified, zlib will
* be used
* Which compression method to use if turning on compression for
* defragmentation operation. If unspecified, zlib will be used.
*
* If compression level is also being specified, set the
* BTRFS_DEFRAG_RANGE_COMPRESS_LEVEL flag and set the compress.type
* 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];

View File

@ -608,7 +608,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 {
@ -636,7 +638,13 @@ struct btrfs_ioctl_defrag_range_args {
* for this defrag operation. If unspecified, zlib will
* be used
*/
__u32 compress_type;
union {
__u32 compress_type;
struct {
__u8 type;
__s8 level;
} compress;
};
/* spare for later */
__u32 unused[4];