Commit 8103d10b authored by Nikolay Borisov's avatar Nikolay Borisov Committed by David Sterba

btrfs: Always trim all unallocated space in btrfs_trim_free_extents

This patch removes support for range parameters of FITRIM ioctl when
trimming unallocated space on devices. This is necessary since ranges
passed from user space are generally interpreted as logical addresses,
whereas btrfs_trim_free_extents used to interpret them as device
physical extents. This could result in counter-intuitive behavior for
users so it's best to remove that support altogether.

Additionally, the existing range support had a bug where if an offset
was passed to FITRIM which overflows u64 e.g. -1 (parsed as u64
18446744073709551615) then wrong data was fed into btrfs_issue_discard,
which in turn leads to wrap-around when aligning the passed range and
results in wrong regions being discarded which leads to data corruption.

Fixes: c2d1b3aa ("btrfs: Honour FITRIM range constraints during free space trim")
Reviewed-by: default avatarQu Wenruo <wqu@suse.com>
Signed-off-by: default avatarNikolay Borisov <nborisov@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 06989c79
...@@ -11137,13 +11137,11 @@ int btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info, ...@@ -11137,13 +11137,11 @@ int btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info,
* it while performing the free space search since we have already * it while performing the free space search since we have already
* held back allocations. * held back allocations.
*/ */
static int btrfs_trim_free_extents(struct btrfs_device *device, static int btrfs_trim_free_extents(struct btrfs_device *device, u64 *trimmed)
struct fstrim_range *range, u64 *trimmed)
{ {
u64 start, len = 0, end = 0; u64 start = SZ_1M, len = 0, end = 0;
int ret; int ret;
start = max_t(u64, range->start, SZ_1M);
*trimmed = 0; *trimmed = 0;
/* Discard not supported = nothing to do. */ /* Discard not supported = nothing to do. */
...@@ -11186,22 +11184,6 @@ static int btrfs_trim_free_extents(struct btrfs_device *device, ...@@ -11186,22 +11184,6 @@ static int btrfs_trim_free_extents(struct btrfs_device *device,
break; break;
} }
/* Keep going until we satisfy minlen or reach end of space */
if (len < range->minlen) {
mutex_unlock(&fs_info->chunk_mutex);
start += len;
continue;
}
/* If we are out of the passed range break */
if (start > range->start + range->len - 1) {
mutex_unlock(&fs_info->chunk_mutex);
break;
}
start = max(range->start, start);
len = min(range->len, len);
ret = btrfs_issue_discard(device->bdev, start, len, ret = btrfs_issue_discard(device->bdev, start, len,
&bytes); &bytes);
if (!ret) if (!ret)
...@@ -11216,10 +11198,6 @@ static int btrfs_trim_free_extents(struct btrfs_device *device, ...@@ -11216,10 +11198,6 @@ static int btrfs_trim_free_extents(struct btrfs_device *device,
start += len; start += len;
*trimmed += bytes; *trimmed += bytes;
/* We've trimmed enough */
if (*trimmed >= range->len)
break;
if (fatal_signal_pending(current)) { if (fatal_signal_pending(current)) {
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
break; break;
...@@ -11303,7 +11281,7 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range) ...@@ -11303,7 +11281,7 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
mutex_lock(&fs_info->fs_devices->device_list_mutex); mutex_lock(&fs_info->fs_devices->device_list_mutex);
devices = &fs_info->fs_devices->devices; devices = &fs_info->fs_devices->devices;
list_for_each_entry(device, devices, dev_list) { list_for_each_entry(device, devices, dev_list) {
ret = btrfs_trim_free_extents(device, range, &group_trimmed); ret = btrfs_trim_free_extents(device, &group_trimmed);
if (ret) { if (ret) {
dev_failed++; dev_failed++;
dev_ret = ret; dev_ret = ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment