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@xxxxxxxxx> 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? > 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. Honza -- Jan Kara <jack@xxxxxxxx> SUSE Labs, CR