Skip to content

Commit

Permalink
btrfs: Honour FITRIM range constraints during free space trim
Browse files Browse the repository at this point in the history
commit c2d1b3a 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: 499f377 ("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>
  • Loading branch information
Nikolay Borisov authored and Greg Kroah-Hartman committed May 25, 2019
1 parent 4354c04 commit 038ec2c
Showing 1 changed file with 19 additions and 6 deletions.
25 changes: 19 additions & 6 deletions fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -11150,9 +11150,9 @@ int btrfs_error_unpin_extent_range(struct btrfs_root *root, u64 start, u64 end)
* 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;
Expand Down Expand Up @@ -11188,8 +11188,8 @@ static int btrfs_trim_free_extents(struct btrfs_device *device,
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);

Expand All @@ -11201,6 +11201,16 @@ static int btrfs_trim_free_extents(struct btrfs_device *device,
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);
Expand All @@ -11211,6 +11221,10 @@ static int btrfs_trim_free_extents(struct btrfs_device *device,
start += len;
*trimmed += bytes;

/* We've trimmed enough */
if (*trimmed >= range->len)
break;

if (fatal_signal_pending(current)) {
ret = -ERESTARTSYS;
break;
Expand Down Expand Up @@ -11295,8 +11309,7 @@ int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range)
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;
Expand Down

0 comments on commit 038ec2c

Please sign in to comment.