[PATCH 6.19 051/844] btrfs: handle user interrupt properly in btrfs_trim_fs()
From: Sasha Levin
Date: Sat Feb 28 2026 - 12:53:09 EST
From: jinbaohong <jinbaohong@xxxxxxxxxxxx>
[ Upstream commit bfb670b9183b0e4ba660aff2e396ec1cc01d0761 ]
When a fatal signal is pending or the process is freezing,
btrfs_trim_block_group() and btrfs_trim_free_extents() return -ERESTARTSYS.
Currently this is treated as a regular error: the loops continue to the
next iteration and count it as a block group or device failure.
Instead, break out of the loops immediately and return -ERESTARTSYS to
userspace without counting it as a failure. Also skip the device loop
entirely if the block group loop was interrupted.
Reviewed-by: Qu Wenruo <wqu@xxxxxxxx>
Signed-off-by: Robbie Ko <robbieko@xxxxxxxxxxxx>
Signed-off-by: jinbaohong <jinbaohong@xxxxxxxxxxxx>
Reviewed-by: Filipe Manana <fdmanana@xxxxxxxx>
Signed-off-by: Filipe Manana <fdmanana@xxxxxxxx>
Reviewed-by: David Sterba <dsterba@xxxxxxxx>
Signed-off-by: David Sterba <dsterba@xxxxxxxx>
Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>
---
fs/btrfs/extent-tree.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 1bf081243efb2..8bdb609f58a7e 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -6555,6 +6555,10 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
range->minlen);
trimmed += group_trimmed;
+ if (ret == -ERESTARTSYS || ret == -EINTR) {
+ btrfs_put_block_group(cache);
+ break;
+ }
if (ret) {
bg_failed++;
bg_ret = ret;
@@ -6568,6 +6572,9 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
"failed to trim %llu block group(s), last error %d",
bg_failed, bg_ret);
+ if (ret == -ERESTARTSYS || ret == -EINTR)
+ return ret;
+
mutex_lock(&fs_devices->device_list_mutex);
list_for_each_entry(device, &fs_devices->devices, dev_list) {
if (test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state))
@@ -6576,6 +6583,8 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
ret = btrfs_trim_free_extents(device, &group_trimmed);
trimmed += group_trimmed;
+ if (ret == -ERESTARTSYS || ret == -EINTR)
+ break;
if (ret) {
dev_failed++;
dev_ret = ret;
@@ -6589,6 +6598,8 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
"failed to trim %llu device(s), last error %d",
dev_failed, dev_ret);
range->len = trimmed;
+ if (ret == -ERESTARTSYS || ret == -EINTR)
+ return ret;
if (bg_ret)
return bg_ret;
return dev_ret;
--
2.51.0