linux/fs/ext4
Eric Sandeen ef2b02d3e6 ext34: ensure do_split leaves enough free space in both blocks
The do_split() function for htree dir blocks is intended to split a leaf
block to make room for a new entry.  It sorts the entries in the original
block by hash value, then moves the last half of the entries to the new
block - without accounting for how much space this actually moves.  (IOW,
it moves half of the entry *count* not half of the entry *space*).  If by
chance we have both large & small entries, and we move only the smallest
entries, and we have a large new entry to insert, we may not have created
enough space for it.

The patch below stores each record size when calculating the dx_map, and
then walks the hash-sorted dx_map, calculating how many entries must be
moved to more evenly split the existing entries between the old block and
the new block, guaranteeing enough space for the new entry.

The dx_map "offs" member is reduced to u16 so that the overall map size
does not change - it is temporarily stored at the end of the new block, and
if it grows too large it may be overwritten.  By making offs and size both
u16, we won't grow the map size.

Also add a few comments to the functions involved.

This fixes the testcase reported by hooanon05@yahoo.co.jp on the
linux-ext4 list, "ext3 dir_index causes an error"

Thanks to Andreas Dilger for discussing the problem & solution with me.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Andreas Dilger <adilger@clusterfs.com>
Tested-by: Junjiro Okajima <hooanon05@yahoo.co.jp>
Cc: Theodore Ts'o <tytso@mit.edu>
Cc: <linux-ext4@vger.kernel.org>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-09-19 11:24:18 -07:00
..
acl.c Introduce is_owner_or_cap() to wrap CAP_FOWNER use with fsuid check 2007-07-17 12:00:03 -07:00
acl.h [PATCH] ext4: rename ext4 symbols to avoid duplication of ext3 symbols 2006-10-11 11:14:15 -07:00
balloc.c jbd2: Fix CONFIG_JBD_DEBUG ifdef to be CONFIG_JBD2_DEBUG 2007-07-18 08:57:06 -04:00
bitmap.c [PATCH] jbd2: enable building of jbd2 and have ext4 use it rather than jbd 2006-10-11 11:14:16 -07:00
dir.c readahead: split ondemand readahead interface into two functions 2007-07-19 10:04:44 -07:00
ext4_jbd2.c [PATCH] ext4: uninline large functions 2006-12-07 08:39:35 -08:00
extents.c "ext4_ext_put_in_cache" uses __u32 to receive physical block number 2007-07-31 15:39:37 -07:00
file.c fallocate support in ext4 2007-07-17 21:42:41 -04:00
fsync.c [PATCH] jbd2: enable building of jbd2 and have ext4 use it rather than jbd 2006-10-11 11:14:16 -07:00
hash.c [PATCH] remove many unneeded #includes of sched.h 2007-02-14 08:09:54 -08:00
ialloc.c ext4: Add nanosecond timestamps 2007-07-18 09:15:20 -04:00
inode.c fix ext4/JBD2 build warnings 2007-07-19 10:04:47 -07:00
ioctl.c ext4: Add nanosecond timestamps 2007-07-18 09:15:20 -04:00
Makefile [PATCH] ext4: uninline large functions 2006-12-07 08:39:35 -08:00
namei.c ext34: ensure do_split leaves enough free space in both blocks 2007-09-19 11:24:18 -07:00
namei.h [PATCH] ext4: rename ext4 symbols to avoid duplication of ext3 symbols 2006-10-11 11:14:15 -07:00
resize.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
super.c quota: fix infinite loop 2007-09-11 17:21:19 -07:00
symlink.c [PATCH] mark struct inode_operations const 1 2007-02-12 09:48:46 -08:00
xattr.c ext4: Expand extra_inodes space per the s_{want,min}_extra_isize fields 2007-07-18 09:19:57 -04:00
xattr.h ext4: Expand extra_inodes space per the s_{want,min}_extra_isize fields 2007-07-18 09:19:57 -04:00
xattr_security.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
xattr_trusted.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00
xattr_user.c header cleaning: don't include smp_lock.h when not used 2007-05-08 11:15:07 -07:00