* [PATCH v2 1/6] btrfs: qgroup: iterate qgroups without memory allocation for qgroup_reserve()
2023-08-31 0:30 [PATCH v2 0/6] btrfs: qgroup: remove GFP_ATOMIC usage for ulist Qu Wenruo
@ 2023-08-31 0:30 ` Qu Wenruo
2023-08-31 0:30 ` [PATCH v2 2/6] btrfs: qgroup: use qgroup_iterator facility for btrfs_qgroup_free_refroot() Qu Wenruo
` (4 subsequent siblings)
5 siblings, 0 replies; 12+ messages in thread
From: Qu Wenruo @ 2023-08-31 0:30 UTC (permalink / raw)
To: linux-btrfs; +Cc: Boris Burkov
Qgroup heavily relies on ulist to go through all the involved
qgroups, but since we're using ulist inside fs_info->qgroup_lock
spinlock, this means we're doing a lot of GFP_ATOMIC allocation.
This patch would reduce the GFP_ATOMIC usage for qgroup_reserve() by
eliminating the memory allocation completely.
This is done by moving the needed memory to btrfs_qgroup::iterator
list_head, so that we can put all the involved qgroup into a on-stack list, thus
eliminate the need to allocate memory holding spinlock.
The only cost is the slightly higher memory usage, but considering the
reduce GFP_ATOMIC during a hot path, it should still be acceptable.
Function qgroup_reserve() is the perfect start point for this
conversion.
Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/qgroup.c | 68 +++++++++++++++++++++++------------------------
fs/btrfs/qgroup.h | 9 +++++++
2 files changed, 42 insertions(+), 35 deletions(-)
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 74244b4bb0e9..de34e2aef710 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -216,6 +216,7 @@ static struct btrfs_qgroup *add_qgroup_rb(struct btrfs_fs_info *fs_info,
INIT_LIST_HEAD(&qgroup->groups);
INIT_LIST_HEAD(&qgroup->members);
INIT_LIST_HEAD(&qgroup->dirty);
+ INIT_LIST_HEAD(&qgroup->iterator);
rb_link_node(&qgroup->node, parent, p);
rb_insert_color(&qgroup->node, &fs_info->qgroup_tree);
@@ -1367,6 +1368,25 @@ static void qgroup_dirty(struct btrfs_fs_info *fs_info,
list_add(&qgroup->dirty, &fs_info->dirty_qgroups);
}
+static void qgroup_iterator_add(struct list_head *head, struct btrfs_qgroup *qgroup)
+{
+ if (!list_empty(&qgroup->iterator))
+ return;
+
+ list_add_tail(&qgroup->iterator, head);
+}
+
+static void qgroup_iterator_clean(struct list_head *head)
+{
+
+ while (!list_empty(head)) {
+ struct btrfs_qgroup *qgroup;
+
+ qgroup = list_first_entry(head, struct btrfs_qgroup, iterator);
+ list_del_init(&qgroup->iterator);
+ }
+}
+
/*
* The easy accounting, we're updating qgroup relationship whose child qgroup
* only has exclusive extents.
@@ -3154,12 +3174,11 @@ static bool qgroup_check_limits(const struct btrfs_qgroup *qg, u64 num_bytes)
static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce,
enum btrfs_qgroup_rsv_type type)
{
- struct btrfs_qgroup *qgroup;
+ struct btrfs_qgroup *cur;
struct btrfs_fs_info *fs_info = root->fs_info;
u64 ref_root = root->root_key.objectid;
int ret = 0;
- struct ulist_node *unode;
- struct ulist_iterator uiter;
+ LIST_HEAD(qgroup_list);
if (!is_fstree(ref_root))
return 0;
@@ -3175,53 +3194,32 @@ static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce,
if (!fs_info->quota_root)
goto out;
- qgroup = find_qgroup_rb(fs_info, ref_root);
- if (!qgroup)
+ cur = find_qgroup_rb(fs_info, ref_root);
+ if (!cur)
goto out;
- /*
- * in a first step, we check all affected qgroups if any limits would
- * be exceeded
- */
- ulist_reinit(fs_info->qgroup_ulist);
- ret = ulist_add(fs_info->qgroup_ulist, qgroup->qgroupid,
- qgroup_to_aux(qgroup), GFP_ATOMIC);
- if (ret < 0)
- goto out;
- ULIST_ITER_INIT(&uiter);
- while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) {
- struct btrfs_qgroup *qg;
+ qgroup_iterator_add(&qgroup_list, cur);
+ list_for_each_entry(cur, &qgroup_list, iterator) {
struct btrfs_qgroup_list *glist;
- qg = unode_aux_to_qgroup(unode);
-
- if (enforce && !qgroup_check_limits(qg, num_bytes)) {
+ if (enforce && !qgroup_check_limits(cur, num_bytes)) {
ret = -EDQUOT;
goto out;
}
- list_for_each_entry(glist, &qg->groups, next_group) {
- ret = ulist_add(fs_info->qgroup_ulist,
- glist->group->qgroupid,
- qgroup_to_aux(glist->group), GFP_ATOMIC);
- if (ret < 0)
- goto out;
- }
+ list_for_each_entry(glist, &cur->groups, next_group)
+ qgroup_iterator_add(&qgroup_list, glist->group);
}
+
ret = 0;
/*
* no limits exceeded, now record the reservation into all qgroups
*/
- ULIST_ITER_INIT(&uiter);
- while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) {
- struct btrfs_qgroup *qg;
-
- qg = unode_aux_to_qgroup(unode);
-
- qgroup_rsv_add(fs_info, qg, num_bytes, type);
- }
+ list_for_each_entry(cur, &qgroup_list, iterator)
+ qgroup_rsv_add(fs_info, cur, num_bytes, type);
out:
+ qgroup_iterator_clean(&qgroup_list);
spin_unlock(&fs_info->qgroup_lock);
return ret;
}
diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h
index 7bffa10589d6..5dc0583622c3 100644
--- a/fs/btrfs/qgroup.h
+++ b/fs/btrfs/qgroup.h
@@ -220,6 +220,15 @@ struct btrfs_qgroup {
struct list_head groups; /* groups this group is member of */
struct list_head members; /* groups that are members of this group */
struct list_head dirty; /* dirty groups */
+
+ /*
+ * For qgroup iteration usage.
+ *
+ * The iteration list should always be empty until
+ * qgroup_iterator_add() is called.
+ * And should be reset to empty after the iteration is finished.
+ */
+ struct list_head iterator;
struct rb_node node; /* tree of qgroups */
/*
--
2.41.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH v2 2/6] btrfs: qgroup: use qgroup_iterator facility for btrfs_qgroup_free_refroot()
2023-08-31 0:30 [PATCH v2 0/6] btrfs: qgroup: remove GFP_ATOMIC usage for ulist Qu Wenruo
2023-08-31 0:30 ` [PATCH v2 1/6] btrfs: qgroup: iterate qgroups without memory allocation for qgroup_reserve() Qu Wenruo
@ 2023-08-31 0:30 ` Qu Wenruo
2023-08-31 0:30 ` [PATCH v2 3/6] btrfs: qgroup: use qgroup_iterator facility for qgroup_convert_meta() Qu Wenruo
` (3 subsequent siblings)
5 siblings, 0 replies; 12+ messages in thread
From: Qu Wenruo @ 2023-08-31 0:30 UTC (permalink / raw)
To: linux-btrfs; +Cc: Boris Burkov
With the new qgroup_iterator_add() and qgroup_iterator_clean(), we can
get rid of the ulist and its GFP_ATOMIC memory allocation.
Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/qgroup.c | 37 +++++++++++--------------------------
1 file changed, 11 insertions(+), 26 deletions(-)
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index de34e2aef710..c2a1173d9f00 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -3237,10 +3237,8 @@ void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info,
u64 ref_root, u64 num_bytes,
enum btrfs_qgroup_rsv_type type)
{
- struct btrfs_qgroup *qgroup;
- struct ulist_node *unode;
- struct ulist_iterator uiter;
- int ret = 0;
+ struct btrfs_qgroup *cur;
+ LIST_HEAD(qgroup_list);
if (!is_fstree(ref_root))
return;
@@ -3257,8 +3255,8 @@ void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info,
if (!fs_info->quota_root)
goto out;
- qgroup = find_qgroup_rb(fs_info, ref_root);
- if (!qgroup)
+ cur = find_qgroup_rb(fs_info, ref_root);
+ if (!cur)
goto out;
if (num_bytes == (u64)-1)
@@ -3266,32 +3264,19 @@ void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info,
* We're freeing all pertrans rsv, get reserved value from
* level 0 qgroup as real num_bytes to free.
*/
- num_bytes = qgroup->rsv.values[type];
+ num_bytes = cur->rsv.values[type];
- ulist_reinit(fs_info->qgroup_ulist);
- ret = ulist_add(fs_info->qgroup_ulist, qgroup->qgroupid,
- qgroup_to_aux(qgroup), GFP_ATOMIC);
- if (ret < 0)
- goto out;
- ULIST_ITER_INIT(&uiter);
- while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) {
- struct btrfs_qgroup *qg;
+ qgroup_iterator_add(&qgroup_list, cur);
+ list_for_each_entry(cur, &qgroup_list, iterator) {
struct btrfs_qgroup_list *glist;
- qg = unode_aux_to_qgroup(unode);
-
- qgroup_rsv_release(fs_info, qg, num_bytes, type);
-
- list_for_each_entry(glist, &qg->groups, next_group) {
- ret = ulist_add(fs_info->qgroup_ulist,
- glist->group->qgroupid,
- qgroup_to_aux(glist->group), GFP_ATOMIC);
- if (ret < 0)
- goto out;
+ qgroup_rsv_release(fs_info, cur, num_bytes, type);
+ list_for_each_entry(glist, &cur->groups, next_group) {
+ qgroup_iterator_add(&qgroup_list, glist->group);
}
}
-
out:
+ qgroup_iterator_clean(&qgroup_list);
spin_unlock(&fs_info->qgroup_lock);
}
--
2.41.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH v2 3/6] btrfs: qgroup: use qgroup_iterator facility for qgroup_convert_meta()
2023-08-31 0:30 [PATCH v2 0/6] btrfs: qgroup: remove GFP_ATOMIC usage for ulist Qu Wenruo
2023-08-31 0:30 ` [PATCH v2 1/6] btrfs: qgroup: iterate qgroups without memory allocation for qgroup_reserve() Qu Wenruo
2023-08-31 0:30 ` [PATCH v2 2/6] btrfs: qgroup: use qgroup_iterator facility for btrfs_qgroup_free_refroot() Qu Wenruo
@ 2023-08-31 0:30 ` Qu Wenruo
2023-08-31 0:30 ` [PATCH v2 4/6] btrfs: qgroup: use qgroup_iterator facility for __qgroup_excl_accounting() Qu Wenruo
` (2 subsequent siblings)
5 siblings, 0 replies; 12+ messages in thread
From: Qu Wenruo @ 2023-08-31 0:30 UTC (permalink / raw)
To: linux-btrfs; +Cc: Boris Burkov
With the new qgroup_iterator_add() and qgroup_iterator_clean(), we can
get rid of the ulist and its GFP_ATOMIC memory allocation.
Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/qgroup.c | 38 +++++++++++++-------------------------
1 file changed, 13 insertions(+), 25 deletions(-)
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index c2a1173d9f00..aa8e9e7be4f8 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -4119,10 +4119,8 @@ void __btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes,
static void qgroup_convert_meta(struct btrfs_fs_info *fs_info, u64 ref_root,
int num_bytes)
{
- struct btrfs_qgroup *qgroup;
- struct ulist_node *unode;
- struct ulist_iterator uiter;
- int ret = 0;
+ struct btrfs_qgroup *cur;
+ LIST_HEAD(qgroup_list);
if (num_bytes == 0)
return;
@@ -4130,34 +4128,24 @@ static void qgroup_convert_meta(struct btrfs_fs_info *fs_info, u64 ref_root,
return;
spin_lock(&fs_info->qgroup_lock);
- qgroup = find_qgroup_rb(fs_info, ref_root);
- if (!qgroup)
+ cur = find_qgroup_rb(fs_info, ref_root);
+ if (!cur)
goto out;
- ulist_reinit(fs_info->qgroup_ulist);
- ret = ulist_add(fs_info->qgroup_ulist, qgroup->qgroupid,
- qgroup_to_aux(qgroup), GFP_ATOMIC);
- if (ret < 0)
- goto out;
- ULIST_ITER_INIT(&uiter);
- while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) {
- struct btrfs_qgroup *qg;
+
+ qgroup_iterator_add(&qgroup_list, cur);
+ list_for_each_entry(cur, &qgroup_list, iterator) {
struct btrfs_qgroup_list *glist;
- qg = unode_aux_to_qgroup(unode);
-
- qgroup_rsv_release(fs_info, qg, num_bytes,
+ qgroup_rsv_release(fs_info, cur, num_bytes,
BTRFS_QGROUP_RSV_META_PREALLOC);
- qgroup_rsv_add(fs_info, qg, num_bytes,
+ qgroup_rsv_add(fs_info, cur, num_bytes,
BTRFS_QGROUP_RSV_META_PERTRANS);
- list_for_each_entry(glist, &qg->groups, next_group) {
- ret = ulist_add(fs_info->qgroup_ulist,
- glist->group->qgroupid,
- qgroup_to_aux(glist->group), GFP_ATOMIC);
- if (ret < 0)
- goto out;
- }
+
+ list_for_each_entry(glist, &cur->groups, next_group)
+ qgroup_iterator_add(&qgroup_list, glist->group);
}
out:
+ qgroup_iterator_clean(&qgroup_list);
spin_unlock(&fs_info->qgroup_lock);
}
--
2.41.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH v2 4/6] btrfs: qgroup: use qgroup_iterator facility for __qgroup_excl_accounting()
2023-08-31 0:30 [PATCH v2 0/6] btrfs: qgroup: remove GFP_ATOMIC usage for ulist Qu Wenruo
` (2 preceding siblings ...)
2023-08-31 0:30 ` [PATCH v2 3/6] btrfs: qgroup: use qgroup_iterator facility for qgroup_convert_meta() Qu Wenruo
@ 2023-08-31 0:30 ` Qu Wenruo
2023-09-01 13:15 ` David Sterba
2023-08-31 0:30 ` [PATCH v2 5/6] btrfs: qgroup: use qgroup_iterator facility to replace @tmp ulist of qgroup_update_refcnt() Qu Wenruo
2023-08-31 0:30 ` [PATCH v2 6/6] btrfs: qgroup: use qgroup_iterator2 facility to replace @qgroups " Qu Wenruo
5 siblings, 1 reply; 12+ messages in thread
From: Qu Wenruo @ 2023-08-31 0:30 UTC (permalink / raw)
To: linux-btrfs; +Cc: Boris Burkov
With the new qgroup_iterator_add() and qgroup_iterator_clean(), we can
get rid of the ulist and its GFP_ATOMIC memory allocation.
Furthermore we can merge the code handling the initial and parent
qgroups into one loop, and drop the @tmp ulist parameter for involved
call sites.
Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/qgroup.c | 72 +++++++++++------------------------------------
1 file changed, 17 insertions(+), 55 deletions(-)
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index aa8e9e7be4f8..08f4fc622180 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -1401,14 +1401,12 @@ static void qgroup_iterator_clean(struct list_head *head)
*
* Caller should hold fs_info->qgroup_lock.
*/
-static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
- struct ulist *tmp, u64 ref_root,
+static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info, u64 ref_root,
struct btrfs_qgroup *src, int sign)
{
struct btrfs_qgroup *qgroup;
- struct btrfs_qgroup_list *glist;
- struct ulist_node *unode;
- struct ulist_iterator uiter;
+ struct btrfs_qgroup *cur;
+ LIST_HEAD(qgroup_list);
u64 num_bytes = src->excl;
int ret = 0;
@@ -1416,53 +1414,30 @@ static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
if (!qgroup)
goto out;
- qgroup->rfer += sign * num_bytes;
- qgroup->rfer_cmpr += sign * num_bytes;
+ qgroup_iterator_add(&qgroup_list, qgroup);
+ list_for_each_entry(cur, &qgroup_list, iterator) {
+ struct btrfs_qgroup_list *glist;
- WARN_ON(sign < 0 && qgroup->excl < num_bytes);
- qgroup->excl += sign * num_bytes;
- qgroup->excl_cmpr += sign * num_bytes;
-
- if (sign > 0)
- qgroup_rsv_add_by_qgroup(fs_info, qgroup, src);
- else
- qgroup_rsv_release_by_qgroup(fs_info, qgroup, src);
-
- qgroup_dirty(fs_info, qgroup);
-
- /* Get all of the parent groups that contain this qgroup */
- list_for_each_entry(glist, &qgroup->groups, next_group) {
- ret = ulist_add(tmp, glist->group->qgroupid,
- qgroup_to_aux(glist->group), GFP_ATOMIC);
- if (ret < 0)
- goto out;
- }
-
- /* Iterate all of the parents and adjust their reference counts */
- ULIST_ITER_INIT(&uiter);
- while ((unode = ulist_next(tmp, &uiter))) {
- qgroup = unode_aux_to_qgroup(unode);
qgroup->rfer += sign * num_bytes;
qgroup->rfer_cmpr += sign * num_bytes;
+
WARN_ON(sign < 0 && qgroup->excl < num_bytes);
qgroup->excl += sign * num_bytes;
+ qgroup->excl_cmpr += sign * num_bytes;
+
if (sign > 0)
qgroup_rsv_add_by_qgroup(fs_info, qgroup, src);
else
qgroup_rsv_release_by_qgroup(fs_info, qgroup, src);
- qgroup->excl_cmpr += sign * num_bytes;
qgroup_dirty(fs_info, qgroup);
- /* Add any parents of the parents */
- list_for_each_entry(glist, &qgroup->groups, next_group) {
- ret = ulist_add(tmp, glist->group->qgroupid,
- qgroup_to_aux(glist->group), GFP_ATOMIC);
- if (ret < 0)
- goto out;
- }
+ /* Append parent qgroups to @qgroup_list. */
+ list_for_each_entry(glist, &qgroup->groups, next_group)
+ qgroup_iterator_add(&qgroup_list, glist->group);
}
ret = 0;
out:
+ qgroup_iterator_clean(&qgroup_list);
return ret;
}
@@ -1479,8 +1454,7 @@ static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
* Return < 0 for other error.
*/
static int quick_update_accounting(struct btrfs_fs_info *fs_info,
- struct ulist *tmp, u64 src, u64 dst,
- int sign)
+ u64 src, u64 dst, int sign)
{
struct btrfs_qgroup *qgroup;
int ret = 1;
@@ -1491,8 +1465,7 @@ static int quick_update_accounting(struct btrfs_fs_info *fs_info,
goto out;
if (qgroup->excl == qgroup->rfer) {
ret = 0;
- err = __qgroup_excl_accounting(fs_info, tmp, dst,
- qgroup, sign);
+ err = __qgroup_excl_accounting(fs_info, dst, qgroup, sign);
if (err < 0) {
ret = err;
goto out;
@@ -1511,7 +1484,6 @@ int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src,
struct btrfs_qgroup *parent;
struct btrfs_qgroup *member;
struct btrfs_qgroup_list *list;
- struct ulist *tmp;
unsigned int nofs_flag;
int ret = 0;
@@ -1521,10 +1493,7 @@ int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src,
/* We hold a transaction handle open, must do a NOFS allocation. */
nofs_flag = memalloc_nofs_save();
- tmp = ulist_alloc(GFP_KERNEL);
memalloc_nofs_restore(nofs_flag);
- if (!tmp)
- return -ENOMEM;
mutex_lock(&fs_info->qgroup_ioctl_lock);
if (!fs_info->quota_root) {
@@ -1562,11 +1531,10 @@ int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src,
spin_unlock(&fs_info->qgroup_lock);
goto out;
}
- ret = quick_update_accounting(fs_info, tmp, src, dst, 1);
+ ret = quick_update_accounting(fs_info, src, dst, 1);
spin_unlock(&fs_info->qgroup_lock);
out:
mutex_unlock(&fs_info->qgroup_ioctl_lock);
- ulist_free(tmp);
return ret;
}
@@ -1577,7 +1545,6 @@ static int __del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src,
struct btrfs_qgroup *parent;
struct btrfs_qgroup *member;
struct btrfs_qgroup_list *list;
- struct ulist *tmp;
bool found = false;
unsigned int nofs_flag;
int ret = 0;
@@ -1585,11 +1552,7 @@ static int __del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src,
/* We hold a transaction handle open, must do a NOFS allocation. */
nofs_flag = memalloc_nofs_save();
- tmp = ulist_alloc(GFP_KERNEL);
memalloc_nofs_restore(nofs_flag);
- if (!tmp)
- return -ENOMEM;
-
if (!fs_info->quota_root) {
ret = -ENOTCONN;
goto out;
@@ -1627,11 +1590,10 @@ static int __del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src,
if (found) {
spin_lock(&fs_info->qgroup_lock);
del_relation_rb(fs_info, src, dst);
- ret = quick_update_accounting(fs_info, tmp, src, dst, -1);
+ ret = quick_update_accounting(fs_info, src, dst, -1);
spin_unlock(&fs_info->qgroup_lock);
}
out:
- ulist_free(tmp);
return ret;
}
--
2.41.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* Re: [PATCH v2 4/6] btrfs: qgroup: use qgroup_iterator facility for __qgroup_excl_accounting()
2023-08-31 0:30 ` [PATCH v2 4/6] btrfs: qgroup: use qgroup_iterator facility for __qgroup_excl_accounting() Qu Wenruo
@ 2023-09-01 13:15 ` David Sterba
0 siblings, 0 replies; 12+ messages in thread
From: David Sterba @ 2023-09-01 13:15 UTC (permalink / raw)
To: Qu Wenruo; +Cc: linux-btrfs, Boris Burkov
On Thu, Aug 31, 2023 at 08:30:35AM +0800, Qu Wenruo wrote:
> With the new qgroup_iterator_add() and qgroup_iterator_clean(), we can
> get rid of the ulist and its GFP_ATOMIC memory allocation.
>
> Furthermore we can merge the code handling the initial and parent
> qgroups into one loop, and drop the @tmp ulist parameter for involved
> call sites.
>
> Reviewed-by: Boris Burkov <boris@bur.io>
> Signed-off-by: Qu Wenruo <wqu@suse.com>
> ---
> fs/btrfs/qgroup.c | 72 +++++++++++------------------------------------
> 1 file changed, 17 insertions(+), 55 deletions(-)
>
> diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
> index aa8e9e7be4f8..08f4fc622180 100644
> --- a/fs/btrfs/qgroup.c
> +++ b/fs/btrfs/qgroup.c
> @@ -1401,14 +1401,12 @@ static void qgroup_iterator_clean(struct list_head *head)
> *
> * Caller should hold fs_info->qgroup_lock.
> */
> -static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
> - struct ulist *tmp, u64 ref_root,
> +static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info, u64 ref_root,
> struct btrfs_qgroup *src, int sign)
> {
> struct btrfs_qgroup *qgroup;
> - struct btrfs_qgroup_list *glist;
> - struct ulist_node *unode;
> - struct ulist_iterator uiter;
> + struct btrfs_qgroup *cur;
> + LIST_HEAD(qgroup_list);
> u64 num_bytes = src->excl;
> int ret = 0;
>
> @@ -1416,53 +1414,30 @@ static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
> if (!qgroup)
> goto out;
>
> - qgroup->rfer += sign * num_bytes;
> - qgroup->rfer_cmpr += sign * num_bytes;
> + qgroup_iterator_add(&qgroup_list, qgroup);
> + list_for_each_entry(cur, &qgroup_list, iterator) {
> + struct btrfs_qgroup_list *glist;
>
> - WARN_ON(sign < 0 && qgroup->excl < num_bytes);
> - qgroup->excl += sign * num_bytes;
> - qgroup->excl_cmpr += sign * num_bytes;
> -
> - if (sign > 0)
> - qgroup_rsv_add_by_qgroup(fs_info, qgroup, src);
> - else
> - qgroup_rsv_release_by_qgroup(fs_info, qgroup, src);
> -
> - qgroup_dirty(fs_info, qgroup);
> -
> - /* Get all of the parent groups that contain this qgroup */
> - list_for_each_entry(glist, &qgroup->groups, next_group) {
> - ret = ulist_add(tmp, glist->group->qgroupid,
> - qgroup_to_aux(glist->group), GFP_ATOMIC);
> - if (ret < 0)
> - goto out;
> - }
> -
> - /* Iterate all of the parents and adjust their reference counts */
> - ULIST_ITER_INIT(&uiter);
> - while ((unode = ulist_next(tmp, &uiter))) {
> - qgroup = unode_aux_to_qgroup(unode);
> qgroup->rfer += sign * num_bytes;
> qgroup->rfer_cmpr += sign * num_bytes;
> +
> WARN_ON(sign < 0 && qgroup->excl < num_bytes);
> qgroup->excl += sign * num_bytes;
> + qgroup->excl_cmpr += sign * num_bytes;
> +
> if (sign > 0)
> qgroup_rsv_add_by_qgroup(fs_info, qgroup, src);
> else
> qgroup_rsv_release_by_qgroup(fs_info, qgroup, src);
> - qgroup->excl_cmpr += sign * num_bytes;
> qgroup_dirty(fs_info, qgroup);
>
> - /* Add any parents of the parents */
> - list_for_each_entry(glist, &qgroup->groups, next_group) {
> - ret = ulist_add(tmp, glist->group->qgroupid,
> - qgroup_to_aux(glist->group), GFP_ATOMIC);
> - if (ret < 0)
> - goto out;
> - }
> + /* Append parent qgroups to @qgroup_list. */
> + list_for_each_entry(glist, &qgroup->groups, next_group)
> + qgroup_iterator_add(&qgroup_list, glist->group);
> }
> ret = 0;
> out:
> + qgroup_iterator_clean(&qgroup_list);
> return ret;
> }
>
> @@ -1479,8 +1454,7 @@ static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
> * Return < 0 for other error.
> */
> static int quick_update_accounting(struct btrfs_fs_info *fs_info,
> - struct ulist *tmp, u64 src, u64 dst,
> - int sign)
> + u64 src, u64 dst, int sign)
> {
> struct btrfs_qgroup *qgroup;
> int ret = 1;
> @@ -1491,8 +1465,7 @@ static int quick_update_accounting(struct btrfs_fs_info *fs_info,
> goto out;
> if (qgroup->excl == qgroup->rfer) {
> ret = 0;
> - err = __qgroup_excl_accounting(fs_info, tmp, dst,
> - qgroup, sign);
> + err = __qgroup_excl_accounting(fs_info, dst, qgroup, sign);
> if (err < 0) {
> ret = err;
> goto out;
> @@ -1511,7 +1484,6 @@ int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src,
> struct btrfs_qgroup *parent;
> struct btrfs_qgroup *member;
> struct btrfs_qgroup_list *list;
> - struct ulist *tmp;
> unsigned int nofs_flag;
> int ret = 0;
>
> @@ -1521,10 +1493,7 @@ int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src,
>
> /* We hold a transaction handle open, must do a NOFS allocation. */
> nofs_flag = memalloc_nofs_save();
> - tmp = ulist_alloc(GFP_KERNEL);
> memalloc_nofs_restore(nofs_flag);
You should have removed the memalloc_nofs_* calls too.
> - if (!tmp)
> - return -ENOMEM;
>
> mutex_lock(&fs_info->qgroup_ioctl_lock);
> if (!fs_info->quota_root) {
> @@ -1585,11 +1552,7 @@ static int __del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src,
>
> /* We hold a transaction handle open, must do a NOFS allocation. */
> nofs_flag = memalloc_nofs_save();
> - tmp = ulist_alloc(GFP_KERNEL);
> memalloc_nofs_restore(nofs_flag);
And here.
> - if (!tmp)
> - return -ENOMEM;
> -
> if (!fs_info->quota_root) {
> ret = -ENOTCONN;
> goto out;
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v2 5/6] btrfs: qgroup: use qgroup_iterator facility to replace @tmp ulist of qgroup_update_refcnt()
2023-08-31 0:30 [PATCH v2 0/6] btrfs: qgroup: remove GFP_ATOMIC usage for ulist Qu Wenruo
` (3 preceding siblings ...)
2023-08-31 0:30 ` [PATCH v2 4/6] btrfs: qgroup: use qgroup_iterator facility for __qgroup_excl_accounting() Qu Wenruo
@ 2023-08-31 0:30 ` Qu Wenruo
2023-09-01 13:16 ` David Sterba
2023-08-31 0:30 ` [PATCH v2 6/6] btrfs: qgroup: use qgroup_iterator2 facility to replace @qgroups " Qu Wenruo
5 siblings, 1 reply; 12+ messages in thread
From: Qu Wenruo @ 2023-08-31 0:30 UTC (permalink / raw)
To: linux-btrfs; +Cc: Boris Burkov
For function qgroup_update_refcnt(), we use @tmp list to iterate all the
involved qgroups of a subvolume.
It's a perfect match for qgroup_iterator facility, as that @tmp ulist
has a very limited lifespan (just inside the while() loop).
By migrating to qgroup_iterator, we can get rid of the GFP_ATOMIC memory
allocation and no more error handling needed.
Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/qgroup.c | 37 +++++++++++--------------------------
1 file changed, 11 insertions(+), 26 deletions(-)
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 08f4fc622180..6fcf302744e2 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -2463,13 +2463,11 @@ int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans,
* 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 *tmp,
- struct ulist *qgroups, u64 seq, int update_old)
+ struct ulist *roots, struct ulist *qgroups,
+ u64 seq, int update_old)
{
struct ulist_node *unode;
struct ulist_iterator uiter;
- struct ulist_node *tmp_unode;
- struct ulist_iterator tmp_uiter;
struct btrfs_qgroup *qg;
int ret = 0;
@@ -2477,40 +2475,35 @@ static int qgroup_update_refcnt(struct btrfs_fs_info *fs_info,
return 0;
ULIST_ITER_INIT(&uiter);
while ((unode = ulist_next(roots, &uiter))) {
+ LIST_HEAD(tmp);
+
qg = find_qgroup_rb(fs_info, unode->val);
if (!qg)
continue;
- ulist_reinit(tmp);
ret = ulist_add(qgroups, qg->qgroupid, qgroup_to_aux(qg),
GFP_ATOMIC);
if (ret < 0)
return ret;
- ret = ulist_add(tmp, qg->qgroupid, qgroup_to_aux(qg), GFP_ATOMIC);
- if (ret < 0)
- return ret;
- ULIST_ITER_INIT(&tmp_uiter);
- while ((tmp_unode = ulist_next(tmp, &tmp_uiter))) {
+ qgroup_iterator_add(&tmp, qg);
+ list_for_each_entry(qg, &tmp, iterator) {
struct btrfs_qgroup_list *glist;
- qg = unode_aux_to_qgroup(tmp_unode);
if (update_old)
btrfs_qgroup_update_old_refcnt(qg, seq, 1);
else
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;
- ret = ulist_add(tmp, glist->group->qgroupid,
- qgroup_to_aux(glist->group),
- GFP_ATOMIC);
- if (ret < 0)
- return ret;
+ qgroup_iterator_add(&tmp, glist->group);
}
}
+ qgroup_iterator_clean(&tmp);
}
return 0;
}
@@ -2675,7 +2668,6 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr,
{
struct btrfs_fs_info *fs_info = trans->fs_info;
struct ulist *qgroups = NULL;
- struct ulist *tmp = NULL;
u64 seq;
u64 nr_new_roots = 0;
u64 nr_old_roots = 0;
@@ -2714,12 +2706,6 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr,
ret = -ENOMEM;
goto out_free;
}
- tmp = ulist_alloc(GFP_NOFS);
- if (!tmp) {
- 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) {
@@ -2734,13 +2720,13 @@ 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, tmp, qgroups, seq,
+ ret = qgroup_update_refcnt(fs_info, old_roots, qgroups, seq,
UPDATE_OLD);
if (ret < 0)
goto out;
/* Update new refcnts using new_roots */
- ret = qgroup_update_refcnt(fs_info, new_roots, tmp, qgroups, seq,
+ ret = qgroup_update_refcnt(fs_info, new_roots, qgroups, seq,
UPDATE_NEW);
if (ret < 0)
goto out;
@@ -2755,7 +2741,6 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr,
out:
spin_unlock(&fs_info->qgroup_lock);
out_free:
- ulist_free(tmp);
ulist_free(qgroups);
ulist_free(old_roots);
ulist_free(new_roots);
--
2.41.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* Re: [PATCH v2 5/6] btrfs: qgroup: use qgroup_iterator facility to replace @tmp ulist of qgroup_update_refcnt()
2023-08-31 0:30 ` [PATCH v2 5/6] btrfs: qgroup: use qgroup_iterator facility to replace @tmp ulist of qgroup_update_refcnt() Qu Wenruo
@ 2023-09-01 13:16 ` David Sterba
2023-09-02 0:16 ` Qu Wenruo
0 siblings, 1 reply; 12+ messages in thread
From: David Sterba @ 2023-09-01 13:16 UTC (permalink / raw)
To: Qu Wenruo; +Cc: linux-btrfs, Boris Burkov
Please don't put the @ in the variable references in the subjects.
On Thu, Aug 31, 2023 at 08:30:36AM +0800, Qu Wenruo wrote:
> For function qgroup_update_refcnt(), we use @tmp list to iterate all the
> involved qgroups of a subvolume.
>
> It's a perfect match for qgroup_iterator facility, as that @tmp ulist
> has a very limited lifespan (just inside the while() loop).
>
> By migrating to qgroup_iterator, we can get rid of the GFP_ATOMIC memory
> allocation and no more error handling needed.
>
> Reviewed-by: Boris Burkov <boris@bur.io>
> Signed-off-by: Qu Wenruo <wqu@suse.com>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 5/6] btrfs: qgroup: use qgroup_iterator facility to replace @tmp ulist of qgroup_update_refcnt()
2023-09-01 13:16 ` David Sterba
@ 2023-09-02 0:16 ` Qu Wenruo
2023-09-05 13:02 ` David Sterba
0 siblings, 1 reply; 12+ messages in thread
From: Qu Wenruo @ 2023-09-02 0:16 UTC (permalink / raw)
To: dsterba, Qu Wenruo; +Cc: linux-btrfs, Boris Burkov
On 2023/9/1 21:16, David Sterba wrote:
> Please don't put the @ in the variable references in the subjects.
Now removed, but I'm wondering what's the guideline for referring the
variable names in the commit message/subject line?
I didn't remember when but I have seen such "@" prefix for variable
names in the mailing list, thus I followed the scheme.
If there is a guideline it can help me from causing more damage in the
future.
Thanks,
Qu
>
> On Thu, Aug 31, 2023 at 08:30:36AM +0800, Qu Wenruo wrote:
>> For function qgroup_update_refcnt(), we use @tmp list to iterate all the
>> involved qgroups of a subvolume.
>>
>> It's a perfect match for qgroup_iterator facility, as that @tmp ulist
>> has a very limited lifespan (just inside the while() loop).
>>
>> By migrating to qgroup_iterator, we can get rid of the GFP_ATOMIC memory
>> allocation and no more error handling needed.
>>
>> Reviewed-by: Boris Burkov <boris@bur.io>
>> Signed-off-by: Qu Wenruo <wqu@suse.com>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 5/6] btrfs: qgroup: use qgroup_iterator facility to replace @tmp ulist of qgroup_update_refcnt()
2023-09-02 0:16 ` Qu Wenruo
@ 2023-09-05 13:02 ` David Sterba
0 siblings, 0 replies; 12+ messages in thread
From: David Sterba @ 2023-09-05 13:02 UTC (permalink / raw)
To: Qu Wenruo; +Cc: dsterba, Qu Wenruo, linux-btrfs, Boris Burkov
On Sat, Sep 02, 2023 at 08:16:52AM +0800, Qu Wenruo wrote:
>
>
> On 2023/9/1 21:16, David Sterba wrote:
> > Please don't put the @ in the variable references in the subjects.
>
> Now removed, but I'm wondering what's the guideline for referring the
> variable names in the commit message/subject line?
In subject it should be plain reference, unquoted and untagged.
> I didn't remember when but I have seen such "@" prefix for variable
> names in the mailing list, thus I followed the scheme.
>
> If there is a guideline it can help me from causing more damage in the
> future.
The guideline has been there for a few years at
https://archive.kernel.org/oldwiki/btrfs.wiki.kernel.org/index.php/Development_notes.html#Patches
after I reminded people to not do it, but this never sticks for long.
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v2 6/6] btrfs: qgroup: use qgroup_iterator2 facility to replace @qgroups ulist of qgroup_update_refcnt()
2023-08-31 0:30 [PATCH v2 0/6] btrfs: qgroup: remove GFP_ATOMIC usage for ulist Qu Wenruo
` (4 preceding siblings ...)
2023-08-31 0:30 ` [PATCH v2 5/6] btrfs: qgroup: use qgroup_iterator facility to replace @tmp ulist of qgroup_update_refcnt() Qu Wenruo
@ 2023-08-31 0:30 ` Qu Wenruo
2023-09-01 13:19 ` David Sterba
5 siblings, 1 reply; 12+ messages in thread
From: Qu Wenruo @ 2023-08-31 0:30 UTC (permalink / raw)
To: linux-btrfs
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(-)
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 */
/*
--
2.41.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* Re: [PATCH v2 6/6] btrfs: qgroup: use qgroup_iterator2 facility to replace @qgroups ulist of qgroup_update_refcnt()
2023-08-31 0:30 ` [PATCH v2 6/6] btrfs: qgroup: use qgroup_iterator2 facility to replace @qgroups " Qu Wenruo
@ 2023-09-01 13:19 ` David Sterba
0 siblings, 0 replies; 12+ messages in thread
From: David Sterba @ 2023-09-01 13:19 UTC (permalink / raw)
To: Qu Wenruo; +Cc: linux-btrfs
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
^ permalink raw reply [flat|nested] 12+ messages in thread