File 0159-btrfsck-fix-block-group-accounting-during-repair.patch of Package btrfsprogs

From 4fc0390c2bbce8a5b39fb592da80bfe1870152a4 Mon Sep 17 00:00:00 2001
From: Chris Mason <chris.mason@oracle.com>
Date: Wed, 8 Feb 2012 21:29:13 -0500
Subject: [PATCH 08/18] btrfsck: fix block group accounting during repair

Signed-off-by: Chris Mason <chris.mason@oracle.com>
---
 btrfsck.c     |   36 +++++++++-----
 convert.c     |   62 +-----------------------
 ctree.h       |    3 +
 extent-tree.c |  148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 174 insertions(+), 75 deletions(-)

Index: btrfs-progs-v0.19-118-gfdb6c04/btrfsck.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/btrfsck.c
+++ btrfs-progs-v0.19-118-gfdb6c04/btrfsck.c
@@ -2725,7 +2725,7 @@ static int add_root_to_pending(struct ex
 static int delete_extent_records(struct btrfs_trans_handle *trans,
 				 struct btrfs_root *root,
 				 struct btrfs_path *path,
-				 u64 bytenr)
+				 u64 bytenr, u64 new_len)
 {
 	struct btrfs_key key;
 	struct btrfs_key found_key;
@@ -2787,7 +2787,7 @@ static int delete_extent_records(struct
 
 		if (found_key.type == BTRFS_EXTENT_ITEM_KEY) {
 			ret = btrfs_update_block_group(trans, root, bytenr,
-						       found_key.offset, 0, 1);
+						       found_key.offset, 0, 0);
 			if (ret)
 				break;
 		}
@@ -2959,7 +2959,7 @@ static int fixup_extent_refs(struct btrf
 
 	/* step one, delete all the existing records */
 	ret = delete_extent_records(trans, info->extent_root, path,
-				    rec->start);
+				    rec->start, rec->max_size);
 
 	if (ret < 0)
 		goto out;
@@ -2987,19 +2987,16 @@ out:
 	return ret;
 }
 
