Whamcloud - gitweb
LU-11604 debugfs: add support for printing linkEA 83/43383/3
authorLi Dongyang <dongyangli@ddn.com>
Wed, 21 Apr 2021 11:50:20 +0000 (21:50 +1000)
committerLi Dongyang <dongyangli@ddn.com>
Tue, 27 Apr 2021 00:50:26 +0000 (00:50 +0000)
Allow debugfs "stat" to decode and print the linkEA for each inode.

Change-Id: I9aa27a857cb68af7670b900f1fc3f9804aa8c837
Signed-off-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-on: https://review.whamcloud.com/43383
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
debugfs/debugfs.8.in
debugfs/debugfs.h
debugfs/xattrs.c
lib/ext2fs/lfsck.h
tests/d_trusted_link/expect [new file with mode: 0644]
tests/d_trusted_link/image.gz [new file with mode: 0644]
tests/d_trusted_link/name [new file with mode: 0644]
tests/d_trusted_link/script [new file with mode: 0644]

index 3497060..cf463e9 100644 (file)
@@ -301,19 +301,29 @@ corruption in the file system.)
 .B dump_unused
 Dump unused blocks which contain non-null bytes.
 .TP
-.BI ea_get " [-f outfile]|[-xVC] [-r] filespec attr_name"
+.BI "ea_get [-f " outfile "]|[-xVC] [-r]" " filespec attr_name"
 Retrieve the value of the extended attribute
 .I attr_name
 in the file
 .I filespec
-and write it either to stdout or to \fIoutfile\fR.
+and write it either to stdout or to \fIoutfile\fR if
+.B -f
+is specified.  If
+.B -C
+is used the xattr is printed with C-format escapes, and if
+.B -x
+is used the xattr is printed in hex format, while the
+.B -V
+option prints in raw format without quotes.  The
+.B -r
+option prints the xattr name in raw format.
 .TP
 .BI ea_list " filespec
 List the extended attributes associated with the file
 .I filespec
 to standard output.
 .TP
-.BI ea_set " [-f infile] [-r] filespec attr_name attr_value
+.BI "ea_set [-f " infile "] [-r] " "filespec attr_name attr_value"
 Set the value of the extended attribute
 .I attr_name
 in the file
index 39bc024..db58aba 100644 (file)
@@ -27,6 +27,7 @@ extern quota_ctx_t current_qctx;
 extern ext2_ino_t      root, cwd;
 extern int ss_sci_idx;
 extern ss_request_table debug_cmds, extent_cmds;
+extern const char *debug_prog_name;
 
 extern void reset_getopt(void);
 extern FILE *open_pager(void);
index 4ee619e..bab09f0 100644 (file)
@@ -84,8 +84,7 @@ static void print_xattr(FILE *f, char *name, char *value, size_t value_len,
        fputc('\n', f);
 }
 
-static void print_fidstr(FILE *f, void *name, void *value,
-                        ext2_ino_t inode_num, size_t value_len)
+static int print_fidstr(FILE *f, void *name, void *value, size_t value_len)
 {
        struct filter_fid_old *ff = value;
        int stripe;
@@ -93,16 +92,15 @@ static void print_fidstr(FILE *f, void *name, void *value,
        /* Since Lustre 2.4 only the parent FID is stored in filter_fid,
         * and the self fid is stored in the LMA and is printed below. */
        if (value_len < sizeof(ff->ff_parent)) {
-               fprintf(stderr, "%s: error: filter_fid for inode %u smaller "
-                       "than expected (%lu bytes).\n",
-                       debug_prog_name, inode_num, value_len);
-               return;
+               fprintf(stderr, "%s: error: xattr '%s' too small (%zu bytes)\n",
+                       debug_prog_name, name, value_len);
+               return -EINVAL;
        }
        fid_le_to_cpu(&ff->ff_parent, &ff->ff_parent);
        stripe = fid_ver(&ff->ff_parent); /* stripe index is stored in f_ver */
        ff->ff_parent.f_ver = 0;
 
-       fprintf(f, "  fid: ");
+       fprintf(f, "fid: ");
        /* Old larger filter_fid should only ever be used with seq = 0.
         * FID-on-OST should use LMA for FID_SEQ_NORMAL OST objects. */
        if (value_len == sizeof(*ff))
@@ -125,23 +123,23 @@ static void print_fidstr(FILE *f, void *name, void *value,
                                ext2fs_le64_to_cpu(ff_new->ff_pfl_end));
        }
        fprintf(f, "\n");
+
+       return 0;
 }
 
