Whamcloud - gitweb
LU-8289 utils: add ll_decode_linkea tool 44/20444/15
authorLi Xi <lixi@ddn.com>
Thu, 6 Oct 2016 23:13:47 +0000 (19:13 -0400)
committerOleg Drokin <oleg.drokin@intel.com>
Thu, 20 Oct 2016 10:37:02 +0000 (10:37 +0000)
A MDT recovered by fsck might contain some files under lost+found
directory of ldiskfs. And in order to get the right path to move
them to, the xattr of trusted.link could be used to extract the
parent FIDs.

This path adds an new tool ll_decode_linkea to dump the parent FIDs
of a file.

Test-Parameters: trivial
Signed-off-by: Li Xi <lixi@ddn.com>
Signed-off-by: Qian Yingjin <qian@ddn.com>
Change-Id: I1da6ea78ab2f9e2db8fbdfdcfb8690c57e9eb2b0
Reviewed-on: http://review.whamcloud.com/20444
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Fan Yong <fan.yong@intel.com>
Reviewed-by: James Simmons <uja.ornl@yahoo.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
lustre/doc/Makefile.am
lustre/doc/ll_decode_linkea.8 [new file with mode: 0644]
lustre/tests/sanity.sh
lustre/tests/test-framework.sh
lustre/utils/.gitignore
lustre/utils/Makefile.am
lustre/utils/ll_decode_linkea.c [new file with mode: 0644]

index e9baeaf..edd4f7b 100644 (file)
@@ -54,7 +54,8 @@ MANFILES = lustre.7 lfs.1 mount.lustre.8 lctl.8 lnetctl.8 \
        llapi_hsm_copytool_recv.3 llapi_hsm_action_end.3 \
        llapi_hsm_action_progress.3 llapi_hsm_action_get_dfid.3 \
        llapi_hsm_action_get_fd.3 lustreapi.7 llapi_hsm_action_begin.3 \
-       llapi_hsm_copytool_register.3 lfs-ladvise.1 llapi_ladvise.3
+       llapi_hsm_copytool_register.3 lfs-ladvise.1 llapi_ladvise.3 \
+       ll_decode_linkea.8
 
 SERVER_MANFILES = mkfs.lustre.8 tunefs.lustre.8 lshowmount.8
 
diff --git a/lustre/doc/ll_decode_linkea.8 b/lustre/doc/ll_decode_linkea.8
new file mode 100644 (file)
index 0000000..9a43aff
--- /dev/null
@@ -0,0 +1,53 @@
+.TH ll_decode_linkea 1 "May 25, 2016" Lustre "utilities"
+.SH NAME
+ll_decode_linkea \- display parent FIDs and name of a Lustre file
+.SH SYNOPSIS
+.B ll_decode_linkea
+.I file
+.RI [ "file ..." ]
+.br
+.SH DESCRIPTION
+.B ll_decode_linkea
+decodes and prints the Lustre parent FIDs and name of a Lustre file, which
+are stored in the "trusted.link" attribute on MDT. This is accessible to
+.B ll_decode_linkea
+not only through Lustre client, but also when the MDT filesystem is mounted
+locally as type ldiskfs for maintenance.
+.PP
+The "trusted.link" extended attribute is saved when file/directory is created,
+and modified when renaming or hard link happens.
+.PP
+The parent FID is useful in case of MDT corruption. The fsck of ldiskfs can
+recover most of the ldiskfs hierarchy, but it might leave some files or
+directories under lost+found. The parent FIDs can be used to determine the
+right Lustre paths to move them to.
+.SH EXAMPLE
+.fi
+root@mdt1# cd /mnt/mdt/lost+found
+.fi
+root@mdt1# ll_decode_linkea \#123451 \#123452
+.fi
+#123451: count 2
+.fi
+    0: [0x200034021:0x2:0x0], name "file1"
+.fi
+    1: [0x200034021:0x1:0x0], name "file1_link"
+.fi
+#123452: count 1
+.fi
+    0: [0x200000007:0x1:0x0], name "file2"
+.PP
+This shows that the 2 files in lost+found. ll_decode_linkea prints all of the
+parent FIDs of these files. file1 has two hard links, that is why it has two
+parent directories. Command
+.B lfs fid2path
+could be used to extract the paths of the parents.
+.PP
+Since "trusted.link" xattr is accessible on Lustre client too,
+.B ll_decode_linkea
+could also be used on Lustre client.
+.PP
+.SH SEE ALSO
+.BR lfs (1),
+.BR lustre (7),
+.BR ll_recover_lost_found_objs (8)
index c61e3bc..53684a0 100755 (executable)
@@ -10202,6 +10202,29 @@ test_154A() {
 }
 run_test 154A "lfs path2fid and fid2path basic checks"
 
