linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] Extent tree rebuilding with snapshots patches
@ 2014-11-26  2:58 Wang Shilong
  2014-11-26  2:58 ` [PATCH resend 1/3] Btrfs-progs: fsck: deal with snapshot one by one when rebuilding extent tree Wang Shilong
                   ` (7 more replies)
  0 siblings, 8 replies; 10+ messages in thread
From: Wang Shilong @ 2014-11-26  2:58 UTC (permalink / raw)
  To: linux-btrfs; +Cc: dsterba

I did send these patches a long while ago, but due to some reasons,
they were not merged, these are important fixes for fsck, without
these patches, extent tree rebuilding did not work with snapshots.

Also, /tests/fsck-tests.sh's extent tree rebuild test could always
detect failure without these patches, unluckily, it need extra
enviroment setting, so i supposed it was always 'NOTRUN'!

last patch fix a regression for root rebuilding, root rebuilding
should be at first, because if root(extent root eg) corrupted,
root items also won't succeed.

patches are based on David's integration-20141125

Wang Shilong (3):
  Btrfs-progs: fsck: deal with snapshot one by one when rebuilding
    extent tree
  Btrfs-progs: fsck: add ability to rebuild extent tree with snapshots
  Btrfs-progs, fsck: move root items repair after root rebuilding

 cmds-check.c | 412 +++++++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 303 insertions(+), 109 deletions(-)

-- 
2.1.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH resend 1/3] Btrfs-progs: fsck: deal with snapshot one by one when rebuilding extent tree
  2014-11-26  2:58 [PATCH 0/3] Extent tree rebuilding with snapshots patches Wang Shilong
@ 2014-11-26  2:58 ` Wang Shilong
  2014-11-26  2:58 ` [PATCH resend 2/3] Btrfs-progs: fsck: add ability to rebuild extent tree with snapshots Wang Shilong
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Wang Shilong @ 2014-11-26  2:58 UTC (permalink / raw)
  To: linux-btrfs; +Cc: dsterba

From: Wang Shilong <wangsl.fnst@cn.fujitsu.com>

Previously, we deal with node block firstly and then leaf block which can
maximize readahead. However, to rebuild extent tree, we need deal with snapshot
one by one.

This patch makes us deal with snapshot one by one if we need rebuild extent
tree otherwise we drop into previous way.

Signed-off-by: Wang Shilong <wangsl.fnst@cn.fujitsu.com>
Signed-off-by: Wang Shilong <wangshilong1991@gmail.com>
---
 cmds-check.c | 248 +++++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 158 insertions(+), 90 deletions(-)

diff --git a/cmds-check.c b/cmds-check.c
index 24b6b59..ff2795d 100644
--- a/cmds-check.c
+++ b/cmds-check.c
@@ -128,10 +128,14 @@ struct inode_backref {
 	char name[0];
 };
 
