aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/xfs_reflink.c48
1 files changed, 47 insertions, 1 deletions
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index bcc2ad4f0899..bac464f0bc59 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -1245,6 +1245,50 @@ err:
1245} 1245}
1246 1246
1247/* 1247/*
1248 * Grab the exclusive iolock for a data copy from src to dest, making
1249 * sure to abide vfs locking order (lowest pointer value goes first) and
1250 * breaking the pnfs layout leases on dest before proceeding. The loop
1251 * is needed because we cannot call the blocking break_layout() with the
1252 * src iolock held, and therefore have to back out both locks.
1253 */
1254static int
1255xfs_iolock_two_inodes_and_break_layout(
1256 struct inode *src,
1257 struct inode *dest)
1258{
1259 int error;
1260
1261retry:
1262 if (src < dest) {
1263 inode_lock(src);
1264 inode_lock_nested(dest, I_MUTEX_NONDIR2);
1265 } else {
1266 /* src >= dest */
1267 inode_lock(dest);
1268 }
1269
1270 error = break_layout(dest, false);
1271 if (error == -EWOULDBLOCK) {
1272 inode_unlock(dest);
1273 if (src < dest)
1274 inode_unlock(src);
1275 error = break_layout(dest, true);
1276 if (error)
1277 return error;
1278 goto retry;
1279 }
1280 if (error) {
1281 inode_unlock(dest);
1282 if (src < dest)
1283 inode_unlock(src);
1284 return error;
1285 }
1286 if (src > dest)
1287 inode_lock_nested(src, I_MUTEX_NONDIR2);
1288 return 0;
1289}
1290
1291/*
1248 * Link a range of blocks from one file to another. 1292 * Link a range of blocks from one file to another.
1249 */ 1293 */
1250int 1294int
@@ -1274,7 +1318,9 @@ xfs_reflink_remap_range(
1274 return -EIO; 1318 return -EIO;
1275 1319
1276 /* Lock both files against IO */ 1320 /* Lock both files against IO */
1277 lock_two_nondirectories(inode_in, inode_out); 1321 ret = xfs_iolock_two_inodes_and_break_layout(inode_in, inode_out);
1322 if (ret)
1323 return ret;
1278 if (same_inode) 1324 if (same_inode)
1279 xfs_ilock(src, XFS_MMAPLOCK_EXCL); 1325 xfs_ilock(src, XFS_MMAPLOCK_EXCL);
1280 else 1326 else