Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1364b1d4 authored by Darrick J. Wong's avatar Darrick J. Wong
Browse files

xfs: reflink should break pnfs leases before sharing blocks



Before we share blocks between files, we need to break the pnfs leases
on the layout before we start slicing and dicing the block map.  The
structure of this function sets us up for the lock contention reduction
in the next patch.

Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: default avatarBrian Foster <bfoster@redhat.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent c47b74fb
Loading
Loading
Loading
Loading
+47 −1
Original line number Diff line number Diff line
@@ -1244,6 +1244,50 @@ xfs_reflink_remap_blocks(
	return error;
}

/*
 * Grab the exclusive iolock for a data copy from src to dest, making
 * sure to abide vfs locking order (lowest pointer value goes first) and
 * breaking the pnfs layout leases on dest before proceeding.  The loop
 * is needed because we cannot call the blocking break_layout() with the
 * src iolock held, and therefore have to back out both locks.
 */
static int
xfs_iolock_two_inodes_and_break_layout(
	struct inode		*src,
	struct inode		*dest)
{
	int			error;

retry:
	if (src < dest) {
		inode_lock(src);
		inode_lock_nested(dest, I_MUTEX_NONDIR2);
	} else {
		/* src >= dest */
		inode_lock(dest);
	}

	error = break_layout(dest, false);
	if (error == -EWOULDBLOCK) {
		inode_unlock(dest);
		if (src < dest)
			inode_unlock(src);
		error = break_layout(dest, true);
		if (error)
			return error;
		goto retry;
	}
	if (error) {
		inode_unlock(dest);
		if (src < dest)
			inode_unlock(src);
		return error;
	}
	if (src > dest)
		inode_lock_nested(src, I_MUTEX_NONDIR2);
	return 0;
}

/*
 * Link a range of blocks from one file to another.
 */
@@ -1274,7 +1318,9 @@ xfs_reflink_remap_range(
		return -EIO;

	/* Lock both files against IO */
	lock_two_nondirectories(inode_in, inode_out);
	ret = xfs_iolock_two_inodes_and_break_layout(inode_in, inode_out);
	if (ret)
		return ret;
	if (same_inode)
		xfs_ilock(src, XFS_MMAPLOCK_EXCL);
	else