• A
    ext4: Fix the race between read_inode_bitmap() and ext4_new_inode() · 39341867
    Aneesh Kumar K.V 提交于
    We need to make sure we update the inode bitmap and clear
    EXT4_BG_INODE_UNINIT flag with sb_bgl_lock held, since
    ext4_read_inode_bitmap() looks at EXT4_BG_INODE_UNINIT to decide
    whether to initialize the inode bitmap each time it is called.
    (introduced by commit c806e68f.)
    
    ext4_read_inode_bitmap does:
    
    spin_lock(sb_bgl_lock(EXT4_SB(sb), block_group));
    if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
    	ext4_init_inode_bitmap(sb, bh, block_group, desc);
    
    and ext4_new_inode does
    if (!ext4_set_bit_atomic(sb_bgl_lock(sbi, group),
                       ino, inode_bitmap_bh->b_data))
    		   ......
    		   ...
    spin_lock(sb_bgl_lock(sbi, group));
    
    gdp->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
    i.e., on allocation we update the bitmap then we take the sb_bgl_lock
    and clear the EXT4_BG_INODE_UNINIT flag. What can happen is a
    parallel ext4_read_inode_bitmap can zero out the bitmap in between
    the above ext4_set_bit_atomic and spin_lock(sb_bg_lock..)
    
    The race results in below user visible errors
    EXT4-fs error (device sdb1): ext4_free_inode: bit already cleared for inode 168449
    EXT4-fs warning (device sdb1): ext4_unlink: Deleting nonexistent file ...
    EXT4-fs warning (device sdb1): ext4_rmdir: empty directory has too many links ...
    # ls -al /mnt/tmp/f/p369/d3/d6/d39/db2/dee/d10f/d3f/l71
    ls: /mnt/tmp/f/p369/d3/d6/d39/db2/dee/d10f/d3f/l71: Stale NFS file handle
    Signed-off-by: NAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
    Signed-off-by: N"Theodore Ts'o" <tytso@mit.edu>
    Cc: stable@kernel.org
    39341867
ialloc.c 29.9 KB