diff options
Diffstat (limited to 'fs/xfs/scrub/nlinks.c')
| -rw-r--r-- | fs/xfs/scrub/nlinks.c | 34 | 
1 files changed, 31 insertions, 3 deletions
diff --git a/fs/xfs/scrub/nlinks.c b/fs/xfs/scrub/nlinks.c index 26721fab5cab..091c79e432e5 100644 --- a/fs/xfs/scrub/nlinks.c +++ b/fs/xfs/scrub/nlinks.c @@ -376,6 +376,36 @@ out_incomplete:  	return error;  } +static uint +xchk_nlinks_ilock_dir( +	struct xfs_inode	*ip) +{ +	uint			lock_mode = XFS_ILOCK_SHARED; + +	/* +	 * We're going to scan the directory entries, so we must be ready to +	 * pull the data fork mappings into memory if they aren't already. +	 */ +	if (xfs_need_iread_extents(&ip->i_df)) +		lock_mode = XFS_ILOCK_EXCL; + +	/* +	 * We're going to scan the parent pointers, so we must be ready to +	 * pull the attr fork mappings into memory if they aren't already. +	 */ +	if (xfs_has_parent(ip->i_mount) && xfs_inode_has_attr_fork(ip) && +	    xfs_need_iread_extents(&ip->i_af)) +		lock_mode = XFS_ILOCK_EXCL; + +	/* +	 * Take the IOLOCK so that other threads cannot start a directory +	 * update while we're scanning. +	 */ +	lock_mode |= XFS_IOLOCK_SHARED; +	xfs_ilock(ip, lock_mode); +	return lock_mode; +} +  /* Walk a directory to bump the observed link counts of the children. */  STATIC int  xchk_nlinks_collect_dir( @@ -394,8 +424,7 @@ xchk_nlinks_collect_dir(  		return 0;  	/* Prevent anyone from changing this directory while we walk it. */ -	xfs_ilock(dp, XFS_IOLOCK_SHARED); -	lock_mode = xfs_ilock_data_map_shared(dp); +	lock_mode = xchk_nlinks_ilock_dir(dp);  	/*  	 * The dotdot entry of an unlinked directory still points to the last @@ -452,7 +481,6 @@ out_abort:  	xchk_iscan_abort(&xnc->collect_iscan);  out_unlock:  	xfs_iunlock(dp, lock_mode); -	xfs_iunlock(dp, XFS_IOLOCK_SHARED);  	return error;  }  | 
