Commit bfb670b9 authored by jinbaohong's avatar jinbaohong Committed by David Sterba
Browse files

btrfs: handle user interrupt properly in btrfs_trim_fs()



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: default avatarQu Wenruo <wqu@suse.com>
Signed-off-by: default avatarRobbie Ko <robbieko@synology.com>
Signed-off-by: default avatarjinbaohong <jinbaohong@synology.com>
Reviewed-by: default avatarFilipe Manana <fdmanana@suse.com>
Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 1cc4ada4
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -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;