From a5905b2a2c478f638420db9a002f2055fce3d5e2 Mon Sep 17 00:00:00 2001 From: Bobi Jam Date: Tue, 14 Aug 2018 12:53:15 +0800 Subject: [PATCH] LU-11245 flr: lfs mirror dump command Adds "lfs mirror dump" command to dump a mirror's content of a mirrored file. Usage: lfs mirror dump <-N|--mirror-id > [-o|--outfile ] Options: --mirror-id Specify the mirror by mirror_id to dump its content. --outfile 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 Change-Id: I2846b1c1968d9cc302c07b57a05687af50530d53 Reviewed-on: https://review.whamcloud.com/32997 Reviewed-by: Andreas Dilger Reviewed-by: Jinshan Xiong Tested-by: Jenkins Tested-by: Maloo Reviewed-by: Oleg Drokin --- lustre/doc/lfs-mirror-dump.1 | 43 ++++++++++ lustre/tests/sanity-flr.sh | 33 ++++---- lustre/utils/lfs.c | 188 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 246 insertions(+), 18 deletions(-) create mode 100644 lustre/doc/lfs-mirror-dump.1 diff --git a/lustre/doc/lfs-mirror-dump.1 b/lustre/doc/lfs-mirror-dump.1 new file mode 100644 index 0000000..becc796 --- /dev/null +++ b/lustre/doc/lfs-mirror-dump.1 @@ -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) diff --git a/lustre/tests/sanity-flr.sh b/lustre/tests/sanity-flr.sh index e906140..bc00ee9 100644 --- a/lustre/tests/sanity-flr.sh +++ b/lustre/tests/sanity-flr.sh @@ -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 diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index c142a3a..e86c86d 100644 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -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 .mirror~\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 " + "[--outfile|-o ] \n" }, { .pc_name = "resync", .pc_func = lfs_mirror_resync, .pc_help = "Resynchronizes out-of-sync mirrored file(s).\n" "usage: lfs mirror resync [--only ] " @@ -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] \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. -- 1.8.3.1