xfs: fix incorrect i_nlink caused by inode racing
commit28b4b05963
upstream. 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:ff7bebeb91
("xfs: refactor the inode recycling code") # goes further back than this Signed-off-by: Long Li <leo.lilong@huawei.com> Reviewed-by: Darrick J. Wong <djwong@kernel.org> Signed-off-by: Darrick J. Wong <djwong@kernel.org> Signed-off-by: Jinliang Zheng <alexjlzheng@tencent.com> Reviewed-by: Hui Li <caelli@tencent.com> Signed-off-by: Jianping Liu <frankjpliu@tencent.com>
This commit is contained in:
parent
793b06ed32
commit
739bb98579
|
@ -412,6 +412,11 @@ xfs_iget_cache_hit(
|
|||
goto out_error;
|
||||
}
|
||||
|
||||
if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {
|
||||
error = -EAGAIN;
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to set XFS_IRECLAIM to prevent xfs_reclaim_inode
|
||||
* from stomping over us while we recycle the inode. We can't
|
||||
|
@ -424,6 +429,7 @@ xfs_iget_cache_hit(
|
|||
rcu_read_unlock();
|
||||
|
||||
error = xfs_reinit_inode(mp, inode);
|
||||
xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
||||
if (error) {
|
||||
bool wake;
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue