]> granicus.if.org Git - zfs/commitdiff
OpenZFS 8067 - zdb should be able to dump literal embedded block pointer
authorMatthew Ahrens <mahrens@delphix.com>
Mon, 1 May 2017 18:06:07 +0000 (11:06 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Fri, 7 Jul 2017 18:28:01 +0000 (11:28 -0700)
Authored by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Alex Reece <alex@delphix.com>
Reviewed by: Yuri Pankov <yuri.pankov@gmail.com>
Approved by: Robert Mustacchi <rm@joyent.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Ported-by: Giuseppe Di Natale <dinatale2@llnl.gov>
OpenZFS-issue: https://www.illumos.org/issues/8067
OpenZFS-commit: https://github.com/openzfs/openzfs/commit/8173085
Closes #6319

cmd/zdb/zdb.c
include/sys/blkptr.h
man/man8/zdb.8
module/zfs/blkptr.c

index 6c4071060377d39327a342f329992184bd8af70d..55a6c4fa1bb1ca409cc0eb3bc31d8c62296e2e0e 100644 (file)
@@ -63,6 +63,7 @@
 #include <sys/ddt.h>
 #include <sys/zfeature.h>
 #include <sys/abd.h>
+#include <sys/blkptr.h>
 #include <zfs_comutil.h>
 #include <libzfs.h>
 
@@ -137,10 +138,11 @@ usage(void)
            "\t%s -O <dataset> <path>\n"
            "\t%s -R [-A] [-e [-V] [-p <path> ...]] [-U <cache>]\n"
            "\t\t<poolname> <vdev>:<offset>:<size>[:<flags>]\n"
+           "\t%s -E [-A] word0:word1:...:word15\n"
            "\t%s -S [-AP] [-e [-V] [-p <path> ...]] [-U <cache>] "
            "<poolname>\n\n",
            cmdname, cmdname, cmdname, cmdname, cmdname, cmdname, cmdname,
-           cmdname);
+           cmdname, cmdname);
 
        (void) fprintf(stderr, "    Dataset name must include at least one "
            "separator character '/' or '@'\n");
@@ -155,6 +157,8 @@ usage(void)
        (void) fprintf(stderr, "        -C config (or cachefile if alone)\n");
        (void) fprintf(stderr, "        -d dataset(s)\n");
        (void) fprintf(stderr, "        -D dedup statistics\n");
+       (void) fprintf(stderr, "        -E decode and display block from an "
+           "embedded block pointer\n");
        (void) fprintf(stderr, "        -h pool history\n");
        (void) fprintf(stderr, "        -i intent logs\n");
        (void) fprintf(stderr, "        -l read label contents\n");
@@ -4092,6 +4096,35 @@ out:
        free(dup);
 }
 
