[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20180607204718.bjpk5jl2ul4dhyi4@localhost.localdomain>
Date: Thu, 7 Jun 2018 16:47:18 -0400
From: Eric Whitney <enwlinux@...il.com>
To: Jan Kara <jack@...e.cz>
Cc: Eric Whitney <enwlinux@...il.com>, linux-ext4@...r.kernel.org,
tytso@....edu
Subject: Re: [RFC PATCH 1/5] ext4: fix reserved cluster accounting at delayed
write time
* Jan Kara <jack@...e.cz>:
> On Sun 13-05-18 13:56:20, Eric Whitney wrote:
> > The code in ext4_da_map_blocks sometimes reserves space for more
> > delayed allocated clusters than it should, resulting in premature
> > ENOSPC, exceeded quota, and inaccurate free space reporting.
> >
> > It fails to check the extents status tree for written and unwritten
> > clusters which have already been allocated and which share a cluster
> > with the block being delayed allocated. In addition, it fails to
> > continue on and search the extent tree when no delayed allocated or
> > allocated clusters have been found in the extents status tree. Written
> > extents may be purged from the extents status tree under memory pressure.
> > Only delayed and unwritten delayed extents are guaranteed to be retained.
> >
> > Signed-off-by: Eric Whitney <enwlinux@...il.com>
>
> Thanks for the patch Eric. Some comments are below.
>
> > diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
> > index c969275ce3ee..872782ba8bc3 100644
> > --- a/fs/ext4/extents.c
> > +++ b/fs/ext4/extents.c
> > @@ -3846,6 +3846,47 @@ int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk)
> > return ext4_find_delalloc_range(inode, lblk_start, lblk_end);
> > }
> >
> > +/*
> > + * If the block range specified by @start and @end contains an es extent
> > + * matched by the matching function specified by @match_fn, return 1. Else,
> > + * return 0.
> > + */
> > +int ext4_find_range(struct inode *inode,
> > + int (*match_fn)(struct extent_status *es),
> > + ext4_lblk_t start,
> > + ext4_lblk_t end)
> > +{
> > + struct extent_status es;
> > +
> > + ext4_es_find_extent_range(inode, match_fn, start, end, &es);
> > + if (es.es_len == 0)
> > + return 0; /* there is no matching extent in this tree */
> > + else if (es.es_lblk <= start &&
> > + start < es.es_lblk + es.es_len)
> > + return 1;
> > + else if (start <= es.es_lblk && es.es_lblk <= end)
> > + return 1;
> > + else
> > + return 0;
>
> No need to elses here. Also how could is possibly happen that es.es_len > 0
> and we don't have an extent we want? That would be a bug in
> ext4_es_find_extent_range(), wouldn't it?
Hi, Jan:
Yes, I just cloned ext4_find_delalloc_range() here without looking too
critically at it. I'll clean this up.
I think we can get an out of range extent here given the implementation
of __es_tree_search(), called by ext4_es_find_extent_range(). If "start"
isn't contained in an extent in the extents status tree, we could get back
an extent containing block numbers bigger than "start". Rejecting a match
if es.es_lblk > end should handle that (and a xfstests-bld run of the 4k
test case appears to confirm). So the conditional becomes:
if (es.es_lblk > end || es.es_len == 0)
return 0;
else
return 1;
>
> > diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c
> > index 763ef185dd17..0c395b5a57a2 100644
> > --- a/fs/ext4/extents_status.c
> > +++ b/fs/ext4/extents_status.c
> > @@ -296,6 +296,70 @@ void ext4_es_find_delayed_extent_range(struct inode *inode,
> > trace_ext4_es_find_delayed_extent_range_exit(inode, es);
> > }
> >
> > +/*
> > + * Find the first es extent in the block range specified by @lblk and @end
> > + * that satisfies the matching function specified by @match_fn. If a
> > + * match is found, it's returned in @es. If not, a struct extents_status
> > + * is returned in @es whose es_lblk, es_len, and es_pblk components are 0.
> > + *
> > + * This function is derived from ext4_es_find_delayed_extent_range().
> > + * In the future, it could be used to replace it with the use of a suitable
> > + * matching function to avoid redundant code.
> > + */
>
> Yes, please do that - write a separate patch implementing
> ext4_es_find_extent_range() and make ext4_es_find_delayed_extent_range()
> use it.
>
> Otherwise the patch looks good to me.
I'll do that.
Thanks for your review!
Eric
>
> Honza
> --
> Jan Kara <jack@...e.com>
> SUSE Labs, CR
Powered by blists - more mailing lists