Skip to content

Commit 251acac

Browse files
committed
btrfs: defrag: add flag to force no-compression
Currently the defrag ioctl cannot rewrite the extents without compression. Add a new flag for that, as setting compression to 0 (or "no compression") means to do no changes to compression so take what is the current default, like mount options or properties. The defrag setting overrides mount or properties. The compression BTRFS_DEFRAG_DONT_COMPRESS is only used for in-memory operations and does not need to have a fixed value. Mount with zstd:9, copy test file from /usr/bin/ (about 260KB): $ mount -o compress=zstd:9 /dev/vda /mnt $ filefrag -vsb testfile filefrag: -b needs a blocksize option, assuming 1024-byte blocks. Filesystem type is: 9123683e File size of testfile is 297704 (292 blocks of 1024 bytes) ext: logical_offset: physical_offset: length: expected: flags: 0: 0.. 127: 13312.. 13439: 128: encoded 1: 128.. 255: 13364.. 13491: 128: 13440: encoded 2: 256.. 291: 13424.. 13459: 36: 13492: last,encoded,eof testfile: 3 extents found $ compsize testfile Processed 1 file, 3 regular extents (3 refs), 0 inline, 1 fragments. Type Perc Disk Usage Uncompressed Referenced TOTAL 42% 124K 292K 292K zstd 42% 124K 292K 292K Defrag to uncompressed: $ btrfs fi defrag --nocomp testfile $ filefrag -vsb testfile filefrag: -b needs a blocksize option, assuming 1024-byte blocks. Filesystem type is: 9123683e File size of testfile is 297704 (292 blocks of 1024 bytes) ext: logical_offset: physical_offset: length: expected: flags: 0: 0.. 291: 291840.. 292131: 292: last,eof testfile: 1 extent found $ compsize testfile Processed 1 file, 1 regular extents (1 refs), 0 inline, 1 fragments. Type Perc Disk Usage Uncompressed Referenced TOTAL 100% 292K 292K 292K none 100% 292K 292K 292K Compress again with LZO: $ btrfs fi defrag -clzo testfile $ filefrag -vsb testfile filefrag: -b needs a blocksize option, assuming 1024-byte blocks. Filesystem type is: 9123683e File size of testfile is 297704 (292 blocks of 1024 bytes) ext: logical_offset: physical_offset: length: expected: flags: 0: 0.. 127: 13312.. 13439: 128: encoded 1: 128.. 255: 13392.. 13519: 128: 13440: encoded 2: 256.. 291: 13480.. 13515: 36: 13520: last,encoded,eof testfile: 3 extents found $ compsize testfile Processed 1 file, 3 regular extents (3 refs), 0 inline, 1 fragments. Type Perc Disk Usage Uncompressed Referenced TOTAL 64% 188K 292K 292K lzo 64% 188K 292K 292K Signed-off-by: David Sterba <dsterba@suse.com>
1 parent ac0b415 commit 251acac

File tree

5 files changed

+29
-10
lines changed

5 files changed

+29
-10
lines changed

fs/btrfs/compression.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ enum btrfs_compression_type {
113113
BTRFS_COMPRESS_LZO = 2,
114114
BTRFS_COMPRESS_ZSTD = 3,
115115
BTRFS_NR_COMPRESS_TYPES = 4,
116+
117+
BTRFS_DEFRAG_DONT_COMPRESS,
116118
};
117119

