diff options
Diffstat (limited to 'fs/xfs/xfs_reflink.c')
-rw-r--r-- | fs/xfs/xfs_reflink.c | 63 |
1 files changed, 37 insertions, 26 deletions
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index c4ec7afd1170..edbe37b7f636 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c | |||
@@ -1190,11 +1190,11 @@ xfs_reflink_remap_blocks( | |||
1190 | } | 1190 | } |
1191 | 1191 | ||
1192 | /* | 1192 | /* |
1193 | * Grab the exclusive iolock for a data copy from src to dest, making | 1193 | * Grab the exclusive iolock for a data copy from src to dest, making sure to |
1194 | * sure to abide vfs locking order (lowest pointer value goes first) and | 1194 | * abide vfs locking order (lowest pointer value goes first) and breaking the |
1195 | * breaking the pnfs layout leases on dest before proceeding. The loop | 1195 | * layout leases before proceeding. The loop is needed because we cannot call |
1196 | * is needed because we cannot call the blocking break_layout() with the | 1196 | * the blocking break_layout() with the iolocks held, and therefore have to |
1197 | * src iolock held, and therefore have to back out both locks. | 1197 | * back out both locks. |
1198 | */ | 1198 | */ |
1199 | static int | 1199 | static int |
1200 | xfs_iolock_two_inodes_and_break_layout( | 1200 | xfs_iolock_two_inodes_and_break_layout( |
@@ -1203,33 +1203,44 @@ xfs_iolock_two_inodes_and_break_layout( | |||
1203 | { | 1203 | { |
1204 | int error; | 1204 | int error; |
1205 | 1205 | ||
1206 | retry: | 1206 | if (src > dest) |
1207 | if (src < dest) { | 1207 | swap(src, dest); |
1208 | inode_lock_shared(src); | ||
1209 | inode_lock_nested(dest, I_MUTEX_NONDIR2); | ||
1210 | } else { | ||
1211 | /* src >= dest */ | ||
1212 | inode_lock(dest); | ||
1213 | } | ||
1214 | 1208 | ||
1215 | error = break_layout(dest, false); | 1209 | retry: |
1216 | if (error == -EWOULDBLOCK) { | 1210 | /* Wait to break both inodes' layouts before we start locking. */ |
1217 | inode_unlock(dest); | 1211 | error = break_layout(src, true); |
1218 | if (src < dest) | 1212 | if (error) |
1219 | inode_unlock_shared(src); | 1213 | return error; |
1214 | if (src != dest) { | ||
1220 | error = break_layout(dest, true); | 1215 | error = break_layout(dest, true); |
1221 | if (error) | 1216 | if (error) |
1222 | return error; | 1217 | return error; |
1223 | goto retry; | ||
1224 | } | 1218 | } |
1219 | |||
1220 | /* Lock one inode and make sure nobody got in and leased it. */ | ||
1221 | inode_lock(src); | ||
1222 | error = break_layout(src, false); | ||
1225 | if (error) { | 1223 | if (error) { |
1224 | inode_unlock(src); | ||
1225 | if (error == -EWOULDBLOCK) | ||
1226 | goto retry; | ||
1227 | return error; | ||
1228 | } | ||
1229 | |||
1230 | if (src == dest) | ||
1231 | return 0; | ||
1232 | |||
1233 | /* Lock the other inode and make sure nobody got in and leased it. */ | ||
1234 | inode_lock_nested(dest, I_MUTEX_NONDIR2); | ||
1235 | error = break_layout(dest, false); | ||
1236 | if (error) { | ||
1237 | inode_unlock(src); | ||
1226 | inode_unlock(dest); | 1238 | inode_unlock(dest); |
1227 | if (src < dest) | 1239 | if (error == -EWOULDBLOCK) |
1228 | inode_unlock_shared(src); | 1240 | goto retry; |
1229 | return error; | 1241 | return error; |
1230 | } | 1242 | } |
1231 | if (src > dest) | 1243 | |
1232 | inode_lock_shared_nested(src, I_MUTEX_NONDIR2); | ||
1233 | return 0; | 1244 | return 0; |
1234 | } | 1245 | } |
1235 | 1246 | ||
@@ -1247,10 +1258,10 @@ xfs_reflink_remap_unlock( | |||
1247 | 1258 | ||
1248 | xfs_iunlock(dest, XFS_MMAPLOCK_EXCL); | 1259 | xfs_iunlock(dest, XFS_MMAPLOCK_EXCL); |
1249 | if (!same_inode) | 1260 | if (!same_inode) |
1250 | xfs_iunlock(src, XFS_MMAPLOCK_SHARED); | 1261 | xfs_iunlock(src, XFS_MMAPLOCK_EXCL); |
1251 | inode_unlock(inode_out); | 1262 | inode_unlock(inode_out); |
1252 | if (!same_inode) | 1263 | if (!same_inode) |
1253 | inode_unlock_shared(inode_in); | 1264 | inode_unlock(inode_in); |
1254 | } | 1265 | } |
1255 | 1266 | ||
1256 | /* | 1267 | /* |
@@ -1325,7 +1336,7 @@ xfs_reflink_remap_prep( | |||
1325 | if (same_inode) | 1336 | if (same_inode) |
1326 | xfs_ilock(src, XFS_MMAPLOCK_EXCL); | 1337 | xfs_ilock(src, XFS_MMAPLOCK_EXCL); |
1327 | else | 1338 | else |
1328 | xfs_lock_two_inodes(src, XFS_MMAPLOCK_SHARED, dest, | 1339 | xfs_lock_two_inodes(src, XFS_MMAPLOCK_EXCL, dest, |
1329 | XFS_MMAPLOCK_EXCL); | 1340 | XFS_MMAPLOCK_EXCL); |
1330 | 1341 | ||
1331 | /* Check file eligibility and prepare for block sharing. */ | 1342 | /* Check file eligibility and prepare for block sharing. */ |