]> git.proxmox.com Git - mirror_zfs.git/blobdiff - cmd/zdb/zdb.c
DLPX-44812 integrate EP-220 large memory scalability
[mirror_zfs.git] / cmd / zdb / zdb.c
index efac66c2237e2709c8a2b437f100312f950e07e0..8379cec3e24d542c5cd6f7970c84b551f0f8e7df 100644 (file)
 #include <sys/arc.h>
 #include <sys/ddt.h>
 #include <sys/zfeature.h>
+#include <sys/abd.h>
 #include <zfs_comutil.h>
-#undef ZFS_MAXNAMELEN
 #include <libzfs.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 ?        \
        zio_checksum_table[(idx)].ci_name : "UNKNOWN")
-#define        ZDB_OT_NAME(idx) ((idx) < DMU_OT_NUMTYPES ?     \
-       dmu_ot[(idx)].ot_name : DMU_OT_IS_VALID(idx) ?  \
-       dmu_ot_byteswap[DMU_OT_BYTESWAP(idx)].ob_name : "UNKNOWN")
 #define        ZDB_OT_TYPE(idx) ((idx) < DMU_OT_NUMTYPES ? (idx) :             \
        (((idx) == DMU_OTN_ZAP_DATA || (idx) == DMU_OTN_ZAP_METADATA) ? \
        DMU_OT_ZAP_OTHER : DMU_OT_NUMTYPES))
 
+static char *
+zdb_ot_name(dmu_object_type_t type)
+{
+       if (type < DMU_OT_NUMTYPES)
+               return (dmu_ot[type].ot_name);
+       else if ((type & DMU_OT_NEWTYPE) &&
+               ((type & DMU_OT_BYTESWAP_MASK) < DMU_BSWAP_NUMFUNCS))
+               return (dmu_ot_byteswap[type & DMU_OT_BYTESWAP_MASK].ob_name);
+       else
+               return ("UNKNOWN");
+}
+
 #ifndef lint
 extern int zfs_recover;
 extern uint64_t zfs_arc_max, zfs_arc_meta_limit;
@@ -118,7 +127,7 @@ usage(void)
 {
        (void) fprintf(stderr,
            "Usage: %s [-CumMdibcsDvhLXFPA] [-t txg] [-e [-p path...]] "
-           "[-U config] [-I inflight I/Os] poolname [object...]\n"
+           "[-U config] [-I inflight I/Os] [-x dumpdir] poolname [object...]\n"
            "       %s [-divPA] [-e -p path...] [-U config] dataset "
            "[object...]\n"
            "       %s -mM [-LXFPA] [-t txg] [-e [-p path...]] [-U config] "
@@ -157,7 +166,7 @@ usage(void)
        (void) fprintf(stderr, "        -R read and display block from a "
            "device\n\n");
        (void) fprintf(stderr, "    Below options are intended for use "
-           "with other options (except -l):\n");
+           "with other options:\n");
        (void) fprintf(stderr, "        -A ignore assertions (-A), enable "
            "panic recovery (-AA) or both (-AAA)\n");
        (void) fprintf(stderr, "        -F attempt automatic rewind within "
@@ -170,12 +179,14 @@ usage(void)
            "has altroot/not in a cachefile\n");
        (void) fprintf(stderr, "        -p <path> -- use one or more with "
            "-e to specify path to vdev dir\n");
-       (void) fprintf(stderr, "        -P print numbers in parseable form\n");
+       (void) fprintf(stderr, "        -x <dumpdir> -- "
+           "dump all read blocks into specified directory\n");
+       (void) fprintf(stderr, "        -P print numbers in parsable form\n");
        (void) fprintf(stderr, "        -t <txg> -- highest txg to use when "
            "searching for uberblocks\n");
        (void) fprintf(stderr, "        -I <number of inflight I/Os> -- "
-           "specify the maximum number of checksumming I/Os "
-           "[default is 200]\n");
+           "specify the maximum number of "
+           "checksumming I/Os [default is 200]\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");
@@ -1287,7 +1298,7 @@ visit_indirect(spa_t *spa, const dnode_phys_t *dnp,
                }
                if (!err)
                        ASSERT3U(fill, ==, BP_GET_FILL(bp));
-               (void) arc_buf_remove_ref(buf, &buf);
+               arc_buf_destroy(buf, &buf);
        }
 
        return (err);
@@ -1878,15 +1889,15 @@ dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)
        dnode_t *dn;
        void *bonus = NULL;
        size_t bsize = 0;
