diff mbox

Btrfs: fix a warning of qgroup account on shared extents

Message ID 1418720398-21847-1-git-send-email-bo.li.liu@oracle.com (mailing list archive)
State New, archived
Headers show

Commit Message

Liu Bo Dec. 16, 2014, 8:59 a.m. UTC
As we don't record tree_mod_seq during adding delayed refs,
we may get inaccurate results from backref walking, ie.
btrfs_find_all_roots.

For shared extents made by ioctl 'clone', removing those extents
can end up warnings of qgroup accounting.

Here is an example, file A and B shares the same extent, both are in "fs tree"
1. remove A and B
2. add delayed ref 'DROP A' and 'DROP B'
3. run delayed ref 'DROP A'
4. qgroup record 'DROP A'
5. run delayed ref 'DROP B'
6. qgroup record 'DROP B'
7. qgroup account on'DROP A', it runs btrfs_find_all_roots() and
   finds no reference on this extent, and in qgroup_account_deleted_refs()
   'DROP B' has the same ref_root and is skipped then.
8. "fs tree"'s reference number is (num - extent_len),
    exclusive number is (num - extent_len)
9. qgroup account on 'DROP B', it's the last ref on this extent, thus
10."fs tree"'s reference number is (num - extent_len),
    exclusive number is (num - extent_len)

So "fs tree" 's numbers are wrong.

This adds an additional check in check_existing_ref() so that we can detect
the above case and make it right.

Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
---
 fs/btrfs/qgroup.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
diff mbox

Patch

diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 48b60db..5eb279b 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -1796,6 +1796,26 @@  static int check_existing_refs(struct btrfs_trans_handle *trans,
 	ulist_free(roots);
 	btrfs_put_tree_mod_seq(fs_info, &oper->elem);
 
+	if (ret == 0 && oper->type == BTRFS_QGROUP_OPER_SUB_SHARED) {
+		struct btrfs_qgroup_operation *tmp;
+		struct rb_node *n;
+
+		n = &oper->n;
+		do {
+			spin_lock(&fs_info->qgroup_op_lock);
+			n = rb_next(n);
+			spin_unlock(&fs_info->qgroup_op_lock);
+			if (!n)
+				return 0;
+
+			tmp = rb_entry(n, struct btrfs_qgroup_operation, n);
+
+			if (tmp->bytenr == oper->bytenr &&
+			    tmp->ref_root == oper->ref_root)
+				return 1;
+		} while (tmp->bytenr == oper->bytenr);
+	}
+
 	return ret;
 }