mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	btrfs: qgroup: use qgroup_iterator_nested to in qgroup_update_refcnt()
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::nested_iterator, allowing nested iteration. Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
		
							parent
							
								
									a4a81383fb
								
							
						
					
					
						commit
						dce28769a3
					
				
					 2 changed files with 53 additions and 42 deletions
				
			
		| 
						 | 
					@ -209,6 +209,7 @@ static struct btrfs_qgroup *add_qgroup_rb(struct btrfs_fs_info *fs_info,
 | 
				
			||||||
	INIT_LIST_HEAD(&qgroup->members);
 | 
						INIT_LIST_HEAD(&qgroup->members);
 | 
				
			||||||
	INIT_LIST_HEAD(&qgroup->dirty);
 | 
						INIT_LIST_HEAD(&qgroup->dirty);
 | 
				
			||||||
	INIT_LIST_HEAD(&qgroup->iterator);
 | 
						INIT_LIST_HEAD(&qgroup->iterator);
 | 
				
			||||||
 | 
						INIT_LIST_HEAD(&qgroup->nested_iterator);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rb_link_node(&qgroup->node, parent, p);
 | 
						rb_link_node(&qgroup->node, parent, p);
 | 
				
			||||||
	rb_insert_color(&qgroup->node, &fs_info->qgroup_tree);
 | 
						rb_insert_color(&qgroup->node, &fs_info->qgroup_tree);
 | 
				
			||||||
| 
						 | 
					@ -2417,22 +2418,39 @@ int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans,
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void qgroup_iterator_nested_add(struct list_head *head, struct btrfs_qgroup *qgroup)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!list_empty(&qgroup->nested_iterator))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_add_tail(&qgroup->nested_iterator, head);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void qgroup_iterator_nested_clean(struct list_head *head)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						while (!list_empty(head)) {
 | 
				
			||||||
 | 
							struct btrfs_qgroup *qgroup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							qgroup = list_first_entry(head, struct btrfs_qgroup, nested_iterator);
 | 
				
			||||||
 | 
							list_del_init(&qgroup->nested_iterator);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define UPDATE_NEW	0
 | 
					#define UPDATE_NEW	0
 | 
				
			||||||
#define UPDATE_OLD	1
 | 
					#define UPDATE_OLD	1
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Walk all of the roots that points to the bytenr and adjust their refcnts.
 | 
					 * 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,
 | 
					static void qgroup_update_refcnt(struct btrfs_fs_info *fs_info,
 | 
				
			||||||
				struct ulist *roots, struct ulist *qgroups,
 | 
									 struct ulist *roots, struct list_head *qgroups,
 | 
				
			||||||
				u64 seq, int update_old)
 | 
									 u64 seq, int update_old)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ulist_node *unode;
 | 
						struct ulist_node *unode;
 | 
				
			||||||
	struct ulist_iterator uiter;
 | 
						struct ulist_iterator uiter;
 | 
				
			||||||
	struct btrfs_qgroup *qg;
 | 
						struct btrfs_qgroup *qg;
 | 
				
			||||||
	int ret = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!roots)
 | 
						if (!roots)
 | 
				
			||||||
		return 0;
 | 
							return;
 | 
				
			||||||
	ULIST_ITER_INIT(&uiter);
 | 
						ULIST_ITER_INIT(&uiter);
 | 
				
			||||||
	while ((unode = ulist_next(roots, &uiter))) {
 | 
						while ((unode = ulist_next(roots, &uiter))) {
 | 
				
			||||||
		LIST_HEAD(tmp);
 | 
							LIST_HEAD(tmp);
 | 
				
			||||||
| 
						 | 
					@ -2441,10 +2459,7 @@ static int qgroup_update_refcnt(struct btrfs_fs_info *fs_info,
 | 
				
			||||||
		if (!qg)
 | 
							if (!qg)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ret = ulist_add(qgroups, qg->qgroupid, qgroup_to_aux(qg),
 | 
							qgroup_iterator_nested_add(qgroups, qg);
 | 
				
			||||||
				GFP_ATOMIC);
 | 
					 | 
				
			||||||
		if (ret < 0)
 | 
					 | 
				
			||||||
			return ret;
 | 
					 | 
				
			||||||
		qgroup_iterator_add(&tmp, qg);
 | 
							qgroup_iterator_add(&tmp, qg);
 | 
				
			||||||
		list_for_each_entry(qg, &tmp, iterator) {
 | 
							list_for_each_entry(qg, &tmp, iterator) {
 | 
				
			||||||
			struct btrfs_qgroup_list *glist;
 | 
								struct btrfs_qgroup_list *glist;
 | 
				
			||||||
| 
						 | 
					@ -2455,17 +2470,12 @@ static int qgroup_update_refcnt(struct btrfs_fs_info *fs_info,
 | 
				
			||||||
				btrfs_qgroup_update_new_refcnt(qg, seq, 1);
 | 
									btrfs_qgroup_update_new_refcnt(qg, seq, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			list_for_each_entry(glist, &qg->groups, next_group) {
 | 
								list_for_each_entry(glist, &qg->groups, next_group) {
 | 
				
			||||||
				ret = ulist_add(qgroups, glist->group->qgroupid,
 | 
									qgroup_iterator_nested_add(qgroups, glist->group);
 | 
				
			||||||
						qgroup_to_aux(glist->group),
 | 
					 | 
				
			||||||
						GFP_ATOMIC);
 | 
					 | 
				
			||||||
				if (ret < 0)
 | 
					 | 
				
			||||||
					return ret;
 | 
					 | 
				
			||||||
				qgroup_iterator_add(&tmp, glist->group);
 | 
									qgroup_iterator_add(&tmp, glist->group);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		qgroup_iterator_clean(&tmp);
 | 
							qgroup_iterator_clean(&tmp);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -2504,22 +2514,16 @@ 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
 | 
					 * But this time we don't need to consider other things, the codes and logic
 | 
				
			||||||
 * is easy to understand now.
 | 
					 * is easy to understand now.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int qgroup_update_counters(struct btrfs_fs_info *fs_info,
 | 
					static void qgroup_update_counters(struct btrfs_fs_info *fs_info,
 | 
				
			||||||
				  struct ulist *qgroups,
 | 
									   struct list_head *qgroups, u64 nr_old_roots,
 | 
				
			||||||
				  u64 nr_old_roots,
 | 
									   u64 nr_new_roots, u64 num_bytes, u64 seq)
 | 
				
			||||||
				  u64 nr_new_roots,
 | 
					 | 
				
			||||||
				  u64 num_bytes, u64 seq)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ulist_node *unode;
 | 
					 | 
				
			||||||
	struct ulist_iterator uiter;
 | 
					 | 
				
			||||||
	struct btrfs_qgroup *qg;
 | 
						struct btrfs_qgroup *qg;
 | 
				
			||||||
	u64 cur_new_count, cur_old_count;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ULIST_ITER_INIT(&uiter);
 | 
						list_for_each_entry(qg, qgroups, nested_iterator) {
 | 
				
			||||||
	while ((unode = ulist_next(qgroups, &uiter))) {
 | 
							u64 cur_new_count, cur_old_count;
 | 
				
			||||||
		bool dirty = false;
 | 
							bool dirty = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		qg = unode_aux_to_qgroup(unode);
 | 
					 | 
				
			||||||
		cur_old_count = btrfs_qgroup_get_old_refcnt(qg, seq);
 | 
							cur_old_count = btrfs_qgroup_get_old_refcnt(qg, seq);
 | 
				
			||||||
		cur_new_count = btrfs_qgroup_get_new_refcnt(qg, seq);
 | 
							cur_new_count = btrfs_qgroup_get_new_refcnt(qg, seq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2590,7 +2594,6 @@ static int qgroup_update_counters(struct btrfs_fs_info *fs_info,
 | 
				
			||||||
		if (dirty)
 | 
							if (dirty)
 | 
				
			||||||
			qgroup_dirty(fs_info, qg);
 | 
								qgroup_dirty(fs_info, qg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -2627,7 +2630,7 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr,
 | 
				
			||||||
				struct ulist *new_roots)
 | 
									struct ulist *new_roots)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct btrfs_fs_info *fs_info = trans->fs_info;
 | 
						struct btrfs_fs_info *fs_info = trans->fs_info;
 | 
				
			||||||
	struct ulist *qgroups = NULL;
 | 
						LIST_HEAD(qgroups);
 | 
				
			||||||
	u64 seq;
 | 
						u64 seq;
 | 
				
			||||||
	u64 nr_new_roots = 0;
 | 
						u64 nr_new_roots = 0;
 | 
				
			||||||
	u64 nr_old_roots = 0;
 | 
						u64 nr_old_roots = 0;
 | 
				
			||||||
| 
						 | 
					@ -2661,11 +2664,6 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr,
 | 
				
			||||||
	trace_btrfs_qgroup_account_extent(fs_info, trans->transid, bytenr,
 | 
						trace_btrfs_qgroup_account_extent(fs_info, trans->transid, bytenr,
 | 
				
			||||||
					num_bytes, nr_old_roots, nr_new_roots);
 | 
										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);
 | 
						mutex_lock(&fs_info->qgroup_rescan_lock);
 | 
				
			||||||
	if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) {
 | 
						if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) {
 | 
				
			||||||
		if (fs_info->qgroup_rescan_progress.objectid <= bytenr) {
 | 
							if (fs_info->qgroup_rescan_progress.objectid <= bytenr) {
 | 
				
			||||||
| 
						 | 
					@ -2680,26 +2678,21 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr,
 | 
				
			||||||
	seq = fs_info->qgroup_seq;
 | 
						seq = fs_info->qgroup_seq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Update old refcnts using old_roots */
 | 
						/* Update old refcnts using old_roots */
 | 
				
			||||||
	ret = qgroup_update_refcnt(fs_info, old_roots, qgroups, seq, UPDATE_OLD);
 | 
						qgroup_update_refcnt(fs_info, old_roots, &qgroups, seq, UPDATE_OLD);
 | 
				
			||||||
	if (ret < 0)
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Update new refcnts using new_roots */
 | 
						/* Update new refcnts using new_roots */
 | 
				
			||||||
	ret = qgroup_update_refcnt(fs_info, new_roots, qgroups, seq, UPDATE_NEW);
 | 
						qgroup_update_refcnt(fs_info, new_roots, &qgroups, seq, UPDATE_NEW);
 | 
				
			||||||
	if (ret < 0)
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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);
 | 
								       num_bytes, seq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Bump qgroup_seq to avoid seq overlap
 | 
						 * Bump qgroup_seq to avoid seq overlap
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	fs_info->qgroup_seq += max(nr_old_roots, nr_new_roots) + 1;
 | 
						fs_info->qgroup_seq += max(nr_old_roots, nr_new_roots) + 1;
 | 
				
			||||||
out:
 | 
					 | 
				
			||||||
	spin_unlock(&fs_info->qgroup_lock);
 | 
						spin_unlock(&fs_info->qgroup_lock);
 | 
				
			||||||
out_free:
 | 
					out_free:
 | 
				
			||||||
	ulist_free(qgroups);
 | 
						qgroup_iterator_nested_clean(&qgroups);
 | 
				
			||||||
	ulist_free(old_roots);
 | 
						ulist_free(old_roots);
 | 
				
			||||||
	ulist_free(new_roots);
 | 
						ulist_free(new_roots);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -229,6 +229,24 @@ struct btrfs_qgroup {
 | 
				
			||||||
	 * finished.
 | 
						 * finished.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	struct list_head iterator;
 | 
						struct list_head iterator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * For nested iterator usage.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Here we support at most one level of nested iterator calls like:
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	LIST_HEAD(all_qgroups);
 | 
				
			||||||
 | 
						 *	{
 | 
				
			||||||
 | 
						 *		LIST_HEAD(local_qgroups);
 | 
				
			||||||
 | 
						 *		qgroup_iterator_add(local_qgroups, qg);
 | 
				
			||||||
 | 
						 *		qgroup_iterator_nested_add(all_qgroups, qg);
 | 
				
			||||||
 | 
						 *		do_some_work(local_qgroups);
 | 
				
			||||||
 | 
						 *		qgroup_iterator_clean(local_qgroups);
 | 
				
			||||||
 | 
						 *	}
 | 
				
			||||||
 | 
						 *	do_some_work(all_qgroups);
 | 
				
			||||||
 | 
						 *	qgroup_iterator_nested_clean(all_qgroups);
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						struct list_head nested_iterator;
 | 
				
			||||||
	struct rb_node node;	  /* tree of qgroups */
 | 
						struct rb_node node;	  /* tree of qgroups */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue