Whamcloud - gitweb
LU-18401 utils: check_iam, support more iam records types 90/56790/6
authorEtienne AUJAMES <etienne.aujames@cea.fr>
Fri, 25 Oct 2024 10:10:55 +0000 (12:10 +0200)
committerOleg Drokin <green@whamcloud.com>
Mon, 9 Dec 2024 06:13:13 +0000 (06:13 +0000)
This patch fix check_iam to support different keysizes (the entries
offset was wrong for keysize other than fid size).

This adds callbacks to print different type of records for different
IAM files.

The type can be specified with the option "-t". If not, the type is
guess from the file name.

If the type is not supported, they keys and records will be dump in
hexadecimal format.

Here the following type of IAM files supported:

- oi.16.*: FID/inode mapping (already supported):

$ check_iam -r /tmp/oi.16.1
[0x200000401:0x448:0x0] 1157/3251524137
[0x200000401:0x449:0x0] 1158/3251524138
...

- lfsck_namespace: LFSCK namespace trace file:

$ check_iam -r /tmp/lfsck_namespace_01
[0:0x0:0x0]     0x0 ()
[0x200000401:0x65:0x0]  0x1 (CHECK_LINKEA)

- lfsck_layout: LFSCK layout trace file:

$ check_iam -r /tmp/lfsck_layout_01
{ parent: [0:0x0:0x0], comp_id: 0, ea_off: 0 }  { cfid: [0:0x0:0x0],
ost_idx: 0 }

- nodemap: nodemap configuration:

$ check_iam -r /tmp/nodemap
{ id: 0x0, type: global(15) }   { is_active: 1 }
{ id: 0x1, type: cluster(1), subtype: cluster } { name: toto, flag:
0xb8, flag2: 0x0, squash_uid: 65534, squash_gid: 65534, squash_projid:
65534}
{ id: 0x1, type: cluster(1), subtype: roles }   { roles: 0xffffffc8}
{ id: 0x1, type: range(2) }     { start_nid: 192.168.1.128@tcp,
end_nid: 192.168.1.130@tcp }

Update regression test: conf-sanity 134

Test-Parameters: trivial
Test-Parameters: testlist=conf-sanity
Test-Parameters: testlist=conf-sanity
Test-Parameters: testlist=conf-sanity env=ONLY=134,ONLY_REPEAT=20
Fixes: 99d1f12c7 ("LU-15581 utils: add check_iam util")
Signed-off-by: Etienne AUJAMES <eaujames@ddn.com>
Change-Id: Ic2cae2cbbf1c29daa661b1916d6321b6d87494dd
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/56790
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Sebastien Buisson <sbuisson@ddn.com>
Reviewed-by: Artem Blagodarenko <ablagodarenko@ddn.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/include/lustre/libiam.h
lustre/tests/conf-sanity.sh
lustre/utils/Makefile.am
lustre/utils/check_iam.c
lustre/utils/libiam.c

