]> git.proxmox.com Git - mirror_zfs.git/blobdiff - cmd/zdb/zdb.c
Fix zdb -R decompression
[mirror_zfs.git] / cmd / zdb / zdb.c
index 13d0bcf0e5f1eeb90fd27cdbef36b54fac82b198..4c0a8245fb9e4ceea70e6b45e29f7417aed6bf2d 100644 (file)
 #include <sys/ddt.h>
 #include <sys/zfeature.h>
 #include <sys/abd.h>
+#include <sys/blkptr.h>
+#include <sys/dsl_crypt.h>
 #include <zfs_comutil.h>
 #include <libzfs.h>
 
+#include "zdb.h"
+
 #define        ZDB_COMPRESS_NAME(idx) ((idx) < ZIO_COMPRESS_FUNCTIONS ?        \
        zio_compress_table[(idx)].ci_name : "UNKNOWN")
 #define        ZDB_CHECKSUM_NAME(idx) ((idx) < ZIO_CHECKSUM_FUNCTIONS ?        \
@@ -91,14 +95,13 @@ extern int zfs_recover;
 extern uint64_t zfs_arc_max, zfs_arc_meta_limit;
 extern int zfs_vdev_async_read_max_active;
 
-const char cmdname[] = "zdb";
+static const char cmdname[] = "zdb";
 uint8_t dump_opt[256];
 
 typedef void object_viewer_t(objset_t *, uint64_t, void *data, size_t size);
 
-extern void dump_intent_log(zilog_t *);
 uint64_t *zopt_object = NULL;
-int zopt_objects = 0;
+static unsigned zopt_objects = 0;
 libzfs_handle_t *g_zfs;
 uint64_t max_inflight = 1000;
 
@@ -124,22 +127,24 @@ static void
 usage(void)
 {
        (void) fprintf(stderr,
-           "Usage:\t%s [-AbcdDFGhiLMPsvVX] [-e [-p <path> ...]] "
+           "Usage:\t%s [-AbcdDFGhiLMPsvX] [-e [-V] [-p <path> ...]] "
            "[-I <inflight I/Os>]\n"
            "\t\t[-o <var>=<value>]... [-t <txg>] [-U <cache>] [-x <dumpdir>]\n"
            "\t\t[<poolname> [<object> ...]]\n"
-           "\t%s [-AdiPv] [-e [-p <path> ...]] [-U <cache>] <dataset> "
-           "[<object> ...]\n"
+           "\t%s [-AdiPv] [-e [-V] [-p <path> ...]] [-U <cache>] <dataset>\n"
+           "\t\t[<object> ...]\n"
            "\t%s -C [-A] [-U <cache>]\n"
            "\t%s -l [-Aqu] <device>\n"
-           "\t%s -m [-AFLPX] [-e [-p <path> ...]] [-t <txg>] [-U <cache>]\n"
-           "\t\t<poolname> [<vdev> [<metaslab> ...]]\n"
+           "\t%s -m [-AFLPX] [-e [-V] [-p <path> ...]] [-t <txg>] "
+           "[-U <cache>]\n\t\t<poolname> [<vdev> [<metaslab> ...]]\n"
            "\t%s -O <dataset> <path>\n"
-           "\t%s -R [-A] [-e [-p <path> ...]] [-U <cache>]\n"
+           "\t%s -R [-A] [-e [-V] [-p <path> ...]] [-U <cache>]\n"
            "\t\t<poolname> <vdev>:<offset>:<size>[:<flags>]\n"
-           "\t%s -S [-AP] [-e [-p <path> ...]] [-U <cache>] <poolname>\n\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");
@@ -154,6 +159,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");
@@ -192,12 +199,11 @@ usage(void)
        (void) fprintf(stderr, "        -u uberblock\n");
        (void) fprintf(stderr, "        -U <cachefile_path> -- use alternate "
            "cachefile\n");
+       (void) fprintf(stderr, "        -V do verbatim import\n");
        (void) fprintf(stderr, "        -x <dumpdir> -- "
            "dump all read blocks into specified directory\n");
        (void) fprintf(stderr, "        -X attempt extreme rewind (does not "
            "work with dataset)\n");
-       (void) fprintf(stderr, "        -V verbatim import (as if it had been "
-           "loaded at boot)\n\n");
        (void) fprintf(stderr, "Specify an option more than once (e.g. -bb) "
            "to make only that option verbose\n");
        (void) fprintf(stderr, "Default is to dump everything non-verbosely\n");
@@ -275,16 +281,16 @@ dump_history_offsets(objset_t *os, uint64_t object, void *data, size_t size)
 }
 
 static void
-zdb_nicenum(uint64_t num, char *buf)
+zdb_nicenum(uint64_t num, char *buf, size_t buflen)
 {
        if (dump_opt['P'])
-               (void) sprintf(buf, "%llu", (longlong_t)num);
+               (void) snprintf(buf, buflen, "%llu", (longlong_t)num);
        else
-               nicenum(num, buf);
+               nicenum(num, buf, sizeof (buf));
 }
 
-const char histo_stars[] = "****************************************";
-const int histo_width = sizeof (histo_stars) - 1;
+static const char histo_stars[] = "****************************************";
+static const uint64_t histo_width = sizeof (histo_stars) - 1;
 
 static void
 dump_histogram(const uint64_t *histo, int size, int offset)
@@ -390,7 +396,7 @@ dump_unknown(objset_t *os, uint64_t object, void *data, size_t size)
 }
 
 /*ARGSUSED*/
-void
+static void
 dump_uint8(objset_t *os, uint64_t object, void *data, size_t size)
 {
 }
@@ -408,7 +414,7 @@ dump_zap(objset_t *os, uint64_t object, void *data, size_t size)
        zap_cursor_t zc;
        zap_attribute_t attr;
        void *prop;
-       int i;
+       unsigned i;
 
        dump_zap_stats(os, object);
        (void) printf("\n");
@@ -458,12 +464,17 @@ dump_bpobj(objset_t *os, uint64_t object, void *data, size_t size)
        uint64_t i;
        char bytes[32], comp[32], uncomp[32];
 
+       /* make sure the output won't get truncated */
+       CTASSERT(sizeof (bytes) >= NN_NUMBUF_SZ);
+       CTASSERT(sizeof (comp) >= NN_NUMBUF_SZ);
+       CTASSERT(sizeof (uncomp) >= NN_NUMBUF_SZ);
+
        if (bpop == NULL)
                return;
 
-       zdb_nicenum(bpop->bpo_bytes, bytes);
-       zdb_nicenum(bpop->bpo_comp, comp);
-       zdb_nicenum(bpop->bpo_uncomp, uncomp);
+       zdb_nicenum(bpop->bpo_bytes, bytes, sizeof (bytes));
+       zdb_nicenum(bpop->bpo_comp, comp, sizeof (comp));
+       zdb_nicenum(bpop->bpo_uncomp, uncomp, sizeof (uncomp));
 
        (void) printf("\t\tnum_blkptrs = %llu\n",
            (u_longlong_t)bpop->bpo_num_blkptrs);
@@ -568,7 +579,7 @@ dump_sa_layouts(objset_t *os, uint64_t object, void *data, size_t size)
        zap_cursor_t zc;
        zap_attribute_t attr;
        uint16_t *layout_attrs;
-       int i;
+       unsigned i;
 
        dump_zap_stats(os, object);
        (void) printf("\n");
@@ -637,11 +648,10 @@ dump_zpldir(objset_t *os, uint64_t object, void *data, size_t size)
        zap_cursor_fini(&zc);
 }
 
-int
+static int
 get_dtl_refcount(vdev_t *vd)
 {
        int refcount = 0;
-       int c;
 
        if (vd->vdev_ops->vdev_op_leaf) {
                space_map_t *sm = vd->vdev_dtl_sm;
@@ -652,19 +662,18 @@ get_dtl_refcount(vdev_t *vd)
                return (0);
        }
 
-       for (c = 0; c < vd->vdev_children; c++)
+       for (unsigned c = 0; c < vd->vdev_children; c++)
                refcount += get_dtl_refcount(vd->vdev_child[c]);
        return (refcount);
 }
 
-int
+static int
 get_metaslab_refcount(vdev_t *vd)
 {
        int refcount = 0;
-       int c, m;
 
        if (vd->vdev_top == vd && !vd->vdev_removing) {
-               for (m = 0; m < vd->vdev_ms_count; m++) {
+               for (unsigned m = 0; m < vd->vdev_ms_count; m++) {
                        space_map_t *sm = vd->vdev_ms[m]->ms_sm;
 
                        if (sm != NULL &&
@@ -672,7 +681,7 @@ get_metaslab_refcount(vdev_t *vd)
                                refcount++;
                }
        }
-       for (c = 0; c < vd->vdev_children; c++)
+       for (unsigned c = 0; c < vd->vdev_children; c++)
                refcount += get_metaslab_refcount(vd->vdev_child[c]);
 
        return (refcount);
@@ -704,7 +713,7 @@ static void
 dump_spacemap(objset_t *os, space_map_t *sm)
 {
        uint64_t alloc, offset, entry;
-       char *ddata[] = { "ALLOC", "FREE", "CONDENSE", "INVALID",
+       const char *ddata[] = { "ALLOC", "FREE", "CONDENSE", "INVALID",
                            "INVALID", "INVALID", "INVALID", "INVALID" };
 
        if (sm == NULL)
@@ -759,7 +768,10 @@ dump_metaslab_stats(metaslab_t *msp)
        avl_tree_t *t = &msp->ms_size_tree;
        int free_pct = range_tree_space(rt) * 100 / msp->ms_size;
 
-       zdb_nicenum(metaslab_block_maxsize(msp), maxbuf);
+       /* max sure nicenum has enough space */
+       CTASSERT(sizeof (maxbuf) >= NN_NUMBUF_SZ);
+
+       zdb_nicenum(metaslab_block_maxsize(msp), maxbuf, sizeof (maxbuf));
 
        (void) printf("\t %25s %10lu   %7s  %6s   %4s %4d%%\n",
            "segments", avl_numnodes(t), "maxsize", maxbuf,
@@ -776,7 +788,8 @@ dump_metaslab(metaslab_t *msp)
        space_map_t *sm = msp->ms_sm;
        char freebuf[32];
 
-       zdb_nicenum(msp->ms_size - space_map_allocated(sm), freebuf);
+       zdb_nicenum(msp->ms_size - space_map_allocated(sm), freebuf,
+           sizeof (freebuf));
 
        (void) printf(
            "\tmetaslab %6llu   offset %12llx   spacemap %6llu   free    %5s\n",
@@ -834,11 +847,10 @@ dump_metaslab_groups(spa_t *spa)
        vdev_t *rvd = spa->spa_root_vdev;
        metaslab_class_t *mc = spa_normal_class(spa);
        uint64_t fragmentation;
-       int c;
 
        metaslab_class_histogram_verify(mc);
 
-       for (c = 0; c < rvd->vdev_children; c++) {
+       for (unsigned c = 0; c < rvd->vdev_children; c++) {
                vdev_t *tvd = rvd->vdev_child[c];
                metaslab_group_t *mg = tvd->vdev_mg;
 
@@ -917,7 +929,7 @@ dump_dde(const ddt_t *ddt, const ddt_entry_t *dde, uint64_t index)
 {
        const ddt_phys_t *ddp = dde->dde_phys;
        const ddt_key_t *ddk = &dde->dde_key;
-       char *types[4] = { "ditto", "single", "double", "triple" };
+       const char *types[4] = { "ditto", "single", "double", "triple" };
        char blkbuf[BP_SPRINTF_LEN];
        blkptr_t blk;
        int p;
@@ -1013,17 +1025,14 @@ dump_all_ddts(spa_t *spa)
 {
        ddt_histogram_t ddh_total;
        ddt_stat_t dds_total;
-       enum zio_checksum c;
-       enum ddt_type type;
-       enum ddt_class class;
 
-       bzero(&ddh_total, sizeof (ddt_histogram_t));
-       bzero(&dds_total, sizeof (ddt_stat_t));
+       bzero(&ddh_total, sizeof (ddh_total));
+       bzero(&dds_total, sizeof (dds_total));
 
-       for (c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) {
+       for (enum zio_checksum c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) {
                ddt_t *ddt = spa->spa_ddt[c];
-               for (type = 0; type < DDT_TYPES; type++) {
-                       for (class = 0; class < DDT_CLASSES;
+               for (enum ddt_type type = 0; type < DDT_TYPES; type++) {
+                       for (enum ddt_class class = 0; class < DDT_CLASSES;
                            class++) {
                                dump_ddt(ddt, type, class);
                        }
@@ -1065,9 +1074,9 @@ dump_dtl(vdev_t *vd, int indent)
 {
        spa_t *spa = vd->vdev_spa;
        boolean_t required;
-       char *name[DTL_TYPES] = { "missing", "partial", "scrub", "outage" };
+       const char *name[DTL_TYPES] = { "missing", "partial", "scrub",
+               "outage" };
        char prefix[256];
-       int c, t;
 
        spa_vdev_state_enter(spa, SCL_NONE);
        required = vdev_dtl_required(vd);
@@ -1081,7 +1090,7 @@ dump_dtl(vdev_t *vd, int indent)
            vd->vdev_parent ? vd->vdev_ops->vdev_op_type : spa_name(spa),
            required ? "DTL-required" : "DTL-expendable");
 
-       for (t = 0; t < DTL_TYPES; t++) {
+       for (int t = 0; t < DTL_TYPES; t++) {
                range_tree_t *rt = vd->vdev_dtl[t];
                if (range_tree_space(rt) == 0)
                        continue;
@@ -1095,7 +1104,7 @@ dump_dtl(vdev_t *vd, int indent)
                            vd->vdev_dtl_sm);
        }
 
-       for (c = 0; c < vd->vdev_children; c++)
+       for (unsigned c = 0; c < vd->vdev_children; c++)
                dump_dtl(vd->vdev_child[c], indent + 4);
 }
 
@@ -1111,7 +1120,6 @@ dump_history(spa_t *spa)
        struct tm t;
        char tbuf[30];
        char internalstr[MAXPATHLEN];
-       int i;
 
        if ((buf = malloc(SPA_OLD_MAXBLOCKSIZE)) == NULL) {
                (void) fprintf(stderr, "%s: unable to allocate I/O buffer\n",
@@ -1136,7 +1144,7 @@ dump_history(spa_t *spa)
        } while (len != 0);
 
        (void) printf("\nHistory:\n");
-       for (i = 0; i < num; i++) {
+       for (unsigned i = 0; i < num; i++) {
                uint64_t time, txg, ievent;
                char *cmd, *intstr;
                boolean_t printed = B_FALSE;
@@ -1355,6 +1363,9 @@ dump_dsl_dir(objset_t *os, uint64_t object, void *data, size_t size)
        time_t crtime;
        char nice[32];
 
+       /* make sure nicenum has enough space */
+       CTASSERT(sizeof (nice) >= NN_NUMBUF_SZ);
+
        if (dd == NULL)
                return;
 
@@ -1370,15 +1381,15 @@ dump_dsl_dir(objset_t *os, uint64_t object, void *data, size_t size)
            (u_longlong_t)dd->dd_origin_obj);
        (void) printf("\t\tchild_dir_zapobj = %llu\n",
            (u_longlong_t)dd->dd_child_dir_zapobj);
-       zdb_nicenum(dd->dd_used_bytes, nice);
+       zdb_nicenum(dd->dd_used_bytes, nice, sizeof (nice));
        (void) printf("\t\tused_bytes = %s\n", nice);
-       zdb_nicenum(dd->dd_compressed_bytes, nice);
+       zdb_nicenum(dd->dd_compressed_bytes, nice, sizeof (nice));
        (void) printf("\t\tcompressed_bytes = %s\n", nice);
-       zdb_nicenum(dd->dd_uncompressed_bytes, nice);
+       zdb_nicenum(dd->dd_uncompressed_bytes, nice, sizeof (nice));
        (void) printf("\t\tuncompressed_bytes = %s\n", nice);
-       zdb_nicenum(dd->dd_quota, nice);
+       zdb_nicenum(dd->dd_quota, nice, sizeof (nice));
        (void) printf("\t\tquota = %s\n", nice);
-       zdb_nicenum(dd->dd_reserved, nice);
+       zdb_nicenum(dd->dd_reserved, nice, sizeof (nice));
        (void) printf("\t\treserved = %s\n", nice);
        (void) printf("\t\tprops_zapobj = %llu\n",
            (u_longlong_t)dd->dd_props_zapobj);
@@ -1388,7 +1399,8 @@ dump_dsl_dir(objset_t *os, uint64_t object, void *data, size_t size)
            (u_longlong_t)dd->dd_flags);
 
 #define        DO(which) \
-       zdb_nicenum(dd->dd_used_breakdown[DD_USED_ ## which], nice); \
+       zdb_nicenum(dd->dd_used_breakdown[DD_USED_ ## which], nice, \
+           sizeof (nice)); \
        (void) printf("\t\tused_breakdown[" #which "] = %s\n", nice)
        DO(HEAD);
        DO(SNAP);
@@ -1407,15 +1419,22 @@ dump_dsl_dataset(objset_t *os, uint64_t object, void *data, size_t size)
        char used[32], compressed[32], uncompressed[32], unique[32];
        char blkbuf[BP_SPRINTF_LEN];
 
+       /* make sure nicenum has enough space */
+       CTASSERT(sizeof (used) >= NN_NUMBUF_SZ);
+       CTASSERT(sizeof (compressed) >= NN_NUMBUF_SZ);
+       CTASSERT(sizeof (uncompressed) >= NN_NUMBUF_SZ);
+       CTASSERT(sizeof (unique) >= NN_NUMBUF_SZ);
+
        if (ds == NULL)
                return;
 
        ASSERT(size == sizeof (*ds));
        crtime = ds->ds_creation_time;
-       zdb_nicenum(ds->ds_referenced_bytes, used);
-       zdb_nicenum(ds->ds_compressed_bytes, compressed);
-       zdb_nicenum(ds->ds_uncompressed_bytes, uncompressed);
-       zdb_nicenum(ds->ds_unique_bytes, unique);
+       zdb_nicenum(ds->ds_referenced_bytes, used, sizeof (used));
+       zdb_nicenum(ds->ds_compressed_bytes, compressed, sizeof (compressed));
+       zdb_nicenum(ds->ds_uncompressed_bytes, uncompressed,
+           sizeof (uncompressed));
+       zdb_nicenum(ds->ds_unique_bytes, unique, sizeof (unique));
        snprintf_blkptr(blkbuf, sizeof (blkbuf), &ds->ds_bp);
 
        (void) printf("\t\tdir_obj = %llu\n",
@@ -1468,18 +1487,21 @@ dump_bptree_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
 }
 
 static void
-dump_bptree(objset_t *os, uint64_t obj, char *name)
+dump_bptree(objset_t *os, uint64_t obj, const char *name)
 {
        char bytes[32];
        bptree_phys_t *bt;
        dmu_buf_t *db;
 
+       /* make sure nicenum has enough space */
+       CTASSERT(sizeof (bytes) >= NN_NUMBUF_SZ);
+
        if (dump_opt['d'] < 3)
                return;
 
        VERIFY3U(0, ==, dmu_bonus_hold(os, obj, FTAG, &db));
        bt = db->db_data;
-       zdb_nicenum(bt->bt_bytes, bytes);
+       zdb_nicenum(bt->bt_bytes, bytes, sizeof (bytes));
        (void) printf("\n    %s: %llu datasets, %s\n",
            name, (unsigned long long)(bt->bt_end - bt->bt_begin), bytes);
        dmu_buf_rele(db, FTAG);
@@ -1505,20 +1527,25 @@ dump_bpobj_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
 }
 
 static void
-dump_full_bpobj(bpobj_t *bpo, char *name, int indent)
+dump_full_bpobj(bpobj_t *bpo, const char *name, int indent)
 {
        char bytes[32];
        char comp[32];
        char uncomp[32];
        uint64_t i;
 
+       /* make sure nicenum has enough space */
+       CTASSERT(sizeof (bytes) >= NN_NUMBUF_SZ);
+       CTASSERT(sizeof (comp) >= NN_NUMBUF_SZ);
+       CTASSERT(sizeof (uncomp) >= NN_NUMBUF_SZ);
+
        if (dump_opt['d'] < 3)
                return;
 
-       zdb_nicenum(bpo->bpo_phys->bpo_bytes, bytes);
+       zdb_nicenum(bpo->bpo_phys->bpo_bytes, bytes, sizeof (bytes));
        if (bpo->bpo_havesubobj && bpo->bpo_phys->bpo_subobjs != 0) {
-               zdb_nicenum(bpo->bpo_phys->bpo_comp, comp);
-               zdb_nicenum(bpo->bpo_phys->bpo_uncomp, uncomp);
+               zdb_nicenum(bpo->bpo_phys->bpo_comp, comp, sizeof (comp));
+               zdb_nicenum(bpo->bpo_phys->bpo_uncomp, uncomp, sizeof (uncomp));
                (void) printf("    %*s: object %llu, %llu local blkptrs, "
                    "%llu subobjs in object, %llu, %s (%s/%s comp)\n",
                    indent * 8, name,
@@ -1572,6 +1599,11 @@ dump_deadlist(dsl_deadlist_t *dl)
        char comp[32];
        char uncomp[32];
 
+       /* make sure nicenum has enough space */
+       CTASSERT(sizeof (bytes) >= NN_NUMBUF_SZ);
+       CTASSERT(sizeof (comp) >= NN_NUMBUF_SZ);
+       CTASSERT(sizeof (uncomp) >= NN_NUMBUF_SZ);
+
        if (dump_opt['d'] < 3)
                return;
 
@@ -1580,9 +1612,9 @@ dump_deadlist(dsl_deadlist_t *dl)
                return;
        }
 
-       zdb_nicenum(dl->dl_phys->dl_used, bytes);
-       zdb_nicenum(dl->dl_phys->dl_comp, comp);
-       zdb_nicenum(dl->dl_phys->dl_uncomp, uncomp);
+       zdb_nicenum(dl->dl_phys->dl_used, bytes, sizeof (bytes));
+       zdb_nicenum(dl->dl_phys->dl_comp, comp, sizeof (comp));
+       zdb_nicenum(dl->dl_phys->dl_uncomp, uncomp, sizeof (uncomp));
        (void) printf("\n    Deadlist: %s (%s/%s comp)\n",
            bytes, comp, uncomp);
 
@@ -1627,14 +1659,14 @@ open_objset(const char *path, dmu_objset_type_t type, void *tag, objset_t **osp)
        uint64_t version = 0;
 
        VERIFY3P(sa_os, ==, NULL);
-       err = dmu_objset_own(path, type, B_TRUE, tag, osp);
+       err = dmu_objset_own(path, type, B_TRUE, B_FALSE, tag, osp);
        if (err != 0) {
                (void) fprintf(stderr, "failed to own dataset '%s': %s\n", path,
                    strerror(err));
                return (err);
        }
 
-       if (dmu_objset_type(*osp) == DMU_OST_ZFS) {
+       if (dmu_objset_type(*osp) == DMU_OST_ZFS && !(*osp)->os_encrypted) {
                (void) zap_lookup(*osp, MASTER_NODE_OBJ, ZPL_VERSION_STR,
                    8, 1, &version);
                if (version >= ZPL_VERSION_SA) {
@@ -1646,7 +1678,7 @@ open_objset(const char *path, dmu_objset_type_t type, void *tag, objset_t **osp)
                if (err != 0) {
                        (void) fprintf(stderr, "sa_setup failed: %s\n",
                            strerror(err));
-                       dmu_objset_disown(*osp, tag);
+                       dmu_objset_disown(*osp, B_FALSE, tag);
                        *osp = NULL;
                }
        }
@@ -1661,7 +1693,7 @@ close_objset(objset_t *os, void *tag)
        VERIFY3P(os, ==, sa_os);
        if (os->os_sa != NULL)
                sa_tear_down(os);
-       dmu_objset_disown(os, tag);
+       dmu_objset_disown(os, B_FALSE, tag);
        sa_attr_table = NULL;
        sa_os = NULL;
 }
@@ -1824,23 +1856,19 @@ dump_znode(objset_t *os, uint64_t object, void *data, size_t size)
                return;
        }
 
-       error = zfs_obj_to_path(os, object, path, sizeof (path));
-       if (error != 0) {
-               (void) snprintf(path, sizeof (path), "\?\?\?<object#%llu>",
-                   (u_longlong_t)object);
-       }
-       if (dump_opt['d'] < 3) {
-               (void) printf("\t%s\n", path);
-               (void) sa_handle_destroy(hdl);
-               return;
-       }
-
        z_crtime = (time_t)crtm[0];
        z_atime = (time_t)acctm[0];
        z_mtime = (time_t)modtm[0];
        z_ctime = (time_t)chgtm[0];
 
-       (void) printf("\tpath   %s\n", path);
+       if (dump_opt['d'] > 4) {
+               error = zfs_obj_to_path(os, object, path, sizeof (path));
+               if (error != 0) {
+                       (void) snprintf(path, sizeof (path),
+                           "\?\?\?<object#%llu>", (u_longlong_t)object);
+               }
+               (void) printf("\tpath   %s\n", path);
+       }
        dump_uidgid(os, uid, gid);
        (void) printf("\tatime  %s", ctime(&z_atime));
        (void) printf("\tmtime  %s", ctime(&z_mtime));
@@ -1933,11 +1961,13 @@ static object_viewer_t *object_viewer[DMU_OT_NUMTYPES + 1] = {
 };
 
 static void
-dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)
+dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header,
+    uint64_t *dnode_slots_used)
 {
        dmu_buf_t *db = NULL;
        dmu_object_info_t doi;
        dnode_t *dn;
+       boolean_t dnode_held = B_FALSE;
        void *bonus = NULL;
        size_t bsize = 0;
        char iblk[32], dblk[32], lsize[32], asize[32], fill[32], dnsize[32];
@@ -1945,6 +1975,13 @@ dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)
        char aux[50];
        int error;
 
+       /* make sure nicenum has enough space */
+       CTASSERT(sizeof (iblk) >= NN_NUMBUF_SZ);
+       CTASSERT(sizeof (dblk) >= NN_NUMBUF_SZ);
+       CTASSERT(sizeof (lsize) >= NN_NUMBUF_SZ);
+       CTASSERT(sizeof (asize) >= NN_NUMBUF_SZ);
+       CTASSERT(sizeof (bonus_size) >= NN_NUMBUF_SZ);
+
        if (*print_header) {
                (void) printf("\n%10s  %3s  %5s  %5s  %5s  %6s  %5s  %6s  %s\n",
                    "Object", "lvl", "iblk", "dblk", "dsize", "dnsize",
@@ -1954,23 +1991,43 @@ dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)
 
        if (object == 0) {
                dn = DMU_META_DNODE(os);
+               dmu_object_info_from_dnode(dn, &doi);
        } else {
-               error = dmu_bonus_hold(os, object, FTAG, &db);
+               /*
+                * Encrypted datasets will have sensitive bonus buffers
+                * encrypted. Therefore we cannot hold the bonus buffer and
+                * must hold the dnode itself instead.
+                */
+               error = dmu_object_info(os, object, &doi);
                if (error)
-                       fatal("dmu_bonus_hold(%llu) failed, errno %u",
-                           object, error);
-               bonus = db->db_data;
-               bsize = db->db_size;
-               dn = DB_DNODE((dmu_buf_impl_t *)db);
-       }
-       dmu_object_info_from_dnode(dn, &doi);
-
-       zdb_nicenum(doi.doi_metadata_block_size, iblk);
-       zdb_nicenum(doi.doi_data_block_size, dblk);
-       zdb_nicenum(doi.doi_max_offset, lsize);
-       zdb_nicenum(doi.doi_physical_blocks_512 << 9, asize);
-       zdb_nicenum(doi.doi_bonus_size, bonus_size);
-       zdb_nicenum(doi.doi_dnodesize, dnsize);
+                       fatal("dmu_object_info() failed, errno %u", error);
+
+               if (os->os_encrypted &&
+                   DMU_OT_IS_ENCRYPTED(doi.doi_bonus_type)) {
+                       error = dnode_hold(os, object, FTAG, &dn);
+                       if (error)
+                               fatal("dnode_hold() failed, errno %u", error);
+                       dnode_held = B_TRUE;
+               } else {
+                       error = dmu_bonus_hold(os, object, FTAG, &db);
+                       if (error)
+                               fatal("dmu_bonus_hold(%llu) failed, errno %u",
+                                   object, error);
+                       bonus = db->db_data;
+                       bsize = db->db_size;
+                       dn = DB_DNODE((dmu_buf_impl_t *)db);
+               }
+       }
+
+       if (dnode_slots_used)
+               *dnode_slots_used = doi.doi_dnodesize / DNODE_MIN_SIZE;
+
+       zdb_nicenum(doi.doi_metadata_block_size, iblk, sizeof (iblk));
+       zdb_nicenum(doi.doi_data_block_size, dblk, sizeof (dblk));
+       zdb_nicenum(doi.doi_max_offset, lsize, sizeof (lsize));
+       zdb_nicenum(doi.doi_physical_blocks_512 << 9, asize, sizeof (asize));
+       zdb_nicenum(doi.doi_bonus_size, bonus_size, sizeof (bonus_size));
+       zdb_nicenum(doi.doi_dnodesize, dnsize, sizeof (dnsize));
        (void) sprintf(fill, "%6.2f", 100.0 * doi.doi_fill_count *
            doi.doi_data_block_size / (object == 0 ? DNODES_PER_BLOCK : 1) /
            doi.doi_max_offset);
@@ -1978,13 +2035,13 @@ dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)
        aux[0] = '\0';
 
        if (doi.doi_checksum != ZIO_CHECKSUM_INHERIT || verbosity >= 6) {
-               (void) snprintf(aux + strlen(aux), sizeof (aux), " (K=%s)",
-                   ZDB_CHECKSUM_NAME(doi.doi_checksum));
+               (void) snprintf(aux + strlen(aux), sizeof (aux) - strlen(aux),
+                   " (K=%s)", ZDB_CHECKSUM_NAME(doi.doi_checksum));
        }
 
        if (doi.doi_compress != ZIO_COMPRESS_INHERIT || verbosity >= 6) {
-               (void) snprintf(aux + strlen(aux), sizeof (aux), " (Z=%s)",
-                   ZDB_COMPRESS_NAME(doi.doi_compress));
+               (void) snprintf(aux + strlen(aux), sizeof (aux) - strlen(aux),
+                   " (Z=%s)", ZDB_COMPRESS_NAME(doi.doi_compress));
        }
 
        (void) printf("%10lld  %3u  %5s  %5s  %5s  %6s  %5s  %6s  %s%s\n",
@@ -2010,9 +2067,20 @@ dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)
                (void) printf("\tdnode maxblkid: %llu\n",
                    (longlong_t)dn->dn_phys->dn_maxblkid);
 
-               object_viewer[ZDB_OT_TYPE(doi.doi_bonus_type)](os, object,
-                   bonus, bsize);
-               object_viewer[ZDB_OT_TYPE(doi.doi_type)](os, object, NULL, 0);
+               if (!dnode_held) {
+                       object_viewer[ZDB_OT_TYPE(doi.doi_bonus_type)](os,
+                           object, bonus, bsize);
+               } else {
+                       (void) printf("\t\t(bonus encrypted)\n");
+               }
+
+               if (!os->os_encrypted || !DMU_OT_IS_ENCRYPTED(doi.doi_type)) {
+                       object_viewer[ZDB_OT_TYPE(doi.doi_type)](os, object,
+                           NULL, 0);
+               } else {
+                       (void) printf("\t\t(object encrypted)\n");
+               }
+
                *print_header = 1;
        }
 
@@ -2035,6 +2103,8 @@ dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)
 
                for (;;) {
                        char segsize[32];
+                       /* make sure nicenum has enough space */
+                       CTASSERT(sizeof (segsize) >= NN_NUMBUF_SZ);
                        error = dnode_next_offset(dn,
                            0, &start, minlvl, blkfill, 0);
                        if (error)
@@ -2042,7 +2112,7 @@ dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)
                        end = start;
                        error = dnode_next_offset(dn,
                            DNODE_FIND_HOLE, &end, minlvl, blkfill, 0);
-                       zdb_nicenum(end - start, segsize);
+                       zdb_nicenum(end - start, segsize, sizeof (segsize));
                        (void) printf("\t\tsegment [%016llx, %016llx)"
                            " size %5s\n", (u_longlong_t)start,
                            (u_longlong_t)end, segsize);
@@ -2054,9 +2124,11 @@ dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)
 
        if (db != NULL)
                dmu_buf_rele(db, FTAG);
+       if (dnode_held)
+               dnode_rele(dn, FTAG);
 }
 
-static char *objset_types[DMU_OST_NUMTYPES] = {
+static const char *objset_types[DMU_OST_NUMTYPES] = {
        "NONE", "META", "ZPL", "ZVOL", "OTHER", "ANY" };
 
 static void
@@ -2068,10 +2140,17 @@ dump_dir(objset_t *os)
        char numbuf[32];
        char blkbuf[BP_SPRINTF_LEN + 20];
        char osname[ZFS_MAX_DATASET_NAME_LEN];
-       char *type = "UNKNOWN";
+       const char *type = "UNKNOWN";
        int verbosity = dump_opt['d'];
        int print_header = 1;
-       int i, error;
+       unsigned i;
+       int error;
+       uint64_t total_slots_used = 0;
+       uint64_t max_slot_used = 0;
+       uint64_t dnode_slots;
+
+       /* make sure nicenum has enough space */
+       CTASSERT(sizeof (numbuf) >= NN_NUMBUF_SZ);
 
        dsl_pool_config_enter(dmu_objset_pool(os), FTAG);
        dmu_objset_fast_stat(os, &dds);
@@ -2091,7 +2170,7 @@ dump_dir(objset_t *os)
 
        ASSERT3U(usedobjs, ==, BP_GET_FILL(os->os_rootbp));
 
-       zdb_nicenum(refdbytes, numbuf);
+       zdb_nicenum(refdbytes, numbuf, sizeof (numbuf));
 
        if (verbosity >= 4) {
                (void) snprintf(blkbuf, sizeof (blkbuf), ", rootbp ");
@@ -2112,7 +2191,7 @@ dump_dir(objset_t *os)
        if (zopt_objects != 0) {
                for (i = 0; i < zopt_objects; i++)
                        dump_object(os, zopt_object[i], verbosity,
-                           &print_header);
+                           &print_header, NULL);
                (void) printf("\n");
                return;
        }
@@ -2129,21 +2208,34 @@ dump_dir(objset_t *os)
        if (BP_IS_HOLE(os->os_rootbp))
                return;
 
-       dump_object(os, 0, verbosity, &print_header);
+       dump_object(os, 0, verbosity, &print_header, NULL);
        object_count = 0;
        if (DMU_USERUSED_DNODE(os) != NULL &&
            DMU_USERUSED_DNODE(os)->dn_type != 0) {
-               dump_object(os, DMU_USERUSED_OBJECT, verbosity, &print_header);
-               dump_object(os, DMU_GROUPUSED_OBJECT, verbosity, &print_header);
+               dump_object(os, DMU_USERUSED_OBJECT, verbosity, &print_header,
+                   NULL);
+               dump_object(os, DMU_GROUPUSED_OBJECT, verbosity, &print_header,
+                   NULL);
        }
 
        object = 0;
        while ((error = dmu_object_next(os, &object, B_FALSE, 0)) == 0) {
-               dump_object(os, object, verbosity, &print_header);
+               dump_object(os, object, verbosity, &print_header, &dnode_slots);
                object_count++;
+               total_slots_used += dnode_slots;
+               max_slot_used = object + dnode_slots - 1;
        }
 
-       ASSERT3U(object_count, ==, usedobjs);
+       (void) printf("\n");
+
+       (void) printf("    Dnode slots:\n");
+       (void) printf("\tTotal used:    %10llu\n",
+           (u_longlong_t)total_slots_used);
+       (void) printf("\tMax used:      %10llu\n",
+           (u_longlong_t)max_slot_used);
+       (void) printf("\tPercent empty: %10lf\n",
+           (double)(max_slot_used - total_slots_used)*100 /
+           (double)max_slot_used);
 
        (void) printf("\n");
 
@@ -2151,6 +2243,8 @@ dump_dir(objset_t *os)
                (void) fprintf(stderr, "dmu_object_next() = %d\n", error);
                abort();
        }
+
+       ASSERT3U(object_count, ==, usedobjs);
 }
 
 static void
@@ -2165,6 +2259,13 @@ dump_uberblock(uberblock_t *ub, const char *header, const char *footer)
        (void) printf("\tguid_sum = %llu\n", (u_longlong_t)ub->ub_guid_sum);
        (void) printf("\ttimestamp = %llu UTC = %s",
            (u_longlong_t)ub->ub_timestamp, asctime(localtime(&timestamp)));
+
+       (void) printf("\tmmp_magic = %016llx\n",
+           (u_longlong_t)ub->ub_mmp_magic);
+       if (ub->ub_mmp_magic == MMP_MAGIC)
+               (void) printf("\tmmp_delay = %0llu\n",
+                   (u_longlong_t)ub->ub_mmp_delay);
+
        if (dump_opt['u'] >= 4) {
                char blkbuf[BP_SPRINTF_LEN];
                snprintf_blkptr(blkbuf, sizeof (blkbuf), &ub->ub_rootbp);
@@ -2529,6 +2630,11 @@ dump_label_uberblocks(label_t *label, uint64_t ashift, int label_num)
                if ((dump_opt['u'] < 3) && (first_label(rec) != label_num))
                        continue;
 
+               if ((dump_opt['u'] < 4) &&
+                   (ub->ub_mmp_magic == MMP_MAGIC) && ub->ub_mmp_delay &&
+                   (i >= VDEV_UBERBLOCK_COUNT(&vd) - MMP_BLOCKS_PER_LABEL))
+                       continue;
+
                print_label_header(label, label_num);
                (void) snprintf(header, ZDB_MAX_UB_HEADER_SIZE,
                    "    Uberblock[%d]\n", i);
@@ -2598,7 +2704,7 @@ dump_path_impl(objset_t *os, uint64_t obj, char *name)
                        return (dump_path_impl(os, child_obj, s + 1));
                /*FALLTHROUGH*/
        case DMU_OT_PLAIN_FILE_CONTENTS:
-               dump_object(os, child_obj, dump_opt['v'], &header);
+               dump_object(os, child_obj, dump_opt['v'], &header, NULL);
                return (0);
        default:
                (void) fprintf(stderr, "object %llu has non-file/directory "
@@ -2627,7 +2733,7 @@ dump_path(char *ds, char *path)
        if (err != 0) {
                (void) fprintf(stderr, "can't lookup root znode: %s\n",
                    strerror(err));
-               dmu_objset_disown(os, FTAG);
+               dmu_objset_disown(os, B_FALSE, FTAG);
                return (EINVAL);
        }
 
@@ -2682,10 +2788,6 @@ dump_label(const char *dev)
                exit(1);
        }
 
-       if (ioctl(fd, BLKFLSBUF) != 0)
-               (void) printf("failed to invalidate cache '%s' : %s\n", path,
-                   strerror(errno));
-
        if (fstat64_blk(fd, &statbuf) != 0) {
                (void) printf("failed to stat '%s': %s\n", path,
                    strerror(errno));
@@ -2693,6 +2795,10 @@ dump_label(const char *dev)
                exit(1);
        }
 
+       if (S_ISBLK(statbuf.st_mode) && ioctl(fd, BLKFLSBUF) != 0)
+               (void) printf("failed to invalidate cache '%s' : %s\n", path,
+                   strerror(errno));
+
        avl_create(&config_tree, cksum_record_compare,
            sizeof (cksum_record_t), offsetof(cksum_record_t, link));
        avl_create(&uberblock_tree, cksum_record_compare,
@@ -2857,7 +2963,7 @@ typedef struct zdb_blkstats {
 #define        ZDB_OT_OTHER    (DMU_OT_NUMTYPES + 2)
 #define        ZDB_OT_TOTAL    (DMU_OT_NUMTYPES + 3)
 
-static char *zdb_ot_extname[] = {
+static const char *zdb_ot_extname[] = {
        "deferred free",
        "dedup ditto",
        "other",
@@ -2874,7 +2980,7 @@ typedef struct zdb_cb {
        uint64_t        zcb_embedded_histogram[NUM_BP_EMBEDDED_TYPES]
            [BPE_PAYLOAD_SIZE + 1];
        uint64_t        zcb_start;
-       uint64_t        zcb_lastprint;
+       hrtime_t        zcb_lastprint;
        uint64_t        zcb_totalasize;
        uint64_t        zcb_errors[256];
        int             zcb_readfails;
@@ -2910,7 +3016,7 @@ zdb_count_block(zdb_cb_t *zcb, zilog_t *zilog, const blkptr_t *bp,
                 * SPA_OLD_MAXBLOCKSIZE; larger blocks go into the last,
                 * "other", bucket.
                 */
-               int idx = BP_GET_PSIZE(bp) >> SPA_MINBLOCKSHIFT;
+               unsigned idx = BP_GET_PSIZE(bp) >> SPA_MINBLOCKSHIFT;
                idx = MIN(idx, SPA_OLD_MAXBLOCKSIZE / SPA_MINBLOCKSIZE + 1);
                zb->zb_psize_histogram[idx]++;
 
@@ -2983,7 +3089,7 @@ zdb_blkptr_done(zio_t *zio)
        abd_free(zio->io_abd);
 
        mutex_enter(&spa->spa_scrub_lock);
-       spa->spa_scrub_inflight--;
+       spa->spa_load_verify_ios--;
        cv_broadcast(&spa->spa_scrub_io_cv);
 
        if (ioerr && !(zio->io_flags & ZIO_FLAG_SPECULATIVE)) {
@@ -3054,9 +3160,9 @@ zdb_blkptr_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
                        flags |= ZIO_FLAG_SPECULATIVE;
 
                mutex_enter(&spa->spa_scrub_lock);
-               while (spa->spa_scrub_inflight > max_inflight)
+               while (spa->spa_load_verify_ios > max_inflight)
                        cv_wait(&spa->spa_scrub_io_cv, &spa->spa_scrub_lock);
-               spa->spa_scrub_inflight++;
+               spa->spa_load_verify_ios++;
                mutex_exit(&spa->spa_scrub_lock);
 
                zio_nowait(zio_read(NULL, spa, bp, abd, size,
@@ -3081,7 +3187,10 @@ zdb_blkptr_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
                int sec_remaining =
                    (zcb->zcb_totalasize - bytes) / 1024 / kb_per_sec;
 
-               zfs_nicenum(bytes, buf, sizeof (buf));
+               /* make sure nicenum has enough space */
+               CTASSERT(sizeof (buf) >= NN_NUMBUF_SZ);
+
+               zfs_nicebytes(bytes, buf, sizeof (buf));
                (void) fprintf(stderr,
                    "\r%5s completed (%4dMB/s) "
                    "estimated time remaining: %uhr %02umin %02usec        ",
@@ -3112,11 +3221,12 @@ static metaslab_ops_t zdb_metaslab_ops = {
 static void
 zdb_ddt_leak_init(spa_t *spa, zdb_cb_t *zcb)
 {
-       ddt_bookmark_t ddb = { 0 };
+       ddt_bookmark_t ddb;
        ddt_entry_t dde;
        int error;
        int p;
 
+       bzero(&ddb, sizeof (ddb));
        while ((error = ddt_walk(spa, &ddb, &dde)) == 0) {
                blkptr_t blk;
                ddt_phys_t *ddp = dde.dde_phys;
@@ -3222,14 +3332,12 @@ zdb_leak_init(spa_t *spa, zdb_cb_t *zcb)
 static void
 zdb_leak_fini(spa_t *spa)
 {
-       int c, m;
-
        if (!dump_opt['L']) {
                vdev_t *rvd = spa->spa_root_vdev;
-               for (c = 0; c < rvd->vdev_children; c++) {
+               for (unsigned c = 0; c < rvd->vdev_children; c++) {
                        vdev_t *vd = rvd->vdev_child[c];
                        ASSERTV(metaslab_group_t *mg = vd->vdev_mg);
-                       for (m = 0; m < vd->vdev_ms_count; m++) {
+                       for (unsigned m = 0; m < vd->vdev_ms_count; m++) {
                                metaslab_t *msp = vd->vdev_ms[m];
                                ASSERT3P(mg, ==, msp->ms_group);
                                mutex_enter(&msp->ms_lock);
@@ -3277,11 +3385,13 @@ dump_block_stats(spa_t *spa)
        zdb_cb_t zcb;
        zdb_blkstats_t *zb, *tzb;
        uint64_t norm_alloc, norm_space, total_alloc, total_found;
-       int flags = TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA | TRAVERSE_HARD;
+       int flags = TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA |
+           TRAVERSE_NO_DECRYPT | TRAVERSE_HARD;
        boolean_t leaks = B_FALSE;
-       int e, c;
+       int e, c, err;
        bp_embedded_type_t i;
 
+       bzero(&zcb, sizeof (zcb));
        (void) printf("\nTraversing all blocks %s%s%s%s%s...\n\n",
            (dump_opt['c'] || !dump_opt['L']) ? "to verify " : "",
            (dump_opt['c'] == 1) ? "metadata " : "",
@@ -3320,7 +3430,7 @@ dump_block_stats(spa_t *spa)
 
        zcb.zcb_totalasize = metaslab_class_get_alloc(spa_normal_class(spa));
        zcb.zcb_start = zcb.zcb_lastprint = gethrtime();
-       zcb.zcb_haderrors |= traverse_pool(spa, 0, flags, zdb_blkptr_cb, &zcb);
+       err = traverse_pool(spa, 0, flags, zdb_blkptr_cb, &zcb);
 
        /*
         * If we've traversed the data blocks then we need to wait for those
@@ -3336,6 +3446,12 @@ dump_block_stats(spa_t *spa)
                }
        }
 
+       /*
+        * Done after zio_wait() since zcb_haderrors is modified in
+        * zdb_blkptr_done()
+        */
+       zcb.zcb_haderrors |= err;
+
        if (zcb.zcb_haderrors) {
                (void) printf("\nError counts:\n\n");
                (void) printf("\t%5s  %s\n", "errno", "count");
@@ -3433,7 +3549,15 @@ dump_block_stats(spa_t *spa)
                for (t = 0; t <= ZDB_OT_TOTAL; t++) {
                        char csize[32], lsize[32], psize[32], asize[32];
                        char avg[32], gang[32];
-                       char *typename;
+                       const char *typename;
+
+                       /* make sure nicenum has enough space */
+                       CTASSERT(sizeof (csize) >= NN_NUMBUF_SZ);
+                       CTASSERT(sizeof (lsize) >= NN_NUMBUF_SZ);
+                       CTASSERT(sizeof (psize) >= NN_NUMBUF_SZ);
+                       CTASSERT(sizeof (asize) >= NN_NUMBUF_SZ);
+                       CTASSERT(sizeof (avg) >= NN_NUMBUF_SZ);
+                       CTASSERT(sizeof (gang) >= NN_NUMBUF_SZ);
 
                        if (t < DMU_OT_NUMTYPES)
                                typename = dmu_ot[t].ot_name;
@@ -3468,12 +3592,17 @@ dump_block_stats(spa_t *spa)
                                    zcb.zcb_type[ZB_TOTAL][t].zb_asize)
                                        continue;
 
-                               zdb_nicenum(zb->zb_count, csize);
-                               zdb_nicenum(zb->zb_lsize, lsize);
-                               zdb_nicenum(zb->zb_psize, psize);
-                               zdb_nicenum(zb->zb_asize, asize);
-                               zdb_nicenum(zb->zb_asize / zb->zb_count, avg);
-                               zdb_nicenum(zb->zb_gangs, gang);
+                               zdb_nicenum(zb->zb_count, csize,
+                                   sizeof (csize));
+                               zdb_nicenum(zb->zb_lsize, lsize,
+                                   sizeof (lsize));
+                               zdb_nicenum(zb->zb_psize, psize,
+                                   sizeof (psize));
+                               zdb_nicenum(zb->zb_asize, asize,
+                                   sizeof (asize));
+                               zdb_nicenum(zb->zb_asize / zb->zb_count, avg,
+                                   sizeof (avg));
+                               zdb_nicenum(zb->zb_gangs, gang, sizeof (gang));
 
                                (void) printf("%6s\t%5s\t%5s\t%5s\t%5s"
                                    "\t%5.2f\t%6.2f\t",
@@ -3574,16 +3703,15 @@ dump_simulated_ddt(spa_t *spa)
        ddt_histogram_t ddh_total;
        ddt_stat_t dds_total;
 
-       bzero(&ddh_total, sizeof (ddt_histogram_t));
-       bzero(&dds_total, sizeof (ddt_stat_t));
-
+       bzero(&ddh_total, sizeof (ddh_total));
+       bzero(&dds_total, sizeof (dds_total));
        avl_create(&t, ddt_entry_compare,
            sizeof (zdb_ddt_entry_t), offsetof(zdb_ddt_entry_t, zdde_node));
 
        spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
 
-       (void) traverse_pool(spa, 0, TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA,
-           zdb_ddt_add_cb, &t);
+       (void) traverse_pool(spa, 0, TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA |
+           TRAVERSE_NO_DECRYPT, zdb_ddt_add_cb, &t);
 
        spa_config_exit(spa, SCL_CONFIG, FTAG);
 
@@ -3727,7 +3855,7 @@ dump_zpool(spa_t *spa)
 #define        ZDB_FLAG_RAW            0x0040
 #define        ZDB_FLAG_PRINT_BLKPTR   0x0080
 
-int flagbits[256];
+static int flagbits[256];
 
 static void
 zdb_print_blkptr(blkptr_t *bp, int flags)
@@ -3768,10 +3896,11 @@ static void
 zdb_dump_block(char *label, void *buf, uint64_t size, int flags)
 {
        uint64_t *d = (uint64_t *)buf;
-       int nwords = size / sizeof (uint64_t);
+       unsigned nwords = size / sizeof (uint64_t);
        int do_bswap = !!(flags & ZDB_FLAG_BSWAP);
-       int i, j;
-       char *hdr, *c;
+       unsigned i, j;
+       const char *hdr;
+       char *c;
 
 
        if (do_bswap)
@@ -3808,19 +3937,19 @@ zdb_dump_block(char *label, void *buf, uint64_t size, int flags)
  * RAID-Zs, you can specify either RAID-Z vdev with 0.0 or 0.1 .
  */
 static vdev_t *
-zdb_vdev_lookup(vdev_t *vdev, char *path)
+zdb_vdev_lookup(vdev_t *vdev, const char *path)
 {
        char *s, *p, *q;
-       int i;
+       unsigned i;
 
        if (vdev == NULL)
                return (NULL);
 
        /* First, assume the x.x.x.x format */
-       i = (int)strtoul(path, &s, 10);
+       i = strtoul(path, &s, 10);
        if (s == path || (s && *s != '.' && *s != '\0'))
                goto name;
-       if (i < 0 || i >= vdev->vdev_children)
+       if (i >= vdev->vdev_children)
                return (NULL);
 
        vdev = vdev->vdev_child[i];
@@ -3855,13 +3984,6 @@ name:
        return (NULL);
 }
 
-/* ARGSUSED */
-static int
-random_get_pseudo_bytes_cb(void *buf, size_t len, void *unused)
-{
-       return (random_get_pseudo_bytes(buf, len));
-}
-
 /*
  * Read a block from a pool and print it out.  The syntax of the
  * block descriptor is:
@@ -3895,7 +4017,8 @@ zdb_read_block(char *thing, spa_t *spa)
        vdev_t *vd;
        abd_t *pabd;
        void *lbuf, *buf;
-       char *s, *p, *dup, *vdev, *flagstr;
+       const char *s, *vdev;
+       char *p, *dup, *flagstr;
        int i, error;
        boolean_t borrowed = B_FALSE;
 
@@ -3907,7 +4030,10 @@ zdb_read_block(char *thing, spa_t *spa)
        s = strtok(NULL, ":");
        size = strtoull(s ? s : "", NULL, 16);
        s = strtok(NULL, ":");
-       flagstr = s ? s : "";
+       if (s)
+               flagstr = strdup(s);
+       else
+               flagstr = strdup("");
 
        s = NULL;
        if (size == 0)
@@ -3918,6 +4044,7 @@ zdb_read_block(char *thing, spa_t *spa)
                s = "offset must be a multiple of sector size";
        if (s) {
                (void) printf("Invalid block specifier: %s  - %s\n", thing, s);
+               free(flagstr);
                free(dup);
                return;
        }
@@ -3945,11 +4072,13 @@ zdb_read_block(char *thing, spa_t *spa)
                        }
                        if (*p != ':' && *p != '\0') {
                                (void) printf("***Invalid flag arg: '%s'\n", s);
+                               free(flagstr);
                                free(dup);
                                return;
                        }
                }
        }
+       free(flagstr);
 
        vd = zdb_vdev_lookup(spa->spa_root_vdev, vdev);
        if (vd == NULL) {
@@ -4024,17 +4153,8 @@ zdb_read_block(char *thing, spa_t *spa)
                 * every decompress function at every inflated blocksize.
                 */
                enum zio_compress c;
-               void *pbuf2 = umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);
                void *lbuf2 = umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);
 
-               abd_copy_to_buf(pbuf2, pabd, psize);
-
-               VERIFY0(abd_iterate_func(pabd, psize, SPA_MAXBLOCKSIZE - psize,
-                   random_get_pseudo_bytes_cb, NULL));
-
-               VERIFY0(random_get_pseudo_bytes((uint8_t *)pbuf2 + psize,
-                   SPA_MAXBLOCKSIZE - psize));
-
                /*
                 * XXX - On the one hand, with SPA_MAXBLOCKSIZE at 16MB,
                 * this could take a while and we should let the user know
@@ -4044,13 +4164,29 @@ zdb_read_block(char *thing, spa_t *spa)
                for (lsize = psize + SPA_MINBLOCKSIZE;
                    lsize <= SPA_MAXBLOCKSIZE; lsize += SPA_MINBLOCKSIZE) {
                        for (c = 0; c < ZIO_COMPRESS_FUNCTIONS; c++) {
+                               /*
+                                * ZLE can easily decompress non zle stream.
+                                * So have an option to disable it.
+                                */
+                               if (c == ZIO_COMPRESS_ZLE &&
+                                   getenv("ZDB_NO_ZLE"))
+                                       continue;
+
                                (void) fprintf(stderr,
                                    "Trying %05llx -> %05llx (%s)\n",
                                    (u_longlong_t)psize, (u_longlong_t)lsize,
                                    zio_compress_table[c].ci_name);
+
+                               /*
+                                * We randomize lbuf2, and decompress to both
+                                * lbuf and lbuf2. This way, we will know if
+                                * decompression fill exactly to lsize.
+                                */
+                               VERIFY0(random_get_pseudo_bytes(lbuf2, lsize));
+
                                if (zio_decompress_data(c, pabd,
                                    lbuf, psize, lsize) == 0 &&
-                                   zio_decompress_data_buf(c, pbuf2,
+                                   zio_decompress_data(c, pabd,
                                    lbuf2, psize, lsize) == 0 &&
                                    bcmp(lbuf, lbuf2, lsize) == 0)
                                        break;
@@ -4058,11 +4194,9 @@ zdb_read_block(char *thing, spa_t *spa)
                        if (c != ZIO_COMPRESS_FUNCTIONS)
                                break;
                }
-
-               umem_free(pbuf2, SPA_MAXBLOCKSIZE);
                umem_free(lbuf2, SPA_MAXBLOCKSIZE);
 
-               if (lsize <= psize) {
+               if (lsize > SPA_MAXBLOCKSIZE) {
                        (void) printf("Decompress of %s failed\n", thing);
                        goto out;
                }
@@ -4096,93 +4230,38 @@ out:
        free(dup);
 }
 
-static boolean_t
-pool_match(nvlist_t *cfg, char *tgt)
+static void
+zdb_embedded_block(char *thing)
 {
-       uint64_t v, guid = strtoull(tgt, NULL, 0);
-       char *s;
-
-       if (guid != 0) {
-               if (nvlist_lookup_uint64(cfg, ZPOOL_CONFIG_POOL_GUID, &v) == 0)
-                       return (v == guid);
-       } else {
-               if (nvlist_lookup_string(cfg, ZPOOL_CONFIG_POOL_NAME, &s) == 0)
-                       return (strcmp(s, tgt) == 0);
-       }
-       return (B_FALSE);
-}
+       blkptr_t bp;
+       unsigned long long *words = (void *)&bp;
+       char buf[SPA_MAXBLOCKSIZE];
+       int err;
 
-static char *
-find_zpool(char **target, nvlist_t **configp, int dirc, char **dirv)
-{
-       nvlist_t *pools;
-       nvlist_t *match = NULL;
-       char *name = NULL;
-       char *sepp = NULL;
-       char sep = '\0';
-       int count = 0;
-       importargs_t args = { 0 };
-
-       args.paths = dirc;
-       args.path = dirv;
-       args.can_be_active = B_TRUE;
-
-       if ((sepp = strpbrk(*target, "/@")) != NULL) {
-               sep = *sepp;
-               *sepp = '\0';
-       }
-
-       pools = zpool_search_import(g_zfs, &args);
-
-       if (pools != NULL) {
-               nvpair_t *elem = NULL;
-               while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
-                       verify(nvpair_value_nvlist(elem, configp) == 0);
-                       if (pool_match(*configp, *target)) {
-                               count++;
-                               if (match != NULL) {
-                                       /* print previously found config */
-                                       if (name != NULL) {
-                                               (void) printf("%s\n", name);
-                                               dump_nvlist(match, 8);
-                                               name = NULL;
-                                       }
-                                       (void) printf("%s\n",
-                                           nvpair_name(elem));
-                                       dump_nvlist(*configp, 8);
-                               } else {
-                                       match = *configp;
-                                       name = nvpair_name(elem);
-                               }
-                       }
-               }
+       bzero(&bp, sizeof (bp));
+       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);
        }
-       if (count > 1)
-               (void) fatal("\tMatched %d pools - use pool GUID "
-                   "instead of pool name or \n"
-                   "\tpool name part of a dataset name to select pool", count);
-
-       if (sepp)
-               *sepp = sep;
-       /*
-        * If pool GUID was specified for pool id, replace it with pool name
-        */
-       if (name && (strstr(*target, name) != *target)) {
-               int sz = 1 + strlen(name) + ((sepp) ? strlen(sepp) : 0);
-
-               *target = umem_alloc(sz, UMEM_NOFAIL);
-               (void) snprintf(*target, sz, "%s%s", name, sepp ? sepp : "");
+       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);
        }
-
-       *configp = name ? match : NULL;
-
-       return (name);
+       zdb_dump_block_raw(buf, BPE_GET_LSIZE(&bp), 0);
 }
 
 int
 main(int argc, char **argv)
 {
-       int i, c;
+       int c;
        struct rlimit rl = { 1024, 1024 };
        spa_t *spa = NULL;
        objset_t *os = NULL;
@@ -4214,13 +4293,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':
@@ -4284,12 +4364,18 @@ 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++;
                        break;
                case 'V':
-                       flags |= ZFS_IMPORT_VERBATIM;
+                       flags = ZFS_IMPORT_VERBATIM;
                        break;
                case 'x':
                        vn_dumpdir = optarg;
@@ -4335,7 +4421,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;
@@ -4349,6 +4435,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);
@@ -4380,21 +4474,31 @@ main(int argc, char **argv)
        target = argv[0];
 
        if (dump_opt['e']) {
+               importargs_t args = { 0 };
                nvlist_t *cfg = NULL;
-               char *name = find_zpool(&target, &cfg, nsearch, searchdirs);
 
-               error = ENOENT;
-               if (name) {
-                       if (dump_opt['C'] > 1) {
-                               (void) printf("\nConfiguration for import:\n");
-                               dump_nvlist(cfg, 8);
-                       }
+               args.paths = nsearch;
+               args.path = searchdirs;
+               args.can_be_active = B_TRUE;
+
+               error = zpool_tryimport(g_zfs, target, &cfg, &args);
+               if (error == 0) {
                        if (nvlist_add_nvlist(cfg,
                            ZPOOL_REWIND_POLICY, policy) != 0) {
                                fatal("can't open '%s': %s",
                                    target, strerror(ENOMEM));
                        }
-                       error = spa_import(name, cfg, NULL, flags);
+
+                       /*
+                        * Disable the activity check to allow examination of
+                        * active pools.
+                        */
+                       if (dump_opt['C'] > 1) {
+                               (void) printf("\nConfiguration for import:\n");
+                               dump_nvlist(cfg, 8);
+                       }
+                       error = spa_import(target, cfg, NULL,
+                           flags | ZFS_IMPORT_SKIP_MMP);
                }
        }
 
@@ -4409,6 +4513,16 @@ main(int argc, char **argv)
 
        if (error == 0) {
                if (target_is_spa || dump_opt['R']) {
+                       /*
+                        * Disable the activity check to allow examination of
+                        * active pools.
+                        */
+                       mutex_enter(&spa_namespace_lock);
+                       if ((spa = spa_lookup(target)) != NULL) {
+                               spa->spa_import_flags |= ZFS_IMPORT_SKIP_MMP;
+                       }
+                       mutex_exit(&spa_namespace_lock);
+
                        error = spa_open_rewind(target, &spa, FTAG, policy,
                            NULL);
                        if (error) {
@@ -4432,6 +4546,8 @@ main(int argc, char **argv)
                        }
                } else {
                        error = open_objset(target, DMU_OST_ANY, FTAG, &os);
+                       if (error == 0)
+                               spa = dmu_objset_spa(os);
                }
        }
        nvlist_free(policy);
@@ -4439,13 +4555,21 @@ main(int argc, char **argv)
        if (error)
                fatal("can't open '%s': %s", target, strerror(error));
 
+       /*
+        * Set the pool failure mode to panic in order to prevent the pool
+        * from suspending.  A suspended I/O will have no way to resume and
+        * can prevent the zdb(8) command from terminating as expected.
+        */
+       if (spa != NULL)
+               spa->spa_failmode = ZIO_FAILURE_MODE_PANIC;
+
        argv++;
        argc--;
        if (!dump_opt['R']) {
                if (argc > 0) {
                        zopt_objects = argc;
                        zopt_object = calloc(zopt_objects, sizeof (uint64_t));
-                       for (i = 0; i < zopt_objects; i++) {
+                       for (unsigned i = 0; i < zopt_objects; i++) {
                                errno = 0;
                                zopt_object[i] = strtoull(argv[i], NULL, 0);
                                if (zopt_object[i] == 0 && errno != 0)
@@ -4470,7 +4594,7 @@ main(int argc, char **argv)
                flagbits['p'] = ZDB_FLAG_PHYS;
                flagbits['r'] = ZDB_FLAG_RAW;
 
-               for (i = 0; i < argc; i++)
+               for (int i = 0; i < argc; i++)
                        zdb_read_block(argv[i], spa);
        }