-static void print_lmastr(FILE *f, void *name, void *value,
-                        ext2_ino_t inode_num, size_t value_len)
+static int print_lmastr(FILE *f, void *name, void *value, size_t value_len)
 {
        struct lustre_mdt_attrs *lma = value;
        struct lustre_ost_attrs *loa = value;
 
        if (value_len < offsetof(typeof(*lma), lma_self_fid) +
                        sizeof(lma->lma_self_fid)) {
-               fprintf(stderr, "%s: error: LMA for inode %u smaller than "
-                       "expected (%lu bytes).\n",
-                       debug_prog_name, inode_num, value_len);
-               return;
+               fprintf(stderr, "%s: error: xattr '%s' too small (%zu bytes)\n",
+                       debug_prog_name, name, value_len);
+               return -EINVAL;
        }
        fid_le_to_cpu(&lma->lma_self_fid, &lma->lma_self_fid);
-       fprintf(f, "  lma: fid="DFID" compat=%x incompat=%x\n",
+       fprintf(f, "lma: fid="DFID" compat=%x incompat=%x\n",
                PFID(&lma->lma_self_fid), ext2fs_le32_to_cpu(lma->lma_compat),
                ext2fs_le32_to_cpu(lma->lma_incompat));
        if (value_len >= offsetof(typeof(*loa), loa_pfl_end) +
@@ -165,12 +163,86 @@ static void print_lmastr(FILE *f, void *name, void *value,
                                ext2fs_le64_to_cpu(loa->loa_pfl_end));
                fprintf(f, "\n");
        }
+
+       return 0;
+}
+
+static int print_linkea(FILE *f, void *name, void *value, size_t value_len)
+{
+       struct link_ea_header *leh = value;
+       struct link_ea_entry *lee;
+       int i;
+
+       if (value_len < sizeof(*leh) ||
+           value_len < ext2fs_le64_to_cpu(leh->leh_len)) {
+               fprintf(stderr, "%s: error: xattr '%s' too small (%zu bytes)\n",
+                       debug_prog_name, name, value_len);
+               return -EINVAL;
+       }
+
+       if (ext2fs_le32_to_cpu(leh->leh_magic) != LINK_EA_MAGIC) {
+               fprintf(stderr, "%s: error: xattr '%s' bad magic '%#x'\n",
+                       debug_prog_name, name,
+                       ext2fs_le32_to_cpu(leh->leh_magic));
+               return -EINVAL;
+       }
+
+       lee = leh->leh_entry;
+       value_len -= sizeof(*leh);
+
+       for (i = 0; i < ext2fs_le32_to_cpu(leh->leh_reccount) &&
+                   value_len > 2; i++) {
+               int reclen = lee->lee_reclen[0] << 8 | lee->lee_reclen[1];
+               struct lu_fid pfid;
+
+               if (value_len < sizeof(*lee) || value_len < reclen) {
+                       fprintf(stderr,
+                               "%s: error: xattr '%s' entry %d too small "
+                               "(%zu bytes)\n",
+                               debug_prog_name, name, i, value_len);
+                       return -EINVAL;
+               }
+
+               memcpy(&pfid, &lee->lee_parent_fid, sizeof(pfid));
+               fid_be_to_cpu(&pfid, &pfid);
+               fprintf(f, "%s idx=%u parent="DFID" name='%.*s'\n",
+                       i == 0 ? "linkea:" : "         ", i, PFID(&pfid),
+                       reclen - (int)sizeof(*lee), lee->lee_name);
+
+               lee = (struct link_ea_entry *)((char *)lee + reclen);
+               value_len -= reclen;
+       }
+
+       return 0;
 }
 
+struct dump_attr_pretty {
+       const char *dap_name;
+       int (*dap_print)(FILE *f, void *name, void *value, size_t value_len);
+} dumpers[] = {
+       {
+               .dap_name = "trusted.fid",
+               .dap_print = print_fidstr,
+       },
+       {
+               .dap_name = "trusted.lma",
+               .dap_print = print_lmastr,
+       },
+       {
+               .dap_name = "trusted.link",
+               .dap_print = print_linkea,
+       },
+       {
+               .dap_name = NULL,
+       }
+};
+
 static int dump_attr(char *name, char *value, size_t value_len,
                     ext2_ino_t inode_num, void *data)
 {
+       struct dump_attr_pretty *dap;
        FILE *out = data;
+       int rc = 0;
 
        fprintf(out, "  ");
        if (EXT2_HAS_INCOMPAT_FEATURE(current_fs->super,
@@ -178,17 +250,16 @@ static int dump_attr(char *name, char *value, size_t value_len,
                                      inode_num != 0) {
                fprintf(out, "inode <%u> ", inode_num);
        }
-       print_xattr(out, name, value, value_len, PRINT_XATTR_STATFMT);
-       if (!strncmp(name, EXT2_ATTR_INDEX_TRUSTED_PREFIX LUSTRE_XATTR_OST_FID,
-                    strlen(name)) ||
-           !strncmp(name, EXT2_ATTR_INDEX_LUSTRE_PREFIX LUSTRE_XATTR_OST_FID,
-                    strlen(name)))
-               print_fidstr(out, name, value, inode_num, value_len);
-       if (!strncmp(name, EXT2_ATTR_INDEX_TRUSTED_PREFIX LUSTRE_XATTR_MDT_LMA,
-                    strlen(name)) ||
-           !strncmp(name, EXT2_ATTR_INDEX_LUSTRE_PREFIX LUSTRE_XATTR_MDT_LMA,
-                    strlen(name)))
-               print_lmastr(out, name, value, inode_num, value_len);
+
+       for (dap = dumpers; dap->dap_name != NULL; dap++) {
+               if (strcmp(name, dap->dap_name) == 0) {
+                       rc = dap->dap_print(out, name, value, value_len);
+                       break;
+               }
+       }
+       if (dap->dap_name == NULL || rc)
+               print_xattr(out, name, value, value_len, PRINT_XATTR_STATFMT);
+
        return 0;
 }
 
index f7b8560..e112a5d 100644 (file)
@@ -104,7 +104,7 @@ struct link_ea_header {
        __u64 leh_len;                  /* total size in bytes */
        __u32 leh_overflow_time;        /* when link xattr ran out of space */
        __u32 padding;
-/*     struct link_ea_entry leh_entry; packed array of variable-size entries */
+       struct link_ea_entry leh_entry[0]; /* packed array of variable-size entries */
 };
 #endif
 
diff --git a/tests/d_trusted_link/expect b/tests/d_trusted_link/expect
new file mode 100644 (file)
index 0000000..5c2bbda
--- /dev/null
@@ -0,0 +1,12 @@
+Extended attributes:
+  linkea: idx=0 parent=[0x200000007:0x1:0x0] name='file'
+          idx=1 parent=[0x240000404:0x1:0x0] name='file-link-1'
+          idx=2 parent=[0x240000404:0x1:0x0] name='file-link-2'
+          idx=3 parent=[0x240000404:0x1:0x0] name='file-link-3'
+          idx=4 parent=[0x240000404:0x1:0x0] name='file-link-4'
+          idx=5 parent=[0x240000404:0x1:0x0] name='file-link-5'
+          idx=6 parent=[0x240000404:0x1:0x0] name='file-link-6'
+          idx=7 parent=[0x240000404:0x1:0x0] name='file-link-7'
+          idx=8 parent=[0x240000404:0x1:0x0] name='file-link-8'
+          idx=9 parent=[0x240000404:0x1:0x0] name='file-link-9'
+          idx=10 parent=[0x240000404:0x1:0x0] name='file-link-10'
diff --git a/tests/d_trusted_link/image.gz b/tests/d_trusted_link/image.gz
new file mode 100644 (file)
index 0000000..b3b7e1c
Binary files /dev/null and b/tests/d_trusted_link/image.gz differ
diff --git a/tests/d_trusted_link/name b/tests/d_trusted_link/name
new file mode 100644 (file)
index 0000000..d776f73
--- /dev/null
@@ -0,0 +1 @@
+decode and print trusted.link xattr in debugfs
diff --git a/tests/d_trusted_link/script b/tests/d_trusted_link/script
new file mode 100644 (file)
index 0000000..0d93015
--- /dev/null
@@ -0,0 +1,26 @@
+if ! test -x $DEBUGFS_EXE; then
+       echo "$test_name: $test_description: skipped (no debugfs)"
+       return 0
+fi
+
+IMAGE=$test_dir/image.gz
+EXP=$test_dir/expect
+OUT=$test_name.log
+gunzip < $IMAGE > $TMPFILE
+
+$DEBUGFS -w -R "ea_list /file" $TMPFILE >> $OUT.new 2>&1
+sed -f $cmd_dir/filter.sed $OUT.new > $OUT
+rm -f $TMPFILE $OUT.new
+
+cmp -s $OUT $EXP
+status=$?
+
+if [ "$status" = 0 ] ; then
+       echo "$test_name: $test_description: ok"
+       touch $test_name.ok
+else
+       echo "$test_name: $test_description: failed"
+       diff $DIFF_OPTS $EXP $OUT > $test_name.failed
+fi
+
+unset IMAGE EXP OUT