-struct dropping_root_item_record {
+struct root_item_record {
 	struct list_head list;
-	struct btrfs_root_item ri;
-	struct btrfs_key found_key;
+	u64 objectid;
+	u64 bytenr;
+	u8 level;
+	u8 drop_level;
+	int level_size;
+	struct btrfs_key drop_key;
 };
 
 #define REF_ERR_NO_DIR_ITEM		(1 << 0)
@@ -4618,7 +4622,7 @@ static int run_next_block(struct btrfs_trans_handle *trans,
 			  struct rb_root *dev_cache,
 			  struct block_group_tree *block_group_cache,
 			  struct device_extent_tree *dev_extent_cache,
-			  struct btrfs_root_item *ri)
+			  struct root_item_record *ri)
 {
 	struct extent_buffer *buf;
 	u64 bytenr;
@@ -4851,11 +4855,8 @@ static int run_next_block(struct btrfs_trans_handle *trans,
 			size = btrfs_level_size(root, level - 1);
 			btrfs_node_key_to_cpu(buf, &key, i);
 			if (ri != NULL) {
-				struct btrfs_key drop_key;
-				btrfs_disk_key_to_cpu(&drop_key,
-						      &ri->drop_progress);
 				if ((level == ri->drop_level)
-				    && is_dropped_key(&key, &drop_key)) {
+				    && is_dropped_key(&key, &ri->drop_key)) {
 					continue;
 				}
 			}
@@ -4896,7 +4897,7 @@ static int add_root_to_pending(struct extent_buffer *buf,
 			       struct cache_tree *pending,
 			       struct cache_tree *seen,
 			       struct cache_tree *nodes,
-			       struct btrfs_key *root_key)
+			       u64 objectid)
 {
 	if (btrfs_header_level(buf) > 0)
 		add_pending(nodes, seen, buf->start, buf->len);
@@ -4905,13 +4906,12 @@ static int add_root_to_pending(struct extent_buffer *buf,
 	add_extent_rec(extent_cache, NULL, 0, buf->start, buf->len,
 		       0, 1, 1, 0, 1, 0, buf->len);
 
-	if (root_key->objectid == BTRFS_TREE_RELOC_OBJECTID ||
+	if (objectid == BTRFS_TREE_RELOC_OBJECTID ||
 	    btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV)
 		add_tree_backref(extent_cache, buf->start, buf->start,
 				 0, 1);
 	else
-		add_tree_backref(extent_cache, buf->start, 0,
-				 root_key->objectid, 1);
+		add_tree_backref(extent_cache, buf->start, 0, objectid, 1);
 	return 0;
 }
 
@@ -6481,6 +6481,99 @@ static int check_devices(struct rb_root *dev_cache,
 	return ret;
 }
 
+static int add_root_item_to_list(struct list_head *head,
+				  u64 objectid, u64 bytenr,
+				  u8 level, u8 drop_level,
+				  int level_size, struct btrfs_key *drop_key)
+{
+
+	struct root_item_record *ri_rec;
+	ri_rec = malloc(sizeof(*ri_rec));
+	if (!ri_rec)
+		return -ENOMEM;
+	ri_rec->bytenr = bytenr;
+	ri_rec->objectid = objectid;
+	ri_rec->level = level;
+	ri_rec->level_size = level_size;
+	ri_rec->drop_level = drop_level;
+	if (drop_key)
+		memcpy(&ri_rec->drop_key, drop_key, sizeof(*drop_key));
+	list_add_tail(&ri_rec->list, head);
+
+	return 0;
+}
+
+static int deal_root_from_list(struct list_head *list,
+			       struct btrfs_trans_handle *trans,
+			       struct btrfs_root *root,
+			       struct block_info *bits,
+			       int bits_nr,
+			       struct cache_tree *pending,
+			       struct cache_tree *seen,
+			       struct cache_tree *reada,
+			       struct cache_tree *nodes,
+			       struct cache_tree *extent_cache,
+			       struct cache_tree *chunk_cache,
+			       struct rb_root *dev_cache,
+			       struct block_group_tree *block_group_cache,
+			       struct device_extent_tree *dev_extent_cache)
+{
+	int ret = 0;
+	u64 last;
+
+	while (!list_empty(list)) {
+		struct root_item_record *rec;
+		struct extent_buffer *buf;
+		rec = list_entry(list->next,
+				 struct root_item_record, list);
+		last = 0;
+		buf = read_tree_block(root->fs_info->tree_root,
+				      rec->bytenr, rec->level_size, 0);
+		if (!extent_buffer_uptodate(buf)) {
+			free_extent_buffer(buf);
+			ret = -EIO;
+			break;
+		}
+		add_root_to_pending(buf, extent_cache, pending,
+				    seen, nodes, rec->objectid);
+		/*
+		 * To rebuild extent tree, we need deal with snapshot
+		 * one by one, otherwise we deal with node firstly which
+		 * can maximize readahead.
+		 */
+		if (!init_extent_tree && !rec->drop_level)
+			goto skip;
+		while (1) {
+			ret = run_next_block(trans, root, bits, bits_nr, &last,
+					     pending, seen, reada,
+					     nodes, extent_cache,
+					     chunk_cache, dev_cache,
+					     block_group_cache,
+					     dev_extent_cache, rec);
+			if (ret != 0)
+				break;
+		}
+skip:
+		free_extent_buffer(buf);
+		list_del(&rec->list);
+		free(rec);
+	}
+	while (ret >= 0) {
+		ret = run_next_block(trans, root, bits, bits_nr, &last,
+				     pending, seen, reada,
+				     nodes, extent_cache,
+				     chunk_cache, dev_cache,
+				     block_group_cache,
+				     dev_extent_cache, NULL);
+		if (ret != 0) {
+			if (ret > 0)
+				ret = 0;
+			break;
+		}
+	}
+	return ret;
+}
+
 static int check_chunks_and_extents(struct btrfs_root *root)
 {
 	struct rb_root dev_cache;
@@ -6497,7 +6590,6 @@ static int check_chunks_and_extents(struct btrfs_root *root)
 	struct btrfs_key key;
 	struct btrfs_key found_key;
 	int ret, err = 0;
-	u64 last = 0;
 	struct block_info *bits;
 	int bits_nr;
 	struct extent_buffer *leaf;
@@ -6505,6 +6597,11 @@ static int check_chunks_and_extents(struct btrfs_root *root)
 	int slot;
 	struct btrfs_root_item ri;
 	struct list_head dropping_trees;
+	struct list_head normal_trees;
+	struct btrfs_root *root1;
+	u64 objectid;
+	u32 level_size;
+	u8 level;
 
 	dev_cache = RB_ROOT;
 	cache_tree_init(&chunk_cache);
@@ -6518,6 +6615,7 @@ static int check_chunks_and_extents(struct btrfs_root *root)
 	cache_tree_init(&reada);
 	cache_tree_init(&corrupt_blocks);
 	INIT_LIST_HEAD(&dropping_trees);
+	INIT_LIST_HEAD(&normal_trees);
 
 	if (repair) {
 		trans = btrfs_start_transaction(root, 1);
@@ -6538,14 +6636,20 @@ static int check_chunks_and_extents(struct btrfs_root *root)
 	}
 
 again:
-	add_root_to_pending(root->fs_info->tree_root->node,
-			    &extent_cache, &pending, &seen, &nodes,
-			    &root->fs_info->tree_root->root_key);
-
-	add_root_to_pending(root->fs_info->chunk_root->node,
-			    &extent_cache, &pending, &seen, &nodes,
-			    &root->fs_info->chunk_root->root_key);
-
+	root1 = root->fs_info->tree_root;
+	level = btrfs_header_level(root1->node);
+	ret = add_root_item_to_list(&normal_trees, root1->root_key.objectid,
+				    root1->node->start, level, 0,
+				    btrfs_level_size(root1, level), NULL);
+	if (ret < 0)
+		goto out;
+	root1 = root->fs_info->chunk_root;
+	level = btrfs_header_level(root1->node);
+	ret = add_root_item_to_list(&normal_trees, root1->root_key.objectid,
+				    root1->node->start, level, 0,
+				    btrfs_level_size(root1, level), NULL);
+	if (ret < 0)
+		goto out;
 	btrfs_init_path(&path);
 	key.offset = 0;
 	key.objectid = 0;
@@ -6567,86 +6671,50 @@ again:
 		btrfs_item_key_to_cpu(leaf, &found_key, path.slots[0]);
 		if (btrfs_key_type(&found_key) == BTRFS_ROOT_ITEM_KEY) {
 			unsigned long offset;
-			struct extent_buffer *buf;
 
 			offset = btrfs_item_ptr_offset(leaf, path.slots[0]);
 			read_extent_buffer(leaf, &ri, offset, sizeof(ri));
 			if (btrfs_disk_key_objectid(&ri.drop_progress) == 0) {
-				buf = read_tree_block(root->fs_info->tree_root,
-						      btrfs_root_bytenr(&ri),
-						      btrfs_level_size(root,
-						      btrfs_root_level(&ri)),
-						      0);
-				if (!buf) {
-					ret = -EIO;
+				level = btrfs_root_level(&ri);
+				level_size = btrfs_level_size(root, level);
+				ret = add_root_item_to_list(&normal_trees,
+						found_key.objectid,
+						btrfs_root_bytenr(&ri), level,
+						0, level_size, NULL);
+				if (ret < 0)
 					goto out;
-				}
-				add_root_to_pending(buf, &extent_cache,
-						    &pending, &seen, &nodes,
-						    &found_key);
-				free_extent_buffer(buf);
 			} else {
-				struct dropping_root_item_record *dri_rec;
-				dri_rec = malloc(sizeof(*dri_rec));
-				if (!dri_rec) {
-					perror("malloc");
-					exit(1);
-				}
-				memcpy(&dri_rec->ri, &ri, sizeof(ri));
-				memcpy(&dri_rec->found_key, &found_key,
-				       sizeof(found_key));
-				list_add_tail(&dri_rec->list, &dropping_trees);
+				level = btrfs_root_level(&ri);
+				level_size = btrfs_level_size(root, level);
+				objectid = found_key.objectid;
+				btrfs_disk_key_to_cpu(&found_key,
+						      &ri.drop_progress);
+				ret = add_root_item_to_list(&dropping_trees,
+						objectid,
+						btrfs_root_bytenr(&ri),
+						level, ri.drop_level,
+						level_size, &found_key);
+				if (ret < 0)
+					goto out;
 			}
 		}
 		path.slots[0]++;
 	}
 	btrfs_release_path(&path);
-	while (1) {
-		ret = run_next_block(trans, root, bits, bits_nr, &last,
-				     &pending, &seen, &reada, &nodes,
-				     &extent_cache, &chunk_cache, &dev_cache,
-				     &block_group_cache, &dev_extent_cache,
-				     NULL);
-		if (ret != 0)
-			break;
-	}
-
-	while (!list_empty(&dropping_trees)) {
-		struct dropping_root_item_record *rec;
-		struct extent_buffer *buf;
-		rec = list_entry(dropping_trees.next,
-				 struct dropping_root_item_record, list);
-		last = 0;
-		if (!bits) {
-			perror("realloc");
-			exit(1);
-		}
-		buf = read_tree_block(root->fs_info->tree_root,
-				      btrfs_root_bytenr(&rec->ri),
-				      btrfs_level_size(root,
-				      btrfs_root_level(&rec->ri)), 0);
-		if (!buf) {
-			ret = -EIO;
-			goto out;
-		}
-		add_root_to_pending(buf, &extent_cache, &pending,
-				    &seen, &nodes, &rec->found_key);
-		while (1) {
-			ret = run_next_block(trans, root, bits, bits_nr, &last,
-					     &pending, &seen, &reada,
-					     &nodes, &extent_cache,
-					     &chunk_cache, &dev_cache,
-					     &block_group_cache,
-					     &dev_extent_cache,
-					     &rec->ri);
-			if (ret != 0)
-				break;
-		}
-		free_extent_buffer(buf);
-		list_del(&rec->list);
-		free(rec);
-	}
-
+	ret = deal_root_from_list(&normal_trees, trans, root,
+				  bits, bits_nr, &pending, &seen,
+				  &reada, &nodes, &extent_cache,
+				  &chunk_cache, &dev_cache, &block_group_cache,
+				  &dev_extent_cache);
+	if (ret < 0)
+		goto out;
+	ret = deal_root_from_list(&dropping_trees, trans, root,
+				  bits, bits_nr, &pending, &seen,
+				  &reada, &nodes, &extent_cache,
+				  &chunk_cache, &dev_cache, &block_group_cache,
+				  &dev_extent_cache);
+	if (ret < 0)
+		goto out;
 	if (ret >= 0)
 		ret = check_extent_refs(trans, root, &extent_cache);
 	if (ret == -EAGAIN) {
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH resend 2/3] Btrfs-progs: fsck: add ability to rebuild extent tree with snapshots
  2014-11-26  2:58 [PATCH 0/3] Extent tree rebuilding with snapshots patches Wang Shilong
  2014-11-26  2:58 ` [PATCH resend 1/3] Btrfs-progs: fsck: deal with snapshot one by one when rebuilding extent tree Wang Shilong
@ 2014-11-26  2:58 ` Wang Shilong
  2014-11-26  2:58 ` [PATCH 3/3] Btrfs-progs, fsck: move root items repair after root rebuilding Wang Shilong
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Wang Shilong @ 2014-11-26  2:58 UTC (permalink / raw)
  To: linux-btrfs; +Cc: dsterba

From: Wang Shilong <wangsl.fnst@cn.fujitsu.com>

This patch makes us to rebuild a really corrupt extent tree with snapshots.
To implement this, we have to verify whether a block is FULL BACKREF.

This idea come from Josef Bacik:

1) We walk down the original tree, every eb we encounter has
btrfs_header_owner(eb) == root->objectid.  We add normal references
for this root (BTRFS_TREE_BLOCK_REF_KEY) for this root.  World peace
is achieved.

2) We walk down the snapshotted tree.  Say we didn't change anything
at all, it was just a clean snapshot and then boom.  So the
btrfs_header_owner(root->node) == root->objectid, so normal backref.
We walk down to the next level, where btrfs_header_owner(eb) !=
root->objectid, but the level above did, so we add normal refs for all
of these blocks.  We go down the next level, now our
btrfs_header_owner(parent) != root->objectid and
btrfs_header_owner(eb) != root->objectid.  This is where we need to
now go back and see if btrfs_header_owner(eb) currently has a ref on
eb.  If it does we are done, move on to the next block in this same
level, we don't have to go further down.

3) Harder case, we snapshotted and then changed things in the original
root.  Do the same thing as in step 2, but now we get down to
btrfs_header_owner(eb) != root->objectid && btrfs_header_owner(parent)
!= root->objectid.  We lookup the references we have for eb and notice
that btrfs_header_owner(eb) no longer refers to eb.  So now we must
set FULL_BACKREF on this extent reference and add a
SHARED_BLOCK_REF_KEY for this eb using the parent->start as the
offset.  And we need to keep walking down and doing the same thing
until we either hit level 0 or btrfs_header_owner(eb) has a ref on the
block.

Signed-off-by: Wang Shilong <wangsl.fnst@cn.fujitsu.com>
Signed-off-by: Wang Shilong <wangshilong1991@gmail.com>
---
 cmds-check.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 129 insertions(+), 3 deletions(-)

diff --git a/cmds-check.c b/cmds-check.c
index ff2795d..a102752 100644
--- a/cmds-check.c
+++ b/cmds-check.c
@@ -112,6 +112,7 @@ struct extent_record {
 	unsigned int owner_ref_checked:1;
 	unsigned int is_root:1;
 	unsigned int metadata:1;
+	unsigned int flag_block_full_backref:1;
 };
 
 struct inode_backref {
@@ -4608,6 +4609,127 @@ static int is_dropped_key(struct btrfs_key *key,
 	return 0;
 }
 
+static int calc_extent_flag(struct btrfs_root *root,
+			   struct cache_tree *extent_cache,
+			   struct extent_buffer *buf,
+			   struct root_item_record *ri,
+			   u64 *flags)
+{
+	int i;
+	int nritems = btrfs_header_nritems(buf);
+	struct btrfs_key key;
+	struct extent_record *rec;
+	struct cache_extent *cache;
+	struct data_backref *dback;
+	struct tree_backref *tback;
+	struct extent_buffer *new_buf;
+	u64 owner = 0;
+	u64 bytenr;
+	u64 offset;
+	u64 ptr;
+	int size;
+	int ret;
+	u8 level;
+
+	/*
+	 * Except file/reloc tree, we can not have
+	 * FULL BACKREF MODE
+	 */
+	if (ri->objectid < BTRFS_FIRST_FREE_OBJECTID)
+		goto normal;
+	/*
+	 * root node
+	 */
+	if (buf->start == ri->bytenr)
+		goto normal;
+	if (btrfs_is_leaf(buf)) {
+		/*
+		 * we are searching from original root, world
+		 * peace is achieved, we use normal backref.
+		 */
+		owner = btrfs_header_owner(buf);
+		if (owner == ri->objectid)
+			goto normal;
+		/*
+		 * we check every eb here, and if any of
+		 * eb dosen't have original root refers
+		 * to this eb, we set full backref flag for
+		 * this extent, otherwise normal backref.
+		 */
+		for (i = 0; i < nritems; i++) {
+			struct btrfs_file_extent_item *fi;
+			btrfs_item_key_to_cpu(buf, &key, i);
+
+			if (key.type != BTRFS_EXTENT_DATA_KEY)
+				continue;
+			fi = btrfs_item_ptr(buf, i,
+					    struct btrfs_file_extent_item);
+			if (btrfs_file_extent_type(buf, fi) ==
+			    BTRFS_FILE_EXTENT_INLINE)
+				continue;
+			if (btrfs_file_extent_disk_bytenr(buf, fi) == 0)
+				continue;
+			bytenr = btrfs_file_extent_disk_bytenr(buf, fi);
+			cache = lookup_cache_extent(extent_cache, bytenr, 1);
+			if (!cache)
+				goto full_backref;
+			offset = btrfs_file_extent_offset(buf, fi);
+			rec = container_of(cache, struct extent_record, cache);
+			dback = find_data_backref(rec, 0, ri->objectid, owner,
+					key.offset - offset, 1, bytenr, bytenr);
+			if (!dback)
+				goto full_backref;
+		}
+		goto full_backref;
+	} else {
+		level = btrfs_header_level(buf);
+		for (i = 0; i < nritems; i++) {
+			ptr = btrfs_node_blockptr(buf, i);
+			size = btrfs_level_size(root, level);
+			if (i == 0) {
+				new_buf = read_tree_block(root, ptr, size, 0);
+				if (!extent_buffer_uptodate(new_buf)) {
+					free_extent_buffer(new_buf);
+					ret = -EIO;
+					return ret;
+				}
+				/*
+				 * we are searching from origin root, world
+				 * peace is achieved, we use normal backref.
+				 */
+				owner = btrfs_header_owner(new_buf);
+				free_extent_buffer(new_buf);
+				if (owner == ri->objectid)
+					goto normal;
+			}
+			cache = lookup_cache_extent(extent_cache, ptr, size);
+			if (!cache)
+				goto full_backref;
+			rec = container_of(cache, struct extent_record, cache);
+			tback = find_tree_backref(rec, 0, owner);
+			if (!tback)
+				goto full_backref;
+		}
+
+	}
+normal:
+	*flags = 0;
+	cache = lookup_cache_extent(extent_cache, buf->start, 1);
+	/* we have added this extent before */
+	BUG_ON(!cache);
+	rec = container_of(cache, struct extent_record, cache);
+	rec->flag_block_full_backref = 0;
+	return 0;
+full_backref:
+	*flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF;
+	cache = lookup_cache_extent(extent_cache, buf->start, 1);
+	/* we have added this extent before */
+	BUG_ON(!cache);
+	rec = container_of(cache, struct extent_record, cache);
+	rec->flag_block_full_backref = 1;
+	return 0;
+}
+
 static int run_next_block(struct btrfs_trans_handle *trans,
 			  struct btrfs_root *root,
 			  struct block_info *bits,
@@ -4702,9 +4824,12 @@ static int run_next_block(struct btrfs_trans_handle *trans,
 				       btrfs_header_level(buf), 1, NULL,
 				       &flags);
 		if (ret < 0)
-			flags = 0;
+			goto out;
 	} else {
 		flags = 0;
+		ret = calc_extent_flag(root, extent_cache, buf, ri, &flags);
+		if (ret < 0)
+			goto out;
 	}
 
 	if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
@@ -5894,9 +6019,10 @@ static int fixup_extent_refs(struct btrfs_trans_handle *trans,
 					rec->start, rec->max_size,
 					rec->metadata, NULL, &flags);
 		if (ret < 0)
-			flags = 0;
+			return ret;
 	} else {
-		flags = 0;
+		if (rec->flag_block_full_backref)
+			flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF;
 	}
 
 	path = btrfs_alloc_path();
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/3] Btrfs-progs, fsck: move root items repair after root rebuilding
  2014-11-26  2:58 [PATCH 0/3] Extent tree rebuilding with snapshots patches Wang Shilong
  2014-11-26  2:58 ` [PATCH resend 1/3] Btrfs-progs: fsck: deal with snapshot one by one when rebuilding extent tree Wang Shilong
  2014-11-26  2:58 ` [PATCH resend 2/3] Btrfs-progs: fsck: add ability to rebuild extent tree with snapshots Wang Shilong
@ 2014-11-26  2:58 ` Wang Shilong
  2014-11-26  2:58 ` [PATCH 0/3] Extent tree rebuilding with snapshots patches Wang Shilong
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Wang Shilong @ 2014-11-26  2:58 UTC (permalink / raw)
  To: linux-btrfs; +Cc: dsterba

If some critical roots are corrupt, reapr_root_items() will fail,
this is detected by fsck_tests.sh's extent rebuilding tests.

Signed-off-by: Wang Shilong <wangshilong1991@gmail.com>
---
 cmds-check.c | 32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/cmds-check.c b/cmds-check.c
index a102752..ae9005e 100644
--- a/cmds-check.c
+++ b/cmds-check.c
@@ -7987,22 +7987,6 @@ int cmd_check(int argc, char **argv)
 
 	root = info->fs_root;
 
-	ret = repair_root_items(info);
-	if (ret < 0)
-		goto close_out;
-	if (repair) {
-		fprintf(stderr, "Fixed %d roots.\n", ret);
-		ret = 0;
-	} else if (ret > 0) {
-		fprintf(stderr,
-		       "Found %d roots with an outdated root item.\n",
-		       ret);
-		fprintf(stderr,
-			"Please run a filesystem check with the option --repair to fix them.\n");
-		ret = 1;
-		goto close_out;
-	}
-
 	/*
 	 * repair mode will force us to commit transaction which
 	 * will make us fail to load log tree when mounting.
@@ -8101,6 +8085,22 @@ int cmd_check(int argc, char **argv)
 	if (ret)
 		fprintf(stderr, "Errors found in extent allocation tree or chunk allocation\n");
 
+	ret = repair_root_items(info);
+	if (ret < 0)
+		goto close_out;
+	if (repair) {
+		fprintf(stderr, "Fixed %d roots.\n", ret);
+		ret = 0;
+	} else if (ret > 0) {
+		fprintf(stderr,
+		       "Found %d roots with an outdated root item.\n",
+		       ret);
+		fprintf(stderr,
+			"Please run a filesystem check with the option --repair to fix them.\n");
+		ret = 1;
+		goto close_out;
+	}
+
 	fprintf(stderr, "checking free space cache\n");
 	ret = check_space_cache(root);
 	if (ret)
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 0/3] Extent tree rebuilding with snapshots patches
  2014-11-26  2:58 [PATCH 0/3] Extent tree rebuilding with snapshots patches Wang Shilong
                   ` (2 preceding siblings ...)
  2014-11-26  2:58 ` [PATCH 3/3] Btrfs-progs, fsck: move root items repair after root rebuilding Wang Shilong
@ 2014-11-26  2:58 ` Wang Shilong
  2014-11-26  2:58 ` [PATCH resend 1/3] Btrfs-progs: fsck: deal with snapshot one by one when rebuilding extent tree Wang Shilong
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Wang Shilong @ 2014-11-26  2:58 UTC (permalink / raw)
  To: linux-btrfs; +Cc: dsterba

I did send these patches a long while ago, but due to some reasons,
they were not merged, these are important fixes for fsck, without
these patches, extent tree rebuilding did not work with snapshots.

Also, /tests/fsck-tests.sh's extent tree rebuild test could always
detect failure without these patches, unluckily, it need extra
enviroment setting, so i supposed it was always 'NOTRUN'!

last patch fix a regression for root rebuilding, root rebuilding
should be at first, because if root(extent root eg) corrupted,
root items also won't succeed.

patches are based on David's integration-20141125

Wang Shilong (3):
  Btrfs-progs: fsck: deal with snapshot one by one when rebuilding
    extent tree
  Btrfs-progs: fsck: add ability to rebuild extent tree with snapshots
  Btrfs-progs, fsck: move root items repair after root rebuilding

 cmds-check.c | 412 +++++++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 303 insertions(+), 109 deletions(-)

-- 
2.1.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH resend 1/3] Btrfs-progs: fsck: deal with snapshot one by one when rebuilding extent tree
  2014-11-26  2:58 [PATCH 0/3] Extent tree rebuilding with snapshots patches Wang Shilong
                   ` (3 preceding siblings ...)
  2014-11-26  2:58 ` [PATCH 0/3] Extent tree rebuilding with snapshots patches Wang Shilong
@ 2014-11-26  2:58 ` Wang Shilong
  2014-11-26  2:58 ` [PATCH resend 2/3] Btrfs-progs: fsck: add ability to rebuild extent tree with snapshots Wang Shilong
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Wang Shilong @ 2014-11-26  2:58 UTC (permalink / raw)
  To: linux-btrfs; +Cc: dsterba

From: Wang Shilong <wangsl.fnst@cn.fujitsu.com>

Previously, we deal with node block firstly and then leaf block which can
maximize readahead. However, to rebuild extent tree, we need deal with snapshot
one by one.

This patch makes us deal with snapshot one by one if we need rebuild extent
tree otherwise we drop into previous way.

Signed-off-by: Wang Shilong <wangsl.fnst@cn.fujitsu.com>
Signed-off-by: Wang Shilong <wangshilong1991@gmail.com>
---
 cmds-check.c | 248 +++++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 158 insertions(+), 90 deletions(-)

diff --git a/cmds-check.c b/cmds-check.c
index 24b6b59..ff2795d 100644
--- a/cmds-check.c
+++ b/cmds-check.c
@@ -128,10 +128,14 @@ struct inode_backref {
 	char name[0];
 };
 
-struct dropping_root_item_record {
+struct root_item_record {
 	struct list_head list;
-	struct btrfs_root_item ri;
-	struct btrfs_key found_key;
+	u64 objectid;
+	u64 bytenr;
+	u8 level;
+	u8 drop_level;
+	int level_size;
+	struct btrfs_key drop_key;
 };
 
 #define REF_ERR_NO_DIR_ITEM		(1 << 0)
@@ -4618,7 +4622,7 @@ static int run_next_block(struct btrfs_trans_handle *trans,
 			  struct rb_root *dev_cache,
 			  struct block_group_tree *block_group_cache,
 			  struct device_extent_tree *dev_extent_cache,
-			  struct btrfs_root_item *ri)
+			  struct root_item_record *ri)
 {
 	struct extent_buffer *buf;
 	u64 bytenr;
@@ -4851,11 +4855,8 @@ static int run_next_block(struct btrfs_trans_handle *trans,
 			size = btrfs_level_size(root, level - 1);
 			btrfs_node_key_to_cpu(buf, &key, i);
 			if (ri != NULL) {
-				struct btrfs_key drop_key;
-				btrfs_disk_key_to_cpu(&drop_key,
-						      &ri->drop_progress);
 				if ((level == ri->drop_level)
-				    && is_dropped_key(&key, &drop_key)) {
+				    && is_dropped_key(&key, &ri->drop_key)) {
 					continue;
 				}
 			}
@@ -4896,7 +4897,7 @@ static int add_root_to_pending(struct extent_buffer *buf,
 			       struct cache_tree *pending,
 			       struct cache_tree *seen,
 			       struct cache_tree *nodes,
-			       struct btrfs_key *root_key)
+			       u64 objectid)
 {
 	if (btrfs_header_level(buf) > 0)
 		add_pending(nodes, seen, buf->start, buf->len);
@@ -4905,13 +4906,12 @@ static int add_root_to_pending(struct extent_buffer *buf,
 	add_extent_rec(extent_cache, NULL, 0, buf->start, buf->len,
 		       0, 1, 1, 0, 1, 0, buf->len);
 
-	if (root_key->objectid == BTRFS_TREE_RELOC_OBJECTID ||
+	if (objectid == BTRFS_TREE_RELOC_OBJECTID ||
 	    btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV)
 		add_tree_backref(extent_cache, buf->start, buf->start,
 				 0, 1);
 	else
-		add_tree_backref(extent_cache, buf->start, 0,
-				 root_key->objectid, 1);
+		add_tree_backref(extent_cache, buf->start, 0, objectid, 1);
 	return 0;
 }
 
@@ -6481,6 +6481,99 @@ static int check_devices(struct rb_root *dev_cache,
 	return ret;
 }
 
+static int add_root_item_to_list(struct list_head *head,
+				  u64 objectid, u64 bytenr,
+				  u8 level, u8 drop_level,
+				  int level_size, struct btrfs_key *drop_key)
+{
+
+	struct root_item_record *ri_rec;
+	ri_rec = malloc(sizeof(*ri_rec));
+	if (!ri_rec)
+		return -ENOMEM;
+	ri_rec->bytenr = bytenr;
+	ri_rec->objectid = objectid;
+	ri_rec->level = level;
+	ri_rec->level_size = level_size;
+	ri_rec->drop_level = drop_level;
+	if (drop_key)
+		memcpy(&ri_rec->drop_key, drop_key, sizeof(*drop_key));
+	list_add_tail(&ri_rec->list, head);
+
+	return 0;
+}
+
+static int deal_root_from_list(struct list_head *list,
+			       struct btrfs_trans_handle *trans,
+			       struct btrfs_root *root,
+			       struct block_info *bits,
+			       int bits_nr,
+			       struct cache_tree *pending,
+			       struct cache_tree *seen,
+			       struct cache_tree *reada,
+			       struct cache_tree *nodes,
+			       struct cache_tree *extent_cache,
+			       struct cache_tree *chunk_cache,
+			       struct rb_root *dev_cache,
+			       struct block_group_tree *block_group_cache,
+			       struct device_extent_tree *dev_extent_cache)
+{
+	int ret = 0;
+	u64 last;
+
+	while (!list_empty(list)) {
+		struct root_item_record *rec;
+		struct extent_buffer *buf;
+		rec = list_entry(list->next,
+				 struct root_item_record, list);
+		last = 0;
+		buf = read_tree_block(root->fs_info->tree_root,
+				      rec->bytenr, rec->level_size, 0);
+		if (!extent_buffer_uptodate(buf)) {
+			free_extent_buffer(buf);
+			ret = -EIO;
+			break;
+		}
+		add_root_to_pending(buf, extent_cache, pending,
+				    seen, nodes, rec->objectid);
+		/*
+		 * To rebuild extent tree, we need deal with snapshot
+		 * one by one, otherwise we deal with node firstly which
+		 * can maximize readahead.
+		 */
+		if (!init_extent_tree && !rec->drop_level)
+			goto skip;
+		while (1) {
+			ret = run_next_block(trans, root, bits, bits_nr, &last,
+					     pending, seen, reada,
+					     nodes, extent_cache,
+					     chunk_cache, dev_cache,
+					     block_group_cache,
+					     dev_extent_cache, rec);
+			if (ret != 0)
+				break;
+		}
+skip:
+		free_extent_buffer(buf);
+		list_del(&rec->list);
+		free(rec);
+	}
+	while (ret >= 0) {
+		ret = run_next_block(trans, root, bits, bits_nr, &last,
+				     pending, seen, reada,
+				     nodes, extent_cache,
+				     chunk_cache, dev_cache,
+				     block_group_cache,
+				     dev_extent_cache, NULL);
+		if (ret != 0) {
+			if (ret > 0)
+				ret = 0;
+			break;
+		}
+	}
+	return ret;
+}
+
 static int check_chunks_and_extents(struct btrfs_root *root)
 {
 	struct rb_root dev_cache;
@@ -6497,7 +6590,6 @@ static int check_chunks_and_extents(struct btrfs_root *root)
 	struct btrfs_key key;
 	struct btrfs_key found_key;
 	int ret, err = 0;
-	u64 last = 0;
 	struct block_info *bits;
 	int bits_nr;
 	struct extent_buffer *leaf;
@@ -6505,6 +6597,11 @@ static int check_chunks_and_extents(struct btrfs_root *root)
 	int slot;
 	struct btrfs_root_item ri;
 	struct list_head dropping_trees;
+	struct list_head normal_trees;
+	struct btrfs_root *root1;
+	u64 objectid;
+	u32 level_size;
+	u8 level;
 
 	dev_cache = RB_ROOT;
 	cache_tree_init(&chunk_cache);
@@ -6518,6 +6615,7 @@ static int check_chunks_and_extents(struct btrfs_root *root)
 	cache_tree_init(&reada);
 	cache_tree_init(&corrupt_blocks);
 	INIT_LIST_HEAD(&dropping_trees);
+	INIT_LIST_HEAD(&normal_trees);
 
 	if (repair) {
 		trans = btrfs_start_transaction(root, 1);
@@ -6538,14 +6636,20 @@ static int check_chunks_and_extents(struct btrfs_root *root)
 	}
 
 again:
-	add_root_to_pending(root->fs_info->tree_root->node,
-			    &extent_cache, &pending, &seen, &nodes,
-			    &root->fs_info->tree_root->root_key);
-
-	add_root_to_pending(root->fs_info->chunk_root->node,
-			    &extent_cache, &pending, &seen, &nodes,
-			    &root->fs_info->chunk_root->root_key);
-
+	root1 = root->fs_info->tree_root;
+	level = btrfs_header_level(root1->node);
+	ret = add_root_item_to_list(&normal_trees, root1->root_key.objectid,
+				    root1->node->start, level, 0,
+				    btrfs_level_size(root1, level), NULL);
+	if (ret < 0)
+		goto out;
+	root1 = root->fs_info->chunk_root;
+	level = btrfs_header_level(root1->node);
+	ret = add_root_item_to_list(&normal_trees, root1->root_key.objectid,
+				    root1->node->start, level, 0,
+				    btrfs_level_size(root1, level), NULL);
+	if (ret < 0)
+		goto out;
 	btrfs_init_path(&path);
 	key.offset = 0;
 	key.objectid = 0;
@@ -6567,86 +6671,50 @@ again:
 		btrfs_item_key_to_cpu(leaf, &found_key, path.slots[0]);
 		if (btrfs_key_type(&found_key) == BTRFS_ROOT_ITEM_KEY) {
 			unsigned long offset;
-			struct extent_buffer *buf;
 
 			offset = btrfs_item_ptr_offset(leaf, path.slots[0]);
 			read_extent_buffer(leaf, &ri, offset, sizeof(ri));
 			if (btrfs_disk_key_objectid(&ri.drop_progress) == 0) {
-				buf = read_tree_block(root->fs_info->tree_root,
-						      btrfs_root_bytenr(&ri),
-						      btrfs_level_size(root,
-						      btrfs_root_level(&ri)),
-						      0);
-				if (!buf) {
-					ret = -EIO;
+				level = btrfs_root_level(&ri);
+				level_size = btrfs_level_size(root, level);
+				ret = add_root_item_to_list(&normal_trees,
+						found_key.objectid,
+						btrfs_root_bytenr(&ri), level,
+						0, level_size, NULL);
+				if (ret < 0)
 					goto out;
-				}
-				add_root_to_pending(buf, &extent_cache,
-						    &pending, &seen, &nodes,
-						    &found_key);
-				free_extent_buffer(buf);
 			} else {
-				struct dropping_root_item_record *dri_rec;
-				dri_rec = malloc(sizeof(*dri_rec));
-				if (!dri_rec) {
-					perror("malloc");
-					exit(1);
-				}
-				memcpy(&dri_rec->ri, &ri, sizeof(ri));
-				memcpy(&dri_rec->found_key, &found_key,
-				       sizeof(found_key));
-				list_add_tail(&dri_rec->list, &dropping_trees);
+				level = btrfs_root_level(&ri);
+				level_size = btrfs_level_size(root, level);
+				objectid = found_key.objectid;
+				btrfs_disk_key_to_cpu(&found_key,
+						      &ri.drop_progress);
+				ret = add_root_item_to_list(&dropping_trees,
+						objectid,
+						btrfs_root_bytenr(&ri),
+						level, ri.drop_level,
+						level_size, &found_key);
+				if (ret < 0)
+					goto out;
 			}
 		}
 		path.slots[0]++;
 	}
 	btrfs_release_path(&path);
-	while (1) {
-		ret = run_next_block(trans, root, bits, bits_nr, &last,
-				     &pending, &seen, &reada, &nodes,
-				     &extent_cache, &chunk_cache, &dev_cache,
-				     &block_group_cache, &dev_extent_cache,
-				     NULL);
-		if (ret != 0)
-			break;
-	}
-
-	while (!list_empty(&dropping_trees)) {
-		struct dropping_root_item_record *rec;
-		struct extent_buffer *buf;
-		rec = list_entry(dropping_trees.next,
-				 struct dropping_root_item_record, list);
-		last = 0;
-		if (!bits) {
-			perror("realloc");
-			exit(1);
-		}
-		buf = read_tree_block(root->fs_info->tree_root,
-				      btrfs_root_bytenr(&rec->ri),
-				      btrfs_level_size(root,
-				      btrfs_root_level(&rec->ri)), 0);
-		if (!buf) {
-			ret = -EIO;
-			goto out;
-		}
-		add_root_to_pending(buf, &extent_cache, &pending,
-				    &seen, &nodes, &rec->found_key);
-		while (1) {
-			ret = run_next_block(trans, root, bits, bits_nr, &last,
-					     &pending, &seen, &reada,
-					     &nodes, &extent_cache,
-					     &chunk_cache, &dev_cache,
-					     &block_group_cache,
-					     &dev_extent_cache,
-					     &rec->ri);
-			if (ret != 0)
-				break;
-		}
-		free_extent_buffer(buf);
-		list_del(&rec->list);
-		free(rec);
-	}
-
+	ret = deal_root_from_list(&normal_trees, trans, root,
+				  bits, bits_nr, &pending, &seen,
+				  &reada, &nodes, &extent_cache,
+				  &chunk_cache, &dev_cache, &block_group_cache,
+				  &dev_extent_cache);
+	if (ret < 0)
+		goto out;
+	ret = deal_root_from_list(&dropping_trees, trans, root,
+				  bits, bits_nr, &pending, &seen,
+				  &reada, &nodes, &extent_cache,
+				  &chunk_cache, &dev_cache, &block_group_cache,
+				  &dev_extent_cache);
+	if (ret < 0)
+		goto out;
 	if (ret >= 0)
 		ret = check_extent_refs(trans, root, &extent_cache);
 	if (ret == -EAGAIN) {
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH resend 2/3] Btrfs-progs: fsck: add ability to rebuild extent tree with snapshots
  2014-11-26  2:58 [PATCH 0/3] Extent tree rebuilding with snapshots patches Wang Shilong
                   ` (4 preceding siblings ...)
  2014-11-26  2:58 ` [PATCH resend 1/3] Btrfs-progs: fsck: deal with snapshot one by one when rebuilding extent tree Wang Shilong
@ 2014-11-26  2:58 ` Wang Shilong
  2014-11-26  2:58 ` [PATCH 3/3] Btrfs-progs, fsck: move root items repair after root rebuilding Wang Shilong
  2014-12-04 15:55 ` [PATCH 0/3] Extent tree rebuilding with snapshots patches David Sterba
  7 siblings, 0 replies; 10+ messages in thread
From: Wang Shilong @ 2014-11-26  2:58 UTC (permalink / raw)
  To: linux-btrfs; +Cc: dsterba

From: Wang Shilong <wangsl.fnst@cn.fujitsu.com>

This patch makes us to rebuild a really corrupt extent tree with snapshots.
To implement this, we have to verify whether a block is FULL BACKREF.

This idea come from Josef Bacik:

1) We walk down the original tree, every eb we encounter has
btrfs_header_owner(eb) == root->objectid.  We add normal references
for this root (BTRFS_TREE_BLOCK_REF_KEY) for this root.  World peace
is achieved.

2) We walk down the snapshotted tree.  Say we didn't change anything
at all, it was just a clean snapshot and then boom.  So the
btrfs_header_owner(root->node) == root->objectid, so normal backref.
We walk down to the next level, where btrfs_header_owner(eb) !=
root->objectid, but the level above did, so we add normal refs for all
of these blocks.  We go down the next level, now our
btrfs_header_owner(parent) != root->objectid and
btrfs_header_owner(eb) != root->objectid.  This is where we need to
now go back and see if btrfs_header_owner(eb) currently has a ref on
eb.  If it does we are done, move on to the next block in this same
level, we don't have to go further down.

3) Harder case, we snapshotted and then changed things in the original
root.  Do the same thing as in step 2, but now we get down to
btrfs_header_owner(eb) != root->objectid && btrfs_header_owner(parent)
!= root->objectid.  We lookup the references we have for eb and notice
that btrfs_header_owner(eb) no longer refers to eb.  So now we must
set FULL_BACKREF on this extent reference and add a
SHARED_BLOCK_REF_KEY for this eb using the parent->start as the
offset.  And we need to keep walking down and doing the same thing
until we either hit level 0 or btrfs_header_owner(eb) has a ref on the
block.

