Btrfs: refactor btrfs_evict_inode() reserve refill dance
authorOmar Sandoval <osandov@fb.com>
Fri, 11 May 2018 20:13:36 +0000 (13:13 -0700)
committerDavid Sterba <dsterba@suse.com>
Mon, 28 May 2018 16:23:52 +0000 (18:23 +0200)
The truncate loop in btrfs_evict_inode() does two things at once:

- It refills the temporary block reserve, potentially stealing from the
  global reserve or committing
- It calls btrfs_truncate_inode_items()

The tangle of continues hides the fact that these two steps are actually
separate. Split the first step out into a separate function both for
clarity and so that we can reuse it in a later patch.

Reviewed-by: Nikolay Borisov <nborisov@suse.com>
Signed-off-by: Omar Sandoval <osandov@fb.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/inode.c

index 73783492a0d1f08bdfe519bd716179ca3c817e2d..f70284acb6acc86879e5f021d39aaef0bd7f1c2f 100644 (file)
@@ -5452,13 +5452,52 @@ static void evict_inode_truncate_pages(struct inode *inode)
        spin_unlock(&io_tree->lock);
 }
 
+static struct btrfs_trans_handle *evict_refill_and_join(struct btrfs_root *root,
+                                                       struct btrfs_block_rsv *rsv,
+                                                       u64 min_size)
+{
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
+       int failures = 0;
+
+       for (;;) {
+               struct btrfs_trans_handle *trans;
+               int ret;
+
+               ret = btrfs_block_rsv_refill(root, rsv, min_size,
+                                            BTRFS_RESERVE_FLUSH_LIMIT);
+
+               if (ret && ++failures > 2) {
+                       btrfs_warn(fs_info,
+                                  "could not allocate space for a delete; will truncate on mount");
+                       return ERR_PTR(-ENOSPC);
+               }
+
+               trans = btrfs_join_transaction(root);
+               if (IS_ERR(trans) || !ret)
+                       return trans;
+
+               /*
+                * Try to steal from the global reserve if there is space for
+                * it.
+                */
+               if (!btrfs_check_space_for_delayed_refs(trans, fs_info) &&
+                   !btrfs_block_rsv_migrate(global_rsv, rsv, min_size, 0))
+                       return trans;
+
+               /* If not, commit and try again. */
+               ret = btrfs_commit_transaction(trans);
+               if (ret)
+                       return ERR_PTR(ret);
+       }
+}
+
 void btrfs_evict_inode(struct inode *inode)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        struct btrfs_trans_handle *trans;
        struct btrfs_root *root = BTRFS_I(inode)->root;
-       struct btrfs_block_rsv *rsv, *global_rsv;
-       int steal_from_global = 0;
+       struct btrfs_block_rsv *rsv;
        u64 min_size;
        int ret;
 
@@ -5511,85 +5550,17 @@ void btrfs_evict_inode(struct inode *inode)
        }
        rsv->size = min_size;
        rsv->failfast = 1;
-       global_rsv = &fs_info->global_block_rsv;
 
        btrfs_i_size_write(BTRFS_I(inode), 0);
 
-       /*
-        * This is a bit simpler than btrfs_truncate since we've already
-        * reserved our space for our orphan item in the unlink, so we just
-        * need to reserve some slack space in case we add bytes and update
-        * inode item when doing the truncate.
-        */
        while (1) {
-               ret = btrfs_block_rsv_refill(root, rsv, min_size,
-                                            BTRFS_RESERVE_FLUSH_LIMIT);
-
-               /*
-                * Try and steal from the global reserve since we will
-                * likely not use this space anyway, we want to try as
-                * hard as possible to get this to work.
-                */
-               if (ret)
-                       steal_from_global++;
-               else
-                       steal_from_global = 0;
-               ret = 0;
-
-               /*
-                * steal_from_global == 0: we reserved stuff, hooray!
-                * steal_from_global == 1: we didn't reserve stuff, boo!
-                * steal_from_global == 2: we've committed, still not a lot of
-                * room but maybe we'll have room in the global reserve this
-                * time.
-                * steal_from_global == 3: abandon all hope!
-                */
-               if (steal_from_global > 2) {
-                       btrfs_warn(fs_info,
-                                  "Could not get space for a delete, will truncate on mount %d",
-                                  ret);
-                       btrfs_orphan_del(NULL, BTRFS_I(inode));
-                       btrfs_free_block_rsv(fs_info, rsv);
-                       goto no_delete;
-               }
-
-               trans = btrfs_join_transaction(root);
+               trans = evict_refill_and_join(root, rsv, min_size);
                if (IS_ERR(trans)) {
                        btrfs_orphan_del(NULL, BTRFS_I(inode));
                        btrfs_free_block_rsv(fs_info, rsv);
                        goto no_delete;
                }
 
-               /*
-                * We can't just steal from the global reserve, we need to make
-                * sure there is room to do it, if not we need to commit and try
-                * again.
-                */
-               if (steal_from_global) {
-                       if (!btrfs_check_space_for_delayed_refs(trans, fs_info))
-                               ret = btrfs_block_rsv_migrate(global_rsv, rsv,
-                                                             min_size, 0);
-                       else
-                               ret = -ENOSPC;
-               }
-
-               /*
-                * Couldn't steal from the global reserve, we have too much
-                * pending stuff built up, commit the transaction and try it
-                * again.
-                */
-               if (ret) {
-                       ret = btrfs_commit_transaction(trans);
-                       if (ret) {
-                               btrfs_orphan_del(NULL, BTRFS_I(inode));
-                               btrfs_free_block_rsv(fs_info, rsv);
-                               goto no_delete;
-                       }
-                       continue;
-               } else {
-                       steal_from_global = 0;
-               }
-
                trans->block_rsv = rsv;
 
                ret = btrfs_truncate_inode_items(trans, root, inode, 0, 0);