| From 9175ddb2401f7f594a2a00cb1c43451473eec4cd Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 12 Nov 2021 16:22:02 +0100 |
| Subject: ext4: avoid trim error on fs with small groups |
| |
| From: Jan Kara <jack@suse.cz> |
| |
| [ Upstream commit 173b6e383d2a204c9921ffc1eca3b87aa2106c33 ] |
| |
| A user reported FITRIM ioctl failing for him on ext4 on some devices |
| without apparent reason. After some debugging we've found out that |
| these devices (being LVM volumes) report rather large discard |
| granularity of 42MB and the filesystem had 1k blocksize and thus group |
| size of 8MB. Because ext4 FITRIM implementation puts discard |
| granularity into minlen, ext4_trim_fs() declared the trim request as |
| invalid. However just silently doing nothing seems to be a more |
| appropriate reaction to such combination of parameters since user did |
| not specify anything wrong. |
| |
| CC: Lukas Czerner <lczerner@redhat.com> |
| Fixes: 5c2ed62fd447 ("ext4: Adjust minlen with discard_granularity in the FITRIM ioctl") |
| Signed-off-by: Jan Kara <jack@suse.cz> |
| Link: https://lore.kernel.org/r/20211112152202.26614-1-jack@suse.cz |
| Signed-off-by: Theodore Ts'o <tytso@mit.edu> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| fs/ext4/ioctl.c | 2 -- |
| fs/ext4/mballoc.c | 8 ++++++++ |
| 2 files changed, 8 insertions(+), 2 deletions(-) |
| |
| diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c |
| index 6718c7ccd6314..3bd79fc4e9487 100644 |
| --- a/fs/ext4/ioctl.c |
| +++ b/fs/ext4/ioctl.c |
| @@ -992,8 +992,6 @@ resizefs_out: |
| sizeof(range))) |
| return -EFAULT; |
| |
| - range.minlen = max((unsigned int)range.minlen, |
| - q->limits.discard_granularity); |
| ret = ext4_trim_fs(sb, &range); |
| if (ret < 0) |
| return ret; |
| diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c |
| index c40d3c44a1d69..28bee66c5fbf0 100644 |
| --- a/fs/ext4/mballoc.c |
| +++ b/fs/ext4/mballoc.c |
| @@ -5284,6 +5284,7 @@ out: |
| */ |
| int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) |
| { |
| + struct request_queue *q = bdev_get_queue(sb->s_bdev); |
| struct ext4_group_info *grp; |
| ext4_group_t group, first_group, last_group; |
| ext4_grpblk_t cnt = 0, first_cluster, last_cluster; |
| @@ -5302,6 +5303,13 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) |
| start >= max_blks || |
| range->len < sb->s_blocksize) |
| return -EINVAL; |
| + /* No point to try to trim less than discard granularity */ |
| + if (range->minlen < q->limits.discard_granularity) { |
| + minlen = EXT4_NUM_B2C(EXT4_SB(sb), |
| + q->limits.discard_granularity >> sb->s_blocksize_bits); |
| + if (minlen > EXT4_CLUSTERS_PER_GROUP(sb)) |
| + goto out; |
| + } |
| if (end >= max_blks) |
| end = max_blks - 1; |
| if (end <= first_data_blk) |
| -- |
| 2.34.1 |
| |