Introduce 'print_inode_ref' to print error msg while checking inode ref.

Add args 'name_ret' and 'namelen_ret' to 'check_inode_ref' because
they are essential while doing nlinks repair.

Signed-off-by: Su Yue <suy.f...@cn.fujitsu.com>
---
 cmds-check.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 74 insertions(+), 19 deletions(-)

diff --git a/cmds-check.c b/cmds-check.c
index c45dfae4..24a39e54 100644
--- a/cmds-check.c
+++ b/cmds-check.c
@@ -4334,34 +4334,76 @@ out:
 }
 
 /*
+ * Print 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 ? "mismath" : "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 ? "mismath" : "missing",
+                      namebuf, filetype);
+}
+
+/*
  * Traverse the given INODE_REF and call find_dir_item() to find related
- * DIR_ITEM/DIR_INDEX.
+ * DIR_ITEM/DIR_INDEX.If repair is enable, research @ref_key and
+ * @path may change.
  *
  * @root:      the root of the fs/file tree
  * @ref_key:   the key of the INODE_REF
+ * @path        the path provides node and slot
  * @refs:      the count of INODE_REF
  * @mode:      the st_mode of INODE_ITEM
+ * @name_ret:   returns with the first ref's name
+ * @name_len_ret:    len of the name_ret
  *
+ * Return <0 on error.
  * 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};
+       int name_len;
        u32 total;
        u32 cur = 0;
-       u32 len;
-       u32 name_len;
+       long len;
        u64 index;
-       int ret, err = 0;
+       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);
@@ -4370,6 +4412,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 (name_len <= BTRFS_NAME_LEN) {
@@ -4382,30 +4425,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 firt 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 fake err bit so 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,
+       tmp_err |= find_dir_item(root, &key, &location, namebuf, len,
                            imode_to_type(mode));
-       err |= ret;
 
        /* 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,
+       tmp_err |= find_dir_item(root, &key, &location, namebuf, len,
                            imode_to_type(mode));
-       err |= ret;
-
+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;
@@ -5093,6 +5146,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];
@@ -5133,8 +5188,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:
-- 
2.11.1



--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to