118120
struct workspace_manager {

fs/btrfs/defrag.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -947,7 +947,7 @@ struct defrag_target_range {
947947
* @extent_thresh: file extent size threshold, any extent size >= this value
948948
* will be ignored
949949
* @newer_than: only defrag extents newer than this value
950-
* @do_compress: whether the defrag is doing compression
950+
* @do_compress: whether the defrag is doing compression or no-compression
951951
* if true, @extent_thresh will be ignored and all regular
952952
* file extents meeting @newer_than will be targets.
953953
* @locked: if the range has already held extent lock
@@ -1364,6 +1364,7 @@ int btrfs_defrag_file(struct btrfs_inode *inode, struct file_ra_state *ra,
13641364
u64 cur;
13651365
u64 last_byte;
13661366
bool do_compress = (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS);
1367+
bool no_compress = (range->flags & BTRFS_DEFRAG_RANGE_NOCOMPRESS);
13671368
int compress_type = BTRFS_COMPRESS_ZLIB;
13681369
int compress_level = 0;
13691370
int ret = 0;
@@ -1394,6 +1395,9 @@ int btrfs_defrag_file(struct btrfs_inode *inode, struct file_ra_state *ra,
13941395
if (range->compress_type)
13951396
compress_type = range->compress_type;
13961397
}
1398+
} else if (range->flags & BTRFS_DEFRAG_RANGE_NOCOMPRESS) {
1399+
compress_type = BTRFS_DEFRAG_DONT_COMPRESS;
1400+
compress_level = 1;
13971401
}
13981402

13991403
if (extent_thresh == 0)
@@ -1444,13 +1448,14 @@ int btrfs_defrag_file(struct btrfs_inode *inode, struct file_ra_state *ra,
14441448
btrfs_inode_unlock(inode, 0);
14451449
break;
14461450
}
1447-
if (do_compress) {
1451+
if (do_compress || no_compress) {
14481452
inode->defrag_compress = compress_type;
14491453
inode->defrag_compress_level = compress_level;
14501454
}
14511455
ret = defrag_one_cluster(inode, ra, cur,
14521456
cluster_end + 1 - cur, extent_thresh,
1453-
newer_than, do_compress, &sectors_defragged,
1457+
newer_than, do_compress || no_compress,
1458+
&sectors_defragged,
14541459
max_to_defrag, &last_scanned);
14551460

14561461
if (sectors_defragged > prev_sectors_defragged)
@@ -1489,7 +1494,7 @@ int btrfs_defrag_file(struct btrfs_inode *inode, struct file_ra_state *ra,
14891494
btrfs_set_fs_incompat(fs_info, COMPRESS_ZSTD);
14901495
ret = sectors_defragged;
14911496
}
1492-
if (do_compress) {
1497+
if (do_compress || no_compress) {
14931498
btrfs_inode_lock(inode, 0);
14941499
inode->defrag_compress = BTRFS_COMPRESS_NONE;
14951500
btrfs_inode_unlock(inode, 0);

fs/btrfs/inode.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -781,12 +781,15 @@ static inline int inode_need_compress(struct btrfs_inode *inode, u64 start,
781781
return 0;
782782
}
783783

784+
/* Defrag ioctl takes precedence over mount options and properties. */
785+
if (inode->defrag_compress == BTRFS_DEFRAG_DONT_COMPRESS)
786+
return 0;
787+
if (BTRFS_COMPRESS_NONE < inode->defrag_compress &&
788+
inode->defrag_compress < BTRFS_NR_COMPRESS_TYPES)
789+
return 1;
784790
/* force compress */
785791
if (btrfs_test_opt(fs_info, FORCE_COMPRESS))
786792
return 1;
787-
/* defrag ioctl */
788-
if (inode->defrag_compress)
789-
return 1;
790793
/* bad compression ratios */
791794
if (inode->flags & BTRFS_INODE_NOCOMPRESS)
792795
return 0;
@@ -942,7 +945,7 @@ static void compress_file_range(struct btrfs_work *work)
942945
goto cleanup_and_bail_uncompressed;
943946
}
944947

945-
if (inode->defrag_compress) {
948+
if (0 < inode->defrag_compress && inode->defrag_compress < BTRFS_NR_COMPRESS_TYPES) {
946949
compress_type = inode->defrag_compress;
947950
compress_level = inode->defrag_compress_level;
948951
} else if (inode->prop_compress) {

fs/btrfs/ioctl.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2554,8 +2554,14 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
25542554
ret = -EOPNOTSUPP;
25552555
goto out;
25562556
}
2557-
/* compression requires us to start the IO */
2558-
if ((range.flags & BTRFS_DEFRAG_RANGE_COMPRESS)) {
2557+
if ((range.flags & BTRFS_DEFRAG_RANGE_COMPRESS) &&
2558+
(range.flags & BTRFS_DEFRAG_RANGE_NOCOMPRESS)) {
2559+
ret = -EINVAL;
2560+
goto out;
2561+
}
2562+
/* Compression or no-compression require to start the IO. */
2563+
if ((range.flags & BTRFS_DEFRAG_RANGE_COMPRESS) ||
2564+
(range.flags & BTRFS_DEFRAG_RANGE_NOCOMPRESS)) {
25592565
range.flags |= BTRFS_DEFRAG_RANGE_START_IO;
25602566
range.extent_thresh = (u32)-1;
25612567
}

include/uapi/linux/btrfs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,8 +616,11 @@ struct btrfs_ioctl_clone_range_args {
616616
#define BTRFS_DEFRAG_RANGE_COMPRESS 1
617617
#define BTRFS_DEFRAG_RANGE_START_IO 2
618618
#define BTRFS_DEFRAG_RANGE_COMPRESS_LEVEL 4
619+
/* Request no compression on the range (uncompress if necessary). */
620+
#define BTRFS_DEFRAG_RANGE_NOCOMPRESS 8
619621
#define BTRFS_DEFRAG_RANGE_FLAGS_SUPP (BTRFS_DEFRAG_RANGE_COMPRESS | \
620622
BTRFS_DEFRAG_RANGE_COMPRESS_LEVEL | \
623+
BTRFS_DEFRAG_RANGE_NOCOMPRESS | \
621624
BTRFS_DEFRAG_RANGE_START_IO)
622625

623626
struct btrfs_ioctl_defrag_range_args {

0 commit comments

Comments
 (0)