+static void
+zdb_embedded_block(char *thing)
+{
+       blkptr_t bp;
+       unsigned long long *words = (void *)&bp;
+       char buf[SPA_MAXBLOCKSIZE];
+       int err;
+
+       memset(&bp, 0, sizeof (blkptr_t));
+
+       err = sscanf(thing, "%llx:%llx:%llx:%llx:%llx:%llx:%llx:%llx:"
+           "%llx:%llx:%llx:%llx:%llx:%llx:%llx:%llx",
+           words + 0, words + 1, words + 2, words + 3,
+           words + 4, words + 5, words + 6, words + 7,
+           words + 8, words + 9, words + 10, words + 11,
+           words + 12, words + 13, words + 14, words + 15);
+       if (err != 16) {
+               (void) printf("invalid input format\n");
+               exit(1);
+       }
+       ASSERT3U(BPE_GET_LSIZE(&bp), <=, SPA_MAXBLOCKSIZE);
+       err = decode_embedded_bp(&bp, buf, BPE_GET_LSIZE(&bp));
+       if (err != 0) {
+               (void) printf("decode failed: %u\n", err);
+               exit(1);
+       }
+       zdb_dump_block_raw(buf, BPE_GET_LSIZE(&bp), 0);
+}
+
 static boolean_t
 pool_match(nvlist_t *cfg, char *tgt)
 {
@@ -4210,13 +4243,14 @@ main(int argc, char **argv)
                spa_config_path = spa_config_path_env;
 
        while ((c = getopt(argc, argv,
-           "AbcCdDeFGhiI:lLmMo:Op:PqRsSt:uU:vVx:X")) != -1) {
+           "AbcCdDeEFGhiI:lLmMo:Op:PqRsSt:uU:vVx:X")) != -1) {
                switch (c) {
                case 'b':
                case 'c':
                case 'C':
                case 'd':
                case 'D':
+               case 'E':
                case 'G':
                case 'h':
                case 'i':
@@ -4280,6 +4314,12 @@ main(int argc, char **argv)
                        break;
                case 'U':
                        spa_config_path = optarg;
+                       if (spa_config_path[0] != '/') {
+                               (void) fprintf(stderr,
+                                   "cachefile must be an absolute path "
+                                   "(i.e. start with a slash)\n");
+                               usage();
+                       }
                        break;
                case 'v':
                        verbose++;
@@ -4331,7 +4371,7 @@ main(int argc, char **argv)
                verbose = MAX(verbose, 1);
 
        for (c = 0; c < 256; c++) {
-               if (dump_all && strchr("AeFlLOPRSX", c) == NULL)
+               if (dump_all && strchr("AeEFlLOPRSX", c) == NULL)
                        dump_opt[c] = 1;
                if (dump_opt[c])
                        dump_opt[c] += verbose;
@@ -4345,6 +4385,14 @@ main(int argc, char **argv)
 
        if (argc < 2 && dump_opt['R'])
                usage();
+
+       if (dump_opt['E']) {
+               if (argc != 1)
+                       usage();
+               zdb_embedded_block(argv[0]);
+               return (0);
+       }
+
        if (argc < 1) {
                if (!dump_opt['e'] && dump_opt['C']) {
                        dump_cachefile(spa_config_path);
index b720482a73fedda22cc08dc2a98af5eda4d587e8..77b1b827ac375f281ed5ec82bbfd877c10619eb8 100644 (file)
@@ -30,6 +30,7 @@ extern "C" {
 void encode_embedded_bp_compressed(blkptr_t *, void *,
     enum zio_compress, int, int);
 void decode_embedded_bp_compressed(const blkptr_t *, void *);
+int decode_embedded_bp(const blkptr_t *, void *, int);
 
 #ifdef __cplusplus
 }
index c899db39571945a5be6cee0db8ddb075c57e9480..4e47de7bef8d031e8f34b2c180fca93c9988627b 100644 (file)
 .\"
 .\"
 .\" Copyright 2012, Richard Lowe.
-.\" Copyright (c) 2012, 2016 by Delphix. All rights reserved.
+.\" Copyright (c) 2012, 2017 by Delphix. All rights reserved.
 .\" Copyright 2017 Nexenta Systems, Inc.
 .\" Copyright (c) 2017 Lawrence Livermore National Security, LLC.
 .\" Copyright (c) 2017 Intel Corporation.
 .\"
-.Dd April 11, 2017
+.Dd April 14, 2017
 .Dt ZDB 8 SMM
 .Os Linux
 .Sh NAME
 .Op Fl A
 .Op Fl U Ar cache
 .Nm
+.Fl E
+.Op Fl A
+.Ar word0 Ns : Ns Ar word1 Ns :...: Ns Ar word15
+.Nm
 .Fl l
 .Op Fl Aqu
 .Ar device
@@ -155,6 +159,10 @@ Display the statistics independently for each deduplication table.
 Dump the contents of the deduplication tables describing duplicate blocks.
 .It Fl DDDDD
 Also dump the contents of the deduplication tables describing unique blocks.
+.It Fl E Ar word0 Ns : Ns Ar word1 Ns :...: Ns Ar word15
+Decode and display block from an embedded block pointer specified by the
+.Ar word
+arguments.
 .It Fl h
 Display pool history similar to
 .Nm zpool Cm history ,
index 99accfa0fe8a8a12e3bb78e319cfdfdf3e03b4a9..bb407af03fec1a93453aeb97a2511e255638cdbd 100644 (file)
@@ -119,3 +119,36 @@ decode_embedded_bp_compressed(const blkptr_t *bp, void *buf)
                buf8[i] = BF64_GET(w, (i % sizeof (w)) * NBBY, NBBY);
        }
 }
+
+/*
+ * Fill in the buffer with the (decompressed) payload of the embedded
+ * blkptr_t.  Takes into account compression and byteorder (the payload is
+ * treated as a stream of bytes).
+ * Return 0 on success, or ENOSPC if it won't fit in the buffer.
+ */
+int
+decode_embedded_bp(const blkptr_t *bp, void *buf, int buflen)
+{
+       int lsize, psize;
+
+       ASSERT(BP_IS_EMBEDDED(bp));
+
+       lsize = BPE_GET_LSIZE(bp);
+       psize = BPE_GET_PSIZE(bp);
+
+       if (lsize > buflen)
+               return (ENOSPC);
+       ASSERT3U(lsize, ==, buflen);
+
+       if (BP_GET_COMPRESS(bp) != ZIO_COMPRESS_OFF) {
+               uint8_t dstbuf[BPE_PAYLOAD_SIZE];
+               decode_embedded_bp_compressed(bp, dstbuf);
+               VERIFY0(zio_decompress_data_buf(BP_GET_COMPRESS(bp),
+                   dstbuf, buf, psize, buflen));
+       } else {
+               ASSERT3U(lsize, ==, psize);
+               decode_embedded_bp_compressed(bp, buf);
+       }
+
+       return (0);
+}