Btrfs: rework qgroup accounting
[deliverable/linux.git] / fs / btrfs / extent-tree.c
index 5590af92094bb67ea61c8ae397cc393b58b75ae6..343eb10230a199c4db63e5c7ff589a0e219722d5 100644 (file)
 #include <linux/ratelimit.h>
 #include <linux/percpu_counter.h>
 #include "hash.h"
-#include "ctree.h"
+#include "tree-log.h"
 #include "disk-io.h"
 #include "print-tree.h"
-#include "transaction.h"
 #include "volumes.h"
 #include "raid56.h"
 #include "locking.h"
 #include "free-space-cache.h"
 #include "math.h"
 #include "sysfs.h"
+#include "qgroup.h"
 
 #undef SCRAMBLE_DELAYED_REFS
 
@@ -81,7 +81,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                                u64 bytenr, u64 num_bytes, u64 parent,
                                u64 root_objectid, u64 owner_objectid,
                                u64 owner_offset, int refs_to_drop,
-                               struct btrfs_delayed_extent_op *extra_op);
+                               struct btrfs_delayed_extent_op *extra_op,
+                               int no_quota);
 static void __run_delayed_extent_op(struct btrfs_delayed_extent_op *extent_op,
                                    struct extent_buffer *leaf,
                                    struct btrfs_extent_item *ei);
@@ -94,7 +95,8 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
                                     struct btrfs_root *root,
                                     u64 parent, u64 root_objectid,
                                     u64 flags, struct btrfs_disk_key *key,
-                                    int level, struct btrfs_key *ins);
+                                    int level, struct btrfs_key *ins,
+                                    int no_quota);
 static int do_chunk_alloc(struct btrfs_trans_handle *trans,
                          struct btrfs_root *extent_root, u64 flags,
                          int force);
@@ -1271,7 +1273,7 @@ fail:
 static noinline int remove_extent_data_ref(struct btrfs_trans_handle *trans,
                                           struct btrfs_root *root,
                                           struct btrfs_path *path,
-                                          int refs_to_drop)
+                                          int refs_to_drop, int *last_ref)
 {
        struct btrfs_key key;
        struct btrfs_extent_data_ref *ref1 = NULL;
@@ -1307,6 +1309,7 @@ static noinline int remove_extent_data_ref(struct btrfs_trans_handle *trans,
 
        if (num_refs == 0) {
                ret = btrfs_del_item(trans, root, path);
+               *last_ref = 1;
        } else {
                if (key.type == BTRFS_EXTENT_DATA_REF_KEY)
                        btrfs_set_extent_data_ref_count(leaf, ref1, num_refs);
@@ -1764,7 +1767,8 @@ void update_inline_extent_backref(struct btrfs_root *root,
                                  struct btrfs_path *path,
                                  struct btrfs_extent_inline_ref *iref,
                                  int refs_to_mod,
-                                 struct btrfs_delayed_extent_op *extent_op)
+                                 struct btrfs_delayed_extent_op *extent_op,
+                                 int *last_ref)
 {
        struct extent_buffer *leaf;
        struct btrfs_extent_item *ei;
@@ -1808,6 +1812,7 @@ void update_inline_extent_backref(struct btrfs_root *root,
                else
                        btrfs_set_shared_data_ref_count(leaf, sref, refs);
        } else {
+               *last_ref = 1;
                size =  btrfs_extent_inline_ref_size(type);
                item_size = btrfs_item_size_nr(leaf, path->slots[0]);
                ptr = (unsigned long)iref;
@@ -1839,7 +1844,7 @@ int insert_inline_extent_backref(struct btrfs_trans_handle *trans,
        if (ret == 0) {
                BUG_ON(owner < BTRFS_FIRST_FREE_OBJECTID);
                update_inline_extent_backref(root, path, iref,
-                                            refs_to_add, extent_op);
+                                            refs_to_add, extent_op, NULL);
        } else if (ret == -ENOENT) {
                setup_inline_extent_backref(root, path, iref, parent,
                                            root_objectid, owner, offset,
@@ -1872,17 +1877,19 @@ static int remove_extent_backref(struct btrfs_trans_handle *trans,
                                 struct btrfs_root *root,
                                 struct btrfs_path *path,
                                 struct btrfs_extent_inline_ref *iref,
-                                int refs_to_drop, int is_data)
+                                int refs_to_drop, int is_data, int *last_ref)
 {
        int ret = 0;
 
        BUG_ON(!is_data && refs_to_drop != 1);
        if (iref) {
                update_inline_extent_backref(root, path, iref,
-                                            -refs_to_drop, NULL);
+                                            -refs_to_drop, NULL, last_ref);
        } else if (is_data) {
-               ret = remove_extent_data_ref(trans, root, path, refs_to_drop);
+               ret = remove_extent_data_ref(trans, root, path, refs_to_drop,
+                                            last_ref);
        } else {
+               *last_ref = 1;
                ret = btrfs_del_item(trans, root, path);
        }
        return ret;
@@ -1946,7 +1953,8 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
 int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
                         struct btrfs_root *root,
                         u64 bytenr, u64 num_bytes, u64 parent,
-                        u64 root_objectid, u64 owner, u64 offset, int for_cow)
+                        u64 root_objectid, u64 owner, u64 offset,
+                        int no_quota)
 {
        int ret;
        struct btrfs_fs_info *fs_info = root->fs_info;
@@ -1958,12 +1966,12 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
                ret = btrfs_add_delayed_tree_ref(fs_info, trans, bytenr,
                                        num_bytes,
                                        parent, root_objectid, (int)owner,
-                                       BTRFS_ADD_DELAYED_REF, NULL, for_cow);
+                                       BTRFS_ADD_DELAYED_REF, NULL, no_quota);
        } else {
                ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr,
                                        num_bytes,
                                        parent, root_objectid, owner, offset,
-                                       BTRFS_ADD_DELAYED_REF, NULL, for_cow);
+                                       BTRFS_ADD_DELAYED_REF, NULL, no_quota);
        }
        return ret;
 }
