Skip to content
  • Eric Sandeen's avatar
    ext34: ensure do_split leaves enough free space in both blocks · ef2b02d3
    Eric Sandeen authored
    
    
    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: default avatarEric Sandeen <sandeen@redhat.com>
    Signed-off-by: default avatarAndreas Dilger <adilger@clusterfs.com>
    Tested-by: default avatarJunjiro 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: default avatarAndrew Morton <akpm@linux-foundation.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    ef2b02d3