]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
btrfs: handle user interrupt properly in btrfs_trim_fs()
authorjinbaohong <jinbaohong@synology.com>
Wed, 28 Jan 2026 07:06:40 +0000 (07:06 +0000)
committerDavid Sterba <dsterba@suse.com>
Tue, 3 Feb 2026 06:56:25 +0000 (07:56 +0100)
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@suse.com>
Signed-off-by: Robbie Ko <robbieko@synology.com>
Signed-off-by: jinbaohong <jinbaohong@synology.com>
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/extent-tree.c

index 8e405a1011f4645e6c98dbd0ba81954badcc8ecb..87fd94449f11bdbeed5714db94907e75157cbe9b 100644 (file)
@@ -6665,6 +6665,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++;
                                if (!bg_ret)
@@ -6679,6 +6683,9 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
                        "failed to trim %llu block group(s), first 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))
@@ -6687,6 +6694,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++;
                        if (!dev_ret)
@@ -6701,6 +6710,8 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
                        "failed to trim %llu device(s), first 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;