Signed-off-by: Wang Shilong <wangsl.fnst@cn.fujitsu.com>
Signed-off-by: Wang Shilong <wangshilong1991@gmail.com>
---
 cmds-check.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 129 insertions(+), 3 deletions(-)

diff --git a/cmds-check.c b/cmds-check.c
index ff2795d..a102752 100644
--- a/cmds-check.c
+++ b/cmds-check.c
@@ -112,6 +112,7 @@ struct extent_record {
 	unsigned int owner_ref_checked:1;
 	unsigned int is_root:1;
 	unsigned int metadata:1;
+	unsigned int flag_block_full_backref:1;
 };
 
 struct inode_backref {
@@ -4608,6 +4609,127 @@ static int is_dropped_key(struct btrfs_key *key,
 	return 0;
 }
 
+static int calc_extent_flag(struct btrfs_root *root,
+			   struct cache_tree *extent_cache,
+			   struct extent_buffer *buf,
+			   struct root_item_record *ri,
+			   u64 *flags)
+{
+	int i;
+	int nritems = btrfs_header_nritems(buf);
+	struct btrfs_key key;
+	struct extent_record *rec;
+	struct cache_extent *cache;
+	struct data_backref *dback;
+	struct tree_backref *tback;
+	struct extent_buffer *new_buf;
+	u64 owner = 0;
+	u64 bytenr;
+	u64 offset;
+	u64 ptr;
+	int size;
+	int ret;
+	u8 level;
+
+	/*
+	 * Except file/reloc tree, we can not have
+	 * FULL BACKREF MODE
+	 */
+	if (ri->objectid < BTRFS_FIRST_FREE_OBJECTID)
+		goto normal;
+	/*
+	 * root node
+	 */
+	if (buf->start == ri->bytenr)
+		goto normal;
+	if (btrfs_is_leaf(buf)) {
+		/*
+		 * we are searching from original root, world
+		 * peace is achieved, we use normal backref.
+		 */
+		owner = btrfs_header_owner(buf);
+		if (owner == ri->objectid)
+			goto normal;
+		/*
+		 * we check every eb here, and if any of
+		 * eb dosen't have original root refers
+		 * to this eb, we set full backref flag for
+		 * this extent, otherwise normal backref.
+		 */
+		for (i = 0; i < nritems; i++) {
+			struct btrfs_file_extent_item *fi;
+			btrfs_item_key_to_cpu(buf, &key, i);
+
+			if (key.type != BTRFS_EXTENT_DATA_KEY)
+				continue;
+			fi = btrfs_item_ptr(buf, i,
+					    struct btrfs_file_extent_item);
+			if (btrfs_file_extent_type(buf, fi) ==
+			    BTRFS_FILE_EXTENT_INLINE)
+				continue;
+			if (btrfs_file_extent_disk_bytenr(buf, fi) == 0)
+				continue;
+			bytenr = btrfs_file_extent_disk_bytenr(buf, fi);
+			cache = lookup_cache_extent(extent_cache, bytenr, 1);
+			if (!cache)
+				goto full_backref;
+			offset = btrfs_file_extent_offset(buf, fi);
+			rec = container_of(cache, struct extent_record, cache);
+			dback = find_data_backref(rec, 0, ri->objectid, owner,
+					key.offset - offset, 1, bytenr, bytenr);
+			if (!dback)
+				goto full_backref;
+		}
+		goto full_backref;
+	} else {
+		level = btrfs_header_level(buf);
+		for (i = 0; i < nritems; i++) {
+			ptr = btrfs_node_blockptr(buf, i);
+			size = btrfs_level_size(root, level);
+			if (i == 0) {
+				new_buf = read_tree_block(root, ptr, size, 0);
+				if (!extent_buffer_uptodate(new_buf)) {
+					free_extent_buffer(new_buf);
+					ret = -EIO;
+					return ret;
+				}
+				/*
+				 * we are searching from origin root, world
+				 * peace is achieved, we use normal backref.
+				 */
+				owner = btrfs_header_owner(new_buf);
+				free_extent_buffer(new_buf);
+				if (owner == ri->objectid)
+					goto normal;
+			}
+			cache = lookup_cache_extent(extent_cache, ptr, size);
+			if (!cache)
+				goto full_backref;
+			rec = container_of(cache, struct extent_record, cache);
+			tback = find_tree_backref(rec, 0, owner);
+			if (!tback)
+				goto full_backref;
+		}
+
+	}
+normal:
+	*flags = 0;
+	cache = lookup_cache_extent(extent_cache, buf->start, 1);
+	/* we have added this extent before */
+	BUG_ON(!cache);
+	rec = container_of(cache, struct extent_record, cache);
+	rec->flag_block_full_backref = 0;
+	return 0;
+full_backref:
+	*flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF;
+	cache = lookup_cache_extent(extent_cache, buf->start, 1);
+	/* we have added this extent before */
+	BUG_ON(!cache);
+	rec = container_of(cache, struct extent_record, cache);
+	rec->flag_block_full_backref = 1;
+	return 0;
+}
+
 static int run_next_block(struct btrfs_trans_handle *trans,
 			  struct btrfs_root *root,
 			  struct block_info *bits,
@@ -4702,9 +4824,12 @@ static int run_next_block(struct btrfs_trans_handle *trans,
 				       btrfs_header_level(buf), 1, NULL,
 				       &flags);
 		if (ret < 0)
-			flags = 0;
+			goto out;
 	} else {
 		flags = 0;
+		ret = calc_extent_flag(root, extent_cache, buf, ri, &flags);
+		if (ret < 0)
+			goto out;
 	}
 
 	if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
@@ -5894,9 +6019,10 @@ static int fixup_extent_refs(struct btrfs_trans_handle *trans,
 					rec->start, rec->max_size,
 					rec->metadata, NULL, &flags);
 		if (ret < 0)
-			flags = 0;
+			return ret;
 	} else {
-		flags = 0;
+		if (rec->flag_block_full_backref)
+			flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF;
 	}
 
 	path = btrfs_alloc_path();
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/3] Btrfs-progs, fsck: move root items repair after root rebuilding
  2014-11-26  2:58 [PATCH 0/3] Extent tree rebuilding with snapshots patches Wang Shilong
                   ` (5 preceding siblings ...)
  2014-11-26  2:58 ` [PATCH resend 2/3] Btrfs-progs: fsck: add ability to rebuild extent tree with snapshots Wang Shilong