index 7811f82..658bead 100644 (file)
@@ -41,17 +41,13 @@ struct dx_countlimit {
 } __attribute__((packed));
 
 struct iam_lfix_root {
-       u_int64_t  ilr_magic;
-       u_int16_t  ilr_keysize;
-       u_int16_t  ilr_recsize;
-       u_int16_t  ilr_ptrsize;
-       u_int8_t   ilr_indirect_levels;
-       u_int8_t   ilr_padding;
-       struct dx_countlimit limit;
-       u_int32_t idle_blocks;
-       u_int8_t  ilr_paddingdd2[12];
-       unsigned char entries[];
-} __attribute__((packed));
+       __le64  ilr_magic;
+       __le16  ilr_keysize;
+       __le16  ilr_recsize;
+       __le16  ilr_ptrsize;
+       __u8    ilr_indirect_levels;
+       __u8    ilr_padding;
+};
 
 struct iam_leaf_head {
        u_int16_t ill_magic;
@@ -79,6 +75,8 @@ struct iam_index_head {
        unsigned char entries[];
 } __attribute__((packed));
 
+typedef __u32 lvar_hash_t;
+
 struct lvar_root {
        u_int32_t vr_magic;
        u_int16_t vr_recsize;
index e23b75b..e10ce86 100755 (executable)
@@ -11271,38 +11271,74 @@ run_test 133 "stripe QOS: free space balance in a pool"
 test_134() {
        [ "$mds1_FSTYPE" == "ldiskfs" ] || skip "ldiskfs only test"
        local errors
-       local rc
+       local rc rc_corrupted
        local mdt_dev=$(facet_device mds1)
        local tmp_dir=$TMP/$tdir
+       local dir=$DIR/$tdir
        local out=$tmp_dir/check_iam.txt
        local CHECK_IAM=${CHECK_IAM:-$(do_facet mds1 "which check_iam 2> /dev/null || true")}
+       local iam_files=$(printf "oi.16.%d " {0..63})
 
        [[ -n "$CHECK_IAM" ]] || skip "check_iam not found"
 
+       setupall
+
+       # Fill the iam files
+       test_mkdir -p $dir || error "failed to mkdir $DIR/$tdir"
+       stack_trap "rm -rf $dir"
+
+       touch $dir/$tfile.{0..1000} || error "failed to touch files"
+       stack_trap "find $dir -type f | xargs -P10 -n1 unlink"
+
+       local f
+       for f in $dir/$tfile.{0..10}; do
+               printf "%s\n" $f.ln.{0..500} | xargs -P10 -n1 ln $f ||
+                       error "failed to create 500 hard links of $f"
+       done
+
+       local nm_name=${TESTNAME:0:15}
+
+       do_facet mgs "$LCTL nodemap_add $nm_name"
+       stack_trap "do_facet mgs $LCTL nodemap_del $nm_name"
+       do_facet mgs "$LCTL nodemap_add_range --name $nm_name --range '121.23.2.[100-120]@tcp'"
+
+       do_facet mds1 "$LCTL lfsck_start -A && $LCTL lfsck_query -w > /dev/null"
+
+       if (( MDS1_VERSION >= $(version_code 2.16.0) )); then
+               # LU-18401
+               iam_files+=$(printf "LFSCK/lfsck_layout_%02u " {0..15})
+               iam_files+=$(printf "LFSCK/lfsck_namespace_%02u " {0..15})
+               iam_files+="CONFIGS/nodemap "
+       fi
+
        mkdir -p $tmp_dir
-       for ((i=0; i<64; i++)); do
-               local f=oi.16.$i
+       for f in $iam_files; do
                #cmd introduce a random corruption to IAM file
-               local cmd="dd if=/dev/urandom of=$tmp_dir/$f bs=2 conv=notrunc count=1 seek=$((RANDOM % 36))"
-               do_facet mds1 "mkdir -p $tmp_dir; \
-                  $DEBUGFS -c -R 'dump $f $tmp_dir/$f' $mdt_dev 2>&1; \
-                  $CHECK_IAM -v $tmp_dir/$f 2>&1; \
+               local tmp_file=$tmp_dir/$(basename $f)
+               local cmd="dd if=/dev/urandom of=$tmp_file bs=2 conv=notrunc count=1 seek=$((RANDOM % 36))"
+
+               local facet
+               [[ "$f" =~ nodemap ]] && facet=mgs || facet=mds1
+               do_facet $facet "mkdir -p $tmp_dir; \
+                  $DEBUGFS -c -R 'dump $f $tmp_file' $mdt_dev 2>&1; \
+                  $CHECK_IAM -rv $tmp_file 2>&1; \
                   echo $cmd; eval $cmd 2>/dev/null;
-                  $CHECK_IAM -v $tmp_dir/$f 2>&1; echo \\\$?" >> $out 2>&1
+                  $CHECK_IAM -v $tmp_file 2>&1; \
+                  rc=\\\$?; echo \\\$rc; exit \\\$rc;" >> $out 2>&1 ||
+                  (( rc_corrupted += ($? == 255) )) || true
        done
 
-       tail -n50 $out
+       tail -n100 $out
 
        stack_trap "rm -rf $tmp_dir && do_facet mds1 rm -rf $tmp_dir" EXIT
 
-       rc=$(grep -c "fault\|except" $out)
+       rc=$(grep -c "\<fault\>\|\<except" $out)
        (( rc == 0 )) || { cat $out &&
                error "check_iam failed with fault or exception $rc"; }
 
-       rc=$(grep -c "^255" $out)
        errors=$(grep -c "FINISHED WITH ERRORS" $out)
 
-       (( rc == errors )) || { cat $out &&
+       (( rc_corrupted == errors )) || { cat $out &&
                error "check_iam errcode does not fit with errors $rc $errors"; }
 }
 run_test 134 "check_iam works without faults"
index 52eac88..3537756 100644 (file)
@@ -151,6 +151,8 @@ llog_reader_LDADD := liblustreapi.la
 llog_reader_DEPENDENCIES := liblustreapi.la
 
 check_iam_SOURCES = check_iam.c
+check_iam_LDADD := liblustreapi.la
+check_iam_DEPENDENCIES := liblustreapi.la
 
 lr_reader_SOURCES = lr_reader.c
 
index 938d819..4fe0d29 100644 (file)
 #include <errno.h>
 
 #include <sys/types.h>
+#include <asm/byteorder.h>
 #include <linux/lustre/lustre_user.h>
 #include <linux/lustre/lustre_fid.h>
-#include <asm/byteorder.h>
+#include <linux/lustre/lustre_disk.h>
+#include <linux/lnet/nidstr.h>
 #include <lustre/libiam.h>
 
+#ifndef ARRAY_SIZE
+# define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
+#endif /* !ARRAY_SIZE */
+
+struct record_cb {
+       int (*key)(const void *key, size_t size);
+       int (*rec)(const void *rec, size_t size);
+       int (*key_rec)(const void *key, size_t keys,
+                      const void *rec, size_t recs);
+};
+
+struct record_type {
+       char *type;
+       char *filename;
+       struct record_cb cb;
+};
+
 static int verbose;
 static bool print_records;
+static struct record_cb *print_cb;
+
+static int hexdump(const void *buf, size_t size);
+static int print_fid(const void *buf, size_t size);
+static int print_oid(const void *buf, size_t size);
+static int print_lfsck_namespace(const void *buf, size_t size);
+static int print_dangling_rec_key(const void *buf, size_t size);
+static int print_dangling_rec(const void *buf, size_t size);
+static int print_nodemap_key(const void *buf, size_t size);
+static int print_nodemap(const void *key, size_t keys,
+                        const void *rec, size_t recs);
+
+#define HEXDUMP_IDX 0
+#define GUESS_START_IDX (HEXDUMP_IDX + 1)
+static struct record_type record_type_array[] = {
+       [HEXDUMP_IDX] {
+               .type = "hexdump",
+               .filename = NULL,
+               .cb = {hexdump, hexdump},
+       },
+       {
+               .type = "oi_map",
+               .filename = "oi.",
+               .cb = {print_fid, print_oid},
+       },
+       {
+               .type = "lfsck_namespace",
+               .filename = "lfsck_namespace_",
+               .cb = {print_fid, print_lfsck_namespace},
+       },
+       {
+               .type = "lfsck_dangling_rec",
+               .filename = "lfsck_layout_",
+               .cb = {print_dangling_rec_key, print_dangling_rec},
+       },
+       {
+               .type = "nodemap",
+               .filename = "nodemap",
+               .cb = {print_nodemap_key, NULL, print_nodemap},
+       },
+       { 0 }
+};
+
+static struct record_type *get_rec_type(const char *type)
+{
+       struct record_type *curr;
+
+       for (curr = &record_type_array[0]; curr->type; curr++) {
+               if (strcmp(type, curr->type) == 0)
+                       return curr;
+       }
+
+       fprintf(stderr, "Record type '%s' not found\n", type);
+
+       return NULL;
+}
+
+static struct record_type *guess_rec_type(const char *filename)
+{
+       struct record_type *curr;
+       struct record_type *start = &record_type_array[GUESS_START_IDX];
+
+       for (curr = start; curr->type; curr++) {
+               if (curr->filename && strstr(filename, curr->filename))
+                       return curr;
+       }
+
+       fprintf(stderr, "Failed to guess record type for '%s', fallback to hexdump\n",
+               filename);
+
+       return &record_type_array[HEXDUMP_IDX];
+}
+
+static void print_rec_types(void)
+{
+       struct record_type *curr;
+
+       for (curr = &record_type_array[0]; curr->type; curr++)
+               printf("%s%s", curr->type, curr[1].type ? ", " : "");
+}
 
 enum {
        ROOT_NODE,
@@ -58,7 +157,14 @@ struct node_info {
 
 static void usage(char *str)
 {
-       printf("Usage: %s [-hrv] iam_file\n", str);
+       printf("Usage: %s [-hrv] [-t rec_type] iam_file\n", basename(str));
+       fputs("\t-h: this help.\n"
+             "\t-r: print IAM keys and records.\n"
+             "\t-v: verbose mode to debug the file.\n"
+             "\t-t: type of record to print (", stdout);
+       print_rec_types();
+       puts(").\n"
+            "\t    If not specified, this will be guess with file name.");
 }
 
 struct iam_params {
@@ -120,11 +226,42 @@ static int check_idle_blocks(char *buf, struct iam_params *params)
        return 0;
 }
 
+static void print_record(int idx, void *entry, struct iam_params *params)
+{
+       void *key = entry;
+       void *rec = entry + params->keysize;
+
+       if (verbose)
+               printf("%03d: ", idx);
+
+       if (print_cb->key_rec) {
+               if (print_cb->key_rec(key, params->keysize,
+                                     rec, params->recsize)) {
+                       fprintf(stderr, "Bad key or rec for idx %d\n", idx);
+                       params->rc = -1;
+               }
+               putchar('\n');
+
+               return;
+       }
+
+       if (print_cb->key && print_cb->key(key, params->keysize)) {
+               fprintf(stderr, "Bad key for idx %d\n", idx);
+               params->rc = -1;
+       }
+       putchar('\t');
+       if (print_cb->rec && print_cb->rec(rec, params->recsize)) {
+               fprintf(stderr, "Bad record for idx %d\n", idx);
+               params->rc = -1;
+       }
+       putchar('\n');
+}
+
 static int check_entries(unsigned char *entries, size_t size, int count,
                         struct iam_params *params, int block_type)
 {
        unsigned int ptr;
-       int i, j, rc;
+       int i, rc;
 
        for (i = 0; i < count; i++) {
                rc = 0;
@@ -139,13 +276,12 @@ static int check_entries(unsigned char *entries, size_t size, int count,
 
                if (block_type == INDEX_NODE) {
 
-                       if (verbose)
-                               printf("key:");
-
-                       for (j = 0; j < params->keysize; j++, entries++)
-                               if (verbose)
-                                       printf("%02x", *entries);
+                       if (verbose && print_cb->key) {
+                               printf("%03d: ", i);
+                               print_cb->key(entries, params->keysize);
+                       }
 
+                       entries += params->keysize;
                        ptr = __le32_to_cpu(*((__le32 *)entries));
 
                        if (ptr >= params->blocks_count) {
@@ -153,7 +289,7 @@ static int check_entries(unsigned char *entries, size_t size, int count,
                                rc = -1;
                        }
                        if (verbose)
-                               printf("ptr: %u%s\n", ptr,
+                               printf("\tptr: %u%s\n", ptr,
                                       rc ? " wrong" : "");
 
                        entries += params->ptrsize;
@@ -167,17 +303,10 @@ static int check_entries(unsigned char *entries, size_t size, int count,
                        }
                        params->node_info[ptr].referenced = 1;
                } else if (block_type == LEAF_NODE) {
-                       struct lu_fid fid;
-                       struct osd_inode_id *inode;
+                       if (print_records)
+                               print_record(i, entries, params);
 
-                       fid_be_to_cpu(&fid, (struct lu_fid *)entries);
-                       inode = (struct osd_inode_id *)(entries + sizeof(fid));
                        entries += params->keysize + params->recsize;
-
-                       if (print_records)
-                               printf(DFID" %u/%u\n", PFID(&fid),
-                                      __be32_to_cpu(inode->oii_ino),
-                                      __be32_to_cpu(inode->oii_gen));
                }
 
        }
@@ -266,41 +395,58 @@ static int check_index(char *buf, struct iam_params *params)
        return 0;
 }
 
-static int check_root(char *buf, size_t size, struct iam_params *params)
+static int check_root(void *buf, size_t size, struct iam_params *params)
 {
-       struct iam_lfix_root *root;
+       __le64 *magic = buf;
        unsigned int counted_limit;
        int min;
        struct dx_countlimit *limit;
+       __u32 *idle_blocks;
+       int root_entry_size;
+       int entries_off;
 
        if (verbose)
-               printf("Root format ");
+               printf("Root format: ");
+
+       switch (__le64_to_cpu(*magic)) {
+       case IAM_LFIX_ROOT_MAGIC: {
+               struct iam_lfix_root *root = buf;
 
-       root = (struct iam_lfix_root *)buf;
-       if (root->ilr_magic == __cpu_to_le64(IAM_LFIX_ROOT_MAGIC)) {
                params->fmt = FMT_LFIX;
+               params->keysize = __le16_to_cpu(root->ilr_keysize);
+               params->recsize = __le16_to_cpu(root->ilr_recsize);
+               params->ptrsize = __le16_to_cpu(root->ilr_ptrsize);
+               params->indirect_levels = root->ilr_indirect_levels;
+               params->root_gap = sizeof(*root);
                if (verbose)
-                       printf("LFIX,");
-       } else if (root->ilr_magic == __cpu_to_le64(IAM_LVAR_ROOT_MAGIC)) {
+                       puts("LFIX");
+               break;
+       }
+       case IAM_LVAR_ROOT_MAGIC: {
+               struct lvar_root *root = buf;
+
                params->fmt = FMT_LVAR;
+               params->keysize = sizeof(lvar_hash_t);
+               params->recsize = __le16_to_cpu(root->vr_recsize);
+               params->ptrsize = __le16_to_cpu(root->vr_ptrsize);
+               params->indirect_levels = root->vr_indirect_levels;
+               params->root_gap = sizeof(*root);
                if (verbose)
-                       printf("LVAR,");
-       } else {
-               printf("Bad magic %llu\n", __le64_to_cpu(root->ilr_magic));
-               params->rc = -1;
+                       puts("LVAR");
+               break;
+       }
+       default:
+               fprintf(stderr, "Bad magic %llu\n", __le64_to_cpu(*magic));
+               return -1;
        }
 
-       limit = &root->limit;
-
-       params->keysize = __le16_to_cpu(root->ilr_keysize);
-       params->recsize = __le16_to_cpu(root->ilr_recsize);
-       params->ptrsize = __le16_to_cpu(root->ilr_ptrsize);
-       params->indirect_levels = root->ilr_indirect_levels;
+       limit = buf + params->root_gap;
+       idle_blocks = buf + params->root_gap + sizeof(*limit);
+       params->idle_blocks = __le32_to_cpu(*idle_blocks);
 
        params->node_info[0].referenced = 1; //self referance
        params->node_info[0].node_type = ROOT_NODE;
 
-       params->idle_blocks = __le32_to_cpu(root->idle_blocks);
        if (params->idle_blocks >= params->blocks_count) {
                printf("Idle blocks number (%lu) is out of blocks range (%lu)\n",
                        params->idle_blocks, params->blocks_count);
@@ -311,10 +457,13 @@ static int check_root(char *buf, size_t size, struct iam_params *params)
        }
 
        if (verbose) {
-               printf("Idle blocks block number %lu\n", params->idle_blocks);
-               printf("keysize %i, recsize %i, ptrsize %i, indirect_levels %i\n",
+               printf("\tkeysize: %i\n"
+                      "\trecsize: %i\n"
+                      "\tptrsize: %i\n"
+                      "\tindirect_levels: %i\n"
+                      "\tidle_blocks: %lu\n",
                       params->keysize, params->recsize, params->ptrsize,
-                      params->indirect_levels);
+                      params->indirect_levels, params->idle_blocks);
        }
 
        if (params->ptrsize != 4 && params->ptrsize != 8) {
@@ -338,9 +487,9 @@ static int check_root(char *buf, size_t size, struct iam_params *params)
                return -1;
        }
 
+       root_entry_size = params->keysize + params->ptrsize;
        counted_limit = root_limit(params->root_gap, params->node_gap,
-                                  params->blocksize,
-                                  params->keysize + params->ptrsize);
+                                  params->blocksize, root_entry_size);
 
 
        if (__le16_to_cpu(limit->limit) != counted_limit) {
@@ -354,23 +503,22 @@ static int check_root(char *buf, size_t size, struct iam_params *params)
 
        if (__le16_to_cpu(limit->count) > __le16_to_cpu(limit->limit)) {
                printf("More elements (%i) then limit (%i)\n",
-                       __le16_to_cpu(root->limit.count),
-                       __le16_to_cpu(root->limit.limit));
+                       __le16_to_cpu(limit->count),
+                       __le16_to_cpu(limit->limit));
                params->rc = -1;
        }
 
        min = (__le16_to_cpu(limit->count) < min) ?
                        __le16_to_cpu(limit->count) : min;
 
-
        if (verbose)
-               printf("count %i, limit %i\n",
-                       __le16_to_cpu(root->limit.count),
-                       __le16_to_cpu(root->limit.limit));
+               printf("Root entries: count %i, limit %i\n",
+                       __le16_to_cpu(limit->count),
+                       __le16_to_cpu(limit->limit));
 
-       /* cound - 1, because limit is entry itself */
-       if (check_entries(root->entries,
-                         size - offsetof(struct iam_lfix_root, entries),
+       /* count - 1, because limit is entry itself */
+       entries_off = params->root_gap + root_entry_size;
+       if (check_entries(buf + entries_off, size - entries_off,
                          min - 1, params, INDEX_NODE)) {
                printf("Broken entries\n");
                return -1;
@@ -391,7 +539,7 @@ static int check_block(char *buf, struct iam_params *params)
        switch (head->ill_magic) {
        case __cpu_to_le16(IAM_LEAF_HEADER_MAGIC):
                        if (verbose)
-                               printf("FIX leaf,");
+                               printf("FIX leaf, ");
                        if (check_leaf(buf, params)) {
                                printf("Broken leaf block\n");
                                params->rc = -1;
@@ -445,6 +593,7 @@ static void print_node_type(int type)
                        break;
        }
 }
+
 static int check_unconnected(struct iam_params *params)
 {
        unsigned long i;
@@ -466,6 +615,270 @@ static int check_unconnected(struct iam_params *params)
        }
        return rc;
 }
+
+
+/*
+ * print callbacks
+ */
+
+static int hexdump(const void *buf, size_t size)
+{
+       const __u8 *ptr = buf;
+       int i;
+
+       printf("0x");
+       for (i = 0; i < size; i++)
+               printf("%02x", ptr[i]);
+
+       return 0;
+}
+
+static int print_fid(const void *buf, size_t size)
+{
+       struct lu_fid fid;
+
+       if (size < sizeof(fid)) {
+               putchar('-');
+               return -1;
+       }
+
+       fid_be_to_cpu(&fid, buf);
+       printf(DFID, PFID(&fid));
+
+       return 0;
+}
+
+static int print_oid(const void *buf, size_t size)
+{
+       const struct osd_inode_id *oid = buf;
+
+       if (size < sizeof(*oid)) {
+               putchar('-');
+               return -1;
+       }
+
+       printf("%u/%u", __be32_to_cpu(oid->oii_ino),
+              __be32_to_cpu(oid->oii_gen));
+
+       return 0;
+}
+
+static int print_lfsck_namespace(const void *buf, size_t size)
+{
+       static const char * const fl2str[] = {
+               "CHECK_LINKEA",         /* LNTF_CHECK_LINKEA */
+               "CHECK_ORPHAN",         /* LNTF_CHECK_PARENT */
+               "CHECK_ORPHAN",         /* LNTF_CHECK_ORPHAN */
+               "UNCERTAIN_LMV",        /* LNTF_UNCERTAIN_LMV */
+               "RECHECK_NAME_HASH",    /* LNTF_RECHECK_NAME_HASH */
+               "CHECK_AGENT_ENTRY",    /* LNTF_CHECK_AGENT_ENTRY */
+       };
+       const __u8 *flags = buf;
+       bool first = true;
+       int i;
+
+       if (size < sizeof(*flags)) {
+               putchar('-');
+               return -1;
+       }
+
+       printf("0x%x (", *flags);
+       if (!*flags) {
+               putchar(')');
+               return 0;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(fl2str); i++) {
+               if (*flags & (1<<i)) {
+                       printf("%s%s", first ? "" : "|", fl2str[i]);
+                       first = false;
+               }
+       }
+
+       putchar(')');
+
+       return 0;
+}
+
+struct lfsck_layout_dangling_key {
+       struct lu_fid   lldk_fid;
+       __u32           lldk_comp_id;
+       __u32           lldk_ea_off;
+};
+
+static inline void lldk_be_to_cpu(struct lfsck_layout_dangling_key *des,
+                                 const struct lfsck_layout_dangling_key *src)
+{
+       fid_be_to_cpu(&des->lldk_fid, &src->lldk_fid);
+       des->lldk_comp_id = __be32_to_cpu(src->lldk_comp_id);
+       des->lldk_ea_off = __be32_to_cpu(src->lldk_ea_off);
+}
+
+static int print_dangling_rec_key(const void *buf, size_t size)
+{
+       const struct lfsck_layout_dangling_key *src = buf;
+       struct lfsck_layout_dangling_key key;
+
+       if (size < sizeof(key)) {
+               putchar('-');
+               return -1;
+       }
+
+       lldk_be_to_cpu(&key, src);
+       printf("{ parent: "DFID", comp_id: %u, ea_off: %u }",
+              PFID(&key.lldk_fid), key.lldk_comp_id, key.lldk_ea_off);
+
+       return 0;
+}
+
+static int print_dangling_rec(const void *buf, size_t size)
+{
+       struct lu_fid fid;
+       __u32 idx;
+
+       if (size < sizeof(fid)) {
+               putchar('-');
+               return -1;
+       }
+
+       fid_be_to_cpu(&fid, buf);
+       idx = fid.f_ver;
+       fid.f_ver = 0x0;
+       printf("{ cfid: "DFID", ost_idx: %d }", PFID(&fid), idx);
+
+       return 0;
+}
+
+static inline enum nodemap_idx_type nm_idx_get_type(unsigned int id)
+{
+       return id >> NM_TYPE_SHIFT;
+}
+
+static enum nodemap_idx_type nodemap_get_key_type(const struct nodemap_key *key)
+{
+       __u32 nodemap_id;
+
+       nodemap_id = __le32_to_cpu(key->nk_nodemap_id);
+       return nm_idx_get_type(nodemap_id);
+}
+
+static int nodemap_get_key_subtype(const struct nodemap_key *key)
+{
+       enum nodemap_idx_type type = nodemap_get_key_type(key);
+
+       return type == NODEMAP_CLUSTER_IDX ? key->nk_cluster_subid : -1;
+}
+
+static const char *nodemap_type2str(int type)
+{
+       static const char * const type2str[] = {
+               [NODEMAP_EMPTY_IDX]     = "empty",
+               [NODEMAP_CLUSTER_IDX]   = "cluster",
+               [NODEMAP_RANGE_IDX]     = "range",
+               [NODEMAP_UIDMAP_IDX]    = "uidmap",
+               [NODEMAP_GIDMAP_IDX]    = "gidmap",
+               [NODEMAP_PROJIDMAP_IDX] = "projidmap",
+               [NODEMAP_NID_MASK_IDX]  = "nid_mask",
+               [NODEMAP_GLOBAL_IDX]    = "global",
+       };
+
+       if (type >= ARRAY_SIZE(type2str) || !type2str[type])
+               return "unknown";
+
+       return type2str[type];
+}
+
+static int print_nodemap_key(const void *buf, size_t size)
+{
+       const struct nodemap_key *nk = buf;
+       int type;
+
+       if (size < sizeof(*nk))
+               return -1;
+
+       type = nodemap_get_key_type(nk);
+       printf("{ id: 0x%x, type: %s(%d) }",
+              __le32_to_cpu(nk->nk_nodemap_id) & NM_TYPE_MASK,
+              nodemap_type2str(type), type);
+
+       return 0;
+}
+
+static int print_nodemap(const void *key, size_t keys,
+                        const void *rec, size_t recs)
+{
+       const struct nodemap_key *nk = key;
+       const union nodemap_rec *nr = rec;
+       int type;
+
+       if (keys < sizeof(*nk) || recs < sizeof(*nr))
+               return -1;
+
+       type = nodemap_get_key_type(nk);
+       printf("{ id: 0x%x, type: %s(%d)",
+              __le32_to_cpu(nk->nk_nodemap_id) & NM_TYPE_MASK,
+              nodemap_type2str(type), type);
+
+       switch (type) {
+       case NODEMAP_EMPTY_IDX:
+               fputs(" }\t{}", stdout);
+               if (nk->nk_nodemap_id)
+                       return -1;
+               break;
+       case NODEMAP_CLUSTER_IDX:
+               fputs(", subtype: ", stdout);
+
+               switch (nodemap_get_key_subtype(nk)) {
+               case NODEMAP_CLUSTER_REC:
+                       printf("cluster }\t{ name: %s, flag: 0x%hhx, flag2: 0x%hhx, squash_uid: %u, squash_gid: %u, squash_projid: %u}",
+                              nr->ncr.ncr_name,
+                              nr->ncr.ncr_flags, nr->ncr.ncr_flags2,
+                              __le32_to_cpu(nr->ncr.ncr_squash_uid),
+                              __le32_to_cpu(nr->ncr.ncr_squash_gid),
+                              __le32_to_cpu(nr->ncr.ncr_squash_projid));
+                       break;
+               case NODEMAP_CLUSTER_ROLES:
+                       printf("roles }\t{ roles: 0x%llx}",
+                              __le64_to_cpu(nr->ncrr.ncrr_roles));
+                       break;
+               default:
+                       printf("unknown(%d) }\t{}",
+                               nodemap_get_key_subtype(nk));
+                       break;
+               }
+               break;
+       case NODEMAP_RANGE_IDX:
+               printf(" }\t{ start_nid: %s, end_nid: %s }",
+                      libcfs_nid2str(__le64_to_cpu(nr->nrr.nrr_start_nid)),
+                      libcfs_nid2str(__le64_to_cpu(nr->nrr.nrr_end_nid)));
+               break;
+       case NODEMAP_NID_MASK_IDX:
+               printf(" }\t{ subnet: %s/%hhd }",
+                      libcfs_nidstr(&nr->nrr2.nrr_nid_prefix),
+                      nr->nrr2.nrr_netmask);
+               break;
+       case NODEMAP_UIDMAP_IDX:
+       case NODEMAP_GIDMAP_IDX:
+       case NODEMAP_PROJIDMAP_IDX:
+               printf(", id_client: %u }\t{ id_fs: %u }",
+                      __le32_to_cpu(nk->nk_id_client),
+                      __le32_to_cpu(nr->nir.nir_id_fs));
+               break;
+       case NODEMAP_GLOBAL_IDX:
+               printf(" }\t{ is_active: %hhu }",
+                      nr->ngr.ngr_is_active);
+
+               if (nk->nk_unused)
+                       return -1;
+               break;
+       default:
+               fputs(" }\t{}", stdout);
+               break;
+       }
+
+       return 0;
+}
+
 int main(int argc, char **argv)
 {
        struct iam_params params;
@@ -474,15 +887,18 @@ int main(int argc, char **argv)
        void *buf;
        int fd;
        struct stat sb;
+       struct record_type *rec_type = NULL;
 
        params.rc = 0;
        print_records = false;
        do {
-               opt = getopt(argc, argv, "hvr");
+               opt = getopt(argc, argv, "hvrt:");
                switch (opt) {
                case 'v':
                                verbose++;
                                break;
+               case 't':
+                               rec_type = get_rec_type(optarg);
                case 'r':
                                print_records = true;
                case -1:
@@ -500,10 +916,16 @@ int main(int argc, char **argv)
                return -1;
        }
 
+       if (!rec_type)
+               rec_type = guess_rec_type(argv[optind]);
+
+       print_cb = &rec_type->cb;
+       if (verbose && print_records)
+               printf("Record type to print: %s\n", rec_type->type);
+
        params.filename = argv[optind];
        params.blocksize = 4096;
        params.current_block = 0;
-       params.root_gap = sizeof(struct iam_lfix_root);
        params.node_gap = 0;
 
        fd = open(params.filename, O_RDONLY);
index 985f2c2..7e5f363 100644 (file)
@@ -50,7 +50,6 @@
 #include <libcfs/util/string.h>
 #include <lustre/libiam.h>
 
-typedef __u32 lvar_hash_t;
 
 /**
  * Stores \a val at \a dst, where the latter is possibly unaligned. Uses