btrfs-progs: add extended inode ref support to btrfsck
authorMark Fasheh <mfasheh@suse.com>
Thu, 7 Jun 2012 23:00:55 +0000 (16:00 -0700)
committerDavid Sterba <dsterba@suse.cz>
Thu, 31 Jan 2013 21:33:23 +0000 (22:33 +0100)
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>
btrfsck.c

index 6274ff761a1330102309aa9b6e9da0eba1ddd5d7..58baade48dd5aec4e7578b1b3edaa1e515065649 100644 (file)
--- 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;