• Long Li's avatar
    xfs: fix incorrect i_nlink caused by inode racing · 28b4b059
    Long Li authored
    The following error occurred during the fsstress test:
    
    XFS: Assertion failed: VFS_I(ip)->i_nlink >= 2, file: fs/xfs/xfs_inode.c, line: 2452
    
    The problem was that inode race condition causes incorrect i_nlink to be
    written to disk, and then it is read into memory. Consider the following
    call graph, inodes that are marked as both XFS_IFLUSHING and
    XFS_IRECLAIMABLE, i_nlink will be reset to 1 and then restored to original
    value in xfs_reinit_inode(). Therefore, the i_nlink of directory on disk
    may be set to 1.
    
      xfsaild
          xfs_inode_item_push
              xfs_iflush_cluster
                  xfs_iflush
                      xfs_inode_to_disk
    
      xfs_iget
          xfs_iget_cache_hit
              xfs_iget_recycle
                  xfs_reinit_inode
                      inode_init_always
    
    xfs_reinit_inode() needs to hold the ILOCK_EXCL as it is changing internal
    inode state and can race with other RCU protected inode lookups. On the
    read side, xfs_iflush_cluster() grabs the ILOCK_SHARED while under rcu +
    ip->i_flags_lock, and so xfs_iflush/xfs_inode_to_disk() are protected from
    racing inode updates (during transactions) by that lock.
    
    Fixes: ff7bebeb ("xfs: refactor the inode recycling code") # goes further back than this
    Signed-off-by: default avatarLong Li <leo.lilong@huawei.com>
    Reviewed-by: default avatarDarrick J. Wong <djwong@kernel.org>
    Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
    28b4b059
xfs_icache.c 55.4 KB