Btrfs: wrap repeated code into scrub_blocked_if_needed()
[sfrench/cifs-2.6.git] / fs / btrfs / transaction.c
index 8c81bdc1ef9bae82c92e5a8836a0f911c1547a55..026f1fea963e1952273cf6d16034755976e9b473 100644 (file)
@@ -57,12 +57,13 @@ static unsigned int btrfs_blocked_trans_types[TRANS_STATE_MAX] = {
                                           __TRANS_JOIN_NOLOCK),
 };
 
-static void put_transaction(struct btrfs_transaction *transaction)
+void btrfs_put_transaction(struct btrfs_transaction *transaction)
 {
        WARN_ON(atomic_read(&transaction->use_count) == 0);
        if (atomic_dec_and_test(&transaction->use_count)) {
                BUG_ON(!list_empty(&transaction->list));
-               WARN_ON(transaction->delayed_refs.root.rb_node);
+               WARN_ON(!RB_EMPTY_ROOT(&transaction->delayed_refs.root));
+               WARN_ON(!RB_EMPTY_ROOT(&transaction->delayed_refs.href_root));
                while (!list_empty(&transaction->pending_chunks)) {
                        struct extent_map *em;
 
@@ -184,6 +185,7 @@ loop:
        cur_trans->start_time = get_seconds();
 
        cur_trans->delayed_refs.root = RB_ROOT;
+       cur_trans->delayed_refs.href_root = RB_ROOT;
        cur_trans->delayed_refs.num_entries = 0;
        cur_trans->delayed_refs.num_heads_ready = 0;
        cur_trans->delayed_refs.num_heads = 0;
@@ -332,7 +334,7 @@ static void wait_current_trans(struct btrfs_root *root)
                wait_event(root->fs_info->transaction_wait,
                           cur_trans->state >= TRANS_STATE_UNBLOCKED ||
                           cur_trans->aborted);
-               put_transaction(cur_trans);
+               btrfs_put_transaction(cur_trans);
        } else {
                spin_unlock(&root->fs_info->trans_lock);
        }
@@ -353,6 +355,17 @@ static int may_wait_transaction(struct btrfs_root *root, int type)
        return 0;
 }
 
+static inline bool need_reserve_reloc_root(struct btrfs_root *root)
+{
+       if (!root->fs_info->reloc_ctl ||
+           !root->ref_cows ||
+           root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID ||
+           root->reloc_root)
+               return false;
+
+       return true;
+}
+
 static struct btrfs_trans_handle *
 start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
                  enum btrfs_reserve_flush_enum flush)
@@ -360,8 +373,9 @@ start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
        struct btrfs_trans_handle *h;
        struct btrfs_transaction *cur_trans;
        u64 num_bytes = 0;
-       int ret;
        u64 qgroup_reserved = 0;
+       bool reloc_reserved = false;
+       int ret;
 
        if (test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state))
                return ERR_PTR(-EROFS);
@@ -390,6 +404,14 @@ start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
                }
 
                num_bytes = btrfs_calc_trans_metadata_size(root, num_items);
+               /*
+                * Do the reservation for the relocation root creation
+                */
+               if (unlikely(need_reserve_reloc_root(root))) {
+                       num_bytes += root->nodesize;
+                       reloc_reserved = true;
+               }
+
                ret = btrfs_block_rsv_add(root,
                                          &root->fs_info->trans_block_rsv,
                                          num_bytes, flush);
@@ -451,6 +473,7 @@ again:
        h->delayed_ref_elem.seq = 0;
        h->type = type;
        h->allocating_chunk = false;
+       h->reloc_reserved = false;
        INIT_LIST_HEAD(&h->qgroup_ref_list);
        INIT_LIST_HEAD(&h->new_bgs);
 
@@ -466,6 +489,7 @@ again:
                                              h->transid, num_bytes, 1);
                h->block_rsv = &root->fs_info->trans_block_rsv;
                h->bytes_reserved = num_bytes;
+               h->reloc_reserved = reloc_reserved;
        }
        h->qgroup_reserved = qgroup_reserved;
 
@@ -610,7 +634,7 @@ int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid)
        }
 
        wait_for_commit(root, cur_trans);
-       put_transaction(cur_trans);
+       btrfs_put_transaction(cur_trans);
 out:
        return ret;
 }
@@ -735,7 +759,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
        smp_mb();
        if (waitqueue_active(&cur_trans->writer_wait))
                wake_up(&cur_trans->writer_wait);
-       put_transaction(cur_trans);
+       btrfs_put_transaction(cur_trans);
 
        if (current->journal_info == trans)
                current->journal_info = NULL;
@@ -744,8 +768,10 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
                btrfs_run_delayed_iputs(root);
 
        if (trans->aborted ||
-           test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state))
+           test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state)) {
+               wake_up_process(info->transaction_kthread);
                err = -EIO;
+       }
        assert_qgroups_uptodate(trans);
 
        kmem_cache_free(btrfs_trans_handle_cachep, trans);
@@ -948,16 +974,19 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
                return ret;
 
        ret = btrfs_run_dev_stats(trans, root->fs_info);
-       WARN_ON(ret);
+       if (ret)
+               return ret;
        ret = btrfs_run_dev_replace(trans, root->fs_info);
