btrfs: abort transaction on failure to add link to inode
authorFilipe Manana <fdmanana@suse.com>
Fri, 25 Jul 2025 15:51:49 +0000 (16:51 +0100)
committerDavid Sterba <dsterba@suse.com>
Thu, 21 Aug 2025 22:58:25 +0000 (00:58 +0200)
If we fail to update the inode or delete the orphan item, we must abort
the transaction to prevent persisting an inconsistent state. For example
if we fail to update the inode item, we have the inconsistency of having
a persisted inode item with a link count of N but we have N + 1 inode ref
items and N + 1 directory entries pointing to our inode in case the
transaction gets committed.

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 9e4aec7..af2f9b2 100644 (file)
@@ -6852,16 +6852,20 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
                struct dentry *parent = dentry->d_parent;
 
                ret = btrfs_update_inode(trans, BTRFS_I(inode));
-               if (ret)
+               if (ret) {
+                       btrfs_abort_transaction(trans, ret);
                        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)
+                       if (ret) {
+                               btrfs_abort_transaction(trans, ret);
                                goto fail;
+                       }
                }
                d_instantiate(dentry, inode);
                btrfs_log_new_name(trans, old_dentry, NULL, 0, parent);