@@ -1973,31 +1981,64 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
                                  u64 bytenr, u64 num_bytes,
                                  u64 parent, u64 root_objectid,
                                  u64 owner, u64 offset, int refs_to_add,
+                                 int no_quota,
                                  struct btrfs_delayed_extent_op *extent_op)
 {
+       struct btrfs_fs_info *fs_info = root->fs_info;
        struct btrfs_path *path;
        struct extent_buffer *leaf;
        struct btrfs_extent_item *item;
+       struct btrfs_key key;
        u64 refs;
        int ret;
+       enum btrfs_qgroup_operation_type type = BTRFS_QGROUP_OPER_ADD_EXCL;
 
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
 
+       if (!is_fstree(root_objectid) || !root->fs_info->quota_enabled)
+               no_quota = 1;
+
        path->reada = 1;
        path->leave_spinning = 1;
        /* this will setup the path even if it fails to insert the back ref */
-       ret = insert_inline_extent_backref(trans, root->fs_info->extent_root,
-                                          path, bytenr, num_bytes, parent,
+       ret = insert_inline_extent_backref(trans, fs_info->extent_root, path,
+                                          bytenr, num_bytes, parent,
                                           root_objectid, owner, offset,
                                           refs_to_add, extent_op);
-       if (ret != -EAGAIN)
+       if ((ret < 0 && ret != -EAGAIN) || (!ret && no_quota))
+               goto out;
+       /*
+        * Ok we were able to insert an inline extent and it appears to be a new
+        * reference, deal with the qgroup accounting.
+        */
+       if (!ret && !no_quota) {
+               ASSERT(root->fs_info->quota_enabled);
+               leaf = path->nodes[0];
+               btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
+               item = btrfs_item_ptr(leaf, path->slots[0],
+                                     struct btrfs_extent_item);
+               if (btrfs_extent_refs(leaf, item) > (u64)refs_to_add)
+                       type = BTRFS_QGROUP_OPER_ADD_SHARED;
+               btrfs_release_path(path);
+
+               ret = btrfs_qgroup_record_ref(trans, fs_info, root_objectid,
+                                             bytenr, num_bytes, type, 0);
                goto out;
+       }
 
+       /*
+        * Ok we had -EAGAIN which means we didn't have space to insert and
+        * inline extent ref, so just update the reference count and add a
+        * normal backref.
+        */
        leaf = path->nodes[0];
+       btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
        item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);
        refs = btrfs_extent_refs(leaf, item);
+       if (refs)
+               type = BTRFS_QGROUP_OPER_ADD_SHARED;
        btrfs_set_extent_refs(leaf, item, refs + refs_to_add);
        if (extent_op)
                __run_delayed_extent_op(extent_op, leaf, item);
@@ -2005,9 +2046,15 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
        btrfs_mark_buffer_dirty(leaf);
        btrfs_release_path(path);
 
+       if (!no_quota) {
+               ret = btrfs_qgroup_record_ref(trans, fs_info, root_objectid,
+                                             bytenr, num_bytes, type, 0);
+               if (ret)
+                       goto out;
+       }
+
        path->reada = 1;
        path->leave_spinning = 1;
-
        /* now insert the actual backref */
        ret = insert_extent_backref(trans, root->fs_info->extent_root,
                                    path, bytenr, parent, root_objectid,
@@ -2041,8 +2088,7 @@ static int run_delayed_data_ref(struct btrfs_trans_handle *trans,
 
        if (node->type == BTRFS_SHARED_DATA_REF_KEY)
                parent = ref->parent;
-       else
-               ref_root = ref->root;
+       ref_root = ref->root;
 
        if (node->action == BTRFS_ADD_DELAYED_REF && insert_reserved) {
                if (extent_op)
@@ -2056,13 +2102,13 @@ static int run_delayed_data_ref(struct btrfs_trans_handle *trans,
                                             node->num_bytes, parent,
                                             ref_root, ref->objectid,
                                             ref->offset, node->ref_mod,
-                                            extent_op);
+                                            node->no_quota, extent_op);
        } else if (node->action == BTRFS_DROP_DELAYED_REF) {
                ret = __btrfs_free_extent(trans, root, node->bytenr,
                                          node->num_bytes, parent,
                                          ref_root, ref->objectid,
                                          ref->offset, node->ref_mod,
-                                         extent_op);
+                                         extent_op, node->no_quota);
        } else {
                BUG();
        }
@@ -2199,8 +2245,7 @@ static int run_delayed_tree_ref(struct btrfs_trans_handle *trans,
 
        if (node->type == BTRFS_SHARED_BLOCK_REF_KEY)
                parent = ref->parent;
-       else
-               ref_root = ref->root;
+       ref_root = ref->root;
 
        ins.objectid = node->bytenr;
        if (skinny_metadata) {
@@ -2218,15 +2263,18 @@ static int run_delayed_tree_ref(struct btrfs_trans_handle *trans,
                                                parent, ref_root,
                                                extent_op->flags_to_set,
                                                &extent_op->key,
-                                               ref->level, &ins);
+                                               ref->level, &ins,
+                                               node->no_quota);
        } else if (node->action == BTRFS_ADD_DELAYED_REF) {
                ret = __btrfs_inc_extent_ref(trans, root, node->bytenr,
                                             node->num_bytes, parent, ref_root,
-                                            ref->level, 0, 1, extent_op);
+                                            ref->level, 0, 1, node->no_quota,
+                                            extent_op);
        } else if (node->action == BTRFS_DROP_DELAYED_REF) {
                ret = __btrfs_free_extent(trans, root, node->bytenr,
                                          node->num_bytes, parent, ref_root,
-                                         ref->level, 0, 1, extent_op);
+                                         ref->level, 0, 1, extent_op,
+                                         node->no_quota);
        } else {
                BUG();
        }
