From: Jan Kara <jack@suse.cz>
To: Lukas Czerner <lczerner@redhat.com>
Cc: linux-ext4@vger.kernel.org, tytso@mit.edu
Subject: Re: [PATCH 1/4 v2] ext4: fix start and len arguments handling in ext4_trim_fs()
Date: Mon, 5 Mar 2012 13:37:57 +0100 [thread overview]
Message-ID: <20120305123757.GD6643@quack.suse.cz> (raw)
In-Reply-To: <1330690318-22627-1-git-send-email-lczerner@redhat.com>
On Fri 02-03-12 13:11:55, Lukas Czerner wrote:
> The overflow can happen when we are calling get_group_no_and_offset()
> which stores the group number in the ext4_grpblk_t type which is
> actually int. However when the blocknr is big enough the group number
> might be bigger than ext4_grpblk_t resulting in overflow. This will
> most likely happen with FITRIM default argument len = ULLONG_MAX.
>
> Fix this by using "end" variable instead of "start+len" as it is easier
> to get right and specifically check that the end is not beyond the end
> of the file system, so we are sure that the result of
> get_group_no_and_offset() will not overflow. Otherwise truncate it to
> the size of the file system.
Looks good. You can add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
>
> Signed-off-by: Lukas Czerner <lczerner@redhat.com>
> ---
> v2: Squash the 'don't forget to discard last block in a group' into this one
> since this is the commit which reveals the bug.
>
> fs/ext4/mballoc.c | 57 +++++++++++++++++++++++++++-------------------------
> 1 files changed, 30 insertions(+), 27 deletions(-)
>
> diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
> index cb990b2..16a3aeb 100644
> --- a/fs/ext4/mballoc.c
> +++ b/fs/ext4/mballoc.c
> @@ -4971,11 +4971,11 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
> start = (e4b.bd_info->bb_first_free > start) ?
> e4b.bd_info->bb_first_free : start;
>
> - while (start < max) {
> - start = mb_find_next_zero_bit(bitmap, max, start);
> - if (start >= max)
> + while (start <= max) {
> + start = mb_find_next_zero_bit(bitmap, max + 1, start);
> + if (start > max)
> break;
> - next = mb_find_next_bit(bitmap, max, start);
> + next = mb_find_next_bit(bitmap, max + 1, start);
>
> if ((next - start) >= minblocks) {
> ext4_trim_extent(sb, start,
> @@ -5027,37 +5027,36 @@ out:
> int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
> {
> struct ext4_group_info *grp;
> - ext4_group_t first_group, last_group;
> - ext4_group_t group, ngroups = ext4_get_groups_count(sb);
> + ext4_group_t group, first_group, last_group;
> ext4_grpblk_t cnt = 0, first_cluster, last_cluster;
> - uint64_t start, len, minlen, trimmed = 0;
> + uint64_t start, end, minlen, trimmed = 0;
> ext4_fsblk_t first_data_blk =
> le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
> + ext4_fsblk_t max_blks = ext4_blocks_count(EXT4_SB(sb)->s_es);
> int ret = 0;
>
> start = range->start >> sb->s_blocksize_bits;
> - len = range->len >> sb->s_blocksize_bits;
> + end = start + (range->len >> sb->s_blocksize_bits) - 1;
> minlen = range->minlen >> sb->s_blocksize_bits;
>
> - if (unlikely(minlen > EXT4_CLUSTERS_PER_GROUP(sb)))
> + if (unlikely(minlen > EXT4_CLUSTERS_PER_GROUP(sb)) ||
> + unlikely(start >= max_blks))
> return -EINVAL;
> - if (start + len <= first_data_blk)
> + if (end >= max_blks)
> + end = max_blks - 1;
> + if (end <= first_data_blk)
> goto out;
> - if (start < first_data_blk) {
> - len -= first_data_blk - start;
> + if (start < first_data_blk)
> start = first_data_blk;
> - }
>
> - /* Determine first and last group to examine based on start and len */
> + /* Determine first and last group to examine based on start and end */
> ext4_get_group_no_and_offset(sb, (ext4_fsblk_t) start,
> &first_group, &first_cluster);
> - ext4_get_group_no_and_offset(sb, (ext4_fsblk_t) (start + len),
> + ext4_get_group_no_and_offset(sb, (ext4_fsblk_t) end,
> &last_group, &last_cluster);
> - last_group = (last_group > ngroups - 1) ? ngroups - 1 : last_group;
> - last_cluster = EXT4_CLUSTERS_PER_GROUP(sb);
>
> - if (first_group > last_group)
> - return -EINVAL;
> + /* end now represents the last cluster to discard in this group */
> + end = EXT4_CLUSTERS_PER_GROUP(sb) - 1;
>
> for (group = first_group; group <= last_group; group++) {
> grp = ext4_get_group_info(sb, group);
> @@ -5069,24 +5068,28 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
> }
>
> /*
> - * For all the groups except the last one, last block will
> - * always be EXT4_BLOCKS_PER_GROUP(sb), so we only need to
> - * change it for the last group in which case start +
> - * len < EXT4_BLOCKS_PER_GROUP(sb).
> + * For all the groups except the last one, last cluster will
> + * always be EXT4_CLUSTERS_PER_GROUP(sb)-1, so we only need to
> + * change it for the last group, note that last_cluster is
> + * already computed earlier by ext4_get_group_no_and_offset()
> */
> - if (first_cluster + len < EXT4_CLUSTERS_PER_GROUP(sb))
> - last_cluster = first_cluster + len;
> - len -= last_cluster - first_cluster;
> + if (group == last_group)
> + end = last_cluster;
>
> if (grp->bb_free >= minlen) {
> cnt = ext4_trim_all_free(sb, group, first_cluster,
> - last_cluster, minlen);
> + end, minlen);
> if (cnt < 0) {
> ret = cnt;
> break;
> }
> }
> trimmed += cnt;
> +
> + /*
> + * For every group except the first one, we are sure
> + * that the first cluster to discard will be cluster #0.
> + */
> first_cluster = 0;
> }
> range->len = trimmed * sb->s_blocksize;
> --
> 1.7.4.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Jan Kara <jack@suse.cz>
SUSE Labs, CR
next prev parent reply other threads:[~2012-03-05 12:37 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-03-02 12:11 [PATCH 1/4 v2] ext4: fix start and len arguments handling in ext4_trim_fs() Lukas Czerner
2012-03-02 12:11 ` [PATCH 2/4 v2] ext4: Fix trimmed block count computing Lukas Czerner
2012-03-05 12:38 ` Jan Kara
2012-03-22 1:22 ` Ted Ts'o
2012-03-02 12:11 ` [PATCH 3/4 v2] ext4: Always set then trimmed blocks count into len Lukas Czerner
2012-03-05 12:38 ` Jan Kara
2012-03-22 1:23 ` Ted Ts'o
2012-03-02 12:11 ` [PATCH 4/4 v2] ext4: Do not discard group with BLOCK_UNINIT set Lukas Czerner
2012-03-05 12:41 ` Jan Kara
2012-03-05 13:12 ` Lukas Czerner
2012-03-06 22:18 ` Ted Ts'o
2012-03-07 7:10 ` Lukas Czerner
2012-03-07 17:22 ` Ted Ts'o
2012-03-05 12:37 ` Jan Kara [this message]
2012-03-22 1:22 ` [PATCH 1/4 v2] ext4: fix start and len arguments handling in ext4_trim_fs() Ted Ts'o
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20120305123757.GD6643@quack.suse.cz \
--to=jack@suse.cz \
--cc=lczerner@redhat.com \
--cc=linux-ext4@vger.kernel.org \
--cc=tytso@mit.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).