]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/xfs/xfs_reflink.c
Merge tag 'for-linus-2019-10-18' of git://git.kernel.dk/linux-block
[linux.git] / fs / xfs / xfs_reflink.c
index c4ec7afd1170a7550df8704b2bb71ae450c927f5..0f08153b4994190fcd21d8b4fd9f6914ae908cb4 100644 (file)
@@ -495,10 +495,8 @@ xfs_reflink_cancel_cow_blocks(
                        ASSERT((*tpp)->t_firstblock == NULLFSBLOCK);
 
                        /* Free the CoW orphan record. */
-                       error = xfs_refcount_free_cow_extent(*tpp,
-                                       del.br_startblock, del.br_blockcount);
-                       if (error)
-                               break;
+                       xfs_refcount_free_cow_extent(*tpp, del.br_startblock,
+                                       del.br_blockcount);
 
                        xfs_bmap_add_free(*tpp, del.br_startblock,
                                          del.br_blockcount, NULL);
@@ -675,15 +673,10 @@ xfs_reflink_end_cow_extent(
        trace_xfs_reflink_cow_remap(ip, &del);
 
        /* Free the CoW orphan record. */
-       error = xfs_refcount_free_cow_extent(tp, del.br_startblock,
-                       del.br_blockcount);
-       if (error)
-               goto out_cancel;
+       xfs_refcount_free_cow_extent(tp, del.br_startblock, del.br_blockcount);
 
        /* Map the new blocks into the data fork. */
-       error = xfs_bmap_map_extent(tp, ip, &del);
-       if (error)
-               goto out_cancel;
+       xfs_bmap_map_extent(tp, ip, &del);
 
        /* Charge this new data fork mapping to the on-disk quota. */
        xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_DELBCOUNT,
@@ -1070,14 +1063,10 @@ xfs_reflink_remap_extent(
                                uirec.br_blockcount, uirec.br_startblock);
 
                /* Update the refcount tree */
-               error = xfs_refcount_increase_extent(tp, &uirec);
-               if (error)
-                       goto out_cancel;
+               xfs_refcount_increase_extent(tp, &uirec);
 
                /* Map the new blocks into the data fork. */
-               error = xfs_bmap_map_extent(tp, ip, &uirec);
-               if (error)
-                       goto out_cancel;
+               xfs_bmap_map_extent(tp, ip, &uirec);
 
                /* Update quota accounting. */
                xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT,
@@ -1190,11 +1179,11 @@ xfs_reflink_remap_blocks(
 }
 
 /*
- * Grab the exclusive iolock for a data copy from src to dest, making
- * sure to abide vfs locking order (lowest pointer value goes first) and
- * breaking the pnfs layout leases on dest before proceeding.  The loop
- * is needed because we cannot call the blocking break_layout() with the
- * src iolock held, and therefore have to back out both locks.
+ * Grab the exclusive iolock for a data copy from src to dest, making sure to
+ * abide vfs locking order (lowest pointer value goes first) and breaking the
+ * layout leases before proceeding.  The loop is needed because we cannot call
+ * the blocking break_layout() with the iolocks held, and therefore have to
+ * back out both locks.
  */
 static int
 xfs_iolock_two_inodes_and_break_layout(
@@ -1203,33 +1192,44 @@ xfs_iolock_two_inodes_and_break_layout(
 {
        int                     error;
 
-retry:
-       if (src < dest) {
-               inode_lock_shared(src);
-               inode_lock_nested(dest, I_MUTEX_NONDIR2);
-       } else {
-               /* src >= dest */
-               inode_lock(dest);
-       }
+       if (src > dest)
+               swap(src, dest);
 
-       error = break_layout(dest, false);
-       if (error == -EWOULDBLOCK) {
-               inode_unlock(dest);
-               if (src < dest)
-                       inode_unlock_shared(src);
+retry:
+       /* Wait to break both inodes' layouts before we start locking. */
+       error = break_layout(src, true);
+       if (error)
+               return error;
+       if (src != dest) {
                error = break_layout(dest, true);
                if (error)
                        return error;
-               goto retry;
        }
+
+       /* Lock one inode and make sure nobody got in and leased it. */
+       inode_lock(src);
+       error = break_layout(src, false);
+       if (error) {
+               inode_unlock(src);
+               if (error == -EWOULDBLOCK)
+                       goto retry;
+               return error;
+       }
+
+       if (src == dest)
+               return 0;
+
+       /* Lock the other inode and make sure nobody got in and leased it. */
+       inode_lock_nested(dest, I_MUTEX_NONDIR2);
+       error = break_layout(dest, false);
        if (error) {
+               inode_unlock(src);
                inode_unlock(dest);
-               if (src < dest)
-                       inode_unlock_shared(src);
+               if (error == -EWOULDBLOCK)
+                       goto retry;
                return error;
        }
-       if (src > dest)
-               inode_lock_shared_nested(src, I_MUTEX_NONDIR2);
+
        return 0;
 }
 
@@ -1247,10 +1247,10 @@ xfs_reflink_remap_unlock(
 
        xfs_iunlock(dest, XFS_MMAPLOCK_EXCL);
        if (!same_inode)
-               xfs_iunlock(src, XFS_MMAPLOCK_SHARED);
+               xfs_iunlock(src, XFS_MMAPLOCK_EXCL);
        inode_unlock(inode_out);
        if (!same_inode)
-               inode_unlock_shared(inode_in);
+               inode_unlock(inode_in);
 }
 
 /*
@@ -1325,7 +1325,7 @@ xfs_reflink_remap_prep(
        if (same_inode)
                xfs_ilock(src, XFS_MMAPLOCK_EXCL);
        else
-               xfs_lock_two_inodes(src, XFS_MMAPLOCK_SHARED, dest,
+               xfs_lock_two_inodes(src, XFS_MMAPLOCK_EXCL, dest,
                                XFS_MMAPLOCK_EXCL);
 
        /* Check file eligibility and prepare for block sharing. */