]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
Btrfs: don't return ino to ino cache if inode item removal fails
authorOmar Sandoval <osandov@fb.com>
Fri, 11 May 2018 20:13:35 +0000 (13:13 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 3 Aug 2018 05:47:43 +0000 (07:47 +0200)
[ Upstream commit c08db7d8d295a4f3a10faaca376de011afff7950 ]

In btrfs_evict_inode(), if btrfs_truncate_inode_items() fails, the inode
item will still be in the tree but we still return the ino to the ino
cache. That will blow up later when someone tries to allocate that ino,
so don't return it to the cache.

Fixes: 581bb050941b ("Btrfs: Cache free inode numbers in memory")
Reviewed-by: Josef Bacik <jbacik@fb.com>
Signed-off-by: Omar Sandoval <osandov@fb.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/btrfs/inode.c

index 888808ed66b5da5fe496fd7942f3dd6fc99a3037..23c6c9d393fb007321f7a174107efc5254bad9fc 100644 (file)
@@ -5426,13 +5426,18 @@ void btrfs_evict_inode(struct inode *inode)
                trans->block_rsv = rsv;
 
                ret = btrfs_truncate_inode_items(trans, root, inode, 0, 0);
-               if (ret != -ENOSPC && ret != -EAGAIN)
+               if (ret) {
+                       trans->block_rsv = &fs_info->trans_block_rsv;
+                       btrfs_end_transaction(trans);
+                       btrfs_btree_balance_dirty(fs_info);
+                       if (ret != -ENOSPC && ret != -EAGAIN) {
+                               btrfs_orphan_del(NULL, BTRFS_I(inode));
+                               btrfs_free_block_rsv(fs_info, rsv);
+                               goto no_delete;
+                       }
+               } else {
                        break;
-
-               trans->block_rsv = &fs_info->trans_block_rsv;
-               btrfs_end_transaction(trans);
-               trans = NULL;
-               btrfs_btree_balance_dirty(fs_info);
+               }
        }
 
        btrfs_free_block_rsv(fs_info, rsv);
@@ -5441,12 +5446,8 @@ void btrfs_evict_inode(struct inode *inode)
         * Errors here aren't a big deal, it just means we leave orphan items
         * in the tree.  They will be cleaned up on the next mount.
         */
-       if (ret == 0) {
-               trans->block_rsv = root->orphan_block_rsv;
-               btrfs_orphan_del(trans, BTRFS_I(inode));
-       } else {
-               btrfs_orphan_del(NULL, BTRFS_I(inode));
-       }
+       trans->block_rsv = root->orphan_block_rsv;
+       btrfs_orphan_del(trans, BTRFS_I(inode));
 
        trans->block_rsv = &fs_info->trans_block_rsv;
        if (!(root == fs_info->tree_root ||