summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Fasheh <mfasheh@suse.com>2012-06-07 16:00:55 -0700
committerDavid Sterba <dsterba@suse.cz>2013-01-31 22:33:23 +0100
commit86279e7ef2f86dd630fcafc1135a4561e5a10f36 (patch)
treeee63c27ee4c245babb563b6fd27a023bd9dae3da
parent905b078928fbbc6377edb1aabb9b9f3c8e0d8a9f (diff)
btrfs-progs: add extended inode ref support to btrfsck
Add a function, process_inode_extref() to be called from process_one_leaf() when an item type of BTRFS_INODE_EXTREF_KEY is encountered. Similarly to process_inode_ref(), process_inode_extref() walks an extref and adds an inode_backref structure for each reference found within. I modified fsck's inode_backref to get a type field (ref_type) which helps us internally track the exact type of backrefs found. Of course this field could be overwritten in case of disk corruption (duplicate refs) but duplicate refs themselves are tracked by btrfsck so that should not be an issue as btrfsck is written today. Signed-off-by: Mark Fasheh <mfasheh@suse.de>
-rw-r--r--btrfsck.c53
1 files changed, 51 insertions, 2 deletions
diff --git a/btrfsck.c b/btrfsck.c
index 6274ff76..58baade4 100644
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -98,6 +98,7 @@ struct inode_backref {
unsigned int found_inode_ref:1;
unsigned int filetype:8;
int errors;
+ unsigned int ref_type;
u64 dir;
u64 index;
u16 namelen;
@@ -471,12 +472,14 @@ static int add_inode_backref(struct cache_tree *inode_cache,
backref->filetype = filetype;
backref->found_dir_item = 1;
- } else if (itemtype == BTRFS_INODE_REF_KEY) {
+ } else if ((itemtype == BTRFS_INODE_REF_KEY) ||
+ (itemtype == BTRFS_INODE_EXTREF_KEY)) {
if (backref->found_inode_ref)
backref->errors |= REF_ERR_DUP_INODE_REF;
if (backref->found_dir_index && backref->index != index)
backref->errors |= REF_ERR_INDEX_UNMATCH;
+ backref->ref_type = itemtype;
backref->index = index;
backref->found_inode_ref = 1;
} else {
@@ -512,7 +515,7 @@ static int merge_inode_recs(struct inode_record *src, struct inode_record *dst,
add_inode_backref(dst_cache, dst->ino,
backref->dir, backref->index,
backref->name, backref->namelen, 0,
- BTRFS_INODE_REF_KEY, backref->errors);
+ backref->ref_type, backref->errors);
}
}
@@ -916,6 +919,49 @@ static int process_inode_ref(struct extent_buffer *eb,
return 0;
}
+static int process_inode_extref(struct extent_buffer *eb,
+ int slot, struct btrfs_key *key,
+ struct shared_node *active_node)
+{
+ u32 total;
+ u32 cur = 0;
+ u32 len;
+ u32 name_len;
+ u64 index;
+ u64 parent;
+ int error;
+ struct cache_tree *inode_cache;
+ struct btrfs_inode_extref *extref;
+ char namebuf[BTRFS_NAME_LEN];
+
+ inode_cache = &active_node->inode_cache;
+
+ extref = btrfs_item_ptr(eb, slot, struct btrfs_inode_extref);
+ total = btrfs_item_size_nr(eb, slot);
+ while (cur < total) {
+ name_len = btrfs_inode_extref_name_len(eb, extref);
+ index = btrfs_inode_extref_index(eb, extref);
+ parent = btrfs_inode_extref_parent(eb, extref);
+ if (name_len <= BTRFS_NAME_LEN) {
+ len = name_len;
+ error = 0;
+ } else {
+ len = BTRFS_NAME_LEN;
+ error = REF_ERR_NAME_TOO_LONG;
+ }
+ read_extent_buffer(eb, namebuf,
+ (unsigned long)(extref + 1), len);
+ add_inode_backref(inode_cache, key->objectid, parent,
+ index, namebuf, len, 0, key->type, error);
+
+ len = sizeof(*extref) + name_len;
+ extref = (struct btrfs_inode_extref *)((char *)extref + len);
+ cur += len;
+ }
+ return 0;
+
+}
+
static u64 count_csum_range(struct btrfs_root *root, u64 start, u64 len)
{
struct btrfs_key key;
@@ -1102,6 +1148,9 @@ static int process_one_leaf(struct btrfs_root *root, struct extent_buffer *eb,
case BTRFS_INODE_REF_KEY:
ret = process_inode_ref(eb, i, &key, active_node);
break;
+ case BTRFS_INODE_EXTREF_KEY:
+ ret = process_inode_extref(eb, i, &key, active_node);
+ break;
case BTRFS_INODE_ITEM_KEY:
ret = process_inode_item(eb, i, &key, active_node);
break;