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; | ||||
| } | ||||
| 
 | ||||
| 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 | ||||
| @ -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; | ||||
| @ -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; | ||||
| 	ret = qgroup_account_ref_step3(fs_info, roots, tmp, seq, sgn, | ||||
| 				       node->num_bytes); | ||||
| 	if (ret) | ||||
| 		goto unlock; | ||||
| 
 | ||||
| 		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: | ||||
| 	spin_unlock(&fs_info->qgroup_lock); | ||||
| 	ulist_free(roots); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user