From 5d54ba9082e5e33f30e04230d930df604ec46a37 Mon Sep 17 00:00:00 2001 From: Li Dongyang Date: Wed, 21 Apr 2021 21:50:20 +1000 Subject: [PATCH] LU-11604 debugfs: add support for printing linkEA Allow debugfs "stat" to decode and print the linkEA for each inode. Change-Id: I9aa27a857cb68af7670b900f1fc3f9804aa8c837 Signed-off-by: Andreas Dilger Reviewed-on: https://review.whamcloud.com/43383 Tested-by: jenkins Tested-by: Maloo --- debugfs/debugfs.8.in | 16 ++++-- debugfs/debugfs.h | 1 + debugfs/xattrs.c | 121 +++++++++++++++++++++++++++++++++--------- lib/ext2fs/lfsck.h | 2 +- tests/d_trusted_link/expect | 12 +++++ tests/d_trusted_link/image.gz | Bin 0 -> 10740 bytes tests/d_trusted_link/name | 1 + tests/d_trusted_link/script | 26 +++++++++ 8 files changed, 150 insertions(+), 29 deletions(-) create mode 100644 tests/d_trusted_link/expect create mode 100644 tests/d_trusted_link/image.gz create mode 100644 tests/d_trusted_link/name create mode 100644 tests/d_trusted_link/script diff --git a/debugfs/debugfs.8.in b/debugfs/debugfs.8.in index 3497060..cf463e9 100644 --- a/debugfs/debugfs.8.in +++ b/debugfs/debugfs.8.in @@ -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 diff --git a/debugfs/debugfs.h b/debugfs/debugfs.h index 39bc024..db58aba 100644 --- a/debugfs/debugfs.h +++ b/debugfs/debugfs.h @@ -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); diff --git a/debugfs/xattrs.c b/debugfs/xattrs.c index 4ee619e..bab09f0 100644 --- a/debugfs/xattrs.c +++ b/debugfs/xattrs.c @@ -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; } diff --git a/lib/ext2fs/lfsck.h b/lib/ext2fs/lfsck.h index f7b8560..e112a5d 100644 --- a/lib/ext2fs/lfsck.h +++ b/lib/ext2fs/lfsck.h @@ -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 index 0000000..5c2bbda --- /dev/null +++ b/tests/d_trusted_link/expect @@ -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 index 0000000000000000000000000000000000000000..b3b7e1ce67ff4b4177e581d5574f71625b4173eb GIT binary patch literal 10740 zcmeI!ZB!Fi8USEcENBsEx2;wb*{&{}u8SX~K?DJ7TR2FOkAwh$BnS#P10uyyi3V+H z#V)0+TEC_nJ~iZPGJH57i3z1ts8Udt%uEfEs0h@FC>1B_NRn;;^zg&ebNbudANSlp z_nz}U?|a|#`c=%E7vOOybB^ndf~~pRUG9zKe!Xq`Cx>pq)o)Gwx7h7++Q#=Tub)^k zXY(tZjjzAz_WEn}M{4h^nDg@Hg#XlTb6x+>#AEX|zj7_{6^>Q%#sZH4O)k#&x?0R2 z3cWd;&wp%sptQ3a-Cb{bf~ozXZ!R6Ooe5gt)*vuF%5Bx(=v&gexbTj(tSfeP!J|h_ zjvKqbofX!OfwIG7Onbqe0SH8%d|wo#KJe3c!&g5&6i#R5l;9_e9MmtZ z0V5i7wpK0vq0YT#!-HEXktLU!N^i{S`VA@#Ura}OVQQC$~9$w$+kgSYCBP%WvOwhZh zt-ro_j*H*`&1)c37%<6eBoG>~Il886_FSvE@8`Ssjum}$<*6SNpdaXu3L*bE8pn}A zN4Ds@uBN)r?KAuG^6K(A+@I7+qB)M&CgwpZEvgf7bkB_a35 z1Y>81gTp2?827;K3yV`C@~0D{^PfJpy3PvJUeczVwD@B0>st4y1|2tZCqyYa?H)NF zY&Ysm?EQvn+9VR{I;{#FSi@|bO!rfHfpDxPKUOAr5v?<7TUZ;aoqBCD5lS7#8aq8 zp$!8nlprZps8%m9%ZjNRq38fwNVHR*YMS)?MffEshR-w09}wH25`JO|kqkk6wpsar z^rp(80)7ffdP3PFoONU%1dedqNng5wDH=)Ji;qC@Bk7Ovc*-uSU8X9hZZSK;lOmPT zmS(2JR=*4lpe~CPrD^eG5S?#Rl=2&>b@Z@EU5%P?4?4@Hwot4`c?|74yADO>qU+=ZdrtV$6b4+=r!5MR%DJ_iHf)(qOCcf67#?mJR59Hy% zRZ*c1H3|3QCM;fDYel??a-fshH7WFyyHel!q`Bi=^dOV!o8*Va8v-nB`flj?2zEK1 zYbl2IiS=K}RvV5&9C5Rr6HTs#@_kc!$@x&0gcCr%4FTegElSjI7mAXk2@w=egZ7AZ z`osxC2PBXP&8kBDC1|TyyGl`EIi@+UXPc2e>Y=7ytx{5yMygLSqkaZ&i&3Liqf4kB zjeMs%ogy^IPBe^)rbjic_Z3=8wWj^Pvc_PeH-@Kr^jE4w7 z1B`JIzQv%y1c-2n;V_n1knxQ{ilr3@(hVoE$+}A zuu$HX(rhNVpMpBdZ%Gm|NnS(V!mshCHQ9e zAyxQW^e@Z@;+BZy8uj~@AShMb7Lig;PFRjGn|#xv@kN$cXtyuBmneb`ND=~w80ce3 zQX_H7a-P{N5#$=q&^W`BB{VG09YejVem6`OTs^}!o z!`^P)z^`M_5g%obx(K-8gZ7~Ff$w0Mzd8o^AFT36-v+M03aNSrV1(6DbTQBa%X8Fe z00AR8=z3rPR*tJn027Rkqc2f$SY{x{gZw*|7s#z3|B7u3OpYbr!SZz-CzWI1=b~60 z##No53TP{@gDX!4F`kZ)u|R~UCFBsO<8=nhJi*x`RUoJ|YTD!lpw_52t-Zmxzjzfq zE8>gBuySuVXIFlHSI+!CbB*dSu&+|q4BYc+>_L73X5d87?cybfB5Iq5&;9*=P4p#D72?Yj9cyw|+FYGi4Uef5T^d!xtWrXFHX)=8I%7n31q z#t&f+TApnwI}=sNZ(jKXZC@3_%n|GwTQ(>% literal 0 HcmV?d00001 diff --git a/tests/d_trusted_link/name b/tests/d_trusted_link/name new file mode 100644 index 0000000..d776f73 --- /dev/null +++ b/tests/d_trusted_link/name @@ -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 index 0000000..0d93015 --- /dev/null +++ b/tests/d_trusted_link/script @@ -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 -- 1.8.3.1