@@ -2574,42 +2622,6 @@ static u64 find_middle(struct rb_root *root)
 }
 #endif
 
-int btrfs_delayed_refs_qgroup_accounting(struct btrfs_trans_handle *trans,
-                                        struct btrfs_fs_info *fs_info)
-{
-       struct qgroup_update *qgroup_update;
-       int ret = 0;
-
-       if (list_empty(&trans->qgroup_ref_list) !=
-           !trans->delayed_ref_elem.seq) {
-               /* list without seq or seq without list */
-               btrfs_err(fs_info,
-                       "qgroup accounting update error, list is%s empty, seq is %#x.%x",
-                       list_empty(&trans->qgroup_ref_list) ? "" : " not",
-                       (u32)(trans->delayed_ref_elem.seq >> 32),
-                       (u32)trans->delayed_ref_elem.seq);
-               BUG();
-       }
-
-       if (!trans->delayed_ref_elem.seq)
-               return 0;
-
-       while (!list_empty(&trans->qgroup_ref_list)) {
-               qgroup_update = list_first_entry(&trans->qgroup_ref_list,
-                                                struct qgroup_update, list);
-               list_del(&qgroup_update->list);
-               if (!ret)
-                       ret = btrfs_qgroup_account_ref(
-                                       trans, fs_info, qgroup_update->node,
-                                       qgroup_update->extent_op);
-               kfree(qgroup_update);
-       }
-
-       btrfs_put_tree_mod_seq(fs_info, &trans->delayed_ref_elem);
-
-       return ret;
-}
-
 static inline u64 heads_to_leaves(struct btrfs_root *root, u64 heads)
 {
        u64 num_bytes;
@@ -2698,8 +2710,6 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
        if (root == root->fs_info->extent_root)
                root = root->fs_info->tree_root;
 
-       btrfs_delayed_refs_qgroup_accounting(trans, root->fs_info);
-
        delayed_refs = &trans->transaction->delayed_refs;
        if (count == 0) {
                count = atomic_read(&delayed_refs->num_entries) * 2;
@@ -2758,6 +2768,9 @@ again:
                goto again;
        }
 out:
+       ret = btrfs_delayed_qgroup_accounting(trans, root->fs_info);
+       if (ret)
+               return ret;
        assert_qgroups_uptodate(trans);
        return 0;
 }
