aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikolay Borisov <nborisov@suse.com>2019-06-03 06:06:00 -0400
committerDavid Sterba <dsterba@suse.com>2019-06-07 08:52:05 -0400
commit8103d10b71610aa65a65d6611cd3ad3f3bd7beeb (patch)
tree11af4b39c6e5589054d62fbbd23a5ea231d62266
parent06989c799f04810f6876900d4760c0edda369cf7 (diff)
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: c2d1b3aae336 ("btrfs: Honour FITRIM range constraints during free space trim") Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Nikolay Borisov <nborisov@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/extent-tree.c28
1 files changed, 3 insertions, 25 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 1aee51a9f3bf..c7adff343ba9 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -11137,13 +11137,11 @@ int btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info,
11137 * it while performing the free space search since we have already 11137 * it while performing the free space search since we have already
11138 * held back allocations. 11138 * held back allocations.
11139 */ 11139 */
11140static int btrfs_trim_free_extents(struct btrfs_device *device, 11140static int btrfs_trim_free_extents(struct btrfs_device *device, u64 *trimmed)
11141 struct fstrim_range *range, u64 *trimmed)
11142{ 11141{
11143 u64 start, len = 0, end = 0; 11142 u64 start = SZ_1M, len = 0, end = 0;
11144 int ret; 11143 int ret;
11145 11144
11146 start = max_t(u64, range->start, SZ_1M);
11147 *trimmed = 0; 11145 *trimmed = 0;
11148 11146
11149 /* Discard not supported = nothing to do. */ 11147 /* Discard not supported = nothing to do. */
@@ -11186,22 +11184,6 @@ static int btrfs_trim_free_extents(struct btrfs_device *device,
11186 break; 11184 break;
11187 } 11185 }
11188 11186
11189 /* Keep going until we satisfy minlen or reach end of space */
11190 if (len < range->minlen) {
11191 mutex_unlock(&fs_info->chunk_mutex);
11192 start += len;
11193 continue;
11194 }
11195
11196 /* If we are out of the passed range break */
11197 if (start > range->start + range->len - 1) {
11198 mutex_unlock(&fs_info->chunk_mutex);
11199 break;
11200 }
11201
11202 start = max(range->start, start);
11203 len = min(range->len, len);
11204
11205 ret = btrfs_issue_discard(device->bdev, start, len, 11187 ret = btrfs_issue_discard(device->bdev, start, len,
11206 &bytes); 11188 &bytes);
11207 if (!ret) 11189 if (!ret)
@@ -11216,10 +11198,6 @@ static int btrfs_trim_free_extents(struct btrfs_device *device,
11216 start += len; 11198 start += len;
11217 *trimmed += bytes; 11199 *trimmed += bytes;
11218 11200
11219 /* We've trimmed enough */
11220 if (*trimmed >= range->len)
11221 break;
11222
11223 if (fatal_signal_pending(current)) { 11201 if (fatal_signal_pending(current)) {
11224 ret = -ERESTARTSYS; 11202 ret = -ERESTARTSYS;
11225 break; 11203 break;
@@ -11303,7 +11281,7 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range)
11303 mutex_lock(&fs_info->fs_devices->device_list_mutex); 11281 mutex_lock(&fs_info->fs_devices->device_list_mutex);
11304 devices = &fs_info->fs_devices->devices; 11282 devices = &fs_info->fs_devices->devices;
11305 list_for_each_entry(device, devices, dev_list) { 11283 list_for_each_entry(device, devices, dev_list) {
11306 ret = btrfs_trim_free_extents(device, range, &group_trimmed); 11284 ret = btrfs_trim_free_extents(device, &group_trimmed);
11307 if (ret) { 11285 if (ret) {
11308 dev_failed++; 11286 dev_failed++;
11309 dev_ret = ret; 11287 dev_ret = ret;