Message ID | 3bde6a9352638ac30cb727ff8b5a304d14d240ce.1693441298.git.wqu@suse.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | btrfs: qgroup: remove GFP_ATOMIC usage for ulist | expand |
On Thu, Aug 31, 2023 at 08:30:37AM +0800, Qu Wenruo wrote: > 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::iterator2, allowing nested iteartion. Please rename it to nested_iterator, the '2' is not very descriptive. > Signed-off-by: Qu Wenruo <wqu@suse.com> > --- > fs/btrfs/qgroup.c | 81 ++++++++++++++++++++++------------------------- > fs/btrfs/qgroup.h | 3 ++ > 2 files changed, 40 insertions(+), 44 deletions(-) > > diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c > index 6fcf302744e2..27debc645f97 100644 > --- a/fs/btrfs/qgroup.c > +++ b/fs/btrfs/qgroup.c > @@ -217,6 +217,7 @@ static struct btrfs_qgroup *add_qgroup_rb(struct btrfs_fs_info *fs_info, > INIT_LIST_HEAD(&qgroup->members); > INIT_LIST_HEAD(&qgroup->dirty); > INIT_LIST_HEAD(&qgroup->iterator); > + INIT_LIST_HEAD(&qgroup->iterator2); > > rb_link_node(&qgroup->node, parent, p); > rb_insert_color(&qgroup->node, &fs_info->qgroup_tree); > @@ -2457,22 +2458,39 @@ int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans, > return ret; > } > > +static void qgroup_iterator2_add(struct list_head *head, struct btrfs_qgroup *qgroup) > +{ > + if (!list_empty(&qgroup->iterator2)) > + return; > + > + list_add_tail(&qgroup->iterator2, head); > +} > + > +static void qgroup_iterator2_clean(struct list_head *head) > +{ > + > + while (!list_empty(head)) { > + struct btrfs_qgroup *qgroup; > + > + qgroup = list_first_entry(head, struct btrfs_qgroup, iterator2); > + list_del_init(&qgroup->iterator2); > + } > +} > #define UPDATE_NEW 0 > #define UPDATE_OLD 1 > /* > * 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, > - struct ulist *roots, struct ulist *qgroups, > - u64 seq, int update_old) > +static void qgroup_update_refcnt(struct btrfs_fs_info *fs_info, > + struct ulist *roots, struct list_head *qgroups, > + u64 seq, int update_old) > { > struct ulist_node *unode; > struct ulist_iterator uiter; > struct btrfs_qgroup *qg; > - int ret = 0; > > if (!roots) > - return 0; > + return; > ULIST_ITER_INIT(&uiter); > while ((unode = ulist_next(roots, &uiter))) { > LIST_HEAD(tmp); > @@ -2481,10 +2499,7 @@ static int qgroup_update_refcnt(struct btrfs_fs_info *fs_info, > if (!qg) > continue; > > - ret = ulist_add(qgroups, qg->qgroupid, qgroup_to_aux(qg), > - GFP_ATOMIC); > - if (ret < 0) > - return ret; > + qgroup_iterator2_add(qgroups, qg); > qgroup_iterator_add(&tmp, qg); > list_for_each_entry(qg, &tmp, iterator) { > struct btrfs_qgroup_list *glist; > @@ -2495,17 +2510,12 @@ static int qgroup_update_refcnt(struct btrfs_fs_info *fs_info, > btrfs_qgroup_update_new_refcnt(qg, seq, 1); > > list_for_each_entry(glist, &qg->groups, next_group) { > - ret = ulist_add(qgroups, glist->group->qgroupid, > - qgroup_to_aux(glist->group), > - GFP_ATOMIC); > - if (ret < 0) > - return ret; > + qgroup_iterator2_add(qgroups, glist->group); > qgroup_iterator_add(&tmp, glist->group); > } > } > qgroup_iterator_clean(&tmp); > } > - return 0; > } > > /* > @@ -2544,22 +2554,18 @@ 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 > * is easy to understand now. > */ > -static int qgroup_update_counters(struct btrfs_fs_info *fs_info, > - struct ulist *qgroups, > - u64 nr_old_roots, > - u64 nr_new_roots, > - u64 num_bytes, u64 seq) > +static void qgroup_update_counters(struct btrfs_fs_info *fs_info, > + struct list_head *qgroups, > + u64 nr_old_roots, > + u64 nr_new_roots, > + u64 num_bytes, u64 seq) > { > - struct ulist_node *unode; > - struct ulist_iterator uiter; > struct btrfs_qgroup *qg; > - u64 cur_new_count, cur_old_count; > > - ULIST_ITER_INIT(&uiter); > - while ((unode = ulist_next(qgroups, &uiter))) { > + list_for_each_entry(qg, qgroups, iterator2) { > + u64 cur_new_count, cur_old_count; > bool dirty = false; > > - qg = unode_aux_to_qgroup(unode); > cur_old_count = btrfs_qgroup_get_old_refcnt(qg, seq); > cur_new_count = btrfs_qgroup_get_new_refcnt(qg, seq); > > @@ -2630,7 +2636,6 @@ static int qgroup_update_counters(struct btrfs_fs_info *fs_info, > if (dirty) > qgroup_dirty(fs_info, qg); > } > - return 0; > } > > /* > @@ -2667,7 +2672,7 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr, > struct ulist *new_roots) > { > struct btrfs_fs_info *fs_info = trans->fs_info; > - struct ulist *qgroups = NULL; > + LIST_HEAD(qgroups); > u64 seq; > u64 nr_new_roots = 0; > u64 nr_old_roots = 0; > @@ -2701,11 +2706,6 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr, > trace_btrfs_qgroup_account_extent(fs_info, trans->transid, bytenr, > 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); > if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) { > if (fs_info->qgroup_rescan_progress.objectid <= bytenr) { > @@ -2720,28 +2720,21 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr, > seq = fs_info->qgroup_seq; > > /* Update old refcnts using old_roots */ > - ret = qgroup_update_refcnt(fs_info, old_roots, qgroups, seq, > - UPDATE_OLD); > - if (ret < 0) > - goto out; > + qgroup_update_refcnt(fs_info, old_roots, &qgroups, seq, UPDATE_OLD); > > /* Update new refcnts using new_roots */ > - ret = qgroup_update_refcnt(fs_info, new_roots, qgroups, seq, > - UPDATE_NEW); > - if (ret < 0) > - goto out; > + qgroup_update_refcnt(fs_info, new_roots, &qgroups, seq, UPDATE_NEW); > > - 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); > > /* > * Bump qgroup_seq to avoid seq overlap > */ > fs_info->qgroup_seq += max(nr_old_roots, nr_new_roots) + 1; > -out: > spin_unlock(&fs_info->qgroup_lock); > out_free: > - ulist_free(qgroups); > + qgroup_iterator2_clean(&qgroups); > ulist_free(old_roots); > ulist_free(new_roots); > return ret; > diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h > index 5dc0583622c3..1cce93585ff9 100644 > --- a/fs/btrfs/qgroup.h > +++ b/fs/btrfs/qgroup.h > @@ -229,6 +229,9 @@ struct btrfs_qgroup { > * And should be reset to empty after the iteration is finished. > */ > struct list_head iterator; > + > + /* For nested iterator usage. */ Please expand the comment e.g. describing in which context it's used or why it must be used instead of the other iterator. > + struct list_head iterator2; > struct rb_node node; /* tree of qgroups */ > > /* > -- > 2.41.0
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 6fcf302744e2..27debc645f97 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -217,6 +217,7 @@ static struct btrfs_qgroup *add_qgroup_rb(struct btrfs_fs_info *fs_info, INIT_LIST_HEAD(&qgroup->members); INIT_LIST_HEAD(&qgroup->dirty); INIT_LIST_HEAD(&qgroup->iterator); + INIT_LIST_HEAD(&qgroup->iterator2); rb_link_node(&qgroup->node, parent, p); rb_insert_color(&qgroup->node, &fs_info->qgroup_tree); @@ -2457,22 +2458,39 @@ int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans, return ret; } +static void qgroup_iterator2_add(struct list_head *head, struct btrfs_qgroup *qgroup) +{ + if (!list_empty(&qgroup->iterator2)) + return; + + list_add_tail(&qgroup->iterator2, head); +} + +static void qgroup_iterator2_clean(struct list_head *head) +{ + + while (!list_empty(head)) { + struct btrfs_qgroup *qgroup; + + qgroup = list_first_entry(head, struct btrfs_qgroup, iterator2); + list_del_init(&qgroup->iterator2); + } +} #define UPDATE_NEW 0 #define UPDATE_OLD 1 /* * 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, - struct ulist *roots, struct ulist *qgroups, - u64 seq, int update_old) +static void qgroup_update_refcnt(struct btrfs_fs_info *fs_info, + struct ulist *roots, struct list_head *qgroups, + u64 seq, int update_old) { struct ulist_node *unode; struct ulist_iterator uiter; struct btrfs_qgroup *qg; - int ret = 0; if (!roots) - return 0; + return; ULIST_ITER_INIT(&uiter); while ((unode = ulist_next(roots, &uiter))) { LIST_HEAD(tmp); @@ -2481,10 +2499,7 @@ static int qgroup_update_refcnt(struct btrfs_fs_info *fs_info, if (!qg) continue; - ret = ulist_add(qgroups, qg->qgroupid, qgroup_to_aux(qg), - GFP_ATOMIC); - if (ret < 0) - return ret; + qgroup_iterator2_add(qgroups, qg); qgroup_iterator_add(&tmp, qg); list_for_each_entry(qg, &tmp, iterator) { struct btrfs_qgroup_list *glist; @@ -2495,17 +2510,12 @@ static int qgroup_update_refcnt(struct btrfs_fs_info *fs_info, btrfs_qgroup_update_new_refcnt(qg, seq, 1); list_for_each_entry(glist, &qg->groups, next_group) { - ret = ulist_add(qgroups, glist->group->qgroupid, - qgroup_to_aux(glist->group), - GFP_ATOMIC); - if (ret < 0) - return ret; + qgroup_iterator2_add(qgroups, glist->group); qgroup_iterator_add(&tmp, glist->group); } } qgroup_iterator_clean(&tmp); } - return 0; } /* @@ -2544,22 +2554,18 @@ 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 * is easy to understand now. */ -static int qgroup_update_counters(struct btrfs_fs_info *fs_info, - struct ulist *qgroups, - u64 nr_old_roots, - u64 nr_new_roots, - u64 num_bytes, u64 seq) +static void qgroup_update_counters(struct btrfs_fs_info *fs_info, + struct list_head *qgroups, + u64 nr_old_roots, + u64 nr_new_roots, + u64 num_bytes, u64 seq) { - struct ulist_node *unode; - struct ulist_iterator uiter; struct btrfs_qgroup *qg; - u64 cur_new_count, cur_old_count; - ULIST_ITER_INIT(&uiter); - while ((unode = ulist_next(qgroups, &uiter))) { + list_for_each_entry(qg, qgroups, iterator2) { + u64 cur_new_count, cur_old_count; bool dirty = false; - qg = unode_aux_to_qgroup(unode); cur_old_count = btrfs_qgroup_get_old_refcnt(qg, seq); cur_new_count = btrfs_qgroup_get_new_refcnt(qg, seq); @@ -2630,7 +2636,6 @@ static int qgroup_update_counters(struct btrfs_fs_info *fs_info, if (dirty) qgroup_dirty(fs_info, qg); } - return 0; } /* @@ -2667,7 +2672,7 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr, struct ulist *new_roots) { struct btrfs_fs_info *fs_info = trans->fs_info; - struct ulist *qgroups = NULL; + LIST_HEAD(qgroups); u64 seq; u64 nr_new_roots = 0; u64 nr_old_roots = 0; @@ -2701,11 +2706,6 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr, trace_btrfs_qgroup_account_extent(fs_info, trans->transid, bytenr, 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); if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) { if (fs_info->qgroup_rescan_progress.objectid <= bytenr) { @@ -2720,28 +2720,21 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr, seq = fs_info->qgroup_seq; /* Update old refcnts using old_roots */ - ret = qgroup_update_refcnt(fs_info, old_roots, qgroups, seq, - UPDATE_OLD); - if (ret < 0) - goto out; + qgroup_update_refcnt(fs_info, old_roots, &qgroups, seq, UPDATE_OLD); /* Update new refcnts using new_roots */ - ret = qgroup_update_refcnt(fs_info, new_roots, qgroups, seq, - UPDATE_NEW); - if (ret < 0) - goto out; + qgroup_update_refcnt(fs_info, new_roots, &qgroups, seq, UPDATE_NEW); - 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); /* * Bump qgroup_seq to avoid seq overlap */ fs_info->qgroup_seq += max(nr_old_roots, nr_new_roots) + 1; -out: spin_unlock(&fs_info->qgroup_lock); out_free: - ulist_free(qgroups); + qgroup_iterator2_clean(&qgroups); ulist_free(old_roots); ulist_free(new_roots); return ret; diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h index 5dc0583622c3..1cce93585ff9 100644 --- a/fs/btrfs/qgroup.h +++ b/fs/btrfs/qgroup.h @@ -229,6 +229,9 @@ struct btrfs_qgroup { * And should be reset to empty after the iteration is finished. */ struct list_head iterator; + + /* For nested iterator usage. */ + struct list_head iterator2; struct rb_node node; /* tree of qgroups */ /*
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::iterator2, allowing nested iteartion. Signed-off-by: Qu Wenruo <wqu@suse.com> --- fs/btrfs/qgroup.c | 81 ++++++++++++++++++++++------------------------- fs/btrfs/qgroup.h | 3 ++ 2 files changed, 40 insertions(+), 44 deletions(-)