@@ -2964,7 +2977,7 @@ out:
 static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root,
                           struct extent_buffer *buf,
-                          int full_backref, int inc, int for_cow)
+                          int full_backref, int inc, int no_quota)
 {
        u64 bytenr;
        u64 num_bytes;
@@ -2983,7 +2996,7 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
        nritems = btrfs_header_nritems(buf);
        level = btrfs_header_level(buf);
 
-       if (!root->ref_cows && level == 0)
+       if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state) && level == 0)
                return 0;
 
        if (inc)
@@ -3014,7 +3027,7 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
                        key.offset -= btrfs_file_extent_offset(buf, fi);
                        ret = process_func(trans, root, bytenr, num_bytes,
                                           parent, ref_root, key.objectid,
-                                          key.offset, for_cow);
+                                          key.offset, no_quota);
                        if (ret)
                                goto fail;
                } else {
@@ -3022,7 +3035,7 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
                        num_bytes = btrfs_level_size(root, level - 1);
                        ret = process_func(trans, root, bytenr, num_bytes,
                                           parent, ref_root, level - 1, 0,
-                                          for_cow);
+                                          no_quota);
                        if (ret)
                                goto fail;
                }
@@ -3033,15 +3046,15 @@ fail:
 }
 
 int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                 struct extent_buffer *buf, int full_backref, int for_cow)
+                 struct extent_buffer *buf, int full_backref, int no_quota)
 {
-       return __btrfs_mod_ref(trans, root, buf, full_backref, 1, for_cow);
+       return __btrfs_mod_ref(trans, root, buf, full_backref, 1, no_quota);
 }
 
 int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                 struct extent_buffer *buf, int full_backref, int for_cow)
