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: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
a4a81383fb
commit
dce28769a3
@ -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 @@ out:
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
* 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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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 {
|
|||||||
* 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 */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user