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)
committerDavid Sterba <dsterba@suse.com>
Mon, 28 May 2018 16:23:51 +0000 (18:23 +0200)
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>
fs/btrfs/inode.c

index 06506cd00e4a26e0fec5aa703497b0f50c1e11d0..73783492a0d1f08bdfe519bd716179ca3c817e2d 100644 (file)
@@ -5593,13 +5593,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);
@@ -5608,12 +5613,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 ||