Whamcloud - gitweb
LU-11245 flr: lfs mirror dump command 97/32997/5
authorBobi Jam <bobijam@whamcloud.com>
Tue, 14 Aug 2018 04:53:15 +0000 (12:53 +0800)
committerOleg Drokin <green@whamcloud.com>
Mon, 10 Sep 2018 16:53:53 +0000 (16:53 +0000)
Adds "lfs mirror dump" command to dump a mirror's content of a
mirrored file.

Usage:

lfs mirror dump <-N|--mirror-id <mirror_id>>
[-o|--outfile <output_file> ] <mirrored_file>

Options:

--mirror-id <mirror_id>
  Specify the mirror by mirror_id to dump its content.
--outfile <output_file>
  Dump the content into file output_file, if not specified, the
  content will be dump to the standard output stream.

Test-Parameters: testlist=sanity-flr
Signed-off-by: Bobi Jam <bobijam@whamcloud.com>
Change-Id: I2846b1c1968d9cc302c07b57a05687af50530d53
Reviewed-on: https://review.whamcloud.com/32997
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Jinshan Xiong <jinshan.xiong@gmail.com>
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/doc/lfs-mirror-dump.1 [new file with mode: 0644]
lustre/tests/sanity-flr.sh
lustre/utils/lfs.c

diff --git a/lustre/doc/lfs-mirror-dump.1 b/lustre/doc/lfs-mirror-dump.1
new file mode 100644 (file)
index 0000000..becc796
--- /dev/null
@@ -0,0 +1,43 @@
+.TH LFS-MIRROR-DUMP 1 2018-08-16 "Lustre" "Lustre Utilities"
+.SH NAME
+lfs mirror dump \- dump a mirror's content of a mirrored file
+.SH SYNOPSIS
+.B lfs mirror dump
+<\fB\-\-mirror-id|\-N\fR <\fImirror_id\fR>>
+[\fB\-\-outfile|\-o\fR <\fIoutput_file\fR>]
+<\fImirrored_file\fR>
+.SH DESCRIPTION
+This command dumps the content of a file's mirror, the file is specified by the
+path name \fImirrored_file\fR, the mirror is specified by its mirror ID
+\fImirror_id\fR.
+.br
+If an \fIoutput_file\fR is specified, the content will be written to the file,
+otherwise the standard output stream will be used.
+.SH OPTIONS
+.TP
+.BR \-\-mirror-id|\-N\fR\ <\fImirror_id\fR>
+This option indicates the content of which mirror specified by \fImirror_id\fR
+needs to be dumped. The \fImirror_id\fR is the numerical unique identifier for
+a mirror.
+.TP
+.BR \-\-outfile|\-o\fR\ <\fIoutput_file\fR>
+The path name of the output file, if not specified, the standard output stream
+will be used.
+.SH EXAMPLES
+.TP
+.B lfs mirror dump --mirror-id 3 /mnt/lustre/file1
+Dump the content of mirror with mirror ID 3 for /mnt/lustre/file1 to STDOUT.
+.TP
+.B lfs mirror dump -N 2 -o /tmp/m2 /mnt/lustre/file1
+Dump the content of mirror with mirror ID 2 for /mnt/lustre/file1 to file
+/tmp/m2.
+.SH AUTHOR
+The \fBlfs mirror dump\fR command is part of the Lustre filesystem.
+.SH SEE ALSO
+.BR lfs (1),
+.BR lfs-setstripe (1),
+.BR lfs-getstripe (1),
+.BR lfs-mirror-create (1),
+.BR lfs-mirror-extend (1),
+.BR lfs-mirror-split (1),
+.BR lfs-mirror-verify (1)
index e906140..bc00ee9 100644 (file)
@@ -1256,9 +1256,9 @@ test_37()
 
        # assume the mirror id will be 1, 2, and 3
        declare -A checksums
-       checksums[1]=$(md5sum $tf | cut -f 1 -d' ')
-       checksums[2]=$(md5sum $tf2 | cut -f 1 -d' ')
-       checksums[3]=$(md5sum $tf3 | cut -f 1 -d' ')
+       checksums[1]=$(cat $tf | md5sum)
+       checksums[2]=$(cat $tf2 | md5sum)
+       checksums[3]=$(cat $tf3 | md5sum)
 
        printf '%s\n' "${checksums[@]}"
 
