Skip to content

Commit c080b41

Browse files
adam900710kdave
authored andcommitted
btrfs: defrag: properly update range->start for autodefrag
[BUG] After commit 7b50803 ("btrfs: defrag: use defrag_one_cluster() to implement btrfs_defrag_file()") autodefrag no longer properly re-defrag the file from previously finished location. [CAUSE] The recent refactoring of defrag only focuses on defrag ioctl subpage support, doesn't take autodefrag into consideration. There are two problems involved which prevents autodefrag to restart its scan: - No range.start update Previously when one defrag target is found, range->start will be updated to indicate where next search should start from. But now btrfs_defrag_file() doesn't update it anymore, making all autodefrag to rescan from file offset 0. This would also make autodefrag to mark the same range dirty again and again, causing extra IO. - No proper quick exit for defrag_one_cluster() Currently if we reached or exceed @max_sectors limit, we just exit defrag_one_cluster(), and let next defrag_one_cluster() call to do a quick exit. This makes @Cur increase, thus no way to properly know which range is defragged and which range is skipped. [FIX] The fix involves two modifications: - Update range->start to next cluster start This is a little different from the old behavior. Previously range->start is updated to the next defrag target. But in the end, the behavior should still be pretty much the same, as now we skip to next defrag target inside btrfs_defrag_file(). Thus if auto-defrag determines to re-scan, then we still do the skip, just at a different timing. - Make defrag_one_cluster() to return >0 to indicate a quick exit So that btrfs_defrag_file() can also do a quick exit, without increasing @Cur to the range end, and re-use @Cur to update @range->start. - Add comment for btrfs_defrag_file() to mention the range->start update Currently only autodefrag utilize this behavior, as defrag ioctl won't set @max_to_defrag parameter, thus unless interrupted it will always try to defrag the whole range. Reported-by: Filipe Manana <fdmanana@suse.com> 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: Filipe Manana <fdmanana@suse.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 484167d commit c080b41

File tree

1 file changed

+16
-2
lines changed

1 file changed

+16
-2
lines changed

fs/btrfs/ioctl.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,8 +1443,10 @@ static int defrag_one_cluster(struct btrfs_inode *inode,
14431443
u32 range_len = entry->len;
14441444

14451445
/* Reached or beyond the limit */
1446-
if (max_sectors && *sectors_defragged >= max_sectors)
1446+
if (max_sectors && *sectors_defragged >= max_sectors) {
1447+
ret = 1;
14471448
break;
1449+
}
14481450

14491451
if (max_sectors)
14501452
range_len = min_t(u32, range_len,
@@ -1487,7 +1489,10 @@ static int defrag_one_cluster(struct btrfs_inode *inode,
14871489
* will be defragged.
14881490
*
14891491
* Return <0 for error.
1490-
* Return >=0 for the number of sectors defragged.
1492+
* Return >=0 for the number of sectors defragged, and range->start will be updated
1493+
* to indicate the file offset where next defrag should be started at.
1494+
* (Mostly for autodefrag, which sets @max_to_defrag thus we may exit early without
1495+
* defragging all the range).
14911496
*/
14921497
int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
14931498
struct btrfs_ioctl_defrag_range_args *range,
@@ -1580,10 +1585,19 @@ int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
15801585
if (ret < 0)
15811586
break;
15821587
cur = cluster_end + 1;
1588+
if (ret > 0) {
1589+
ret = 0;
1590+
break;
1591+
}
15831592
}
15841593

15851594
if (ra_allocated)
15861595
kfree(ra);
1596+
/*
1597+
* Update range.start for autodefrag, this will indicate where to start
1598+
* in next run.
1599+
*/
1600+
range->start = cur;
15871601
if (sectors_defragged) {
15881602
/*
15891603
* We have defragged some sectors, for compression case they

0 commit comments

Comments
 (0)