+test_154B() {
+       [[ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.4.1) ]] &&
+               skip "Need MDS version at least 2.4.1" && return
+
+       mkdir -p $DIR/$tdir || error "mkdir $tdir failed"
+       touch $DIR/$tdir/$tfile || error "touch $DIR/$tdir/$tfile failed"
+       local linkea=$($LL_DECODE_LINKEA $DIR/$tdir/$tfile | grep 'pfid')
+       [ -z "$linkea" ] && error "decode linkea $DIR/$tdir/$tfile failed"
+
+       local name=$(echo $linkea | awk '/pfid/ {print $5}' | sed -e "s/'//g")
+       local PFID=$(echo $linkea | awk '/pfid/ {print $3}' | sed -e "s/,//g")
+
+       # check that we get the same pathname
+       echo "PFID: $PFID, name: $name"
+       local FOUND=$($LFS fid2path $MOUNT "$PFID")
+       [ -z "$FOUND" ] && error "fid2path unable to get $PFID path"
+       [ "$FOUND/$name" != "$DIR/$tdir/$tfile" ] &&
+               error "ll_decode_linkea has $FOUND/$name != $DIR/$tdir/$tfile"
+
+       rm -rf $DIR/$tdir || error "Can not delete directory $DIR/$tdir"
+}
+run_test 154B "verify the ll_decode_linkea tool"
+
 test_154a() {
        [ $PARALLEL == "yes" ] && skip "skip parallel run" && return
        [[ $(lustre_version_code $SINGLEMDS) -ge $(version_code 2.2.51) ]] ||
index 541f90f..57070ce 100755 (executable)
@@ -270,6 +270,8 @@ init_test_env() {
     fi
     export LL_DECODE_FILTER_FID=${LL_DECODE_FILTER_FID:-"$LUSTRE/utils/ll_decode_filter_fid"}
     [ ! -f "$LL_DECODE_FILTER_FID" ] && export LL_DECODE_FILTER_FID="ll_decode_filter_fid"
+    export LL_DECODE_LINKEA=${LL_DECODE_LINKEA:-"$LUSTRE/utils/ll_decode_linkea"}
+    [ ! -f "$LL_DECODE_LINKEA" ] && export LL_DECODE_LINKEA="ll_decode_linkea"
     export MKFS=${MKFS:-"$LUSTRE/utils/mkfs.lustre"}
     [ ! -f "$MKFS" ] && export MKFS="mkfs.lustre"
     export TUNEFS=${TUNEFS:-"$LUSTRE/utils/tunefs.lustre"}
index 41c8add..0fdc8c6 100644 (file)
@@ -23,5 +23,6 @@
 /lshowmount
 /lustre_rsync
 /ll_decode_filter_fid
+/ll_decode_linkea
 /lhsmd_posix
 /lhsmtool_posix
index 3db356a..e0b6631 100644 (file)
@@ -34,7 +34,7 @@ rootsbin_PROGRAMS = mount.lustre
 bin_SCRIPTS   = llstat llobdstat plot-llstat
 bin_PROGRAMS  = lfs
 sbin_SCRIPTS  = ldlm_debug_upcall
-sbin_PROGRAMS = lctl l_getidentity llverfs lustre_rsync
+sbin_PROGRAMS = lctl l_getidentity llverfs lustre_rsync ll_decode_linkea
 
 if TESTS
 bin_PROGRAMS  += req_layout
diff --git a/lustre/utils/ll_decode_linkea.c b/lustre/utils/ll_decode_linkea.c
new file mode 100644 (file)
index 0000000..337c1b9
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, see
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright (c) 2016, DDN Storage Corporation.
+ */
+/*
+ * lustre/utils/ll_decode_linkea.c
+ *
+ * Tool for printing the MDT link_ea structure on the objects
+ * in human readable form.
+ *
+ * Author: Li Xi <lixi@ddn.com>
+ */
+
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/xattr.h>
+#include <lustre/lustre_idl.h>
+#include <lustre/lustre_user.h>
+
+#define BUFFER_SIZE 65536
+
+int decode_linkea(const char *fname)
+{
+       char buf[BUFFER_SIZE];
+       struct link_ea_header *leh;
+       ssize_t size;
+       struct link_ea_entry *lee;
+       int i;
+       __u64 length;
+       int reclen;
+       struct lu_fid pfid;
+
+       size = getxattr(fname, "trusted.link", buf, BUFFER_SIZE);
+       if (size < 0) {
+               if (errno == ERANGE) {
+                       fprintf(stderr, "%s: failed to read trusted.link "
+                               "xattr, the buffer size %u might be too "
+                               "small\n", fname, BUFFER_SIZE);
+               } else {
+                       fprintf(stderr,
+                               "%s: failed to read trusted.link xattr: %s\n",
+                               fname, strerror(errno));
+               }
+               return -1;
+       }
+
+       leh = (struct link_ea_header *)buf;
+       if (leh->leh_magic == __swab32(LINK_EA_MAGIC)) {
+               leh->leh_magic = LINK_EA_MAGIC;
+               leh->leh_reccount = __swab32(leh->leh_reccount);
+               leh->leh_len = __swab64(leh->leh_len);
+       }
+       if (leh->leh_magic != LINK_EA_MAGIC) {
+               fprintf(stderr,
+                       "%s: magic mismatch, expected 0x%lx, got 0x%x\n",
+                       fname, LINK_EA_MAGIC, leh->leh_magic);
+               return -1;
+       }
+       if (leh->leh_reccount == 0) {
+               fprintf(stderr, "%s: empty record count\n", fname);
+               return -1;
+       }
+       if (leh->leh_len > size) {
+               fprintf(stderr,
+                       "%s: invalid length %llu, should smaller than %zd\n",
+                       fname, leh->leh_len, size);
+               return -1;
+       }
+
+       length = sizeof(struct link_ea_header);
+       lee = (struct link_ea_entry *)(leh + 1);
+       printf("%s: count %u\n", fname, leh->leh_reccount);
+       for (i = 0; i < leh->leh_reccount; i++) {
+               reclen = (lee->lee_reclen[0] << 8) | lee->lee_reclen[1];
+               length += reclen;
+               if (length > leh->leh_len) {
+                       fprintf(stderr,
+                               "%s: length exceeded, expected %lld, got %lld\n",
+                               fname, leh->leh_len, length);
+                       return -1;
+               }
+               memcpy(&pfid, &lee->lee_parent_fid, sizeof(pfid));
+               fid_be_to_cpu(&pfid, &pfid);
+
+               printf("    %d: pfid "DFID", name '%s'\n", i, PFID(&pfid),
+                      lee->lee_name);
+               lee = (struct link_ea_entry *)((char *)lee + reclen);
+       }
+
+       if (length != leh->leh_len) {
+               fprintf(stderr,
+                       "%s: length mismatch, expected %lld, got %lld\n",
+                       fname, leh->leh_len, length);
+               return -1;
+       }
+
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+       int     rc = 0;
+       int     rc2;
+       int     i;
+
+       for (i = 1; i < argc; i++) {
+               rc2 = decode_linkea(argv[i]);
+               if (rc2 != 0)
+                       rc = rc2;
+       }
+
+       return rc;
+}