@@ -1275,7 +1275,7 @@ test_37()
 
        local sum
        for i in ${mirror_array[@]}; do
-               sum=$(mirror_io dump -i $i $tf | md5sum | cut -f 1 -d' ')
+               sum=$($LFS mirror dump -N $i $tf | md5sum)
                [ "$sum" = "${checksums[$i]}" ] ||
                        error "$i: mismatch: \'${checksums[$i]}\' vs. \'$sum\'"
        done
@@ -1298,7 +1298,7 @@ test_37()
        # verify copying is successful by checking checksums
        remount_client $MOUNT
        for i in ${mirror_array[@]}; do
-               sum=$(mirror_io dump -i $i $tf | md5sum | cut -f 1 -d' ')
+               sum=$($LFS mirror dump -N $i $tf | md5sum)
                [ "$sum" = "${checksums[1]}" ] ||
                        error "$i: mismatch checksum after copy"
        done
@@ -1343,13 +1343,13 @@ test_38() {
        local fsize=$((RANDOM << 8 + 1048576))
        $TRUNCATE $ref $fsize
 
-       local ref_cksum=$(md5sum $ref | cut -f 1 -d' ')
+       local ref_cksum=$(cat $ref | md5sum)
 
        # case 1: verify write to mirrored file & resync work
        cp $ref $tf || error "copy from $ref to $f error"
        verify_flr_state $tf "wp"
 
-       local file_cksum=$(md5sum $tf | cut -f 1 -d' ')
+       local file_cksum=$(cat $tf | md5sum)
        [ "$file_cksum" = "$ref_cksum" ] || error "write failed, cksum mismatch"
 
        get_mirror_ids $tf
@@ -1357,8 +1357,7 @@ test_38() {
 
        local valid_mirror stale_mirror id mirror_cksum
        for id in "${mirror_array[@]}"; do
-               mirror_cksum=$(mirror_io dump -i $id $tf |
-                               md5sum | cut -f 1 -d' ')
+               mirror_cksum=$($LFS mirror dump -N $id $tf | md5sum)
                [ "$ref_cksum" == "$mirror_cksum" ] &&
                        { valid_mirror=$id; continue; }
 
@@ -1371,8 +1370,7 @@ test_38() {
        mirror_io resync $tf || error "resync failed"
        verify_flr_state $tf "ro"
 
-       mirror_cksum=$(mirror_io dump -i $stale_mirror $tf |
-                       md5sum | cut -f 1 -d' ')
+       mirror_cksum=$($LFS mirror dump -N $stale_mirror $tf | md5sum)
        [ "$file_cksum" = "$ref_cksum" ] || error "resync failed"
 
        # case 2: inject an error to make mirror_io exit after changing
@@ -1480,7 +1478,7 @@ test_41() {
        dd if=/dev/urandom of=$tf-1 bs=1M count=4 conv=notrunc ||
                error "writing $tf-1 failed"
 
-       local sum0=$(cat $tf-1 | md5sum | cut -f 1 -d' ')
+       local sum0=$(cat $tf-1 | md5sum)
 
        echo " **verify files be WRITE_PENDING"
        verify_flr_state $tf "wp"
@@ -1497,11 +1495,10 @@ test_41() {
        $LFS mirror resync $tf $tf-1 || error "mirror resync $tf $tf-1 failed"
 
        echo " **verify $tf-1 data consistency in all mirrors"
-       local sum
        for i in 1 2 3; do
-               sum=$(mirror_io dump -i $i $tf-1 | md5sum | cut -f 1 -d' ')
-               [ "$sum" = "$sum0" ] ||
-                       error "$i: mismatch: $sum vs. $sum0"
+               local sum=$($LFS mirror dump -N$i $tf-1 | md5sum)
+               [[ "$sum" = "$sum0" ]] ||
+                       error "$tf-1.$i: checksum mismatch: $sum != $sum0"
        done
 
        echo " **verify files be RDONLY"
@@ -2081,9 +2078,9 @@ test_200() {
        mirror_io resync $tf
        get_mirror_ids $tf
 
-       local csum=$(mirror_io dump -i ${mirror_array[0]} $tf | md5sum)
+       local csum=$($LFS mirror dump -N ${mirror_array[0]} $tf | md5sum)
        for id in ${mirror_array[@]:1}; do
-               [ "$(mirror_io dump -i $id $tf | md5sum)" = "$csum" ] ||
+               [ "$($LFS mirror dump -N $id $tf | md5sum)" = "$csum" ] ||
                        error "checksum error for mirror $id"
        done
 
index c142a3a..e86c86d 100644 (file)
@@ -124,6 +124,7 @@ static int lfs_mirror_list_commands(int argc, char **argv);
 static int lfs_list_commands(int argc, char **argv);
 static inline int lfs_mirror_resync(int argc, char **argv);
 static inline int lfs_mirror_verify(int argc, char **argv);
+static inline int lfs_mirror_dump(int argc, char **argv);
 
 enum setstripe_origin {
        SO_SETSTRIPE,
@@ -283,6 +284,10 @@ command_t mirror_cmdlist[] = {
        "\t             mirror will be stored into. If not specified,\n"
        "\t             a new file named <mirrored_file>.mirror~<mirror_id>\n"
        "\t             will be used.\n" },
+       { .pc_name = "dump", .pc_func = lfs_mirror_dump,
+         .pc_help = "Dump the content of a specified mirror of a file.\n"
+                 "usage: lfs mirror dump <--mirror-id|-N <mirror_id> "
+                 "[--outfile|-o <output_file>] <mirrored_file>\n" },
        { .pc_name = "resync", .pc_func = lfs_mirror_resync,
          .pc_help = "Resynchronizes out-of-sync mirrored file(s).\n"
                "usage: lfs mirror resync [--only <mirror_id[,...]>] "
@@ -581,6 +586,7 @@ command_t cmdlist[] = {
         "lfs mirror extend - add mirror(s) to an existing file\n"
         "lfs mirror split  - split a mirror from an existing mirrored file\n"
         "lfs mirror resync - resynchronize out-of-sync mirrored file(s)\n"
+        "lfs mirror dump   - dump a mirror content of a mirrored file\n"
         "lfs mirror verify - verify mirrored file(s)\n"},
        {"getsom", lfs_getsom, 0, "To list the SOM info for a given file.\n"
         "usage: getsom [-s] [-b] [-f] <path>\n"
@@ -8259,6 +8265,188 @@ error:
        return rc;
 }
 
+static inline int lfs_mirror_dump(int argc, char **argv)
+{
+       int rc = CMD_HELP;
+       __u16 mirror_id = 0;
+       const char *outfile = NULL;
+       char *fname;
+       struct stat stbuf;
+       int fd = 0;
+       struct llapi_layout *layout;
+       int outfd;
+       int c;
+       const size_t buflen = 4 << 20;
+       void *buf;
+       off_t pos;
+
+       struct option long_opts[] = {
+       { .val = 'N',   .name = "mirror-id",    .has_arg = required_argument },
+       { .val = 'o',   .name = "outfile",      .has_arg = required_argument },
+       { .name = NULL } };
+
+       while ((c = getopt_long(argc, argv, "N:o:", long_opts, NULL)) >= 0) {
+               char *end;
+
+               switch (c) {
+               case 'N':
+                       mirror_id = strtoul(optarg, &end, 0);
+                       if (*end != '\0' || mirror_id == 0) {
+                               fprintf(stderr,
+                                       "%s %s: invalid mirror ID '%s'\n",
+                                       progname, argv[0], optarg);
+                               return rc;
+                       }
+                       break;
+               case 'o':
+                       outfile = optarg;
+                       break;
+               }
+       }
+
+       if (argc == optind) {
+               fprintf(stderr, "%s %s: no mirrored file provided\n",
+                       progname, argv[0]);
+               return rc;
+       } else if (argc > optind + 1) {
+               fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
+               return rc;
+       }
+
+       if (mirror_id == 0) {
+               fprintf(stderr, "%s %s: no valid mirror ID is provided\n",
+                       progname, argv[0]);
+               return rc;
+       }
+
+       /* open mirror file */
+       fname = argv[optind];
+
+       if (stat(fname, &stbuf) < 0) {
+               fprintf(stderr, "%s %s: cannot stat file '%s': %s.\n",
+                       progname, argv[0], fname, strerror(errno));
+               return rc;
+       }
+
+       if (!S_ISREG(stbuf.st_mode)) {
+               fprintf(stderr, "%s %s: '%s' is not a regular file.\n",
+                       progname, argv[0], fname);
+               return rc;
+       }
+
+       fd = open(fname, O_DIRECT | O_RDONLY);
+       if (fd < 0) {
+               fprintf(stderr, "%s %s: cannot open '%s': %s.\n",
+                       progname, argv[0], fname, strerror(errno));
+               return rc;
+       }
+
+       /* verify mirror id */
+       layout = llapi_layout_get_by_fd(fd, 0);
+       if (layout == NULL) {
+               fprintf(stderr, "%s %s: could not get layout of file '%s'.\n",
+                       progname, argv[0], fname);
+               rc = -EINVAL;
+               goto close_fd;
+       }
+
+       rc = llapi_layout_comp_iterate(layout, find_mirror_id, &mirror_id);
+       if (rc < 0) {
+               fprintf(stderr, "%s %s: failed to iterate layout of '%s'.\n",
+                       progname, argv[0], fname);
+               llapi_layout_free(layout);
+               goto close_fd;
+       } else if (rc == LLAPI_LAYOUT_ITER_CONT) {
+               fprintf(stderr,
+                       "%s %s: file '%s' does not contain mirror with ID %u\n",
+                       progname, argv[0], fname, mirror_id);
+               llapi_layout_free(layout);
+
+               rc = -EINVAL;
+               goto close_fd;
+       }
+       llapi_layout_free(layout);
+
+       /* open output file */
+       if (outfile) {
+               outfd = open(outfile, O_EXCL | O_WRONLY | O_CREAT, 0644);
+               if (outfd < 0) {
+                       fprintf(stderr, "%s %s: cannot create file '%s':%s.\n",
+                               progname, argv[0], outfile, strerror(errno));
+                       rc = -errno;
+                       goto close_fd;
+               }
+       } else {
+               outfd = STDOUT_FILENO;
+       }
+
+       /* allocate buffer */
+       rc = posix_memalign(&buf, sysconf(_SC_PAGESIZE), buflen);
+       if (rc) {
+               fprintf(stderr, "%s %s: posix_memalign returns %d.\n",
+                               progname, argv[0], rc);
+               goto close_outfd;
+       }
+
+       pos = 0;
+       while (1) {
+               ssize_t bytes_read;
+               ssize_t written = 0;
+
+               bytes_read = llapi_mirror_read(fd, mirror_id, buf, buflen, pos);
+               if (bytes_read < 0) {
+                       rc = bytes_read;
+                       fprintf(stderr,
+                               "%s %s: fail to read data from mirror %u:%s.\n",
+                               progname, argv[0], mirror_id, strerror(-rc));
+                       goto free_buf;
+               }
+
+               /* EOF reached */
+               if (bytes_read == 0)
+                       break;
+
+               while (written < bytes_read) {
+                       ssize_t written2;
+
+                       written2 = write(outfd, buf + written,
+                                        bytes_read - written);
+                       if (written2 < 0) {
+                               fprintf(stderr,
+                                       "%s %s: fail to write %s:%s.\n",
+                                       progname, argv[0], outfile ? : "STDOUT",
+                                       strerror(errno));
+                               rc = -errno;
+                               goto free_buf;
+                       }
+                       written += written2;
+               }
+
+               if (written != bytes_read) {
+                       fprintf(stderr,
+               "%s %s: written %ld bytes does not match with %ld read.\n",
+                               progname, argv[0], written, bytes_read);
+                       rc = -EIO;
+                       goto free_buf;
+               }
+
+               pos += bytes_read;
+       }
+
+       fsync(outfd);
+       rc = 0;
+
+free_buf:
+       free(buf);
+close_outfd:
+       if (outfile)
+               close(outfd);
+close_fd:
+       close(fd);
+
+       return rc;
+}
+
 /**
  * struct verify_chunk - Mirror chunk to be verified.
  * @chunk:        [start, end) of the chunk.