@ 2014-11-26  2:58 ` Wang Shilong
  2014-11-26  3:06   ` Wang Shilong
  2014-12-04 15:55 ` [PATCH 0/3] Extent tree rebuilding with snapshots patches David Sterba
  7 siblings, 1 reply; 10+ messages in thread
From: Wang Shilong @ 2014-11-26  2:58 UTC (permalink / raw)
  To: linux-btrfs; +Cc: dsterba

If some critical roots are corrupt, reapr_root_items() will fail,
this is detected by fsck_tests.sh's extent rebuilding tests.

Signed-off-by: Wang Shilong <wangshilong1991@gmail.com>
---
 cmds-check.c | 32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/cmds-check.c b/cmds-check.c
index a102752..ae9005e 100644
--- a/cmds-check.c
+++ b/cmds-check.c
@@ -7987,22 +7987,6 @@ int cmd_check(int argc, char **argv)
 
 	root = info->fs_root;
 
-	ret = repair_root_items(info);
-	if (ret < 0)
-		goto close_out;
-	if (repair) {
-		fprintf(stderr, "Fixed %d roots.\n", ret);
-		ret = 0;
-	} else if (ret > 0) {
-		fprintf(stderr,
-		       "Found %d roots with an outdated root item.\n",
-		       ret);
-		fprintf(stderr,
-			"Please run a filesystem check with the option --repair to fix them.\n");
-		ret = 1;
-		goto close_out;
-	}
-
 	/*
 	 * repair mode will force us to commit transaction which
 	 * will make us fail to load log tree when mounting.
@@ -8101,6 +8085,22 @@ int cmd_check(int argc, char **argv)
 	if (ret)
 		fprintf(stderr, "Errors found in extent allocation tree or chunk allocation\n");
 
+	ret = repair_root_items(info);
+	if (ret < 0)
+		goto close_out;
+	if (repair) {
+		fprintf(stderr, "Fixed %d roots.\n", ret);
+		ret = 0;
+	} else if (ret > 0) {
+		fprintf(stderr,
+		       "Found %d roots with an outdated root item.\n",
+		       ret);
+		fprintf(stderr,
+			"Please run a filesystem check with the option --repair to fix them.\n");
+		ret = 1;
+		goto close_out;
+	}
+
 	fprintf(stderr, "checking free space cache\n");
 	ret = check_space_cache(root);
 	if (ret)
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/3] Btrfs-progs, fsck: move root items repair after root rebuilding
  2014-11-26  2:58 ` [PATCH 3/3] Btrfs-progs, fsck: move root items repair after root rebuilding Wang Shilong
