btrfs-progs: check: introduce print_inode_ref()
authorSu Yue <suy.fnst@cn.fujitsu.com>
Mon, 28 Aug 2017 06:31:47 +0000 (14:31 +0800)
committerDavid Sterba <dsterba@suse.com>
Mon, 16 Oct 2017 18:33:00 +0000 (20:33 +0200)
Introduce print_inode_ref() to print error msg while checking inode ref.

Add args @name_ret and @namelen_ret to check_inode_ref().
Name is essential if the inode item is to be put into lost+found
while doing nlinks repair.

Signed-off-by: Su Yue <suy.fnst@cn.fujitsu.com>
Signed-off-by: David Sterba <dsterba@suse.com>
cmds-check.c

index 962bd65..5f1ee04 100644 (file)
@@ -4437,6 +4437,38 @@ out:
 }
 
 /*
+ * Prints inode ref error message
+ */
+static void print_inode_ref_err(struct btrfs_root *root, struct btrfs_key *key,
+                               u64 index, const char *namebuf, int name_len,
+                               u8 filetype, int err)
+{
+       if (!err)
+               return;
+
+       /* root dir error */
+       if (key->objectid == BTRFS_FIRST_FREE_OBJECTID) {
+               error(
+       "root %llu root dir shouldn't have INODE REF[%llu %llu] name %s",
+                     root->objectid, key->objectid, key->offset, namebuf);
+               return;
+       }
+
+       /* normal error */
+       if (err & (DIR_ITEM_MISMATCH | DIR_ITEM_MISSING))
+               error("root %llu DIR ITEM[%llu %llu] %s name %s filetype %u",
+                     root->objectid, key->offset,
+                     btrfs_name_hash(namebuf, name_len),
+                     err & DIR_ITEM_MISMATCH ? "mismatch" : "missing",
+                     namebuf, filetype);
+       if (err & (DIR_INDEX_MISMATCH | DIR_INDEX_MISSING))
+               error("root %llu DIR INDEX[%llu %llu] %s name %s filetype %u",
+                     root->objectid, key->offset, index,
+                     err & DIR_ITEM_MISMATCH ? "mismatch" : "missing",
+                     namebuf, filetype);
+}
+
+/*
  * Traverse the given INODE_REF and call find_dir_item() to find related
  * DIR_ITEM/DIR_INDEX.
  *
@@ -4448,24 +4480,28 @@ out:
  * Return 0 if no error occurred.
  */
 static int check_inode_ref(struct btrfs_root *root, struct btrfs_key *ref_key,
-                          struct extent_buffer *node, int slot, u64 *refs,
-                          int mode)
+                          struct btrfs_path *path, char *name_ret,
+                          u32 *namelen_ret, u64 *refs, int mode)
 {
        struct btrfs_key key;
        struct btrfs_key location;
        struct btrfs_inode_ref *ref;
+       struct extent_buffer *node;
        char namebuf[BTRFS_NAME_LEN] = {0};
        u32 total;
        u32 cur = 0;
        u32 len;
        u32 name_len;
        u64 index;
-       int ret;
        int err = 0;
+       int tmp_err;
+       int slot;
 
        location.objectid = ref_key->objectid;
        location.type = BTRFS_INODE_ITEM_KEY;
        location.offset = 0;
+       node = path->nodes[0];
+       slot = path->slots[0];
 
        ref = btrfs_item_ptr(node, slot, struct btrfs_inode_ref);
        total = btrfs_item_size_nr(node, slot);
@@ -4474,6 +4510,7 @@ next:
        /* Update inode ref count */
        (*refs)++;
 
+       tmp_err = 0;
        index = btrfs_inode_ref_index(node, ref);
        name_len = btrfs_inode_ref_name_len(node, ref);
        if (cur + sizeof(*ref) + name_len > total ||
@@ -4490,28 +4527,40 @@ next:
 
        read_extent_buffer(node, namebuf, (unsigned long)(ref + 1), len);
 
-       /* Check root dir ref name */
-       if (index == 0 && strncmp(namebuf, "..", name_len)) {
-               error("root %llu INODE_REF[%llu %llu] ROOT_DIR name shouldn't be %s",
-                     root->objectid, ref_key->objectid, ref_key->offset,
-                     namebuf);
-               err |= ROOT_DIR_ERROR;
+       /* copy the fisrt name found to name_ret */
+       if (*refs == 1 && name_ret) {
+               memcpy(name_ret, namebuf, len);
+               *namelen_ret = len;
+       }
+
+       /* Check root dir ref */
+       if (ref_key->objectid == BTRFS_FIRST_FREE_OBJECTID) {
+               if (index != 0 || len != strlen("..") ||
+                   strncmp("..", namebuf, len) ||
+                   ref_key->offset != BTRFS_FIRST_FREE_OBJECTID) {
+                       /* set err bits then repair will delete the ref */
+                       err |= DIR_INDEX_MISSING;
+                       err |= DIR_ITEM_MISSING;
+               }
+               goto end;
        }
 
        /* Find related DIR_INDEX */
        key.objectid = ref_key->offset;
        key.type = BTRFS_DIR_INDEX_KEY;
        key.offset = index;
-       ret = find_dir_item(root, &key, &location, namebuf, len, mode);
-       err |= ret;
+       tmp_err |= find_dir_item(root, &key, &location, namebuf, len, mode);
 
        /* Find related dir_item */
        key.objectid = ref_key->offset;
        key.type = BTRFS_DIR_ITEM_KEY;
        key.offset = btrfs_name_hash(namebuf, len);
-       ret = find_dir_item(root, &key, &location, namebuf, len, mode);
-       err |= ret;
+       tmp_err |= find_dir_item(root, &key, &location, namebuf, len, mode);
 
+end:
+       print_inode_ref_err(root, ref_key, index, namebuf, name_len,
+                           imode_to_type(mode), tmp_err);
+       err |= tmp_err;
        len = sizeof(*ref) + name_len;
        ref = (struct btrfs_inode_ref *)((char *)ref + len);
        cur += len;
@@ -5222,6 +5271,8 @@ static int check_inode_item(struct btrfs_root *root, struct btrfs_path *path,
        int slot;
        int ret;
        int err = 0;
+       char namebuf[BTRFS_NAME_LEN] = {0};
+       u32 name_len = 0;
 
        node = path->nodes[0];
        slot = path->slots[0];
@@ -5262,8 +5313,8 @@ static int check_inode_item(struct btrfs_root *root, struct btrfs_path *path,
 
                switch (key.type) {
                case BTRFS_INODE_REF_KEY:
-                       ret = check_inode_ref(root, &key, node, slot, &refs,
-                                             mode);
+                       ret = check_inode_ref(root, &key, path, namebuf,
+                                             &name_len, &refs, mode);
                        err |= ret;
                        break;
                case BTRFS_INODE_EXTREF_KEY: