diff --git a/cddl/contrib/opensolaris/cmd/zdb/zdb.c b/cddl/contrib/opensolaris/cmd/zdb/zdb.c index 64506d39e81f..baa8a51b5364 100644 --- a/cddl/contrib/opensolaris/cmd/zdb/zdb.c +++ b/cddl/contrib/opensolaris/cmd/zdb/zdb.c @@ -61,6 +61,7 @@ #include #include #include +#include #include #undef verify #include @@ -134,10 +135,11 @@ usage(void) "\t%s -O \n" "\t%s -R [-A] [-e [-V] [-p ...]] [-U ]\n" "\t\t ::[:]\n" + "\t%s -E [-A] word0:word1:...:word15\n" "\t%s -S [-AP] [-e [-V] [-p ...]] [-U ] " "\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"); @@ -152,6 +154,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"); @@ -3653,6 +3657,33 @@ zdb_read_block(char *thing, spa_t *spa) free(dup); } +static void +zdb_embedded_block(char *thing) +{ + blkptr_t bp = { 0 }; + unsigned long long *words = (void *)&bp; + char buf[SPA_MAXBLOCKSIZE]; + int err; + + 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) { @@ -3771,13 +3802,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': @@ -3841,6 +3873,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++; @@ -3889,7 +3927,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; @@ -3903,6 +3941,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); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/blkptr.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/blkptr.c index ff93ff445691..d7a7fdb0e1b1 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/blkptr.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/blkptr.c @@ -117,3 +117,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); +} diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/blkptr.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/blkptr.h index b720482a73fe..77b1b827ac37 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/blkptr.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/blkptr.h @@ -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 }