summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2012-02-23 15:52:58 +0800
committerChris Mason <chris.mason@fusionio.com>2012-07-03 16:27:46 -0400
commitcfdd42686c7534cd54270aa382f8a28c61bf2c70 (patch)
tree4c8fe1ef8a4d72c5fcbcf1463b19e17b7b7d35d8
parent1ee733a9ca10f5dc4c7954efcc18f9033abbe218 (diff)
Btrfs-progs: fix btrfsck's snapshot wrong "unresolved refs"
If the fs/file tree is not the parent of the snapshot, it is reasonable that we can not find the relative reference and back reference. But btrfsck doesn't consider this case, and reports "unresolved refs" message, it's wrong, fix it. Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
-rw-r--r--btrfsck.c72
1 files changed, 67 insertions, 5 deletions
diff --git a/btrfsck.c b/btrfsck.c
index 572dde0f..088b9f42 100644
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -750,7 +750,65 @@ static int leave_shared_node(struct btrfs_root *root,
return 0;
}
-static int process_dir_item(struct extent_buffer *eb,
+static int is_child_root(struct btrfs_root *root, u64 parent_root_id,
+ u64 child_root_id)
+{
+ struct btrfs_path path;
+ struct btrfs_key key;
+ struct extent_buffer *leaf;
+ int has_parent = 0;
+ int ret;
+
+ btrfs_init_path(&path);
+
+ key.objectid = parent_root_id;
+ key.type = BTRFS_ROOT_REF_KEY;
+ key.offset = child_root_id;
+ ret = btrfs_search_slot(NULL, root->fs_info->tree_root, &key, &path,
+ 0, 0);
+ BUG_ON(ret < 0);
+ btrfs_release_path(root, &path);
+ if (!ret)
+ return 1;
+
+ key.objectid = child_root_id;
+ key.type = BTRFS_ROOT_BACKREF_KEY;
+ key.offset = 0;
+ ret = btrfs_search_slot(NULL, root->fs_info->tree_root, &key, &path,
+ 0, 0);
+ BUG_ON(ret <= 0);
+
+ while (1) {
+ leaf = path.nodes[0];
+ if (path.slots[0] >= btrfs_header_nritems(leaf)) {
+ ret = btrfs_next_leaf(root->fs_info->tree_root, &path);
+ BUG_ON(ret < 0);
+
+ if (ret > 0)
+ break;
+ }
+
+ btrfs_item_key_to_cpu(leaf, &key, path.slots[0]);
+ if (key.objectid != child_root_id ||
+ key.type != BTRFS_ROOT_BACKREF_KEY)
+ break;
+
+ has_parent = 1;
+
+ if (key.offset == parent_root_id) {
+ btrfs_release_path(root, &path);
+ return 1;
+ }
+
+ path.slots[0]++;
+ }
+
+ btrfs_release_path(root, &path);
+ return has_parent? 0 : -1;
+}
+
+static int process_dir_item(struct btrfs_root *root,
+ struct extent_buffer *eb,
int slot, struct btrfs_key *key,
struct shared_node *active_node)
{
@@ -798,9 +856,13 @@ static int process_dir_item(struct extent_buffer *eb,
key->objectid, key->offset, namebuf,
len, filetype, key->type, error);
} else if (location.type == BTRFS_ROOT_ITEM_KEY) {
- add_inode_backref(root_cache, location.objectid,
- key->objectid, key->offset, namebuf,
- len, filetype, key->type, error);
+ u64 parent = root->objectid;
+
+ if (is_child_root(root, parent, location.objectid))
+ add_inode_backref(root_cache, location.objectid,
+ key->objectid, key->offset,
+ namebuf, len, filetype,
+ key->type, error);
} else {
fprintf(stderr, "warning line %d\n", __LINE__);
}
@@ -1035,7 +1097,7 @@ static int process_one_leaf(struct btrfs_root *root, struct extent_buffer *eb,
switch (key.type) {
case BTRFS_DIR_ITEM_KEY:
case BTRFS_DIR_INDEX_KEY:
- ret = process_dir_item(eb, i, &key, active_node);
+ ret = process_dir_item(root, eb, i, &key, active_node);
break;
case BTRFS_INODE_REF_KEY:
ret = process_inode_ref(eb, i, &key, active_node);