Commit 6b34cd8
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
1 file changed
Lines changed: 6 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1518 | 1518 | | |
1519 | 1519 | | |
1520 | 1520 | | |
1521 | | - | |
| 1521 | + | |
1522 | 1522 | | |
1523 | 1523 | | |
1524 | | - | |
| 1524 | + | |
1525 | 1525 | | |
1526 | 1526 | | |
| 1527 | + | |
| 1528 | + | |
| 1529 | + | |
| 1530 | + | |
1527 | 1531 | | |
1528 | 1532 | | |
1529 | 1533 | | |
| |||
1536 | 1540 | | |
1537 | 1541 | | |
1538 | 1542 | | |
1539 | | - | |
1540 | | - | |
1541 | | - | |
1542 | | - | |
1543 | 1543 | | |
1544 | 1544 | | |
1545 | 1545 | | |
| |||
0 commit comments