@ 2014-11-26  3:06   ` Wang Shilong
  0 siblings, 0 replies; 10+ messages in thread
From: Wang Shilong @ 2014-11-26  3:06 UTC (permalink / raw)
  To: linux-btrfs; +Cc: dsterba

Oops, sorry for sending this twice, just entered one more *.patch…


> 
> I did send these patches a long while ago, but due to some reasons,
> they were not merged, these are important fixes for fsck, without
> these patches, extent tree rebuilding did not work with snapshots.
> 
> Also, /tests/fsck-tests.sh's extent tree rebuild test could always
> detect failure without these patches, unluckily, it need extra
> enviroment setting, so i supposed it was always 'NOTRUN'!
> 
> last patch fix a regression for root rebuilding, root rebuilding
> should be at first, because if root(extent root eg) corrupted,
> root items also won't succeed.
> 
> patches are based on David's integration-20141125
> 
> Wang Shilong (3):
>  Btrfs-progs: fsck: deal with snapshot one by one when rebuilding
>    extent tree
>  Btrfs-progs: fsck: add ability to rebuild extent tree with snapshots
>  Btrfs-progs, fsck: move root items repair after root rebuilding
> 
> cmds-check.c | 412 +++++++++++++++++++++++++++++++++++++++++++----------------
> 1 file changed, 303 insertions(+), 109 deletions(-)
> 
> -- 
> 2.1.0
> 

Best Regards,
Wang Shilong


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 0/3] Extent tree rebuilding with snapshots patches
  2014-11-26  2:58 [PATCH 0/3] Extent tree rebuilding with snapshots patches Wang Shilong
                   ` (6 preceding siblings ...)
  2014-11-26  2:58 ` [PATCH 3/3] Btrfs-progs, fsck: move root items repair after root rebuilding Wang Shilong
@ 2014-12-04 15:55 ` David Sterba
  7 siblings, 0 replies; 10+ messages in thread
