On 5/28/19 4:21 PM, Qu Wenruo wrote:
Normally the range->len is set to default value (U64_MAX), but when it's
not default value, we should check if the range overflows.
And if overflows, return -EINVAL before doing anything.
Signed-off-by: Qu Wenruo <w...@suse.com>
fstests patch
https://patchwork.kernel.org/patch/10964105/
makes the sub-test like [1] in generic/260 skipped
[1]
-----
fssize=$($DF_PROG -k | grep "$SCRATCH_MNT" | grep "$SCRATCH_DEV" | awk
'{print $3}')
beyond_eofs=$((fssize*2048))
fstrim -o $beyond_eofs $SCRATCH_MNT <-- should_fail
-----
Originally [1] reported expected EINVAL until the patch
6ba9fc8e628b btrfs: Ensure btrfs_trim_fs can trim the whole filesystem
Not sure how will some of the production machines will find this as,
not compatible with previous versions? Nevertheless in practical terms
things are fine.
Reviewed-by: Anand Jain <anand.j...@oracle.com>
Thanks, Anand
---
fs/btrfs/extent-tree.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index f79e477a378e..62bfba6d3c07 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -11245,6 +11245,7 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct
fstrim_range *range)
struct btrfs_device *device;
struct list_head *devices;
u64 group_trimmed;
+ u64 range_end = U64_MAX;
u64 start;
u64 end;
u64 trimmed = 0;
@@ -11254,16 +11255,23 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info,
struct fstrim_range *range)
int dev_ret = 0;
int ret = 0;
+ /*
+ * Check range overflow if range->len is set.
+ * The default range->len is U64_MAX.
+ */
+ if (range->len != U64_MAX && check_add_overflow(range->start,
+ range->len, &range_end))
+ return -EINVAL;
+
cache = btrfs_lookup_first_block_group(fs_info, range->start);
for (; cache; cache = next_block_group(cache)) {
- if (cache->key.objectid >= (range->start + range->len)) {
+ if (cache->key.objectid >= range_end) {
btrfs_put_block_group(cache);
break;
}
start = max(range->start, cache->key.objectid);
- end = min(range->start + range->len,
- cache->key.objectid + cache->key.offset);
+ end = min(range_end, cache->key.objectid + cache->key.offset);
if (end - start >= range->minlen) {
if (!block_group_cache_done(cache)) {