+                 struct extent_buffer *buf, int full_backref, int no_quota)
 {
-       return __btrfs_mod_ref(trans, root, buf, full_backref, 0, for_cow);
+       return __btrfs_mod_ref(trans, root, buf, full_backref, 0, no_quota);
 }
 
 static int write_one_cache_group(struct btrfs_trans_handle *trans,
@@ -4204,6 +4217,104 @@ static int flush_space(struct btrfs_root *root,
 
        return ret;
 }
+
+static inline u64
+btrfs_calc_reclaim_metadata_size(struct btrfs_root *root,
+                                struct btrfs_space_info *space_info)
+{
+       u64 used;
+       u64 expected;
+       u64 to_reclaim;
+
+       to_reclaim = min_t(u64, num_online_cpus() * 1024 * 1024,
+                               16 * 1024 * 1024);
+       spin_lock(&space_info->lock);
+       if (can_overcommit(root, space_info, to_reclaim,
+                          BTRFS_RESERVE_FLUSH_ALL)) {
+               to_reclaim = 0;
+               goto out;
+       }
+
+       used = space_info->bytes_used + space_info->bytes_reserved +
+              space_info->bytes_pinned + space_info->bytes_readonly +
+              space_info->bytes_may_use;
+       if (can_overcommit(root, space_info, 1024 * 1024,
+                          BTRFS_RESERVE_FLUSH_ALL))
+               expected = div_factor_fine(space_info->total_bytes, 95);
+       else
+               expected = div_factor_fine(space_info->total_bytes, 90);
+
+       if (used > expected)
+               to_reclaim = used - expected;
+       else
+               to_reclaim = 0;
+       to_reclaim = min(to_reclaim, space_info->bytes_may_use +
+                                    space_info->bytes_reserved);
+out:
+       spin_unlock(&space_info->lock);
+
+       return to_reclaim;
+}
+
+static inline int need_do_async_reclaim(struct btrfs_space_info *space_info,
+                                       struct btrfs_fs_info *fs_info, u64 used)
+{
+       return (used >= div_factor_fine(space_info->total_bytes, 98) &&
+               !btrfs_fs_closing(fs_info) &&
+               !test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state));
+}
+
+static int btrfs_need_do_async_reclaim(struct btrfs_space_info *space_info,
+                                      struct btrfs_fs_info *fs_info)
+{
+       u64 used;
+
+       spin_lock(&space_info->lock);
+       used = space_info->bytes_used + space_info->bytes_reserved +
+              space_info->bytes_pinned + space_info->bytes_readonly +
+              space_info->bytes_may_use;
+       if (need_do_async_reclaim(space_info, fs_info, used)) {
+               spin_unlock(&space_info->lock);
+               return 1;
+       }
+       spin_unlock(&space_info->lock);
+
+       return 0;
+}
+
+static void btrfs_async_reclaim_metadata_space(struct work_struct *work)
+{
+       struct btrfs_fs_info *fs_info;
+       struct btrfs_space_info *space_info;
+       u64 to_reclaim;
+       int flush_state;
+
+       fs_info = container_of(work, struct btrfs_fs_info, async_reclaim_work);
+       space_info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA);
+
+       to_reclaim = btrfs_calc_reclaim_metadata_size(fs_info->fs_root,
+                                                     space_info);
+       if (!to_reclaim)
+               return;
+
+       flush_state = FLUSH_DELAYED_ITEMS_NR;
+       do {
+               flush_space(fs_info->fs_root, space_info, to_reclaim,
+                           to_reclaim, flush_state);
+               flush_state++;
+               if (!btrfs_need_do_async_reclaim(space_info, fs_info))
+                       return;
+       } while (flush_state <= COMMIT_TRANS);
+
+       if (btrfs_need_do_async_reclaim(space_info, fs_info))
+               queue_work(system_unbound_wq, work);
+}
+
+void btrfs_init_async_reclaim_work(struct work_struct *work)
+{
+       INIT_WORK(work, btrfs_async_reclaim_metadata_space);
+}
+
 /**
  * reserve_metadata_bytes - try to reserve bytes from the block_rsv's space
  * @root - the root we're allocating for
@@ -4311,8 +4422,13 @@ again:
        if (ret && flush != BTRFS_RESERVE_NO_FLUSH) {
                flushing = true;
                space_info->flush = 1;
+       } else if (!ret && space_info->flags & BTRFS_BLOCK_GROUP_METADATA) {
+               used += orig_bytes;
+               if (need_do_async_reclaim(space_info, root->fs_info, used) &&
+                   !work_busy(&root->fs_info->async_reclaim_work))
+                       queue_work(system_unbound_wq,
+                                  &root->fs_info->async_reclaim_work);
        }
-
        spin_unlock(&space_info->lock);
 
        if (!ret || flush == BTRFS_RESERVE_NO_FLUSH)
@@ -4369,7 +4485,7 @@ static struct btrfs_block_rsv *get_block_rsv(
 {
        struct btrfs_block_rsv *block_rsv = NULL;
 
-       if (root->ref_cows)
+       if (test_bit(BTRFS_ROOT_REF_COWS, &root->state))
                block_rsv = trans->block_rsv;
 
        if (root == root->fs_info->csum_root && trans->adding_csums)
@@ -5621,7 +5737,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                                u64 bytenr, u64 num_bytes, u64 parent,
                                u64 root_objectid, u64 owner_objectid,
                                u64 owner_offset, int refs_to_drop,
-                               struct btrfs_delayed_extent_op *extent_op)
+                               struct btrfs_delayed_extent_op *extent_op,
+                               int no_quota)
 {
        struct btrfs_key key;
        struct btrfs_path *path;
@@ -5637,9 +5754,14 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
        int num_to_del = 1;
        u32 item_size;
        u64 refs;
+       int last_ref = 0;
+       enum btrfs_qgroup_operation_type type = BTRFS_QGROUP_OPER_SUB_EXCL;
        bool skinny_metadata = btrfs_fs_incompat(root->fs_info,
                                                 SKINNY_METADATA);
 
+       if (!info->quota_enabled || !is_fstree(root_objectid))
+               no_quota = 1;
+
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
@@ -5687,7 +5809,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                        BUG_ON(iref);
                        ret = remove_extent_backref(trans, extent_root, path,
                                                    NULL, refs_to_drop,
-                                                   is_data);
+                                                   is_data, &last_ref);
                        if (ret) {
                                btrfs_abort_transaction(trans, extent_root, ret);
                                goto out;
@@ -5814,6 +5936,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
        refs -= refs_to_drop;
 
        if (refs > 0) {
+               type = BTRFS_QGROUP_OPER_SUB_SHARED;
                if (extent_op)
                        __run_delayed_extent_op(extent_op, leaf, ei);
                /*
@@ -5829,7 +5952,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                if (found_extent) {
                        ret = remove_extent_backref(trans, extent_root, path,
                                                    iref, refs_to_drop,
-                                                   is_data);
+                                                   is_data, &last_ref);
                        if (ret) {
                                btrfs_abort_transaction(trans, extent_root, ret);
                                goto out;
@@ -5850,6 +5973,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                        }
                }
 
+               last_ref = 1;
                ret = btrfs_del_items(trans, extent_root, path, path->slots[0],
                                      num_to_del);
                if (ret) {
@@ -5872,6 +5996,20 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                        goto out;
                }
        }
+       btrfs_release_path(path);
+
+       /* Deal with the quota accounting */
+       if (!ret && last_ref && !no_quota) {
+               int mod_seq = 0;
+
+               if (owner_objectid >= BTRFS_FIRST_FREE_OBJECTID &&
+                   type == BTRFS_QGROUP_OPER_SUB_SHARED)
+                       mod_seq = 1;
+
+               ret = btrfs_qgroup_record_ref(trans, info, root_objectid,
+                                             bytenr, num_bytes, type,
+                                             mod_seq);
+       }
 out:
        btrfs_free_path(path);
        return ret;
