Commit 7c2d238a authored by Darrick J. Wong's avatar Darrick J. Wong
Browse files

xfs: allow xfs_lock_two_inodes to take different EXCL/SHARED modes



Refactor xfs_lock_two_inodes to take separate locking modes for each
inode.  Specifically, this enables us to take a SHARED lock on one inode
and an EXCL lock on the other.  The lock class (MMAPLOCK/ILOCK) must be
the same for each inode.

Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 1364b1d4
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -1872,7 +1872,7 @@ xfs_swap_extents(
	 */
	 */
	lock_two_nondirectories(VFS_I(ip), VFS_I(tip));
	lock_two_nondirectories(VFS_I(ip), VFS_I(tip));
	lock_flags = XFS_MMAPLOCK_EXCL;
	lock_flags = XFS_MMAPLOCK_EXCL;
	xfs_lock_two_inodes(ip, tip, XFS_MMAPLOCK_EXCL);
	xfs_lock_two_inodes(ip, XFS_MMAPLOCK_EXCL, tip, XFS_MMAPLOCK_EXCL);


	/* Verify that both files have the same format */
	/* Verify that both files have the same format */
	if ((VFS_I(ip)->i_mode & S_IFMT) != (VFS_I(tip)->i_mode & S_IFMT)) {
	if ((VFS_I(ip)->i_mode & S_IFMT) != (VFS_I(tip)->i_mode & S_IFMT)) {
@@ -1919,7 +1919,7 @@ xfs_swap_extents(
	 * Lock and join the inodes to the tansaction so that transaction commit
	 * Lock and join the inodes to the tansaction so that transaction commit
	 * or cancel will unlock the inodes from this point onwards.
	 * or cancel will unlock the inodes from this point onwards.
	 */
	 */
	xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);
	xfs_lock_two_inodes(ip, XFS_ILOCK_EXCL, tip, XFS_ILOCK_EXCL);
	lock_flags |= XFS_ILOCK_EXCL;
	lock_flags |= XFS_ILOCK_EXCL;
	xfs_trans_ijoin(tp, ip, 0);
	xfs_trans_ijoin(tp, ip, 0);
	xfs_trans_ijoin(tp, tip, 0);
	xfs_trans_ijoin(tp, tip, 0);
+32 −17
Original line number Original line Diff line number Diff line
@@ -546,23 +546,36 @@ xfs_lock_inodes(


/*
/*
 * xfs_lock_two_inodes() can only be used to lock one type of lock at a time -
 * xfs_lock_two_inodes() can only be used to lock one type of lock at a time -
 * the iolock, the mmaplock or the ilock, but not more than one at a time. If we
 * the mmaplock or the ilock, but not more than one type at a time. If we lock
 * lock more than one at a time, lockdep will report false positives saying we
 * more than one at a time, lockdep will report false positives saying we have
 * have violated locking orders.
 * violated locking orders.  The iolock must be double-locked separately since
 * we use i_rwsem for that.  We now support taking one lock EXCL and the other
 * SHARED.
 */
 */
void
void
xfs_lock_two_inodes(
xfs_lock_two_inodes(
	xfs_inode_t		*ip0,
	struct xfs_inode	*ip0,
	xfs_inode_t		*ip1,
	uint			ip0_mode,
	uint			lock_mode)
	struct xfs_inode	*ip1,
	uint			ip1_mode)
{
{
	xfs_inode_t		*temp;
	struct xfs_inode	*temp;
	uint			mode_temp;
	int			attempts = 0;
	int			attempts = 0;
	xfs_log_item_t		*lp;
	xfs_log_item_t		*lp;


	ASSERT(!(lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL)));
	ASSERT(hweight32(ip0_mode) == 1);
	if (lock_mode & (XFS_MMAPLOCK_SHARED|XFS_MMAPLOCK_EXCL))
	ASSERT(hweight32(ip1_mode) == 1);
		ASSERT(!(lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL)));
	ASSERT(!(ip0_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL)));
	ASSERT(!(ip1_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL)));
	ASSERT(!(ip0_mode & (XFS_MMAPLOCK_SHARED|XFS_MMAPLOCK_EXCL)) ||
	       !(ip0_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL)));
	ASSERT(!(ip1_mode & (XFS_MMAPLOCK_SHARED|XFS_MMAPLOCK_EXCL)) ||
	       !(ip1_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL)));
	ASSERT(!(ip1_mode & (XFS_MMAPLOCK_SHARED|XFS_MMAPLOCK_EXCL)) ||
	       !(ip0_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL)));
	ASSERT(!(ip0_mode & (XFS_MMAPLOCK_SHARED|XFS_MMAPLOCK_EXCL)) ||
	       !(ip1_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL)));


	ASSERT(ip0->i_ino != ip1->i_ino);
	ASSERT(ip0->i_ino != ip1->i_ino);


