]>
Commit | Line | Data |
---|---|---|
f5edbeaf GKH |
1 | From c2d1b3aae33605a61cbab445d8ae1c708ccd2698 Mon Sep 17 00:00:00 2001 |
2 | From: Nikolay Borisov <nborisov@suse.com> | |
3 | Date: Mon, 25 Mar 2019 14:31:21 +0200 | |
4 | Subject: btrfs: Honour FITRIM range constraints during free space trim | |
5 | ||
6 | From: Nikolay Borisov <nborisov@suse.com> | |
7 | ||
8 | commit c2d1b3aae33605a61cbab445d8ae1c708ccd2698 upstream. | |
9 | ||
10 | Up until now trimming the freespace was done irrespective of what the | |
11 | arguments of the FITRIM ioctl were. For example fstrim's -o/-l arguments | |
12 | will be entirely ignored. Fix it by correctly handling those paramter. | |
13 | This requires breaking if the found freespace extent is after the end of | |
14 | the passed range as well as completing trim after trimming | |
15 | fstrim_range::len bytes. | |
16 | ||
17 | Fixes: 499f377f49f0 ("btrfs: iterate over unused chunk space in FITRIM") | |
18 | CC: stable@vger.kernel.org # 4.4+ | |
19 | Signed-off-by: Nikolay Borisov <nborisov@suse.com> | |
20 | Reviewed-by: David Sterba <dsterba@suse.com> | |
21 | Signed-off-by: David Sterba <dsterba@suse.com> | |
22 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
23 | ||
24 | --- | |
25 | fs/btrfs/extent-tree.c | 25 +++++++++++++++++++------ | |
26 | 1 file changed, 19 insertions(+), 6 deletions(-) | |
27 | ||
28 | --- a/fs/btrfs/extent-tree.c | |
29 | +++ b/fs/btrfs/extent-tree.c | |
30 | @@ -11315,9 +11315,9 @@ int btrfs_error_unpin_extent_range(struc | |
31 | * held back allocations. | |
32 | */ | |
33 | static int btrfs_trim_free_extents(struct btrfs_device *device, | |
34 | - u64 minlen, u64 *trimmed) | |
35 | + struct fstrim_range *range, u64 *trimmed) | |
36 | { | |
37 | - u64 start = 0, len = 0; | |
38 | + u64 start = range->start, len = 0; | |
39 | int ret; | |
40 | ||
41 | *trimmed = 0; | |
42 | @@ -11360,8 +11360,8 @@ static int btrfs_trim_free_extents(struc | |
43 | if (!trans) | |
44 | up_read(&fs_info->commit_root_sem); | |
45 | ||
46 | - ret = find_free_dev_extent_start(trans, device, minlen, start, | |
47 | - &start, &len); | |
48 | + ret = find_free_dev_extent_start(trans, device, range->minlen, | |
49 | + start, &start, &len); | |
50 | if (trans) { | |
51 | up_read(&fs_info->commit_root_sem); | |
52 | btrfs_put_transaction(trans); | |
53 | @@ -11374,6 +11374,16 @@ static int btrfs_trim_free_extents(struc | |
54 | break; | |
55 | } | |
56 | ||
57 | + /* If we are out of the passed range break */ | |
58 | + if (start > range->start + range->len - 1) { | |
59 | + mutex_unlock(&fs_info->chunk_mutex); | |
60 | + ret = 0; | |
61 | + break; | |
62 | + } | |
63 | + | |
64 | + start = max(range->start, start); | |
65 | + len = min(range->len, len); | |
66 | + | |
67 | ret = btrfs_issue_discard(device->bdev, start, len, &bytes); | |
68 | mutex_unlock(&fs_info->chunk_mutex); | |
69 | ||
70 | @@ -11383,6 +11393,10 @@ static int btrfs_trim_free_extents(struc | |
71 | start += len; | |
72 | *trimmed += bytes; | |
73 | ||
74 | + /* We've trimmed enough */ | |
75 | + if (*trimmed >= range->len) | |
76 | + break; | |
77 | + | |
78 | if (fatal_signal_pending(current)) { | |
79 | ret = -ERESTARTSYS; | |
80 | break; | |
81 | @@ -11466,8 +11480,7 @@ int btrfs_trim_fs(struct btrfs_fs_info * | |
82 | mutex_lock(&fs_info->fs_devices->device_list_mutex); | |
83 | devices = &fs_info->fs_devices->devices; | |
84 | list_for_each_entry(device, devices, dev_list) { | |
85 | - ret = btrfs_trim_free_extents(device, range->minlen, | |
86 | - &group_trimmed); | |
87 | + ret = btrfs_trim_free_extents(device, range, &group_trimmed); | |
88 | if (ret) { | |
89 | dev_failed++; | |
90 | dev_ret = ret; |