diff options
author | Darrick J. Wong <darrick.wong@oracle.com> | 2018-01-18 14:07:53 -0800 |
---|---|---|
committer | Darrick J. Wong <darrick.wong@oracle.com> | 2018-01-29 07:27:23 -0800 |
commit | 01c2e13dcae9757ea987af8933f9fcc6e33f2d7c (patch) | |
tree | 369b006ec50bc6d70de8a3085482e9bc49655068 /fs/xfs/xfs_reflink.c | |
parent | 7c2d238ac6c435c07780a54719760da2beb46a43 (diff) | |
download | linux-stable-01c2e13dcae9757ea987af8933f9fcc6e33f2d7c.tar.gz linux-stable-01c2e13dcae9757ea987af8933f9fcc6e33f2d7c.tar.bz2 linux-stable-01c2e13dcae9757ea987af8933f9fcc6e33f2d7c.zip |
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>
Diffstat (limited to 'fs/xfs/xfs_reflink.c')
-rw-r--r-- | fs/xfs/xfs_reflink.c | 25 |
1 files changed, 15 insertions, 10 deletions
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index bcc58c24287c..85a119e1463b 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c @@ -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(src, XFS_MMAPLOCK_SHARED); + inode_unlock(inode_out); if (!same_inode) - xfs_iunlock(dest, XFS_MMAPLOCK_EXCL); - unlock_two_nondirectories(inode_in, inode_out); + inode_unlock_shared(inode_in); if (ret) trace_xfs_reflink_remap_range_error(dest, ret, _RET_IP_); return ret; |