@@ -6008,7 +6146,7 @@ out:
 /* Can return -ENOMEM */
 int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                      u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid,
-                     u64 owner, u64 offset, int for_cow)
+                     u64 owner, u64 offset, int no_quota)
 {
        int ret;
        struct btrfs_fs_info *fs_info = root->fs_info;
@@ -6028,13 +6166,13 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                ret = btrfs_add_delayed_tree_ref(fs_info, trans, bytenr,
                                        num_bytes,
                                        parent, root_objectid, (int)owner,
-                                       BTRFS_DROP_DELAYED_REF, NULL, for_cow);
+                                       BTRFS_DROP_DELAYED_REF, NULL, no_quota);
        } else {
                ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr,
                                                num_bytes,
                                                parent, root_objectid, owner,
                                                offset, BTRFS_DROP_DELAYED_REF,
-                                               NULL, for_cow);
+                                               NULL, no_quota);
        }
        return ret;
 }
@@ -6514,8 +6652,14 @@ loop:
                loop++;
                if (loop == LOOP_ALLOC_CHUNK) {
                        struct btrfs_trans_handle *trans;
+                       int exist = 0;
+
+                       trans = current->journal_info;
+                       if (trans)
+                               exist = 1;
+                       else
+                               trans = btrfs_join_transaction(root);
 
-                       trans = btrfs_join_transaction(root);
                        if (IS_ERR(trans)) {
                                ret = PTR_ERR(trans);
                                goto out;
@@ -6532,7 +6676,8 @@ loop:
                                                        root, ret);
                        else
                                ret = 0;
-                       btrfs_end_transaction(trans, root);
+                       if (!exist)
+                               btrfs_end_transaction(trans, root);
                        if (ret)
                                goto out;
                }
