This patch make the qgroup account the information of data or metadata
by different infos.
Signed-off-by: Dongsheng Yang <yangds.fnst@xxxxxxxxxxxxxx>
---
fs/btrfs/extent-tree.c | 48 +++++----
fs/btrfs/qgroup.c | 239 ++++++++++++++++++++++++++----------------
fs/btrfs/qgroup.h | 25 ++++-
fs/btrfs/tests/qgroup-tests.c | 15 ++-
fs/btrfs/transaction.c | 11 +-
5 files changed, 217 insertions(+), 121 deletions(-)
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 3f49316..cb27da6 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -83,7 +83,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
u64 root_objectid, u64 owner_objectid,
u64 owner_offset, int refs_to_drop,
struct btrfs_delayed_extent_op *extra_op,
- int no_quota);
+ int no_quota, unsigned int quota_type);
static void __run_delayed_extent_op(struct btrfs_delayed_extent_op *extent_op,
struct extent_buffer *leaf,
struct btrfs_extent_item *ei);
@@ -1971,7 +1971,8 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
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_delayed_extent_op *extent_op,
+ unsigned int quota_type)
{
struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_path *path;
@@ -2013,7 +2014,8 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
btrfs_release_path(path);
ret = btrfs_qgroup_record_ref(trans, fs_info, root_objectid,
- bytenr, num_bytes, type, 0);
+ bytenr, num_bytes, type,
+ quota_type, 0);
goto out;
}
@@ -2037,7 +2039,8 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
if (!no_quota) {
ret = btrfs_qgroup_record_ref(trans, fs_info, root_objectid,
- bytenr, num_bytes, type, 0);
+ bytenr, num_bytes, type,
+ quota_type, 0);
if (ret)
goto out;
}
@@ -2091,13 +2094,15 @@ static int run_delayed_data_ref(struct btrfs_trans_handle *trans,
node->num_bytes, parent,
ref_root, ref->objectid,
ref->offset, node->ref_mod,
- node->no_quota, extent_op);
+ node->no_quota, extent_op,
+ BTRFS_QGROUP_REF_TYPE_DATA);
} 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, node->no_quota);
+ extent_op, node->no_quota,
+ BTRFS_QGROUP_REF_TYPE_DATA);
} else {
BUG();
}
@@ -2258,12 +2263,12 @@ static int run_delayed_tree_ref(struct btrfs_trans_handle *trans,
ret = __btrfs_inc_extent_ref(trans, root, node->bytenr,
node->num_bytes, parent, ref_root,
ref->level, 0, 1, node->no_quota,
- extent_op);
+ extent_op, BTRFS_QGROUP_REF_TYPE_METADATA);
} 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,
- node->no_quota);
+ node->no_quota, BTRFS_QGROUP_REF_TYPE_METADATA);
} else {
BUG();
}
@@ -3694,7 +3699,7 @@ commit_trans:
data_sinfo->flags, bytes, 1);
return -ENOSPC;
}
- ret = btrfs_qgroup_reserve(root, write_bytes);
+ ret = btrfs_qgroup_reserve(root, write_bytes, BTRFS_QGROUP_REF_TYPE_DATA);
if (ret)
goto out;
data_sinfo->bytes_may_use += bytes;
@@ -4929,7 +4934,7 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
if (root->fs_info->quota_enabled) {
/* One for parent inode, two for dir entries */
num_bytes = 3 * root->nodesize;
- ret = btrfs_qgroup_reserve(root, num_bytes);
+ ret = btrfs_qgroup_reserve(root, num_bytes, BTRFS_QGROUP_REF_TYPE_METADATA);
if (ret)
return ret;
} else {
@@ -4949,7 +4954,7 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
if (ret) {
if (*qgroup_reserved)
- btrfs_qgroup_free(root, *qgroup_reserved);
+ btrfs_qgroup_free(root, *qgroup_reserved, BTRFS_QGROUP_REF_TYPE_METADATA);
}
return ret;
@@ -5119,7 +5124,8 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
spin_unlock(&BTRFS_I(inode)->lock);
if (root->fs_info->quota_enabled) {
- ret = btrfs_qgroup_reserve(root, nr_extents * root->nodesize);
+ ret = btrfs_qgroup_reserve(root, nr_extents * root->nodesize,
+ BTRFS_QGROUP_REF_TYPE_METADATA);
if (ret)
goto out_fail;
}
@@ -5127,7 +5133,8 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
ret = reserve_metadata_bytes(root, block_rsv, to_reserve, flush);
if (unlikely(ret)) {
if (root->fs_info->quota_enabled)
- btrfs_qgroup_free(root, nr_extents * root->nodesize);
+ btrfs_qgroup_free(root, nr_extents * root->nodesize,
+ BTRFS_QGROUP_REF_TYPE_METADATA);
goto out_fail;
}
@@ -5785,7 +5792,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
u64 root_objectid, u64 owner_objectid,
u64 owner_offset, int refs_to_drop,
struct btrfs_delayed_extent_op *extent_op,
- int no_quota)
+ int no_quota, unsigned int quota_type)
{
struct btrfs_key key;
struct btrfs_path *path;
@@ -6055,7 +6062,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
ret = btrfs_qgroup_record_ref(trans, info, root_objectid,
bytenr, num_bytes, type,
- mod_seq);
+ quota_type, mod_seq);
}
out:
btrfs_free_path(path);
@@ -6996,7 +7003,8 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
/* 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);
+ BTRFS_QGROUP_OPER_ADD_EXCL,
+ BTRFS_QGROUP_REF_TYPE_DATA, 0);
if (ret)
return ret;
@@ -7084,7 +7092,8 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
if (!no_quota) {
ret = btrfs_qgroup_record_ref(trans, fs_info, root_objectid,
ins->objectid, num_bytes,
- BTRFS_QGROUP_OPER_ADD_EXCL, 0);
+ BTRFS_QGROUP_OPER_ADD_EXCL,
+ BTRFS_QGROUP_REF_TYPE_METADATA, 0);
if (ret)
return ret;
}
@@ -7462,7 +7471,8 @@ static int account_leaf_items(struct btrfs_trans_handle *trans,
ret = btrfs_qgroup_record_ref(trans, root->fs_info,
root->objectid,
bytenr, num_bytes,
- BTRFS_QGROUP_OPER_SUB_SUBTREE, 0);
+ BTRFS_QGROUP_OPER_SUB_SUBTREE,
+ BTRFS_QGROUP_REF_TYPE_METADATA, 0);
if (ret)
return ret;
}
@@ -7612,7 +7622,7 @@ walk_down:
child_bytenr,
root->nodesize,
BTRFS_QGROUP_OPER_SUB_SUBTREE,
- 0);
+ BTRFS_QGROUP_REF_TYPE_METADATA, 0);
if (ret)
goto out;
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 34eb4f5..9dd2627 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -1451,7 +1451,8 @@ static int insert_qgroup_oper(struct btrfs_fs_info *fs_info,
int btrfs_qgroup_record_ref(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 ref_root,
u64 bytenr, u64 num_bytes,
- enum btrfs_qgroup_operation_type type, int mod_seq)
+ enum btrfs_qgroup_operation_type type,
+ unsigned int quota_type, int mod_seq)
{
struct btrfs_qgroup_operation *oper;
int ret;
@@ -1467,6 +1468,7 @@ int btrfs_qgroup_record_ref(struct btrfs_trans_handle *trans,
oper->bytenr = bytenr;
oper->num_bytes = num_bytes;
oper->type = type;
+ oper->quota_type = quota_type;
oper->seq = atomic_inc_return(&fs_info->qgroup_op_seq);
INIT_LIST_HEAD(&oper->elem.list);
oper->elem.seq = 0;
@@ -1542,11 +1544,14 @@ static int qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
ASSERT(0);
}
- /*
- * FIXME: use the data_info to store all information currently.
- * will seperate the information into data and metadata later.
- **/
- info = &qgroup->data_info;
+ if (!btrfs_fs_incompat(fs_info, QGROUP_TYPE)) {
+ info = &qgroup->data_info;
+ } else {
+ if (oper->quota_type == BTRFS_QGROUP_REF_TYPE_DATA)
+ info = &qgroup->data_info;
+ else
+ info = &qgroup->metadata_info;
+ }
info->rfer += sign * oper->num_bytes;
info->rfer_cmpr += sign * oper->num_bytes;
@@ -1571,11 +1576,14 @@ static int qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
ULIST_ITER_INIT(&uiter);
while ((unode = ulist_next(tmp, &uiter))) {
qgroup = u64_to_ptr(unode->aux);
- /*
- * FIXME: use the data_info to store all information currently.
- * will seperate the information into data and metadata later.
- **/
- info = &qgroup->data_info;
+ if (!btrfs_fs_incompat(fs_info, QGROUP_TYPE)) {
+ info = &qgroup->data_info;
+ } else {
+ if (oper->quota_type == BTRFS_QGROUP_REF_TYPE_DATA)
+ info = &qgroup->data_info;
+ else
+ info = &qgroup->metadata_info;
+ }
info->rfer += sign * oper->num_bytes;
info->rfer_cmpr += sign * oper->num_bytes;
WARN_ON(sign < 0 && info->excl < oper->num_bytes);
@@ -1842,13 +1850,14 @@ static int qgroup_calc_new_refcnt(struct btrfs_fs_info *fs_info,
*/
static int qgroup_adjust_counters(struct btrfs_fs_info *fs_info,
u64 root_to_skip, u64 num_bytes,
- struct ulist *qgroups, u64 seq,
- int old_roots, int new_roots, int rescan)
+ u8 quota_type, struct ulist *qgroups,
+ u64 seq, int old_roots, int new_roots,
+ int rescan)
{
struct ulist_node *unode;
struct ulist_iterator uiter;
struct btrfs_qgroup *qg;
- struct btrfs_qgroup_info *data_info;
+ struct btrfs_qgroup_info *info;
u64 cur_new_count, cur_old_count;
ULIST_ITER_INIT(&uiter);
@@ -1857,14 +1866,21 @@ static int qgroup_adjust_counters(struct btrfs_fs_info *fs_info,
qg = u64_to_ptr(unode->aux);
- data_info = &qg->data_info;
+ if (!btrfs_fs_incompat(fs_info, QGROUP_TYPE)) {
+ info = &qg->data_info;
+ } else {
+ if (quota_type == BTRFS_QGROUP_REF_TYPE_DATA)
+ info = &qg->data_info;
+ else
+ info = &qg->metadata_info;
+ }
/*
* Wasn't referenced before but is now, add to the reference
* counters.
*/
if (qg->old_refcnt <= seq && qg->new_refcnt > seq) {
- data_info->rfer += num_bytes;
- data_info->rfer_cmpr += num_bytes;
+ info->rfer += num_bytes;
+ info->rfer_cmpr += num_bytes;
dirty = true;
}
@@ -1873,8 +1889,8 @@ static int qgroup_adjust_counters(struct btrfs_fs_info *fs_info,
* reference counters.
*/
if (qg->old_refcnt > seq && qg->new_refcnt <= seq) {
- data_info->rfer -= num_bytes;
- data_info->rfer_cmpr -= num_bytes;
+ info->rfer -= num_bytes;
+ info->rfer_cmpr -= num_bytes;
dirty = true;
}
@@ -1895,13 +1911,8 @@ static int qgroup_adjust_counters(struct btrfs_fs_info *fs_info,
if (old_roots && cur_old_count == old_roots &&
(cur_new_count != new_roots || new_roots == 0)) {
WARN_ON(cur_new_count != new_roots && new_roots == 0);
- /*
- * FIXME: use the data_info to store all information currently.
- * will seperate the information into data and metadata later.
- **/
- data_info = &qg->data_info;
- data_info->excl -= num_bytes;
- data_info->excl_cmpr -= num_bytes;
+ info->excl -= num_bytes;
+ info->excl_cmpr -= num_bytes;
dirty = true;
}
@@ -1911,13 +1922,8 @@ static int qgroup_adjust_counters(struct btrfs_fs_info *fs_info,
*/
if ((!old_roots || (old_roots && cur_old_count != old_roots))
&& cur_new_count == new_roots) {
- /*
- * FIXME: use the data_info to store all information currently.
- * will seperate the information into data and metadata later.
- **/
- data_info = &qg->data_info;
- data_info->excl += num_bytes;
- data_info->excl_cmpr += num_bytes;
+ info->excl += num_bytes;
+ info->excl_cmpr += num_bytes;
dirty = true;
}
@@ -2102,7 +2108,8 @@ static int qgroup_shared_accounting(struct btrfs_trans_handle *trans,
* solution for this.
*/
qgroup_adjust_counters(fs_info, oper->ref_root, oper->num_bytes,
- qgroups, seq, old_roots, new_roots, 0);
+ oper->quota_type, qgroups, seq, old_roots,
+ new_roots, 0);
out:
spin_unlock(&fs_info->qgroup_lock);
ulist_free(qgroups);
@@ -2171,11 +2178,16 @@ static int qgroup_subtree_accounting(struct btrfs_trans_handle *trans,
qg = find_qgroup_rb(fs_info, root_obj);
if (!qg)
goto out_unlock;
- /*
- * FIXME: use the data_info to store all information currently.
- * will seperate the information into data and metadata later.
- **/
- info = &qg->data_info;
+
+ if (!btrfs_fs_incompat(fs_info, QGROUP_TYPE)) {
+ info = &qg->data_info;
+ } else {
+ if (oper->quota_type == BTRFS_QGROUP_REF_TYPE_DATA)
+ info = &qg->data_info;
+ else
+ info = &qg->metadata_info;
+ }
+
info->excl += oper->num_bytes;
info->excl_cmpr += oper->num_bytes;
qgroup_dirty(fs_info, qg);
@@ -2197,11 +2209,15 @@ static int qgroup_subtree_accounting(struct btrfs_trans_handle *trans,
ULIST_ITER_INIT(&uiter);
while ((unode = ulist_next(parents, &uiter))) {
qg = u64_to_ptr(unode->aux);
- /*
- * FIXME: use the data_info to store all information currently.
- * will seperate the information into data and metadata later.
- **/
- info = &qg->data_info;
+
+ if (!btrfs_fs_incompat(fs_info, QGROUP_TYPE)) {
+ info = &qg->data_info;
+ } else {
+ if (oper->quota_type == BTRFS_QGROUP_REF_TYPE_DATA)
+ info = &qg->data_info;
+ else
+ info = &qg->metadata_info;
+ }
info->excl += oper->num_bytes;
info->excl_cmpr += oper->num_bytes;
qgroup_dirty(fs_info, qg);
@@ -2579,12 +2595,47 @@ out:
return ret;
}
-int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes)
+static int exceed_limits(struct btrfs_qgroup_info *info,
+ struct btrfs_qgroup_limits *limits,
+ struct btrfs_qgroup_info *another_info,
+ u64 num_bytes)
+{
+ if (another_info) {
+ /*
+ * For the mixed limits.
+ */
+ if ((limits->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) &&
+ info->reserved + (s64)info->excl +
+ another_info->reserved + (s64)another_info->excl +
+ num_bytes > limits->max_excl)
+ return 1;
+
+ if ((limits->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) &&
+ info->reserved + (s64)info->rfer +
+ another_info->reserved + (s64)another_info->rfer +
+ num_bytes > limits->max_rfer)
+ return 1;
+
+ } else {
+ if ((limits->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) &&
+ info->reserved + (s64)info->excl + num_bytes >
+ limits->max_excl)
+ return 1;
+
+ if ((limits->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) &&
+ info->reserved + (s64)info->rfer + num_bytes >
+ limits->max_rfer)
+ return 1;
+ }
+
+ return 0;
+}
+
+int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes, u8 type)
{
struct btrfs_root *quota_root;
struct btrfs_qgroup *qgroup;
- struct btrfs_qgroup_info *data_info;
- struct btrfs_qgroup_limits *mixed_limits;
+ struct btrfs_qgroup_info *info;
struct btrfs_fs_info *fs_info = root->fs_info;
u64 ref_root = root->root_key.objectid;
int ret = 0;
@@ -2617,33 +2668,32 @@ int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes)
goto out;
ULIST_ITER_INIT(&uiter);
while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) {
- struct btrfs_qgroup *qg;
+ struct btrfs_qgroup *qgroup;
struct btrfs_qgroup_list *glist;
- qg = u64_to_ptr(unode->aux);
-
- /*
- * FIXME: use the data_info to store all information currently.
- * will seperate the information into data and metadata later.
- **/
- data_info = &qgroup->data_info;
- mixed_limits = &qgroup->mixed_limits;
+ qgroup = u64_to_ptr(unode->aux);
- if ((mixed_limits->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) &&
- data_info->reserved + (s64)data_info->rfer + num_bytes >
- mixed_limits->max_rfer) {
- ret = -EDQUOT;
- goto out;
+ if (type == BTRFS_QGROUP_REF_TYPE_DATA) {
+ info = &qgroup->data_info;
+ if (exceed_limits(info, &qgroup->data_limits, NULL, num_bytes)) {
+ ret = -EDQUOT;
+ goto out;
+ }
+ } else {
+ info = &qgroup->metadata_info;
+ if (exceed_limits(info, &qgroup->metadata_limits, NULL, num_bytes)) {
+ ret = -EDQUOT;
+ goto out;
+ }
}
- if ((mixed_limits->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) &&
- data_info->reserved + (s64)data_info->excl + num_bytes >
- mixed_limits->max_excl) {
+ if (exceed_limits(&qgroup->data_info, &qgroup->mixed_limits,
+ &qgroup->metadata_info, num_bytes)) {
ret = -EDQUOT;
goto out;
}
- list_for_each_entry(glist, &qg->groups, next_group) {
+ list_for_each_entry(glist, &qgroup->groups, next_group) {
ret = ulist_add(fs_info->qgroup_ulist,
glist->group->qgroupid,
(uintptr_t)glist->group, GFP_ATOMIC);
@@ -2661,13 +2711,16 @@ int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes)
qg = u64_to_ptr(unode->aux);
- /*
- * FIXME: use the data_info to store all information currently.
- * will seperate the information into data and metadata later.
- **/
- data_info = &qg->data_info;
+ if (!btrfs_fs_incompat(fs_info, QGROUP_TYPE)) {
+ info = &qg->data_info;
+ } else {
+ if (type == BTRFS_QGROUP_REF_TYPE_DATA)
+ info = &qg->data_info;
+ else
+ info = &qg->metadata_info;
+ }
- data_info->reserved += num_bytes;
+ info->reserved += num_bytes;
}
out:
@@ -2675,11 +2728,11 @@ out:
return ret;
}
-void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes)
+void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes, u8 type)
{
struct btrfs_root *quota_root;
struct btrfs_qgroup *qgroup;
- struct btrfs_qgroup_info *data_info;
+ struct btrfs_qgroup_info *info;
struct btrfs_fs_info *fs_info = root->fs_info;
struct ulist_node *unode;
struct ulist_iterator uiter;
@@ -2714,13 +2767,16 @@ void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes)
qg = u64_to_ptr(unode->aux);
- /*
- * FIXME: use the data_info to store all information currently.
- * will seperate the information into data and metadata later.
- **/
- data_info = &qg->data_info;
+ if (!btrfs_fs_incompat(fs_info, QGROUP_TYPE)) {
+ info = &qg->data_info;
+ } else {
+ if (type == BTRFS_QGROUP_REF_TYPE_DATA)
+ info = &qg->data_info;
+ else
+ info = &qg->metadata_info;
+ }
- data_info->reserved -= num_bytes;
+ info->reserved -= num_bytes;
list_for_each_entry(glist, &qg->groups, next_group) {
ret = ulist_add(fs_info->qgroup_ulist,
@@ -2830,7 +2886,7 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path,
goto out;
}
- ret = qgroup_adjust_counters(fs_info, 0, num_bytes, qgroups,
+ ret = qgroup_adjust_counters(fs_info, 0, num_bytes, 0, qgroups,
seq, 0, new_roots, 1);
if (ret < 0) {
spin_unlock(&fs_info->qgroup_lock);
@@ -2979,22 +3035,25 @@ qgroup_rescan_zero_tracking(struct btrfs_fs_info *fs_info)
{
struct rb_node *n;
struct btrfs_qgroup *qgroup;
- struct btrfs_qgroup_info *data_info;
+ struct btrfs_qgroup_info *info;
spin_lock(&fs_info->qgroup_lock);
/* clear all current qgroup tracking information */
for (n = rb_first(&fs_info->qgroup_tree); n; n = rb_next(n)) {
qgroup = rb_entry(n, struct btrfs_qgroup, node);
- /*
- * FIXME: use the data_info to store all information currently.
- * will seperate the information into data and metadata later.
- **/
- data_info = &qgroup->data_info;
- data_info->rfer = 0;
- data_info->rfer_cmpr = 0;
- data_info->excl = 0;
- data_info->excl_cmpr = 0;
+ info = &qgroup->data_info;
+
+again:
+ info->rfer = 0;
+ info->rfer_cmpr = 0;
+ info->excl = 0;
+ info->excl_cmpr = 0;
+
+ if (info != &qgroup->metadata_info) {
+ info = &qgroup->metadata_info;
+ goto again;
+ }
}
spin_unlock(&fs_info->qgroup_lock);
}
diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h
index 52d8b19..11b73f3 100644
--- a/fs/btrfs/qgroup.h
+++ b/fs/btrfs/qgroup.h
@@ -20,6 +20,22 @@
#define __BTRFS_QGROUP__
/*
+ * Type for quota reference. Caller of qgroup_record_ref()
+ * should choose one type of the reference passed to qgroup.
+ * Then qgroup will account the reference in the chosen info.
+ */
+#define BTRFS_QGROUP_REF_TYPE_DATA (1 << 0)
+#define BTRFS_QGROUP_REF_TYPE_METADATA (1 << 1)
+
+/*
+ * To keep the compatibility, define a default type to manage
+ * the all reference in the older kernel. Choose the data_info
+ * to account all reference in older kernel which did not record
+ * and account reference for data and metadata separately.
+ */
+#define BTRFS_QGROUP_REF_TYPE_DEFAULT BTRFS_QGROUP_REF_TYPE_DATA
+
+/*
* A description of the operations, all of these operations only happen when we
* are adding the 1st reference for that subvolume in the case of adding space
* or on the last reference delete in the case of subtraction. The only
@@ -53,6 +69,10 @@ struct btrfs_qgroup_operation {
u64 num_bytes;
u64 seq;
enum btrfs_qgroup_operation_type type;
+ /*
+ * DATA or METADATA;
+ **/
+ unsigned int quota_type;
struct seq_list elem;
struct rb_node n;
struct list_head list;
@@ -86,6 +106,7 @@ int btrfs_qgroup_record_ref(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 ref_root,
u64 bytenr, u64 num_bytes,
enum btrfs_qgroup_operation_type type,
+ unsigned int quota_type,
int mod_seq);
int btrfs_delayed_qgroup_accounting(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info);
@@ -97,8 +118,8 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans,
int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 srcid, u64 objectid,
struct btrfs_qgroup_inherit *inherit);
-int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes);
-void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes);
+int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes, u8 type);
+void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes, u8 type);
void assert_qgroups_uptodate(struct btrfs_trans_handle *trans);
diff --git a/fs/btrfs/tests/qgroup-tests.c b/fs/btrfs/tests/qgroup-tests.c
index c32a7ba..2c978ce 100644
--- a/fs/btrfs/tests/qgroup-tests.c
+++ b/fs/btrfs/tests/qgroup-tests.c
@@ -239,7 +239,8 @@ static int test_no_shared_qgroup(struct btrfs_root *root)
}
ret = btrfs_qgroup_record_ref(&trans, fs_info, 5, 4096, 4096,
- BTRFS_QGROUP_OPER_ADD_EXCL, 0);
+ BTRFS_QGROUP_OPER_ADD_EXCL,
+ BTRFS_QGROUP_REF_TYPE_DEFAULT, 0);
if (ret) {
test_msg("Couldn't add space to a qgroup %d\n", ret);
return ret;
@@ -265,7 +266,8 @@ static int test_no_shared_qgroup(struct btrfs_root *root)
return -EINVAL;
ret = btrfs_qgroup_record_ref(&trans, fs_info, 5, 4096, 4096,
- BTRFS_QGROUP_OPER_SUB_EXCL, 0);
+ BTRFS_QGROUP_OPER_SUB_EXCL,
+ BTRFS_QGROUP_REF_TYPE_DEFAULT, 0);
if (ret) {
test_msg("Couldn't remove space from the qgroup %d\n", ret);
return -EINVAL;
@@ -312,7 +314,8 @@ static int test_multiple_refs(struct btrfs_root *root)
return ret;
ret = btrfs_qgroup_record_ref(&trans, fs_info, 5, 4096, 4096,
- BTRFS_QGROUP_OPER_ADD_EXCL, 0);
+ BTRFS_QGROUP_OPER_ADD_EXCL,
+ BTRFS_QGROUP_REF_TYPE_DEFAULT, 0);
if (ret) {
test_msg("Couldn't add space to a qgroup %d\n", ret);
return ret;
@@ -334,7 +337,8 @@ static int test_multiple_refs(struct btrfs_root *root)
return ret;
ret = btrfs_qgroup_record_ref(&trans, fs_info, 256, 4096, 4096,
- BTRFS_QGROUP_OPER_ADD_SHARED, 0);
+ BTRFS_QGROUP_OPER_ADD_SHARED,
+ BTRFS_QGROUP_REF_TYPE_DEFAULT, 0);
if (ret) {
test_msg("Qgroup record ref failed %d\n", ret);
return ret;
@@ -361,7 +365,8 @@ static int test_multiple_refs(struct btrfs_root *root)
return ret;
ret = btrfs_qgroup_record_ref(&trans, fs_info, 256, 4096, 4096,
- BTRFS_QGROUP_OPER_SUB_SHARED, 0);
+ BTRFS_QGROUP_OPER_SUB_SHARED,
+ BTRFS_QGROUP_REF_TYPE_DEFAULT, 0);
if (ret) {
test_msg("Qgroup record ref failed %d\n", ret);
return ret;
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 7e80f32..8d4bffb 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -440,7 +440,8 @@ start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
if (root->fs_info->quota_enabled &&
is_fstree(root->root_key.objectid)) {
qgroup_reserved = num_items * root->nodesize;
- ret = btrfs_qgroup_reserve(root, qgroup_reserved);
+ ret = btrfs_qgroup_reserve(root, qgroup_reserved,
+ BTRFS_QGROUP_REF_TYPE_METADATA);
if (ret)
return ERR_PTR(ret);
}
@@ -555,7 +556,7 @@ alloc_fail:
num_bytes);
reserve_fail:
if (qgroup_reserved)
- btrfs_qgroup_free(root, qgroup_reserved);
+ btrfs_qgroup_free(root, qgroup_reserved, BTRFS_QGROUP_REF_TYPE_METADATA);
return ERR_PTR(ret);
}
@@ -777,7 +778,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
* the same root has to be passed here between start_transaction
* and end_transaction. Subvolume quota depends on this.
*/
- btrfs_qgroup_free(trans->root, trans->qgroup_reserved);
+ btrfs_qgroup_free(trans->root, trans->qgroup_reserved, BTRFS_QGROUP_REF_TYPE_METADATA);
trans->qgroup_reserved = 0;
}
@@ -1783,7 +1784,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
btrfs_trans_release_metadata(trans, root);
trans->block_rsv = NULL;
if (trans->qgroup_reserved) {
- btrfs_qgroup_free(root, trans->qgroup_reserved);
+ btrfs_qgroup_free(root, trans->qgroup_reserved, BTRFS_QGROUP_REF_TYPE_METADATA);
trans->qgroup_reserved = 0;
}
@@ -2079,7 +2080,7 @@ cleanup_transaction:
btrfs_trans_release_metadata(trans, root);
trans->block_rsv = NULL;
if (trans->qgroup_reserved) {
- btrfs_qgroup_free(root, trans->qgroup_reserved);
+ btrfs_qgroup_free(root, trans->qgroup_reserved, BTRFS_QGROUP_REF_TYPE_METADATA);
trans->qgroup_reserved = 0;
}
btrfs_warn(root->fs_info, "Skipping commit of aborted transaction.");
--
1.8.4.2
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html