-       char iblk[32], dblk[32], lsize[32], asize[32], fill[32];
+       char iblk[32], dblk[32], lsize[32], asize[32], fill[32], dnsize[32];
        char bonus_size[32];
        char aux[50];
        int error;
 
        if (*print_header) {
-               (void) printf("\n%10s  %3s  %5s  %5s  %5s  %5s  %6s  %s\n",
-                   "Object", "lvl", "iblk", "dblk", "dsize", "lsize",
-                   "%full", "type");
+               (void) printf("\n%10s  %3s  %5s  %5s  %5s  %6s  %5s  %6s  %s\n",
+                   "Object", "lvl", "iblk", "dblk", "dsize", "dnsize",
+                   "lsize", "%full", "type");
                *print_header = 0;
        }
 
@@ -1908,6 +1919,7 @@ dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)
        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);
        (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);
@@ -1924,22 +1936,24 @@ dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)
                    ZDB_COMPRESS_NAME(doi.doi_compress));
        }
 
-       (void) printf("%10lld  %3u  %5s  %5s  %5s  %5s  %6s  %s%s\n",
+       (void) printf("%10lld  %3u  %5s  %5s  %5s  %6s  %5s  %6s  %s%s\n",
            (u_longlong_t)object, doi.doi_indirection, iblk, dblk,
-           asize, lsize, fill, ZDB_OT_NAME(doi.doi_type), aux);
+           asize, dnsize, lsize, fill, zdb_ot_name(doi.doi_type), aux);
 
        if (doi.doi_bonus_type != DMU_OT_NONE && verbosity > 3) {
-               (void) printf("%10s  %3s  %5s  %5s  %5s  %5s  %6s  %s\n",
-                   "", "", "", "", "", bonus_size, "bonus",
-                   ZDB_OT_NAME(doi.doi_bonus_type));
+               (void) printf("%10s  %3s  %5s  %5s  %5s  %5s  %5s  %6s  %s\n",
+                   "", "", "", "", "", "", bonus_size, "bonus",
+                   zdb_ot_name(doi.doi_bonus_type));
        }
 
        if (verbosity >= 4) {
-               (void) printf("\tdnode flags: %s%s%s\n",
+               (void) printf("\tdnode flags: %s%s%s%s\n",
                    (dn->dn_phys->dn_flags & DNODE_FLAG_USED_BYTES) ?
                    "USED_BYTES " : "",
                    (dn->dn_phys->dn_flags & DNODE_FLAG_USERUSED_ACCOUNTED) ?
                    "USERUSED_ACCOUNTED " : "",
+                   (dn->dn_phys->dn_flags & DNODE_FLAG_USEROBJUSED_ACCOUNTED) ?
+                   "USEROBJUSED_ACCOUNTED " : "",
                    (dn->dn_phys->dn_flags & DNODE_FLAG_SPILL_BLKPTR) ?
                    "SPILL_BLKPTR" : "");
                (void) printf("\tdnode maxblkid: %llu\n",
@@ -2002,7 +2016,7 @@ dump_dir(objset_t *os)
        uint64_t refdbytes, usedobjs, scratch;
        char numbuf[32];
        char blkbuf[BP_SPRINTF_LEN + 20];
-       char osname[MAXNAMELEN];
+       char osname[ZFS_MAX_DATASET_NAME_LEN];
        char *type = "UNKNOWN";
        int verbosity = dump_opt['d'];
        int print_header = 1;
@@ -2343,7 +2357,7 @@ typedef struct zdb_cb {
        uint64_t        zcb_dedup_blocks;
        uint64_t        zcb_embedded_blocks[NUM_BP_EMBEDDED_TYPES];
        uint64_t        zcb_embedded_histogram[NUM_BP_EMBEDDED_TYPES]
-           [BPE_PAYLOAD_SIZE];
+           [BPE_PAYLOAD_SIZE + 1];
        uint64_t        zcb_start;
        uint64_t        zcb_lastprint;
        uint64_t        zcb_totalasize;
@@ -2451,7 +2465,7 @@ zdb_blkptr_done(zio_t *zio)
        zdb_cb_t *zcb = zio->io_private;
        zbookmark_phys_t *zb = &zio->io_bookmark;
 
-       zio_data_buf_free(zio->io_data, zio->io_size);
+       abd_free(zio->io_abd);
 
        mutex_enter(&spa->spa_scrub_lock);
        spa->spa_scrub_inflight--;
@@ -2517,7 +2531,7 @@ zdb_blkptr_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
        if (!BP_IS_EMBEDDED(bp) &&
            (dump_opt['c'] > 1 || (dump_opt['c'] && is_metadata))) {
                size_t size = BP_GET_PSIZE(bp);
-               void *data = zio_data_buf_alloc(size);
+               abd_t *abd = abd_alloc(size, B_FALSE);
                int flags = ZIO_FLAG_CANFAIL | ZIO_FLAG_SCRUB | ZIO_FLAG_RAW;
 
                /* If it's an intent log block, failure is expected. */
@@ -2530,7 +2544,7 @@ zdb_blkptr_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
                spa->spa_scrub_inflight++;
                mutex_exit(&spa->spa_scrub_lock);
 
-               zio_nowait(zio_read(NULL, spa, bp, data, size,
+               zio_nowait(zio_read(NULL, spa, bp, abd, size,
                    zdb_blkptr_done, zcb, ZIO_PRIORITY_ASYNC_READ, flags, zb));
        }
 
@@ -3277,7 +3291,7 @@ zdb_vdev_lookup(vdev_t *vdev, char *path)
                return (NULL);
 
        vdev = vdev->vdev_child[i];
-       if (*s == '\0')
+       if (s && *s == '\0')
                return (vdev);
        return (zdb_vdev_lookup(vdev, s+1));
 
@@ -3308,6 +3322,13 @@ 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:
@@ -3339,7 +3360,8 @@ zdb_read_block(char *thing, spa_t *spa)
        uint64_t offset = 0, size = 0, psize = 0, lsize = 0, blkptr_offset = 0;
        zio_t *zio;
        vdev_t *vd;
-       void *pbuf, *lbuf, *buf;
+       abd_t *pabd;
+       void *lbuf, *buf;
        char *s, *p, *dup, *vdev, *flagstr;
        int i, error;
 
@@ -3383,8 +3405,10 @@ zdb_read_block(char *thing, spa_t *spa)
                                continue;
 
                        p = &flagstr[i + 1];
-                       if (bit == ZDB_FLAG_PRINT_BLKPTR)
+                       if (bit == ZDB_FLAG_PRINT_BLKPTR) {
                                blkptr_offset = strtoull(p, &p, 16);
+                               i = p - &flagstr[i + 1];
+                       }
                        if (*p != ':' && *p != '\0') {
                                (void) printf("***Invalid flag arg: '%s'\n", s);
                                free(dup);
@@ -3410,7 +3434,7 @@ zdb_read_block(char *thing, spa_t *spa)
        psize = size;
        lsize = size;
 
-       pbuf = umem_alloc_aligned(SPA_MAXBLOCKSIZE, 512, UMEM_NOFAIL);
+       pabd = abd_alloc_linear(SPA_MAXBLOCKSIZE, B_FALSE);
        lbuf = umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);
 
        BP_ZERO(bp);
@@ -3438,15 +3462,15 @@ zdb_read_block(char *thing, spa_t *spa)
                /*
                 * Treat this as a normal block read.
                 */
-               zio_nowait(zio_read(zio, spa, bp, pbuf, psize, NULL, NULL,
+               zio_nowait(zio_read(zio, spa, bp, pabd, psize, NULL, NULL,
                    ZIO_PRIORITY_SYNC_READ,
                    ZIO_FLAG_CANFAIL | ZIO_FLAG_RAW, NULL));
        } else {
                /*
                 * Treat this as a vdev child I/O.
                 */
-               zio_nowait(zio_vdev_child_io(zio, bp, vd, offset, pbuf, psize,
-                   ZIO_TYPE_READ, ZIO_PRIORITY_SYNC_READ,
+               zio_nowait(zio_vdev_child_io(zio, bp, vd, offset, pabd,
+                   psize, ZIO_TYPE_READ, ZIO_PRIORITY_SYNC_READ,
                    ZIO_FLAG_DONT_CACHE | ZIO_FLAG_DONT_QUEUE |
                    ZIO_FLAG_DONT_PROPAGATE | ZIO_FLAG_DONT_RETRY |
                    ZIO_FLAG_CANFAIL | ZIO_FLAG_RAW, NULL, NULL));
@@ -3469,27 +3493,36 @@ zdb_read_block(char *thing, spa_t *spa)
                void *pbuf2 = umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);
                void *lbuf2 = umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);
 
-               bcopy(pbuf, pbuf2, psize);
+               abd_copy_to_buf(pbuf2, pabd, psize);
 
-               VERIFY(random_get_pseudo_bytes((uint8_t *)pbuf + psize,
-                   SPA_MAXBLOCKSIZE - psize) == 0);
+               VERIFY0(abd_iterate_func(pabd, psize, SPA_MAXBLOCKSIZE - psize,
+                   random_get_pseudo_bytes_cb, NULL));
 
-               VERIFY(random_get_pseudo_bytes((uint8_t *)pbuf2 + psize,
-                   SPA_MAXBLOCKSIZE - psize) == 0);
+               VERIFY0(random_get_pseudo_bytes((uint8_t *)pbuf2 + psize,
+                   SPA_MAXBLOCKSIZE - psize));
 
-               for (lsize = SPA_MAXBLOCKSIZE; lsize > psize;
-                   lsize -= SPA_MINBLOCKSIZE) {
+               /*
+                * XXX - On the one hand, with SPA_MAXBLOCKSIZE at 16MB,
+                * this could take a while and we should let the user know
+                * we are not stuck.  On the other hand, printing progress
+                * info gets old after a while.  What to do?
+                */
+               for (lsize = psize + SPA_MINBLOCKSIZE;
+                   lsize <= SPA_MAXBLOCKSIZE; lsize += SPA_MINBLOCKSIZE) {
                        for (c = 0; c < ZIO_COMPRESS_FUNCTIONS; c++) {
-                               if (zio_decompress_data(c, pbuf, lbuf,
-                                   psize, lsize) == 0 &&
-                                   zio_decompress_data(c, pbuf2, lbuf2,
-                                   psize, lsize) == 0 &&
+                               (void) fprintf(stderr,
+                                   "Trying %05llx -> %05llx (%s)\n",
+                                   (u_longlong_t)psize, (u_longlong_t)lsize,
+                                   zio_compress_table[c].ci_name);
+                               if (zio_decompress_data(c, pabd,
+                                   lbuf, psize, lsize) == 0 &&
+                                   zio_decompress_data_buf(c, pbuf2,
+                                   lbuf2, psize, lsize) == 0 &&
                                    bcmp(lbuf, lbuf2, lsize) == 0)
                                        break;
                        }
                        if (c != ZIO_COMPRESS_FUNCTIONS)
                                break;
-                       lsize -= SPA_MINBLOCKSIZE;
                }
 
                umem_free(pbuf2, SPA_MAXBLOCKSIZE);
@@ -3502,7 +3535,7 @@ zdb_read_block(char *thing, spa_t *spa)
                buf = lbuf;
                size = lsize;
        } else {
-               buf = pbuf;
+               buf = abd_to_buf(pabd);
                size = psize;
        }
 
@@ -3520,7 +3553,7 @@ zdb_read_block(char *thing, spa_t *spa)
                zdb_dump_block(thing, buf, size, flags);
 
 out:
-       umem_free(pbuf, SPA_MAXBLOCKSIZE);
+       abd_free(pabd);
        umem_free(lbuf, SPA_MAXBLOCKSIZE);
        free(dup);
 }
@@ -3548,7 +3581,7 @@ find_zpool(char **target, nvlist_t **configp, int dirc, char **dirv)
        nvlist_t *match = NULL;
        char *name = NULL;
        char *sepp = NULL;
-       char sep = 0;
+       char sep = '\0';
        int count = 0;
        importargs_t args = { 0 };
 
@@ -3626,7 +3659,6 @@ main(int argc, char **argv)
        int flags = ZFS_IMPORT_MISSING_LOG;
        int rewind = ZPOOL_NEVER_REWIND;
        char *spa_config_path_env;
-       const char *opts = "bcdhilmMI:suCDRSAFLXevp:t:U:PV";
        boolean_t target_is_spa = B_TRUE;
 
        (void) setrlimit(RLIMIT_NOFILE, &rl);
@@ -3643,7 +3675,8 @@ main(int argc, char **argv)
        if (spa_config_path_env != NULL)
                spa_config_path = spa_config_path_env;
 
-       while ((c = getopt(argc, argv, opts)) != -1) {
+       while ((c = getopt(argc, argv,
+           "bcdhilmMI:suCDRSAFLXx:evp:t:U:PV")) != -1) {
                switch (c) {
                case 'b':
                case 'c':
@@ -3697,6 +3730,9 @@ main(int argc, char **argv)
                        }
                        searchdirs[nsearch++] = optarg;
                        break;
+               case 'x':
+                       vn_dumpdir = optarg;
+                       break;
                case 't':
                        max_txg = strtoull(optarg, NULL, 0);
                        if (max_txg < TXG_INITIAL) {