diff options
| -rw-r--r-- | fs/xfs/xfs_reflink.c | 48 |
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 | */ | ||
| 1254 | static int | ||
| 1255 | xfs_iolock_two_inodes_and_break_layout( | ||
| 1256 | struct inode *src, | ||
| 1257 | struct inode *dest) | ||
| 1258 | { | ||
| 1259 | int error; | ||
| 1260 | |||
| 1261 | retry: | ||
| 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 | */ |
| 1250 | int | 1294 | int |
| @@ -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 |
