]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/xfs/xfs_inode.c
Merge tag 'compiler-attributes-for-linus-v5.4' of git://github.com/ojeda/linux
[linux.git] / fs / xfs / xfs_inode.c
index 6467d5e1df2dd1508f39aa9f3dc6df6ad37c2e5b..18f4b262e61cee569c9e0ee06e7645c509e1b341 100644 (file)
@@ -2018,7 +2018,7 @@ xfs_iunlink_add_backref(
        if (XFS_TEST_ERROR(false, pag->pag_mount, XFS_ERRTAG_IUNLINK_FALLBACK))
                return 0;
 
-       iu = kmem_zalloc(sizeof(*iu), KM_SLEEP | KM_NOFS);
+       iu = kmem_zalloc(sizeof(*iu), KM_NOFS);
        iu->iu_agino = prev_agino;
        iu->iu_next_unlinked = this_agino;
 
@@ -3282,7 +3282,8 @@ xfs_rename(
                                        spaceres);
 
        /*
-        * Set up the target.
+        * Check for expected errors before we dirty the transaction
+        * so we can return an error without a transaction abort.
         */
        if (target_ip == NULL) {
                /*
@@ -3294,6 +3295,46 @@ xfs_rename(
                        if (error)
                                goto out_trans_cancel;
                }
+       } else {
+               /*
+                * If target exists and it's a directory, check that whether
+                * it can be destroyed.
+                */
+               if (S_ISDIR(VFS_I(target_ip)->i_mode) &&
+                   (!xfs_dir_isempty(target_ip) ||
+                    (VFS_I(target_ip)->i_nlink > 2))) {
+                       error = -EEXIST;
+                       goto out_trans_cancel;
+               }
+       }
+
+       /*
+        * Directory entry creation below may acquire the AGF. Remove
+        * the whiteout from the unlinked list first to preserve correct
+        * AGI/AGF locking order. This dirties the transaction so failures
+        * after this point will abort and log recovery will clean up the
+        * mess.
+        *
+        * For whiteouts, we need to bump the link count on the whiteout
+        * inode. After this point, we have a real link, clear the tmpfile
+        * state flag from the inode so it doesn't accidentally get misused
+        * in future.
+        */
+       if (wip) {
+               ASSERT(VFS_I(wip)->i_nlink == 0);
+               error = xfs_iunlink_remove(tp, wip);
+               if (error)
+                       goto out_trans_cancel;
+
+               xfs_bumplink(tp, wip);
+               xfs_trans_log_inode(tp, wip, XFS_ILOG_CORE);
+               VFS_I(wip)->i_state &= ~I_LINKABLE;
+       }
+
+       /*
+        * Set up the target.
+        */
+       if (target_ip == NULL) {
                /*
                 * If target does not exist and the rename crosses
                 * directories, adjust the target directory link count
@@ -3311,22 +3352,6 @@ xfs_rename(
                        xfs_bumplink(tp, target_dp);
                }
        } else { /* target_ip != NULL */
-               /*
-                * If target exists and it's a directory, check that both
-                * target and source are directories and that target can be
-                * destroyed, or that neither is a directory.
-                */
-               if (S_ISDIR(VFS_I(target_ip)->i_mode)) {
-                       /*
-                        * Make sure target dir is empty.
-                        */
-                       if (!(xfs_dir_isempty(target_ip)) ||
-                           (VFS_I(target_ip)->i_nlink > 2)) {
-                               error = -EEXIST;
-                               goto out_trans_cancel;
-                       }
-               }
-
                /*
                 * Link the source inode under the target name.
                 * If the source inode is a directory and we are moving
@@ -3417,30 +3442,6 @@ xfs_rename(
        if (error)
                goto out_trans_cancel;
 
-       /*
-        * For whiteouts, we need to bump the link count on the whiteout inode.
-        * This means that failures all the way up to this point leave the inode
-        * on the unlinked list and so cleanup is a simple matter of dropping
-        * the remaining reference to it. If we fail here after bumping the link
-        * count, we're shutting down the filesystem so we'll never see the
-        * intermediate state on disk.
-        */
-       if (wip) {
-               ASSERT(VFS_I(wip)->i_nlink == 0);
-               xfs_bumplink(tp, wip);
-               error = xfs_iunlink_remove(tp, wip);
-               if (error)
-                       goto out_trans_cancel;
-               xfs_trans_log_inode(tp, wip, XFS_ILOG_CORE);
-
-               /*
-                * Now we have a real link, clear the "I'm a tmpfile" state
-                * flag from the inode so it doesn't accidentally get misused in
-                * future.
-                */
-               VFS_I(wip)->i_state &= ~I_LINKABLE;
-       }
-
        xfs_trans_ichgtime(tp, src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
        xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE);
        if (new_parent)