The function is separated into a preparation part and the three accounting
steps mentioned in the qgroups documentation. The goal is to make steps two
and three usable by the rescan functionality. A side effect is that the
function is restructured into readable subunits.
Signed-off-by: Jan Schmidt list.bt...@jan-o-sch.net
---
fs/btrfs/qgroup.c | 253 +++--
1 files changed, 148 insertions(+), 105 deletions(-)
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index f175471..c50e5a5 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -1185,6 +1185,144 @@ int btrfs_qgroup_record_ref(struct btrfs_trans_handle
*trans,
return 0;
}
+static int qgroup_account_ref_step1(struct btrfs_fs_info *fs_info,
+ struct ulist *roots, struct ulist *tmp,
+ u64 seq)
+{
+ struct ulist_node *unode;
+ struct ulist_iterator uiter;
+ struct ulist_node *tmp_unode;
+ struct ulist_iterator tmp_uiter;
+ struct btrfs_qgroup *qg;
+ int ret;
+
+ ULIST_ITER_INIT(uiter);
+ while ((unode = ulist_next(roots, uiter))) {
+ qg = find_qgroup_rb(fs_info, unode-val);
+ if (!qg)
+ continue;
+
+ ulist_reinit(tmp);
+ /* XXX id not needed */
+ ret = ulist_add(tmp, qg-qgroupid,
+ (u64)(uintptr_t)qg, GFP_ATOMIC);
+ if (ret 0)
+ return ret;
+ ULIST_ITER_INIT(tmp_uiter);
+ while ((tmp_unode = ulist_next(tmp, tmp_uiter))) {
+ struct btrfs_qgroup_list *glist;
+
+ qg = (struct btrfs_qgroup *)(uintptr_t)tmp_unode-aux;
+ if (qg-refcnt seq)
+ qg-refcnt = seq + 1;
+ else
+ ++qg-refcnt;
+
+ list_for_each_entry(glist, qg-groups, next_group) {
+ ret = ulist_add(tmp, glist-group-qgroupid,
+ (u64)(uintptr_t)glist-group,
+ GFP_ATOMIC);
+ if (ret 0)
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int qgroup_account_ref_step2(struct btrfs_fs_info *fs_info,
+ struct ulist *roots, struct ulist *tmp,
+ u64 seq, int sgn, u64 num_bytes,
+ struct btrfs_qgroup *qgroup)
+{
+ struct ulist_node *unode;
+ struct ulist_iterator uiter;
+ struct btrfs_qgroup *qg;
+ struct btrfs_qgroup_list *glist;
+ int ret;
+
+ ulist_reinit(tmp);
+ ret = ulist_add(tmp, qgroup-qgroupid, (uintptr_t)qgroup, GFP_ATOMIC);
+ if (ret 0)
+ return ret;
+
+ ULIST_ITER_INIT(uiter);
+ while ((unode = ulist_next(tmp, uiter))) {
+ qg = (struct btrfs_qgroup *)(uintptr_t)unode-aux;
+ if (qg-refcnt seq) {
+ /* not visited by step 1 */
+ qg-rfer += sgn * num_bytes;
+ qg-rfer_cmpr += sgn * num_bytes;
+ if (roots-nnodes == 0) {
+ qg-excl += sgn * num_bytes;
+ qg-excl_cmpr += sgn * num_bytes;
+ }
+ qgroup_dirty(fs_info, qg);
+ }
+ WARN_ON(qg-tag = seq);
+ qg-tag = seq;
+
+ list_for_each_entry(glist, qg-groups, next_group) {
+ ret = ulist_add(tmp, glist-group-qgroupid,
+ (uintptr_t)glist-group, GFP_ATOMIC);
+ if (ret 0)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int qgroup_account_ref_step3(struct btrfs_fs_info *fs_info,
+ struct ulist *roots, struct ulist *tmp,
+ u64 seq, int sgn, u64 num_bytes)
+{
+ struct ulist_node *unode;
+ struct ulist_iterator uiter;
+ struct btrfs_qgroup *qg;
+ struct ulist_node *tmp_unode;
+ struct ulist_iterator tmp_uiter;
+ int ret;
+
+ ULIST_ITER_INIT(uiter);
+ while ((unode = ulist_next(roots, uiter))) {
+ qg = find_qgroup_rb(fs_info, unode-val);
+ if (!qg)
+ continue;
+
+ ulist_reinit(tmp);
+ ret = ulist_add(tmp, qg-qgroupid, (uintptr_t)qg, GFP_ATOMIC);
+ if (ret 0)
+ return ret;
+
+ ULIST_ITER_INIT(tmp_uiter);
+ while ((tmp_unode =