From: David Sterba @ 2014-12-04 15:55 UTC (permalink / raw)
  To: Wang Shilong; +Cc: linux-btrfs, dsterba

On Wed, Nov 26, 2014 at 10:58:49AM +0800, Wang Shilong wrote:
> I did send these patches a long while ago, but due to some reasons,
> they were not merged, these are important fixes for fsck, without
> these patches, extent tree rebuilding did not work with snapshots.

I have the patches in my local git, but fsck fixes need special care
(reviews or tests), so this was holding them back. I'll queue them for
3.18.

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2014-12-04 15:55 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-11-26  2:58 [PATCH 0/3] Extent tree rebuilding with snapshots patches Wang Shilong
2014-11-26  2:58 ` [PATCH resend 1/3] Btrfs-progs: fsck: deal with snapshot one by one when rebuilding extent tree Wang Shilong
2014-11-26  2:58 ` [PATCH resend 2/3] Btrfs-progs: fsck: add ability to rebuild extent tree with snapshots Wang Shilong
2014-11-26  2:58 ` [PATCH 3/3] Btrfs-progs, fsck: move root items repair after root rebuilding Wang Shilong
2014-11-26  2:58 ` [PATCH 0/3] Extent tree rebuilding with snapshots patches Wang Shilong
2014-11-26  2:58 ` [PATCH resend 1/3] Btrfs-progs: fsck: deal with snapshot one by one when rebuilding extent tree Wang Shilong
2014-11-26  2:58 ` [PATCH resend 2/3] Btrfs-progs: fsck: add ability to rebuild extent tree with snapshots Wang Shilong
2014-11-26  2:58 ` [PATCH 3/3] Btrfs-progs, fsck: move root items repair after root rebuilding Wang Shilong
2014-11-26  3:06   ` Wang Shilong
2014-12-04 15:55 ` [PATCH 0/3] Extent tree rebuilding with snapshots patches David Sterba

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).