-       WARN_ON(ret);
-
+       if (ret)
+               return ret;
        ret = btrfs_run_qgroups(trans, root->fs_info);
-       BUG_ON(ret);
+       if (ret)
+               return ret;
 
        /* run_qgroups might have added some more refs */
        ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
-       BUG_ON(ret);
+       if (ret)
+               return ret;
 
        while (!list_empty(&fs_info->dirty_cowonly_roots)) {
                next = fs_info->dirty_cowonly_roots.next;
@@ -1453,7 +1482,7 @@ static void do_async_commit(struct work_struct *work)
         * We've got freeze protection passed with the transaction.
         * Tell lockdep about it.
         */
-       if (ac->newtrans->type < TRANS_JOIN_NOLOCK)
+       if (ac->newtrans->type & __TRANS_FREEZABLE)
                rwsem_acquire_read(
                     &ac->root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1],
                     0, 1, _THIS_IP_);
@@ -1494,7 +1523,7 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
         * Tell lockdep we've released the freeze rwsem, since the
         * async commit thread will be the one to unlock it.
         */
-       if (trans->type < TRANS_JOIN_NOLOCK)
+       if (ac->newtrans->type & __TRANS_FREEZABLE)
                rwsem_release(
                        &root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1],
                        1, _THIS_IP_);
@@ -1510,7 +1539,7 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
        if (current->journal_info == trans)
                current->journal_info = NULL;
 
-       put_transaction(cur_trans);
+       btrfs_put_transaction(cur_trans);
        return 0;
 }
 
@@ -1552,8 +1581,10 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans,
                root->fs_info->running_transaction = NULL;
        spin_unlock(&root->fs_info->trans_lock);
 
-       put_transaction(cur_trans);
-       put_transaction(cur_trans);
+       if (trans->type & __TRANS_FREEZABLE)
+               sb_end_intwrite(root->fs_info->sb);
+       btrfs_put_transaction(cur_trans);
+       btrfs_put_transaction(cur_trans);
 
        trace_btrfs_transaction_commit(root);
 
@@ -1571,15 +1602,19 @@ static int btrfs_flush_all_pending_stuffs(struct btrfs_trans_handle *trans,
        int ret;
 
        ret = btrfs_run_delayed_items(trans, root);
-       if (ret)
-               return ret;
-
        /*
         * running the delayed items may have added new refs. account
         * them now so that they hinder processing of more delayed refs
         * as little as possible.
         */
-       btrfs_delayed_refs_qgroup_accounting(trans, root->fs_info);
+       if (ret) {
+               btrfs_delayed_refs_qgroup_accounting(trans, root->fs_info);
+               return ret;
+       }
+
+       ret = btrfs_delayed_refs_qgroup_accounting(trans, root->fs_info);
+       if (ret)
+               return ret;
 
        /*
         * rename don't use btrfs_join_transaction, so, once we
@@ -1596,14 +1631,14 @@ static int btrfs_flush_all_pending_stuffs(struct btrfs_trans_handle *trans,
 static inline int btrfs_start_delalloc_flush(struct btrfs_fs_info *fs_info)
 {
        if (btrfs_test_opt(fs_info->tree_root, FLUSHONCOMMIT))
-               return btrfs_start_all_delalloc_inodes(fs_info, 1);
+               return btrfs_start_delalloc_roots(fs_info, 1);
        return 0;
 }
 
 static inline void btrfs_wait_delalloc_flush(struct btrfs_fs_info *fs_info)
 {
        if (btrfs_test_opt(fs_info->tree_root, FLUSHONCOMMIT))
-               btrfs_wait_all_ordered_extents(fs_info);
+               btrfs_wait_ordered_roots(fs_info, -1);
 }
 
 int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
@@ -1669,7 +1704,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
                wait_for_commit(root, cur_trans);
 
-               put_transaction(cur_trans);
+               btrfs_put_transaction(cur_trans);
 
                return ret;
        }
@@ -1686,7 +1721,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
                        wait_for_commit(root, prev_trans);
 
-                       put_transaction(prev_trans);
+                       btrfs_put_transaction(prev_trans);
                } else {
                        spin_unlock(&root->fs_info->trans_lock);
                }
@@ -1713,6 +1748,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                goto cleanup_transaction;
 
        btrfs_wait_delalloc_flush(root->fs_info);
+
+       btrfs_scrub_pause(root);
        /*
         * Ok now we need to make sure to block out any other joins while we
         * commit the transaction.  We could have started a join before setting
@@ -1777,7 +1814,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
        WARN_ON(cur_trans != trans->transaction);
 
-       btrfs_scrub_pause(root);
        /* btrfs_commit_tree_roots is responsible for getting the
         * various roots consistent with each other.  Every pointer
         * in the tree of tree roots has to point to the most up to date
@@ -1885,8 +1921,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        list_del_init(&cur_trans->list);
        spin_unlock(&root->fs_info->trans_lock);
 
-       put_transaction(cur_trans);
-       put_transaction(cur_trans);
+       btrfs_put_transaction(cur_trans);
+       btrfs_put_transaction(cur_trans);
 
        if (trans->type & __TRANS_FREEZABLE)
                sb_end_intwrite(root->fs_info->sb);