Skip to content

Commit 6b34cd8

Browse files
fdmananakdave
authored andcommitted
btrfs: fix too long loop when defragging a 1 byte file
When attempting to defrag a file with a single byte, we can end up in a too long loop, which is nearly infinite because at btrfs_defrag_file() we end up with the variable last_byte assigned with a value of 18446744073709551615 (which is (u64)-1). The problem comes from the fact we end up doing: last_byte = round_up(last_byte, fs_info->sectorsize) - 1; So if last_byte was assigned 0, which is i_size - 1, we underflow and end up with the value 18446744073709551615. This is trivial to reproduce and the following script triggers it: $ cat test.sh #!/bin/bash DEV=/dev/sdj MNT=/mnt/sdj mkfs.btrfs -f $DEV mount $DEV $MNT echo -n "X" > $MNT/foobar btrfs filesystem defragment $MNT/foobar umount $MNT So fix this by not decrementing last_byte by 1 before doing the sector size round up. Also, to make it easier to follow, make the round up right after computing last_byte. Reported-by: Anthony Ruhier <aruhier@mailbox.org> Fixes: 7b50803 ("btrfs: defrag: use defrag_one_cluster() to implement btrfs_defrag_file()") Link: https://lore.kernel.org/linux-btrfs/0a269612-e43f-da22-c5bc-b34b1b56ebe8@mailbox.org/ CC: stable@vger.kernel.org # 5.16 Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 36c86a9 commit 6b34cd8

File tree

1 file changed

+6
-6
lines changed

1 file changed

+6
-6
lines changed

fs/btrfs/ioctl.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1518,12 +1518,16 @@ int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
15181518

15191519
if (range->start + range->len > range->start) {
15201520
/* Got a specific range */
1521-
last_byte = min(isize, range->start + range->len) - 1;
1521+
last_byte = min(isize, range->start + range->len);
15221522
} else {
15231523
/* Defrag until file end */
1524-
last_byte = isize - 1;
1524+
last_byte = isize;
15251525
}
15261526

1527+
/* Align the range */
1528+
cur = round_down(range->start, fs_info->sectorsize);
1529+
last_byte = round_up(last_byte, fs_info->sectorsize) - 1;
1530+
15271531
/*
15281532
* If we were not given a ra, allocate a readahead context. As
15291533
* readahead is just an optimization, defrag will work without it so
@@ -1536,10 +1540,6 @@ int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
15361540
file_ra_state_init(ra, inode->i_mapping);
15371541
}
15381542

1539-
/* Align the range */
1540-
cur = round_down(range->start, fs_info->sectorsize);
1541-
last_byte = round_up(last_byte, fs_info->sectorsize) - 1;
1542-
15431543
while (cur < last_byte) {
15441544
u64 cluster_end;
15451545

0 commit comments

Comments
 (0)