xfs: only grab shared inode locks for source file during reflink

Reflink and dedupe operations remap blocks from a source file into a
destination file.  The destination file needs exclusive locks on all
levels because we're updating its block map, but the source file isn't
undergoing any block map changes so we can use a shared lock.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
Darrick J. Wong
2018-01-18 14:07:53 -08:00
parent 7c2d238ac6
commit 01c2e13dca
2 changed files with 20 additions and 10 deletions

View File

@@ -1202,13 +1202,16 @@ xfs_reflink_remap_blocks(
/* drange = (destoff, destoff + len); srange = (srcoff, srcoff + len) */
while (len) {
uint lock_mode;
trace_xfs_reflink_remap_blocks_loop(src, srcoff, len,
dest, destoff);
/* Read extent from the source file */
nimaps = 1;
xfs_ilock(src, XFS_ILOCK_EXCL);
lock_mode = xfs_ilock_data_map_shared(src);
error = xfs_bmapi_read(src, srcoff, len, &imap, &nimaps, 0);
xfs_iunlock(src, XFS_ILOCK_EXCL);
xfs_iunlock(src, lock_mode);
if (error)
goto err;
ASSERT(nimaps == 1);
@@ -1260,7 +1263,7 @@ xfs_iolock_two_inodes_and_break_layout(
retry:
if (src < dest) {
inode_lock(src);
inode_lock_shared(src);
inode_lock_nested(dest, I_MUTEX_NONDIR2);
} else {
/* src >= dest */
@@ -1271,7 +1274,7 @@ retry:
if (error == -EWOULDBLOCK) {
inode_unlock(dest);
if (src < dest)
inode_unlock(src);
inode_unlock_shared(src);
error = break_layout(dest, true);
if (error)
return error;
@@ -1280,11 +1283,11 @@ retry:
if (error) {
inode_unlock(dest);
if (src < dest)
inode_unlock(src);
inode_unlock_shared(src);
return error;
}
if (src > dest)
inode_lock_nested(src, I_MUTEX_NONDIR2);
inode_lock_shared_nested(src, I_MUTEX_NONDIR2);
return 0;
}
@@ -1324,7 +1327,7 @@ xfs_reflink_remap_range(
if (same_inode)
xfs_ilock(src, XFS_MMAPLOCK_EXCL);
else
xfs_lock_two_inodes(src, XFS_MMAPLOCK_EXCL, dest,
xfs_lock_two_inodes(src, XFS_MMAPLOCK_SHARED, dest,
XFS_MMAPLOCK_EXCL);
/* Check file eligibility and prepare for block sharing. */
@@ -1393,10 +1396,12 @@ xfs_reflink_remap_range(
is_dedupe);
out_unlock:
xfs_iunlock(src, XFS_MMAPLOCK_EXCL);
xfs_iunlock(dest, XFS_MMAPLOCK_EXCL);
if (!same_inode)
xfs_iunlock(dest, XFS_MMAPLOCK_EXCL);
unlock_two_nondirectories(inode_in, inode_out);
xfs_iunlock(src, XFS_MMAPLOCK_SHARED);
inode_unlock(inode_out);
if (!same_inode)
inode_unlock_shared(inode_in);
if (ret)
trace_xfs_reflink_remap_range_error(dest, ret, _RET_IP_);
return ret;