Commit dce28769 authored by Qu Wenruo's avatar Qu Wenruo Committed by David Sterba

btrfs: qgroup: use qgroup_iterator_nested to in qgroup_update_refcnt()

The ulist @qgroups is utilized to record all involved qgroups from both
old and new roots inside btrfs_qgroup_account_extent().

Due to the fact that qgroup_update_refcnt() itself is already utilizing
qgroup_iterator, here we have to introduce another list_head,
btrfs_qgroup::nested_iterator, allowing nested iteration.
Signed-off-by: default avatarQu Wenruo <wqu@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent a4a81383
...@@ -209,6 +209,7 @@ static struct btrfs_qgroup *add_qgroup_rb(struct btrfs_fs_info *fs_info, ...@@ -209,6 +209,7 @@ static struct btrfs_qgroup *add_qgroup_rb(struct btrfs_fs_info *fs_info,
INIT_LIST_HEAD(&qgroup->members); INIT_LIST_HEAD(&qgroup->members);
INIT_LIST_HEAD(&qgroup->dirty); INIT_LIST_HEAD(&qgroup->dirty);
INIT_LIST_HEAD(&qgroup->iterator); INIT_LIST_HEAD(&qgroup->iterator);
INIT_LIST_HEAD(&qgroup->nested_iterator);
rb_link_node(&qgroup->node, parent, p); rb_link_node(&qgroup->node, parent, p);
rb_insert_color(&qgroup->node, &fs_info->qgroup_tree); rb_insert_color(&qgroup->node, &fs_info->qgroup_tree);
...@@ -2417,22 +2418,39 @@ int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans, ...@@ -2417,22 +2418,39 @@ int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans,
return ret; return ret;
} }
static void qgroup_iterator_nested_add(struct list_head *head, struct btrfs_qgroup *qgroup)
{
if (!list_empty(&qgroup->nested_iterator))
return;
list_add_tail(&qgroup->nested_iterator, head);
}
static void qgroup_iterator_nested_clean(struct list_head *head)
{
while (!list_empty(head)) {
struct btrfs_qgroup *qgroup;
qgroup = list_first_entry(head, struct btrfs_qgroup, nested_iterator);
list_del_init(&qgroup->nested_iterator);
}
}
#define UPDATE_NEW 0 #define UPDATE_NEW 0
#define UPDATE_OLD 1 #define UPDATE_OLD 1
/* /*
* Walk all of the roots that points to the bytenr and adjust their refcnts. * Walk all of the roots that points to the bytenr and adjust their refcnts.
*/ */
static int qgroup_update_refcnt(struct btrfs_fs_info *fs_info, static void qgroup_update_refcnt(struct btrfs_fs_info *fs_info,
struct ulist *roots, struct ulist *qgroups, struct ulist *roots, struct list_head *qgroups,
u64 seq, int update_old) u64 seq, int update_old)
{ {
struct ulist_node *unode; struct ulist_node *unode;
struct ulist_iterator uiter; struct ulist_iterator uiter;
struct btrfs_qgroup *qg; struct btrfs_qgroup *qg;
int ret = 0;
if (!roots) if (!roots)
return 0; return;
ULIST_ITER_INIT(&uiter); ULIST_ITER_INIT(&uiter);
while ((unode = ulist_next(roots, &uiter))) { while ((unode = ulist_next(roots, &uiter))) {
LIST_HEAD(tmp); LIST_HEAD(tmp);
...@@ -2441,10 +2459,7 @@ static int qgroup_update_refcnt(struct btrfs_fs_info *fs_info, ...@@ -2441,10 +2459,7 @@ static int qgroup_update_refcnt(struct btrfs_fs_info *fs_info,
if (!qg) if (!qg)
continue; continue;
ret = ulist_add(qgroups, qg->qgroupid, qgroup_to_aux(qg), qgroup_iterator_nested_add(qgroups, qg);
GFP_ATOMIC);
if (ret < 0)
return ret;
qgroup_iterator_add(&tmp, qg); qgroup_iterator_add(&tmp, qg);
list_for_each_entry(qg, &tmp, iterator) { list_for_each_entry(qg, &tmp, iterator) {
struct btrfs_qgroup_list *glist; struct btrfs_qgroup_list *glist;
...@@ -2455,17 +2470,12 @@ static int qgroup_update_refcnt(struct btrfs_fs_info *fs_info, ...@@ -2455,17 +2470,12 @@ static int qgroup_update_refcnt(struct btrfs_fs_info *fs_info,
btrfs_qgroup_update_new_refcnt(qg, seq, 1); btrfs_qgroup_update_new_refcnt(qg, seq, 1);
list_for_each_entry(glist, &qg->groups, next_group) { list_for_each_entry(glist, &qg->groups, next_group) {
ret = ulist_add(qgroups, glist->group->qgroupid, qgroup_iterator_nested_add(qgroups, glist->group);
qgroup_to_aux(glist->group),
GFP_ATOMIC);
if (ret < 0)
return ret;
qgroup_iterator_add(&tmp, glist->group); qgroup_iterator_add(&tmp, glist->group);
} }
} }
qgroup_iterator_clean(&tmp); qgroup_iterator_clean(&tmp);
} }
return 0;
} }
/* /*
...@@ -2504,22 +2514,16 @@ static int qgroup_update_refcnt(struct btrfs_fs_info *fs_info, ...@@ -2504,22 +2514,16 @@ static int qgroup_update_refcnt(struct btrfs_fs_info *fs_info,
* But this time we don't need to consider other things, the codes and logic * But this time we don't need to consider other things, the codes and logic
* is easy to understand now. * is easy to understand now.
*/ */
static int qgroup_update_counters(struct btrfs_fs_info *fs_info, static void qgroup_update_counters(struct btrfs_fs_info *fs_info,
struct ulist *qgroups, struct list_head *qgroups, u64 nr_old_roots,
u64 nr_old_roots, u64 nr_new_roots, u64 num_bytes, u64 seq)
u64 nr_new_roots,
u64 num_bytes, u64 seq)
{ {
struct ulist_node *unode;
struct ulist_iterator uiter;
struct btrfs_qgroup *qg; struct btrfs_qgroup *qg;
u64 cur_new_count, cur_old_count;
ULIST_ITER_INIT(&uiter); list_for_each_entry(qg, qgroups, nested_iterator) {
while ((unode = ulist_next(qgroups, &uiter))) { u64 cur_new_count, cur_old_count;
bool dirty = false; bool dirty = false;
qg = unode_aux_to_qgroup(unode);
cur_old_count = btrfs_qgroup_get_old_refcnt(qg, seq); cur_old_count = btrfs_qgroup_get_old_refcnt(qg, seq);
cur_new_count = btrfs_qgroup_get_new_refcnt(qg, seq); cur_new_count = btrfs_qgroup_get_new_refcnt(qg, seq);
...@@ -2590,7 +2594,6 @@ static int qgroup_update_counters(struct btrfs_fs_info *fs_info, ...@@ -2590,7 +2594,6 @@ static int qgroup_update_counters(struct btrfs_fs_info *fs_info,
if (dirty) if (dirty)
qgroup_dirty(fs_info, qg); qgroup_dirty(fs_info, qg);
} }
return 0;
} }
/* /*
...@@ -2627,7 +2630,7 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr, ...@@ -2627,7 +2630,7 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr,
struct ulist *new_roots) struct ulist *new_roots)
{ {
struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_fs_info *fs_info = trans->fs_info;
struct ulist *qgroups = NULL; LIST_HEAD(qgroups);
u64 seq; u64 seq;
u64 nr_new_roots = 0; u64 nr_new_roots = 0;
u64 nr_old_roots = 0; u64 nr_old_roots = 0;
...@@ -2661,11 +2664,6 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr, ...@@ -2661,11 +2664,6 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr,
trace_btrfs_qgroup_account_extent(fs_info, trans->transid, bytenr, trace_btrfs_qgroup_account_extent(fs_info, trans->transid, bytenr,
num_bytes, nr_old_roots, nr_new_roots); num_bytes, nr_old_roots, nr_new_roots);
qgroups = ulist_alloc(GFP_NOFS);
if (!qgroups) {
ret = -ENOMEM;
goto out_free;
}
mutex_lock(&fs_info->qgroup_rescan_lock); mutex_lock(&fs_info->qgroup_rescan_lock);
if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) { if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) {
if (fs_info->qgroup_rescan_progress.objectid <= bytenr) { if (fs_info->qgroup_rescan_progress.objectid <= bytenr) {
...@@ -2680,26 +2678,21 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr, ...@@ -2680,26 +2678,21 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr,
seq = fs_info->qgroup_seq; seq = fs_info->qgroup_seq;
/* Update old refcnts using old_roots */ /* Update old refcnts using old_roots */
ret = qgroup_update_refcnt(fs_info, old_roots, qgroups, seq, UPDATE_OLD); qgroup_update_refcnt(fs_info, old_roots, &qgroups, seq, UPDATE_OLD);
if (ret < 0)
goto out;
/* Update new refcnts using new_roots */ /* Update new refcnts using new_roots */
ret = qgroup_update_refcnt(fs_info, new_roots, qgroups, seq, UPDATE_NEW); qgroup_update_refcnt(fs_info, new_roots, &qgroups, seq, UPDATE_NEW);
if (ret < 0)
goto out;
qgroup_update_counters(fs_info, qgroups, nr_old_roots, nr_new_roots, qgroup_update_counters(fs_info, &qgroups, nr_old_roots, nr_new_roots,
num_bytes, seq); num_bytes, seq);
/* /*
* Bump qgroup_seq to avoid seq overlap * Bump qgroup_seq to avoid seq overlap
*/ */
fs_info->qgroup_seq += max(nr_old_roots, nr_new_roots) + 1; fs_info->qgroup_seq += max(nr_old_roots, nr_new_roots) + 1;
out:
spin_unlock(&fs_info->qgroup_lock); spin_unlock(&fs_info->qgroup_lock);
out_free: out_free:
ulist_free(qgroups); qgroup_iterator_nested_clean(&qgroups);
ulist_free(old_roots); ulist_free(old_roots);
ulist_free(new_roots); ulist_free(new_roots);
return ret; return ret;
......
...@@ -229,6 +229,24 @@ struct btrfs_qgroup { ...@@ -229,6 +229,24 @@ struct btrfs_qgroup {
* finished. * finished.
*/ */
struct list_head iterator; struct list_head iterator;
/*
* For nested iterator usage.
*
* Here we support at most one level of nested iterator calls like:
*
* LIST_HEAD(all_qgroups);
* {
* LIST_HEAD(local_qgroups);
* qgroup_iterator_add(local_qgroups, qg);
* qgroup_iterator_nested_add(all_qgroups, qg);
* do_some_work(local_qgroups);
* qgroup_iterator_clean(local_qgroups);
* }
* do_some_work(all_qgroups);
* qgroup_iterator_nested_clean(all_qgroups);
*/
struct list_head nested_iterator;
struct rb_node node; /* tree of qgroups */ struct rb_node node; /* tree of qgroups */
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment