[RFC,08/11] btrfs: qgroup: Record current referenced roots at qgroup_record_ref().
diff mbox

Message ID 1427098117-25152-9-git-send-email-quwenruo@cn.fujitsu.com
State Under Review
Headers show

Commit Message

Qu Wenruo March 23, 2015, 8:08 a.m. UTC
One of problems in old qgroup is, we can only get a view on the final
results when we are going to adjust qgroup accounting.

This makes the following operataion get wrong result:
1. Subvol 257 add an exclusive extent A.
2. Subvol 258 add a shared reference to extent A.
3. Subvol 259 add a shared reference to extent A.
4. Sync

Subvol 258 and 259's qgroup data is consistent, but subvol 257 still
have exclusive reference on extent A.

The problem happens on step 2, where we should decrease exclusive
reference number, but old implement just record the operation type,
and let qgroup get roots reference number at step 4, where extent A is
finally referred by 3 roots.

At the time quota running, it can only see the final result, extent A is
referred by 3 roots (new_refcnt = 3) and before that, referred by 2
roots(old_refcnt = 2).
Quota will only decrease exclusive refer when old_refcnt == old_roots.
However in that case, old_refcnt is the final one, not the one in before
step 2, causing the exclusive counts of 257 untouched.

This patch will records root reference counts at qgroup_record_ref()
timing, which will give correct result.

Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
---
 fs/btrfs/qgroup.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

Patch
diff mbox

diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index b82c43c..4ad4106 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -1379,6 +1379,14 @@  int btrfs_qgroup_record_ref(struct btrfs_trans_handle *trans,
 
 	trace_btrfs_qgroup_record_ref(oper);
 
+	if (type == BTRFS_QGROUP_OPER_ADD_SHARED ||
+	    type == BTRFS_QGROUP_OPER_SUB_SHARED) {
+		ret = btrfs_find_all_roots(trans, fs_info, NULL, bytenr, node_seq,
+					   &oper->new_roots, 1);
+		if (ret < 0)
+			goto out;
+	}
+
 	if (type == BTRFS_QGROUP_OPER_SUB_SUBTREE) {
 		/*
 		 * If any operation for this bytenr/ref_root combo
@@ -1390,8 +1398,8 @@  int btrfs_qgroup_record_ref(struct btrfs_trans_handle *trans,
 		 * drop snapshot.
 		 */
 		if (qgroup_oper_exists(fs_info, oper)) {
-			kfree(oper);
-			return 0;
+			ret = 0;
+			goto out;
 		}
 	}
 
@@ -1399,8 +1407,7 @@  int btrfs_qgroup_record_ref(struct btrfs_trans_handle *trans,
 	if (ret) {
 		/* Shouldn't happen so have an assert for developers */
 		ASSERT(0);
-		kfree(oper);
-		return ret;
+		goto out;
 	}
 	list_add_tail(&oper->list, &trans->qgroup_ref_list);
 
@@ -1408,6 +1415,11 @@  int btrfs_qgroup_record_ref(struct btrfs_trans_handle *trans,
 		btrfs_get_tree_mod_seq(fs_info, &oper->elem);
 
 	return 0;
+out:
+	if (ret < 0)
+		ulist_free(oper->new_roots);
+	kfree(oper);
+	return ret;
 }
 
 /*