btrfs: simplify error handling logic for btrfs_link()
authorFilipe Manana <fdmanana@suse.com>
Fri, 25 Jul 2025 16:08:13 +0000 (17:08 +0100)
committerDavid Sterba <dsterba@suse.com>
Thu, 21 Aug 2025 22:58:28 +0000 (00:58 +0200)
Instead of incrementing the inode's link count and refcount early before
adding the link, updating the inode and deleting orphan item, do it after
all those steps succeeded right before calling d_instantiate(). This makes
the error handling logic simpler by avoiding the need for the 'drop_inode'
variable to signal if we need to undo the link count increment and the
inode refcount increase under the 'fail' label.

This also reduces the level of indentation by one, making the code easier
to read.

Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/inode.c

index 4ed5ab5d3ac15bccbcb2aba463f5529d93a9ee0c..321a46be0377b4e0140ad4a808b09460f5e57fd7 100644 (file)
@@ -6805,7 +6805,6 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
        struct fscrypt_name fname;
        u64 index;
        int ret;
-       int drop_inode = 0;
 
        /* do not allow sys_link's with other subvols of the same device */
        if (btrfs_root_id(root) != btrfs_root_id(BTRFS_I(inode)->root))
@@ -6837,50 +6836,44 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
 
        /* There are several dir indexes for this inode, clear the cache. */
        BTRFS_I(inode)->dir_index = 0ULL;
-       inc_nlink(inode);
        inode_inc_iversion(inode);
        inode_set_ctime_current(inode);
-       ihold(inode);
        set_bit(BTRFS_INODE_COPY_EVERYTHING, &BTRFS_I(inode)->runtime_flags);
 
        ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode),
                             &fname.disk_name, 1, index);
+       if (ret)
+               goto fail;
 
+       /* Link added now we update the inode item with the new link count. */
+       inc_nlink(inode);
+       ret = btrfs_update_inode(trans, BTRFS_I(inode));
        if (ret) {
-               drop_inode = 1;
-       } else {
-               struct dentry *parent = dentry->d_parent;
+               btrfs_abort_transaction(trans, ret);
+               goto fail;
+       }
 
-               ret = btrfs_update_inode(trans, BTRFS_I(inode));
+       if (inode->i_nlink == 1) {
+               /*
+                * If the new hard link count is 1, it's a file created with the
+                * open(2) O_TMPFILE flag.
+                */
+               ret = btrfs_orphan_del(trans, BTRFS_I(inode));
                if (ret) {
                        btrfs_abort_transaction(trans, ret);
-                       drop_inode = 1;
                        goto fail;
                }
-               if (inode->i_nlink == 1) {
-                       /*
-                        * If new hard link count is 1, it's a file created
-                        * with open(2) O_TMPFILE flag.
-                        */
-                       ret = btrfs_orphan_del(trans, BTRFS_I(inode));
-                       if (ret) {
-                               btrfs_abort_transaction(trans, ret);
-                               drop_inode = 1;
-                               goto fail;
-                       }
-               }
-               d_instantiate(dentry, inode);
-               btrfs_log_new_name(trans, old_dentry, NULL, 0, parent);
        }
 
+       /* Grab reference for the new dentry passed to d_instantiate(). */
+       ihold(inode);
+       d_instantiate(dentry, inode);
+       btrfs_log_new_name(trans, old_dentry, NULL, 0, dentry->d_parent);
+
 fail:
        fscrypt_free_filename(&fname);
        if (trans)
                btrfs_end_transaction(trans);
-       if (drop_inode) {
-               inode_dec_link_count(inode);
-               iput(inode);
-       }
        btrfs_btree_balance_dirty(fs_info);
        return ret;
 }