On Jun 17, 2020, at 1:19 PM, Eric Sandeen <sandeen@xxxxxxxxxx> wrote: > > If for any reason a directory passed to do_split() does not have enough > active entries to exceed half the size of the block, we can end up > iterating over all "count" entries without finding a split point. > > In this case, count == move, and split will be zero, and we will > attempt a negative index into map[]. > > Guard against this by detecting this case, and falling back to > split-to-half-of-count instead; in this case we will still have > plenty of space (> half blocksize) in each split block. > > Fixes: ef2b02d3e617 ("ext34: ensure do_split leaves enough free space in both blocks") > Signed-off-by: Eric Sandeen <sandeen@xxxxxxxxxx> Reviewed-by: Andreas Dilger <adilger@xxxxxxxxx> > --- > > diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c > index a8aca4772aaa..8b60881f07ee 100644 > --- a/fs/ext4/namei.c > +++ b/fs/ext4/namei.c > @@ -1858,7 +1858,7 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, > blocksize, hinfo, map); > map -= count; > dx_sort_map(map, count); > - /* Split the existing block in the middle, size-wise */ > + /* Ensure that neither split block is over half full */ > size = 0; > move = 0; > for (i = count-1; i >= 0; i--) { > @@ -1868,8 +1868,18 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, > size += map[i].size; > move++; > } > - /* map index at which we will split */ > - split = count - move; > + /* > + * map index at which we will split > + * > + * If the sum of active entries didn't exceed half the block size, just > + * split it in half by count; each resulting block will have at least > + * half the space free. > + */ > + if (i > 0) > + split = count - move; > + else > + split = count/2; > + > hash2 = map[split].hash; > continued = hash2 == map[split - 1].hash; > dxtrace(printk(KERN_INFO "Split block %lu at %x, %i/%i\n", > > Cheers, Andreas
Attachment:
signature.asc
Description: Message signed with OpenPGP