mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-26 12:30:54 +07:00
Btrfs: split btrfs_qgroup_account_ref into four functions
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.btrfs@jan-o-sch.net> Signed-off-by: Josef Bacik <jbacik@fusionio.com>
This commit is contained in:
parent
3c76cd84e0
commit
46b665ceb1
@ -1185,6 +1185,144 @@ int btrfs_qgroup_record_ref(struct btrfs_trans_handle *trans,
|
|||||||
return 0;
|
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 = ulist_next(tmp, &tmp_uiter))) {
|
||||||
|
struct btrfs_qgroup_list *glist;
|
||||||
|
|
||||||
|
qg = (struct btrfs_qgroup *)(uintptr_t)tmp_unode->aux;
|
||||||
|
if (qg->tag == seq)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (qg->refcnt - seq == roots->nnodes) {
|
||||||
|
qg->excl -= sgn * num_bytes;
|
||||||
|
qg->excl_cmpr -= sgn * num_bytes;
|
||||||
|
qgroup_dirty(fs_info, qg);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* btrfs_qgroup_account_ref is called for every ref that is added to or deleted
|
* btrfs_qgroup_account_ref is called for every ref that is added to or deleted
|
||||||
* from the fs. First, all roots referencing the extent are searched, and
|
* from the fs. First, all roots referencing the extent are searched, and
|
||||||
@ -1200,10 +1338,8 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans,
|
|||||||
struct btrfs_root *quota_root;
|
struct btrfs_root *quota_root;
|
||||||
u64 ref_root;
|
u64 ref_root;
|
||||||
struct btrfs_qgroup *qgroup;
|
struct btrfs_qgroup *qgroup;
|
||||||
struct ulist_node *unode;
|
|
||||||
struct ulist *roots = NULL;
|
struct ulist *roots = NULL;
|
||||||
struct ulist *tmp = NULL;
|
struct ulist *tmp = NULL;
|
||||||
struct ulist_iterator uiter;
|
|
||||||
u64 seq;
|
u64 seq;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int sgn;
|
int sgn;
|
||||||
@ -1287,119 +1423,26 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans,
|
|||||||
seq = fs_info->qgroup_seq;
|
seq = fs_info->qgroup_seq;
|
||||||
fs_info->qgroup_seq += roots->nnodes + 1; /* max refcnt */
|
fs_info->qgroup_seq += roots->nnodes + 1; /* max refcnt */
|
||||||
|
|
||||||
ULIST_ITER_INIT(&uiter);
|
ret = qgroup_account_ref_step1(fs_info, roots, tmp, seq);
|
||||||
while ((unode = ulist_next(roots, &uiter))) {
|
if (ret)
|
||||||
struct ulist_node *tmp_unode;
|
goto unlock;
|
||||||
struct ulist_iterator tmp_uiter;
|
|
||||||
struct btrfs_qgroup *qg;
|
|
||||||
|
|
||||||
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)
|
|
||||||
goto unlock;
|
|
||||||
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)
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* step 2: walk from the new root
|
* step 2: walk from the new root
|
||||||
*/
|
*/
|
||||||
ulist_reinit(tmp);
|
ret = qgroup_account_ref_step2(fs_info, roots, tmp, seq, sgn,
|
||||||
ret = ulist_add(tmp, qgroup->qgroupid,
|
node->num_bytes, qgroup);
|
||||||
(uintptr_t)qgroup, GFP_ATOMIC);
|
if (ret)
|
||||||
if (ret < 0)
|
|
||||||
goto unlock;
|
goto unlock;
|
||||||
ULIST_ITER_INIT(&uiter);
|
|
||||||
while ((unode = ulist_next(tmp, &uiter))) {
|
|
||||||
struct btrfs_qgroup *qg;
|
|
||||||
struct btrfs_qgroup_list *glist;
|
|
||||||
|
|
||||||
qg = (struct btrfs_qgroup *)(uintptr_t)unode->aux;
|
|
||||||
if (qg->refcnt < seq) {
|
|
||||||
/* not visited by step 1 */
|
|
||||||
qg->rfer += sgn * node->num_bytes;
|
|
||||||
qg->rfer_cmpr += sgn * node->num_bytes;
|
|
||||||
if (roots->nnodes == 0) {
|
|
||||||
qg->excl += sgn * node->num_bytes;
|
|
||||||
qg->excl_cmpr += sgn * node->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)
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* step 3: walk again from old refs
|
* step 3: walk again from old refs
|
||||||
*/
|
*/
|
||||||
ULIST_ITER_INIT(&uiter);
|
ret = qgroup_account_ref_step3(fs_info, roots, tmp, seq, sgn,
|
||||||
while ((unode = ulist_next(roots, &uiter))) {
|
node->num_bytes);
|
||||||
struct btrfs_qgroup *qg;
|
if (ret)
|
||||||
struct ulist_node *tmp_unode;
|
goto unlock;
|
||||||
struct ulist_iterator tmp_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)
|
|
||||||
goto unlock;
|
|
||||||
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->tag == seq)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (qg->refcnt - seq == roots->nnodes) {
|
|
||||||
qg->excl -= sgn * node->num_bytes;
|
|
||||||
qg->excl_cmpr -= sgn * node->num_bytes;
|
|
||||||
qgroup_dirty(fs_info, qg);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret = 0;
|
|
||||||
unlock:
|
unlock:
|
||||||
spin_unlock(&fs_info->qgroup_lock);
|
spin_unlock(&fs_info->qgroup_lock);
|
||||||
ulist_free(roots);
|
ulist_free(roots);
|
||||||
|
Loading…
Reference in New Issue
Block a user