@@ -570,10 +583,13 @@ xfs_lock_two_inodes(
		temp = ip0;
		temp = ip0;
		ip0 = ip1;
		ip0 = ip1;
		ip1 = temp;
		ip1 = temp;
		mode_temp = ip0_mode;
		ip0_mode = ip1_mode;
		ip1_mode = mode_temp;
	}
	}


 again:
 again:
	xfs_ilock(ip0, xfs_lock_inumorder(lock_mode, 0));
	xfs_ilock(ip0, xfs_lock_inumorder(ip0_mode, 0));


	/*
	/*
	 * If the first lock we have locked is in the AIL, we must TRY to get
	 * If the first lock we have locked is in the AIL, we must TRY to get
@@ -582,18 +598,17 @@ xfs_lock_two_inodes(
	 */
	 */
	lp = (xfs_log_item_t *)ip0->i_itemp;
	lp = (xfs_log_item_t *)ip0->i_itemp;
	if (lp && (lp->li_flags & XFS_LI_IN_AIL)) {
	if (lp && (lp->li_flags & XFS_LI_IN_AIL)) {
		if (!xfs_ilock_nowait(ip1, xfs_lock_inumorder(lock_mode, 1))) {
		if (!xfs_ilock_nowait(ip1, xfs_lock_inumorder(ip1_mode, 1))) {
			xfs_iunlock(ip0, lock_mode);
			xfs_iunlock(ip0, ip0_mode);
			if ((++attempts % 5) == 0)
			if ((++attempts % 5) == 0)
				delay(1); /* Don't just spin the CPU */
				delay(1); /* Don't just spin the CPU */
			goto again;
			goto again;
		}
		}
	} else {
	} else {
		xfs_ilock(ip1, xfs_lock_inumorder(lock_mode, 1));
		xfs_ilock(ip1, xfs_lock_inumorder(ip1_mode, 1));
	}
	}
}
}



void
void
__xfs_iflock(
__xfs_iflock(
	struct xfs_inode	*ip)
	struct xfs_inode	*ip)
@@ -1421,7 +1436,7 @@ xfs_link(
	if (error)
	if (error)
		goto std_return;
		goto std_return;


	xfs_lock_two_inodes(sip, tdp, XFS_ILOCK_EXCL);
	xfs_lock_two_inodes(sip, XFS_ILOCK_EXCL, tdp, XFS_ILOCK_EXCL);


	xfs_trans_ijoin(tp, sip, XFS_ILOCK_EXCL);
	xfs_trans_ijoin(tp, sip, XFS_ILOCK_EXCL);
	xfs_trans_ijoin(tp, tdp, XFS_ILOCK_EXCL);
	xfs_trans_ijoin(tp, tdp, XFS_ILOCK_EXCL);
@@ -2585,7 +2600,7 @@ xfs_remove(
		goto std_return;
		goto std_return;
	}
	}


	xfs_lock_two_inodes(dp, ip, XFS_ILOCK_EXCL);
	xfs_lock_two_inodes(dp, XFS_ILOCK_EXCL, ip, XFS_ILOCK_EXCL);


	xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
	xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+2 −1
Original line number Original line Diff line number Diff line
@@ -423,7 +423,8 @@ void xfs_iunpin_wait(xfs_inode_t *);
#define xfs_ipincount(ip)	((unsigned int) atomic_read(&ip->i_pincount))
#define xfs_ipincount(ip)	((unsigned int) atomic_read(&ip->i_pincount))


int		xfs_iflush(struct xfs_inode *, struct xfs_buf **);
int		xfs_iflush(struct xfs_inode *, struct xfs_buf **);
void		xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint);
void		xfs_lock_two_inodes(struct xfs_inode *ip0, uint ip0_mode,
				struct xfs_inode *ip1, uint ip1_mode);


xfs_extlen_t	xfs_get_extsz_hint(struct xfs_inode *ip);
xfs_extlen_t	xfs_get_extsz_hint(struct xfs_inode *ip);
xfs_extlen_t	xfs_get_cowextsz_hint(struct xfs_inode *ip);
xfs_extlen_t	xfs_get_cowextsz_hint(struct xfs_inode *ip);
+3 −2
Original line number Original line Diff line number Diff line
@@ -944,7 +944,7 @@ xfs_reflink_set_inode_flag(
	if (src->i_ino == dest->i_ino)
	if (src->i_ino == dest->i_ino)
		xfs_ilock(src, XFS_ILOCK_EXCL);
		xfs_ilock(src, XFS_ILOCK_EXCL);
	else
	else
		xfs_lock_two_inodes(src, dest, XFS_ILOCK_EXCL);
		xfs_lock_two_inodes(src, XFS_ILOCK_EXCL, dest, XFS_ILOCK_EXCL);


	if (!xfs_is_reflink_inode(src)) {
	if (!xfs_is_reflink_inode(src)) {
		trace_xfs_reflink_set_inode_flag(src);
		trace_xfs_reflink_set_inode_flag(src);
@@ -1324,7 +1324,8 @@ xfs_reflink_remap_range(
	if (same_inode)
	if (same_inode)
		xfs_ilock(src, XFS_MMAPLOCK_EXCL);
		xfs_ilock(src, XFS_MMAPLOCK_EXCL);
	else
	else
		xfs_lock_two_inodes(src, dest, XFS_MMAPLOCK_EXCL);
		xfs_lock_two_inodes(src, XFS_MMAPLOCK_EXCL, dest,
				XFS_MMAPLOCK_EXCL);


	/* Check file eligibility and prepare for block sharing. */
	/* Check file eligibility and prepare for block sharing. */
	ret = -EINVAL;
	ret = -EINVAL;