-static int check_extent_refs(struct btrfs_root *root,
-		      struct cache_tree *extent_cache, int repair)
+static int check_extent_refs(struct btrfs_trans_handle *trans,
+			     struct btrfs_root *root,
+			     struct cache_tree *extent_cache, int repair)
 {
 	struct extent_record *rec;
 	struct cache_extent *cache;
-	struct btrfs_trans_handle *trans = NULL;
 	int err = 0;
 	int ret = 0;
 	int fixed = 0;
 
-	if (repair)
-		trans = btrfs_start_transaction(root, 1);
-
 	if (repair) {
 		/*
 		 * if we're doing a repair, we have to make sure
@@ -3074,12 +3071,12 @@ repair_abort:
 			fprintf(stderr, "failed to repair damaged filesystem, aborting\n");
 			exit(1);
 		}
-		btrfs_commit_transaction(trans, root);
 	}
 	return err;
 }
 
-static int check_extents(struct btrfs_root *root, int repair)
+static int check_extents(struct btrfs_trans_handle *trans,
+			 struct btrfs_root *root, int repair)
 {
 	struct cache_tree extent_cache;
 	struct cache_tree seen;
@@ -3160,7 +3157,7 @@ static int check_extents(struct btrfs_ro
 		if (ret != 0)
 			break;
 	}
-	ret = check_extent_refs(root, &extent_cache, repair);
+	ret = check_extent_refs(trans, root, &extent_cache, repair);
 	free(bits);
 	return ret;
 }
@@ -3183,6 +3180,7 @@ int main(int ac, char **av)
 	struct cache_tree root_cache;
 	struct btrfs_root *root;
 	struct btrfs_fs_info *info;
+	struct btrfs_trans_handle *trans = NULL;
 	u64 bytenr = 0;
 	int ret;
 	int num;
@@ -3244,9 +3242,16 @@ int main(int ac, char **av)
 	root = info->fs_root;
 
 	fprintf(stderr, "checking extents\n");
-	ret = check_extents(root, repair);
+	if (repair)
+		trans = btrfs_start_transaction(root, 1);
+
+	ret = check_extents(trans, root, repair);
 	if (ret)
 		goto out;
+
+	if (repair)
+		btrfs_fix_block_accounting(trans, root);
+
 	fprintf(stderr, "checking fs roots\n");
 	ret = check_fs_roots(root, &root_cache);
 	if (ret)
@@ -3256,6 +3261,11 @@ int main(int ac, char **av)
 	ret = check_root_refs(root, &root_cache);
 out:
 	free_root_recs(&root_cache);
+	if (repair) {
+		ret = btrfs_commit_transaction(trans, root);
+		if (ret)
+			exit(1);
+	}
 	close_ctree(root);
 
 	if (found_old_backref) {
Index: btrfs-progs-v0.19-118-gfdb6c04/convert.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/convert.c
+++ btrfs-progs-v0.19-118-gfdb6c04/convert.c
@@ -1504,66 +1504,6 @@ fail:
 	return new_root;
 }
 
-/*
- * Fixup block accounting. The initial block accounting created by
- * make_block_groups isn't accuracy in this case.
- */
-static int fixup_block_accounting(struct btrfs_trans_handle *trans,
-				  struct btrfs_root *root)
-{
-	int ret;
-	int slot;
-	u64 start = 0;
-	u64 bytes_used = 0;
-	struct btrfs_path path;
-	struct btrfs_key key;
-	struct extent_buffer *leaf;
-	struct btrfs_block_group_cache *cache;
-	struct btrfs_fs_info *fs_info = root->fs_info;
-
-	while(1) {
-		cache = btrfs_lookup_block_group(fs_info, start);
-		if (!cache)
-			break;
-		start = cache->key.objectid + cache->key.offset;
-		btrfs_set_block_group_used(&cache->item, 0);
-		cache->space_info->bytes_used = 0;
-	}
-
-	btrfs_init_path(&path);
-	key.offset = 0;
-	key.objectid = 0;
-	btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
-	ret = btrfs_search_slot(trans, root->fs_info->extent_root,
-				&key, &path, 0, 0);
-	if (ret < 0)
-		return ret;
-	while(1) {
-		leaf = path.nodes[0];
-		slot = path.slots[0];
-		if (slot >= btrfs_header_nritems(leaf)) {
-			ret = btrfs_next_leaf(root, &path);
-			if (ret < 0)
-				return ret;
-			if (ret > 0)
-				break;
-			leaf = path.nodes[0];
-			slot = path.slots[0];
-		}
-		btrfs_item_key_to_cpu(leaf, &key, slot);
-		if (key.type == BTRFS_EXTENT_ITEM_KEY) {
-			bytes_used += key.offset;
-			ret = btrfs_update_block_group(trans, root,
-				  key.objectid, key.offset, 1, 0);
-			BUG_ON(ret);
-		}
-		path.slots[0]++;
-	}
-	btrfs_set_super_bytes_used(&root->fs_info->super_copy, bytes_used);
-	btrfs_release_path(root, &path);
-	return 0;
-}
-
 static int create_chunk_mapping(struct btrfs_trans_handle *trans,
 				struct btrfs_root *root)
 {
@@ -1735,7 +1675,7 @@ static int init_btrfs(struct btrfs_root
 	ret = btrfs_make_block_groups(trans, root);
 	if (ret)
 		goto err;
-	ret = fixup_block_accounting(trans, root);
+	ret = btrfs_fixup_block_accounting(trans, root);
 	if (ret)
 		goto err;
 	ret = create_chunk_mapping(trans, root);
Index: btrfs-progs-v0.19-118-gfdb6c04/ctree.h
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/ctree.h
+++ btrfs-progs-v0.19-118-gfdb6c04/ctree.h
@@ -1785,6 +1785,9 @@ static inline u32 btrfs_level_size(struc
 	btrfs_item_offset_nr(leaf, slot)))
 
 /* extent-tree.c */
+int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans,
+				 struct btrfs_root *root);
+int btrfs_check_block_accounting(struct btrfs_root *root);
 void btrfs_pin_extent(struct btrfs_fs_info *fs_info, u64 bytenr, u64 num_bytes);
 int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
 			 struct btrfs_root *root);
Index: btrfs-progs-v0.19-118-gfdb6c04/extent-tree.c
===================================================================
--- btrfs-progs-v0.19-118-gfdb6c04.orig/extent-tree.c
+++ btrfs-progs-v0.19-118-gfdb6c04/extent-tree.c
@@ -1734,7 +1734,12 @@ static int update_space_info(struct btrf
 	if (found) {
 		found->total_bytes += total_bytes;
 		found->bytes_used += bytes_used;
-		WARN_ON(found->total_bytes < found->bytes_used);
+		if (found->total_bytes < found->bytes_used) {
+			fprintf(stderr, "warning, bad space info total_bytes "
+				"%llu used %llu\n",
+			       (unsigned long long)found->total_bytes,
+			       (unsigned long long)found->bytes_used);
+		}
 		*space_info = found;
 		return 0;
 	}
@@ -1853,6 +1858,7 @@ static int update_block_group(struct btr
 
 		old_val = btrfs_block_group_used(&cache->item);
 		num_bytes = min(total, cache->key.offset - byte_in_group);
+
 		if (alloc) {
 			old_val += num_bytes;
 			cache->space_info->bytes_used += num_bytes;
@@ -3274,3 +3280,143 @@ int btrfs_update_block_group(struct btrf
 	return update_block_group(trans, root, bytenr, num_bytes,
 				  alloc, mark_free);
 }
+
+static int btrfs_count_extents_in_block_group(struct btrfs_root *root,
+					      struct btrfs_path *path, u64 start,
+					      u64 len,
+					      u64 *total)
+{
+	struct btrfs_key key;
+	struct extent_buffer *leaf;
+	u64 bytes_used = 0;
+	int ret;
+	int slot;
+
+	key.offset = 0;
+	key.objectid = start;
+	btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
+	ret = btrfs_search_slot(NULL, root->fs_info->extent_root,
+				&key, path, 0, 0);
+	if (ret < 0)
+		return ret;
+	while(1) {
+		leaf = path->nodes[0];
+		slot = path->slots[0];
+		if (slot >= btrfs_header_nritems(leaf)) {
+			ret = btrfs_next_leaf(root, path);
+			if (ret < 0)
+				return ret;
+			if (ret > 0)
+				break;
+			leaf = path->nodes[0];
+			slot = path->slots[0];
+		}
+		btrfs_item_key_to_cpu(leaf, &key, slot);
+		if (key.objectid > start + len)
+			break;
+		if (key.type == BTRFS_EXTENT_ITEM_KEY)
+			bytes_used += key.offset;
+		path->slots[0]++;
+	}
+	*total = bytes_used;
+	btrfs_release_path(root, path);
+	return 0;
+}
+
+int btrfs_check_block_accounting(struct btrfs_root *root)
+{
+	int ret;
+	u64 start = 0;
+	u64 bytes_used = 0;
+	struct btrfs_path path;
+	struct btrfs_block_group_cache *cache;
+	struct btrfs_fs_info *fs_info = root->fs_info;
+
+	btrfs_init_path(&path);
+
+	while(1) {
+		cache = btrfs_lookup_block_group(fs_info, start);
+		if (!cache)
+			break;
+
+		ret = btrfs_count_extents_in_block_group(root, &path,
+							 cache->key.objectid,
+							 cache->key.offset,
+							 &bytes_used);
+
+		if (ret == 0) {
+			u64 on_disk = btrfs_block_group_used(&cache->item);
+			if (on_disk != bytes_used) {
+				fprintf(stderr, "bad block group accounting found %llu "
+					"expected %llu block group %llu\n",
+					(unsigned long long)bytes_used,
+					(unsigned long long)on_disk,
+					(unsigned long long)cache->key.objectid);
+			}
+		}
+		start = cache->key.objectid + cache->key.offset;
+
+		cache->space_info->bytes_used = 0;
+	}
+	return 0;
+}
+
+/*
+ * Fixup block accounting. The initial block accounting created by
+ * make_block_groups isn't accuracy in this case.
+ */
+int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans,
+			       struct btrfs_root *root)
+{
+	int ret;
+	int slot;
+	u64 start = 0;
+	u64 bytes_used = 0;
+	struct btrfs_path path;
+	struct btrfs_key key;
+	struct extent_buffer *leaf;
+	struct btrfs_block_group_cache *cache;
+	struct btrfs_fs_info *fs_info = root->fs_info;
+
+	while(1) {
+		cache = btrfs_lookup_block_group(fs_info, start);
+		if (!cache)
+			break;
+		start = cache->key.objectid + cache->key.offset;
+		btrfs_set_block_group_used(&cache->item, 0);
+		cache->space_info->bytes_used = 0;
+	}
+
+	btrfs_init_path(&path);
+	key.offset = 0;
+	key.objectid = 0;
+	btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
+	ret = btrfs_search_slot(trans, root->fs_info->extent_root,
+				&key, &path, 0, 0);
+	if (ret < 0)
+		return ret;
+	while(1) {
+		leaf = path.nodes[0];
+		slot = path.slots[0];
+		if (slot >= btrfs_header_nritems(leaf)) {
+			ret = btrfs_next_leaf(root, &path);
+			if (ret < 0)
+				return ret;
+			if (ret > 0)
+				break;
+			leaf = path.nodes[0];
+			slot = path.slots[0];
+		}
+		btrfs_item_key_to_cpu(leaf, &key, slot);
+		if (key.type == BTRFS_EXTENT_ITEM_KEY) {
+			bytes_used += key.offset;
+			ret = btrfs_update_block_group(trans, root,
+				  key.objectid, key.offset, 1, 0);
+			BUG_ON(ret);
+		}
+		path.slots[0]++;
+	}
+	btrfs_set_super_bytes_used(&root->fs_info->super_copy, bytes_used);
+	btrfs_release_path(root, &path);
+	return 0;
+}
openSUSE Build Service is sponsored by