Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 374909
b: refs/heads/master
c: 46b665c
h: refs/heads/master
i:
  374907: 0b7a699
v: v3
  • Loading branch information
Jan Schmidt authored and Josef Bacik committed May 6, 2013
1 parent 354cb6a commit 3007e51
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 106 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 3c76cd84e0c0d3ceb094a1020f8c55c2417e18d3
refs/heads/master: 46b665ceb1edd2ac149ff701313c115f52dc0348
253 changes: 148 additions & 105 deletions trunk/fs/btrfs/qgroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = 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
* from the fs. First, all roots referencing the extent are searched, and
Expand All @@ -1200,10 +1338,8 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *quota_root;
u64 ref_root;
struct btrfs_qgroup *qgroup;
struct ulist_node *unode;
struct ulist *roots = NULL;
struct ulist *tmp = NULL;
struct ulist_iterator uiter;
u64 seq;
int ret = 0;
int sgn;
Expand Down Expand Up @@ -1287,119 +1423,26 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans,
seq = fs_info->qgroup_seq;
fs_info->qgroup_seq += roots->nnodes + 1; /* max refcnt */

ULIST_ITER_INIT(&uiter);
while ((unode = ulist_next(roots, &uiter))) {
struct ulist_node *tmp_unode;
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;
}
}
}
ret = qgroup_account_ref_step1(fs_info, roots, tmp, seq);
if (ret)
goto unlock;

/*
* step 2: walk from the new root
*/
ulist_reinit(tmp);
ret = ulist_add(tmp, qgroup->qgroupid,
(uintptr_t)qgroup, GFP_ATOMIC);
if (ret < 0)
ret = qgroup_account_ref_step2(fs_info, roots, tmp, seq, sgn,
node->num_bytes, qgroup);
if (ret)
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
*/
ULIST_ITER_INIT(&uiter);
while ((unode = ulist_next(roots, &uiter))) {
struct btrfs_qgroup *qg;
struct ulist_node *tmp_unode;
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);
}
ret = qgroup_account_ref_step3(fs_info, roots, tmp, seq, sgn,
node->num_bytes);
if (ret)
goto unlock;

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:
spin_unlock(&fs_info->qgroup_lock);
ulist_free(roots);
Expand Down

0 comments on commit 3007e51

Please sign in to comment.