@@ -6733,6 +6878,13 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
        btrfs_mark_buffer_dirty(path->nodes[0]);
        btrfs_free_path(path);
 
+       /* Always set parent to 0 here since its exclusive anyway. */
+       ret = btrfs_qgroup_record_ref(trans, fs_info, root_objectid,
+                                     ins->objectid, ins->offset,
+                                     BTRFS_QGROUP_OPER_ADD_EXCL, 0);
+       if (ret)
+               return ret;
+
        ret = update_block_group(root, ins->objectid, ins->offset, 1);
        if (ret) { /* -ENOENT, logic error */
                btrfs_err(fs_info, "update block group failed for %llu %llu",
@@ -6747,7 +6899,8 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
                                     struct btrfs_root *root,
                                     u64 parent, u64 root_objectid,
                                     u64 flags, struct btrfs_disk_key *key,
-                                    int level, struct btrfs_key *ins)
+                                    int level, struct btrfs_key *ins,
+                                    int no_quota)
 {
        int ret;
        struct btrfs_fs_info *fs_info = root->fs_info;
@@ -6757,6 +6910,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
        struct btrfs_path *path;
        struct extent_buffer *leaf;
        u32 size = sizeof(*extent_item) + sizeof(*iref);
+       u64 num_bytes = ins->offset;
        bool skinny_metadata = btrfs_fs_incompat(root->fs_info,
                                                 SKINNY_METADATA);
 
@@ -6790,6 +6944,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
 
        if (skinny_metadata) {
                iref = (struct btrfs_extent_inline_ref *)(extent_item + 1);
+               num_bytes = root->leafsize;
        } else {
                block_info = (struct btrfs_tree_block_info *)(extent_item + 1);
                btrfs_set_tree_block_key(leaf, block_info, key);
@@ -6811,6 +6966,14 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
        btrfs_mark_buffer_dirty(leaf);
        btrfs_free_path(path);
 
+       if (!no_quota) {
+               ret = btrfs_qgroup_record_ref(trans, fs_info, root_objectid,
+                                             ins->objectid, num_bytes,
+                                             BTRFS_QGROUP_OPER_ADD_EXCL, 0);
+               if (ret)
+                       return ret;
+       }
+
        ret = update_block_group(root, ins->objectid, root->leafsize, 1);
        if (ret) { /* -ENOENT, logic error */
                btrfs_err(fs_info, "update block group failed for %llu %llu",
@@ -7735,7 +7898,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
                }
        }
 
-       if (root->in_radix) {
+       if (test_bit(BTRFS_ROOT_IN_RADIX, &root->state)) {
                btrfs_drop_and_free_fs_root(tree_root->fs_info, root);
        } else {
                free_extent_buffer(root->node);
@@ -8611,7 +8774,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
 
        extent_root = root->fs_info->extent_root;
 
-       root->fs_info->last_trans_log_full_commit = trans->transid;
+       btrfs_set_log_full_commit(root->fs_info, trans);
 
        cache = btrfs_create_block_group_cache(root, chunk_offset, size);
        if (!cache)
This page took 0.03339 seconds and 5 git commands to generate.