| From c2d1b3aae33605a61cbab445d8ae1c708ccd2698 Mon Sep 17 00:00:00 2001 |
| From: Nikolay Borisov <nborisov@suse.com> |
| Date: Mon, 25 Mar 2019 14:31:21 +0200 |
| Subject: btrfs: Honour FITRIM range constraints during free space trim |
| |
| From: Nikolay Borisov <nborisov@suse.com> |
| |
| commit c2d1b3aae33605a61cbab445d8ae1c708ccd2698 upstream. |
| |
| Up until now trimming the freespace was done irrespective of what the |
| arguments of the FITRIM ioctl were. For example fstrim's -o/-l arguments |
| will be entirely ignored. Fix it by correctly handling those paramter. |
| This requires breaking if the found freespace extent is after the end of |
| the passed range as well as completing trim after trimming |
| fstrim_range::len bytes. |
| |
| Fixes: 499f377f49f0 ("btrfs: iterate over unused chunk space in FITRIM") |
| CC: stable@vger.kernel.org # 4.4+ |
| Signed-off-by: Nikolay Borisov <nborisov@suse.com> |
| Reviewed-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| |
| --- |
| fs/btrfs/extent-tree.c | 25 +++++++++++++++++++------ |
| 1 file changed, 19 insertions(+), 6 deletions(-) |
| |
| --- a/fs/btrfs/extent-tree.c |
| +++ b/fs/btrfs/extent-tree.c |
| @@ -11150,9 +11150,9 @@ int btrfs_error_unpin_extent_range(struc |
| * transaction. |
| */ |
| static int btrfs_trim_free_extents(struct btrfs_device *device, |
| - u64 minlen, u64 *trimmed) |
| + struct fstrim_range *range, u64 *trimmed) |
| { |
| - u64 start = 0, len = 0; |
| + u64 start = range->start, len = 0; |
| int ret; |
| |
| *trimmed = 0; |
| @@ -11188,8 +11188,8 @@ static int btrfs_trim_free_extents(struc |
| atomic_inc(&trans->use_count); |
| spin_unlock(&fs_info->trans_lock); |
| |
| - ret = find_free_dev_extent_start(trans, device, minlen, start, |
| - &start, &len); |
| + ret = find_free_dev_extent_start(trans, device, range->minlen, |
| + start, &start, &len); |
| if (trans) |
| btrfs_put_transaction(trans); |
| |
| @@ -11201,6 +11201,16 @@ static int btrfs_trim_free_extents(struc |
| break; |
| } |
| |
| + /* If we are out of the passed range break */ |
| + if (start > range->start + range->len - 1) { |
| + mutex_unlock(&fs_info->chunk_mutex); |
| + ret = 0; |
| + break; |
| + } |
| + |
| + start = max(range->start, start); |
| + len = min(range->len, len); |
| + |
| ret = btrfs_issue_discard(device->bdev, start, len, &bytes); |
| up_read(&fs_info->commit_root_sem); |
| mutex_unlock(&fs_info->chunk_mutex); |
| @@ -11211,6 +11221,10 @@ static int btrfs_trim_free_extents(struc |
| start += len; |
| *trimmed += bytes; |
| |
| + /* We've trimmed enough */ |
| + if (*trimmed >= range->len) |
| + break; |
| + |
| if (fatal_signal_pending(current)) { |
| ret = -ERESTARTSYS; |
| break; |
| @@ -11295,8 +11309,7 @@ int btrfs_trim_fs(struct btrfs_root *roo |
| mutex_lock(&fs_info->fs_devices->device_list_mutex); |
| devices = &fs_info->fs_devices->devices; |
| list_for_each_entry(device, devices, dev_list) { |
| - ret = btrfs_trim_free_extents(device, range->minlen, |
| - &group_trimmed); |
| + ret = btrfs_trim_free_extents(device, range, &group_trimmed); |
| if (ret) { |
| dev_failed++; |
| dev_ret = ret; |