zfs.c revision c55e05cb35da47582b7afd38734d2f0d9c6deb40
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
*/
/* Portions Copyright 2010 Robert Milkowski */
#include <sys/zfs_context.h>
#include <sys/mdb_modapi.h>
#include <sys/dmu_objset.h>
#include <sys/dsl_pool.h>
#include <sys/metaslab_impl.h>
#include <sys/space_map.h>
#include <sys/spa_impl.h>
#include <sys/vdev_impl.h>
#include <sys/zap_leaf.h>
#include <sys/zap_impl.h>
#include <ctype.h>
#ifdef _KERNEL
#define ZFS_OBJ_NAME "zfs"
extern int64_t mdb_gethrtime(void);
#else
#define ZFS_OBJ_NAME "libzpool.so.1"
#endif
#ifndef _KERNEL
int aok;
#endif
static int
{
char name[64];
return (DCMD_ERR);
}
} else {
}
return (DCMD_ERR);
}
if (off % 8 != 0) {
mdb_warn("member %s of type %s is unsupported bitfield",
return (DCMD_ERR);
}
off /= 8;
mdb_warn("failed to read %s from %s at %p",
return (DCMD_ERR);
}
/* mdb_warn("read %s from %s at %p+%llx\n", member, type, addr, off); */
return (0);
}
static boolean_t
strisprint(const char *cp)
{
return (B_FALSE);
}
return (B_TRUE);
}
static int verbose;
static int
{
mdb_warn("must supply starting address\n");
return (WALK_ERR);
}
return (WALK_NEXT);
}
static int
{
"INVALID", "INVALID", "INVALID", "INVALID" };
int mapshift = SPA_MINBLOCKSHIFT;
return (WALK_DONE);
}
if (SM_DEBUG_DECODE(entry)) {
mdb_printf("DEBUG: %3u %10s: txg=%llu pass=%llu\n",
} else {
mdb_printf("Entry: %3u offsets=%08llx-%08llx type=%c "
"size=%06llx", number,
if (verbose)
mdb_printf("\n");
}
return (WALK_NEXT);
}
static int
{
static int gotid;
static mdb_ctf_id_t dd_id;
char dd_myname[MAXNAMELEN];
if (!gotid) {
&dd_id) == -1) {
mdb_warn("couldn't find struct dsl_dir");
return (DCMD_ERR);
}
}
return (DCMD_ERR);
}
if (dd_parent) {
return (DCMD_ERR);
}
if (dd_myname[0])
else
return (0);
}
static int
{
static int gotid;
char ds_snapname[MAXNAMELEN];
buf[0] = '\0';
if (!gotid) {
&os_id) == -1) {
mdb_warn("couldn't find struct objset");
return (DCMD_ERR);
}
&ds_id) == -1) {
mdb_warn("couldn't find struct dsl_dataset");
return (DCMD_ERR);
}
}
return (DCMD_ERR);
if (os_dsl_dataset == 0) {
return (0);
}
return (DCMD_ERR);
}
return (DCMD_ERR);
if (ds_snapname[0]) {
}
return (0);
}
static void
const char *prefix)
{
const char *cp;
} else {
}
}
/* ARGSUSED */
static int
{
/*
* This table can be approximately generated by running:
* egrep "^[a-z0-9_]+ [a-z0-9_]+( =.*)?;" *.c | cut -d ' ' -f 2
*/
static const char *params[] = {
"arc_reduce_dnlc_percent",
"zfs_arc_max",
"zfs_arc_min",
"arc_shrink_shift",
"zfs_mdcomp_disable",
"zfs_prefetch_disable",
"zfetch_max_streams",
"zfetch_min_sec_reap",
"zfetch_block_cap",
"zfetch_array_rd_sz",
"zfs_default_bs",
"zfs_default_ibs",
"metaslab_aliquot",
"reference_tracking_enable",
"reference_history",
"spa_max_replication_override",
"spa_mode_global",
"zfs_flags",
"zfs_txg_synctime_ms",
"zfs_txg_timeout",
"zfs_write_limit_min",
"zfs_write_limit_max",
"zfs_write_limit_shift",
"zfs_write_limit_override",
"zfs_no_write_throttle",
"zfs_vdev_cache_max",
"zfs_vdev_cache_size",
"zfs_vdev_cache_bshift",
"vdev_mirror_shift",
"zfs_vdev_max_pending",
"zfs_vdev_min_pending",
"zfs_scrub_limit",
"zfs_no_scrub_io",
"zfs_no_scrub_prefetch",
"zfs_vdev_time_shift",
"zfs_vdev_ramp_rate",
"zfs_vdev_aggregation_limit",
"fzap_default_block_shift",
"zfs_immediate_write_sz",
"zfs_read_chunk_size",
"zfs_nocacheflush",
"zil_replay_disable",
"metaslab_gang_bang",
"metaslab_df_alloc_threshold",
"metaslab_df_free_pct",
"zio_injection_enabled",
"zvol_immediate_write_sz",
};
int sz;
if (sz == 4) {
} else if (sz == 8) {
} else {
}
}
return (DCMD_OK);
}
/* ARGSUSED */
static int
{
char buf[BP_SPRINTF_LEN];
mdb_warn("failed to read blkptr_t");
return (DCMD_ERR);
}
mdb_warn("Could not find blkptr enumerated types");
return (DCMD_ERR);
}
return (DCMD_OK);
}
typedef struct mdb_dmu_buf_impl {
struct {
} db;
void *db_objset;
struct {
} db_holds;
/* ARGSUSED */
static int
{
char objectname[32];
char blkidname[32];
char path[MAXNAMELEN];
if (DCMD_HDRSPEC(flags))
mdb_printf(" addr object lvl blkid holds os\n");
addr, 0) == -1)
return (DCMD_ERR);
else
else
return (DCMD_ERR);
}
return (DCMD_OK);
}
/* ARGSUSED */
static int
{
#define HISTOSZ 32
int i, maxidx;
mdb_warn("failed to read 'dbuf_hash_table'");
return (DCMD_ERR);
}
for (i = 0; i < HISTOSZ; i++) {
histo[i] = 0;
histo2[i] = 0;
}
ndbufs = 0;
int len;
mdb_warn("failed to read hash bucket %u at %p",
return (DCMD_ERR);
}
len = 0;
while (dbp != 0) {
dbp) == -1) {
return (DCMD_ERR);
}
histo2[i]++;
len++;
ndbufs++;
}
}
mdb_printf("hash table has %llu buckets, %llu dbufs "
mdb_printf("\n");
maxidx = 0;
for (i = 0; i < HISTOSZ; i++)
if (histo[i] > 0)
maxidx = i;
mdb_printf("hash chain length number of buckets\n");
for (i = 0; i <= maxidx; i++)
mdb_printf("\n");
maxidx = 0;
for (i = 0; i < HISTOSZ; i++)
if (histo2[i] > 0)
maxidx = i;
mdb_printf("hash chain depth number of dbufs\n");
for (i = 0; i <= maxidx; i++)
mdb_printf("%u or more %llu %llu%%\n",
return (DCMD_OK);
}
#define CHAIN_END 0xffff
/*
* ::zap_leaf [-v]
*
* Print a zap_leaf_phys_t, assumed to be 16k
*/
/* ARGSUSED */
static int
{
zap_leaf_t l;
int i;
return (DCMD_USAGE);
if (four)
l.l_bs = 12;
if (!(flags & DCMD_ADDRSPEC)) {
return (DCMD_USAGE);
}
return (DCMD_ERR);
}
mdb_warn("This does not appear to be a zap_leaf_phys_t");
return (DCMD_ERR);
}
"ENTRIES_CDSORTED" : "");
if (verbose) {
mdb_printf(" hash table:\n");
for (i = 0; i < ZAP_LEAF_HASH_NUMENTRIES(&l); i++) {
}
}
mdb_printf(" chunks:\n");
for (i = 0; i < ZAP_LEAF_NUMCHUNKS(&l); i++) {
/* LINTED: alignment */
case ZAP_CHUNK_FREE:
if (verbose) {
mdb_printf(" %u: free; lf_next = %u\n",
}
break;
case ZAP_CHUNK_ENTRY:
mdb_printf(" %u: entry\n", i);
if (verbose) {
mdb_printf(" le_next = %u\n",
}
mdb_printf(" le_name_chunk = %u\n",
mdb_printf(" le_name_numints = %u\n",
mdb_printf(" le_value_chunk = %u\n",
mdb_printf(" le_value_intlen = %u\n",
mdb_printf(" le_value_numints = %u\n",
mdb_printf(" le_cd = %u\n",
mdb_printf(" le_hash = %llx\n",
break;
case ZAP_CHUNK_ARRAY:
mdb_printf(" %u: array", i);
mdb_printf("\n");
if (verbose) {
int j;
mdb_printf(" ");
for (j = 0; j < ZAP_LEAF_ARRAY_BYTES; j++) {
mdb_printf("%02x ",
}
mdb_printf("\n");
}
mdb_printf(" lf_next = %u\n",
}
break;
default:
mdb_printf(" %u: undefined type %u\n",
}
}
return (DCMD_OK);
}
typedef struct dbufs_data {
char *osname;
} dbufs_data_t;
#define DBUFS_UNSET (0xbaddcafedeadbeefULL)
/* ARGSUSED */
static int
{
char osname[MAXNAMELEN];
return (WALK_ERR);
}
}
return (WALK_NEXT);
}
/* ARGSUSED */
static int
{
return (DCMD_USAGE);
}
if (object) {
} else {
}
}
if (blkid) {
} else {
}
}
mdb_warn("couldn't find struct dmu_buf_impl_t");
return (DCMD_ERR);
}
mdb_warn("can't walk dbufs");
return (DCMD_ERR);
}
return (DCMD_OK);
}
typedef struct abuf_find_data {
/* ARGSUSED */
static int
{
return (WALK_ERR);
}
}
return (WALK_NEXT);
}
/* ARGSUSED */
static int
{
int i;
const char *syms[] = {
"ARC_mru",
"ARC_mru_ghost",
"ARC_mfu",
"ARC_mfu_ghost",
};
if (argc != 2)
return (DCMD_USAGE);
for (i = 0; i < 2; i ++) {
case MDB_TYPE_STRING:
break;
case MDB_TYPE_IMMEDIATE:
break;
default:
return (DCMD_USAGE);
}
}
mdb_warn("couldn't find struct arc_buf_hdr");
return (DCMD_ERR);
}
return (DCMD_ERR);
}
return (DCMD_ERR);
}
}
return (DCMD_OK);
}
typedef struct dbgmsg_arg {
} dbgmsg_arg_t;
/* ARGSUSED */
static int
{
static mdb_ctf_id_t id;
char buf[1024];
if (!gotid) {
-1) {
mdb_warn("couldn't find struct zfs_dbgmsg");
return (WALK_ERR);
}
mdb_warn("couldn't find zdm_msg");
return (WALK_ERR);
}
off /= 8;
}
return (WALK_ERR);
}
return (DCMD_ERR);
}
if (da->da_address)
if (da->da_verbose)
if (da->da_verbose)
return (WALK_NEXT);
}
/* ARGSUSED */
static int
{
dbgmsg_arg_t da = { 0 };
return (DCMD_USAGE);
mdb_warn("can't find zfs_dbgmsgs");
return (DCMD_ERR);
}
mdb_warn("can't walk zfs_dbgmsgs");
return (DCMD_ERR);
}
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
int nstats, i;
const char *suffix;
static const char *bytestats[] = {
"p", "c", "c_min", "c_max", "size", "duplicate_buffers_size",
"arc_meta_used", "arc_meta_limit", "arc_meta_max",
};
static const char *extras[] = {
"arc_no_grow", "arc_tempreserve",
};
mdb_warn("failed to find 'arc_stats'");
return (DCMD_ERR);
}
return (DCMD_ERR);
}
/* NB: -a / opt_a are ignored for backwards compatability */
return (DCMD_USAGE);
shift = 20;
switch (shift) {
case 0:
suffix = "B";
break;
case 10:
suffix = "KB";
break;
case 20:
suffix = "MB";
break;
case 30:
suffix = "GB";
break;
default:
suffix = "XX";
}
for (i = 0; i < nstats; i++) {
int j;
for (j = 0; bytestats[j]; j++) {
break;
}
}
if (bytes) {
} else {
}
}
for (i = 0; extras[i]; i++) {
return (DCMD_ERR);
}
mdb_warn("expected scalar for variable '%s'\n",
extras[i]);
return (DCMD_ERR);
}
return (DCMD_ERR);
}
/* NB: all the 64-bit extras happen to be byte counts */
}
return (DCMD_OK);
}
/*
* ::spa
*
* -c Print configuration information as well
* -v Print vdev state
* -e Print vdev error stats
*
* Print a summarized spa_t. When given no arguments, prints out a table of all
* active pools on the system.
*/
/* ARGSUSED */
static int
{
"SPARE", "L2CACHE", "UNINIT", "UNAVAIL", "POTENTIAL" };
const char *state;
return (DCMD_USAGE);
if (!(flags & DCMD_ADDRSPEC)) {
mdb_warn("can't walk spa");
return (DCMD_ERR);
}
return (DCMD_OK);
}
if (flags & DCMD_PIPE_OUT) {
return (DCMD_OK);
}
if (DCMD_HDRSPEC(flags))
return (DCMD_ERR);
}
state = "UNKNOWN";
else
if (config) {
mdb_printf("\n");
mdb_inc_indent(4);
return (DCMD_ERR);
mdb_dec_indent(4);
}
mdb_arg_t v;
v.a_type = MDB_TYPE_STRING;
mdb_printf("\n");
mdb_inc_indent(4);
&v) != DCMD_OK)
return (DCMD_ERR);
mdb_dec_indent(4);
}
return (DCMD_OK);
}
typedef struct mdb_spa_config_spa {
/*
* ::spa_config
*
* Given a spa_t, print the configuration information stored in spa_config.
* Since it's just an nvlist, format it as an indented list of name=value pairs.
* We simply read the value of spa_config and pass off to ::nvlist.
*/
/* ARGSUSED */
static int
{
return (DCMD_USAGE);
addr, 0) == -1)
return (DCMD_ERR);
mdb_printf("(none)\n");
return (DCMD_OK);
}
0, NULL));
}
/*
* ::vdev
*
* Print out a summarized vdev_t, in the following form:
*
* ADDR STATE AUX DESC
*
* If '-r' is specified, recursively visit all children.
*
* With '-e', the statistics associated with the vdev are printed as well.
*/
static int
int recursive)
{
char desc[MAXNAMELEN];
int c, children;
return (DCMD_ERR);
}
if (flags & DCMD_PIPE_OUT) {
} else {
mdb_warn("failed to read vdev_path at %p\n",
return (DCMD_ERR);
}
mdb_warn("failed to read vdev_ops at %p\n",
return (DCMD_ERR);
}
} else {
}
mdb_printf("%<u>%-?s %-9s %-12s %-*s%</u>\n",
"ADDR", "STATE", "AUX",
"DESCRIPTION");
switch (vdev.vdev_state) {
case VDEV_STATE_CLOSED:
state = "CLOSED";
break;
case VDEV_STATE_OFFLINE:
state = "OFFLINE";
break;
case VDEV_STATE_CANT_OPEN:
state = "CANT_OPEN";
break;
case VDEV_STATE_DEGRADED:
state = "DEGRADED";
break;
case VDEV_STATE_HEALTHY:
state = "HEALTHY";
break;
case VDEV_STATE_REMOVED:
state = "REMOVED";
break;
case VDEV_STATE_FAULTED:
state = "FAULTED";
break;
default:
state = "UNKNOWN";
break;
}
case VDEV_AUX_NONE:
aux = "-";
break;
case VDEV_AUX_OPEN_FAILED:
aux = "OPEN_FAILED";
break;
case VDEV_AUX_CORRUPT_DATA:
aux = "CORRUPT_DATA";
break;
case VDEV_AUX_NO_REPLICAS:
aux = "NO_REPLICAS";
break;
case VDEV_AUX_BAD_GUID_SUM:
aux = "BAD_GUID_SUM";
break;
case VDEV_AUX_TOO_SMALL:
aux = "TOO_SMALL";
break;
case VDEV_AUX_BAD_LABEL:
aux = "BAD_LABEL";
break;
case VDEV_AUX_VERSION_NEWER:
aux = "VERS_NEWER";
break;
case VDEV_AUX_VERSION_OLDER:
aux = "VERS_OLDER";
break;
case VDEV_AUX_UNSUP_FEAT:
aux = "UNSUP_FEAT";
break;
case VDEV_AUX_SPARED:
aux = "SPARED";
break;
case VDEV_AUX_ERR_EXCEEDED:
aux = "ERR_EXCEEDED";
break;
case VDEV_AUX_IO_FAILURE:
aux = "IO_FAILURE";
break;
case VDEV_AUX_BAD_LOG:
aux = "BAD_LOG";
break;
case VDEV_AUX_EXTERNAL:
aux = "EXTERNAL";
break;
case VDEV_AUX_SPLIT_POOL:
aux = "SPLIT_POOL";
break;
default:
aux = "UNKNOWN";
break;
}
if (stats) {
int i;
mdb_inc_indent(4);
mdb_printf("\n");
mdb_printf("%<u> %12s %12s %12s %12s "
"%12s%</u>\n", "READ", "WRITE", "FREE", "CLAIM",
"IOCTL");
mdb_printf("OPS ");
for (i = 1; i < ZIO_TYPES; i++)
mdb_printf("\n");
mdb_printf("BYTES ");
for (i = 1; i < ZIO_TYPES; i++)
mdb_printf("\n");
mdb_printf("ECKSUM %10#llx\n",
mdb_dec_indent(4);
}
if (stats)
mdb_printf("\n");
}
return (DCMD_OK);
return (DCMD_ERR);
}
for (c = 0; c < children; c++) {
return (DCMD_ERR);
}
return (DCMD_OK);
}
static int
{
return (DCMD_USAGE);
if (!(flags & DCMD_ADDRSPEC)) {
mdb_warn("no vdev_t address given\n");
return (DCMD_ERR);
}
}
typedef struct metaslab_walk_data {
int mw_curvdev;
int mw_curms;
static int
{
return (WALK_DONE);
return (WALK_ERR);
}
mssp) == -1) {
return (WALK_ERR);
}
}
mw->mw_curvdev++;
return (WALK_NEXT);
}
return (WALK_ERR);
}
}
/* ARGSUSED */
static int
{
mdb_warn("must supply address of spa_t\n");
return (WALK_ERR);
}
return (DCMD_ERR);
}
childp) == -1) {
return (DCMD_ERR);
}
return (WALK_NEXT);
}
typedef struct mdb_spa {
} mdb_spa_t;
typedef struct mdb_dsl_dir {
typedef struct mdb_dsl_dir_phys {
typedef struct mdb_vdev {
} mdb_vdev_t;
typedef struct mdb_metaslab {
typedef struct space_data {
} space_data_t;
/* ARGSUSED */
static int
{
return (WALK_ERR);
}
return (WALK_NEXT);
}
/*
* ::spa_space [-b]
*
* Given a spa_t, print out it's on-disk space usage and in-core
* estimates of future usage. If -b is given, print space in bytes.
* Otherwise print in megabytes.
*/
/* ARGSUSED */
static int
{
int shift = 20;
char *suffix = "M";
argc)
return (DCMD_USAGE);
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
if (bytes) {
shift = 0;
suffix = "";
}
dp_root_dir, dp_root_dir) ||
return (DCMD_ERR);
}
mdb_printf("dd_space_towrite = %llu%s %llu%s %llu%s %llu%s\n",
mdb_printf("dd_phys.dd_used_bytes = %llu%s\n",
mdb_printf("dd_phys.dd_compressed_bytes = %llu%s\n",
mdb_printf("dd_phys.dd_uncompressed_bytes = %llu%s\n",
mdb_warn("can't walk metaslabs");
return (DCMD_ERR);
}
mdb_printf("ms_allocmap = %llu%s %llu%s %llu%s %llu%s\n",
mdb_printf("ms_freemap = %llu%s %llu%s %llu%s %llu%s\n",
mdb_printf("current syncing avail = %llu%s\n",
return (DCMD_OK);
}
/*
* ::spa_verify
*
* Given a spa_t, verify that that the pool is self-consistent.
* Currently, it only checks to make sure that the vdev tree exists.
*/
/* ARGSUSED */
static int
{
return (DCMD_USAGE);
return (DCMD_ERR);
}
mdb_printf("no vdev tree present\n");
return (DCMD_OK);
}
return (DCMD_OK);
}
static int
const char *name)
{
int ret, i;
/*
* Iterate over aux vdevs and print those out as well. This is a
* little annoying because we don't have a root vdev to pass to ::vdev.
* Instead, we print a single line and then call it for each child
* vdev.
*/
mdb_warn("failed to read l2cache vdevs at %p",
return (DCMD_ERR);
}
return (ret);
}
}
}
return (0);
}
/*
* ::spa_vdevs
*
* -e Include error stats
*
* Print out a summarized list of vdevs for the given spa_t.
* This is accomplished by invoking "::vdev -re" on the root vdev, as well as
* iterating over the cache devices.
*/
/* ARGSUSED */
static int
{
mdb_arg_t v[3];
int ret;
return (DCMD_USAGE);
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
return (DCMD_ERR);
}
/*
* Unitialized spa_t structures can have a NULL root vdev.
*/
mdb_printf("no associated vdevs\n");
return (DCMD_OK);
}
v[0].a_type = MDB_TYPE_STRING;
flags, 1, v);
return (ret);
return (DCMD_ERR);
return (DCMD_OK);
}
/*
* ::zio
*
* Print a summary of zio_t and all its children. This is intended to display a
* zio tree, and hence we only pick the most important pieces of information for
* the main summary. More detailed information can always be found by doing a
* '::print zio' on the underlying zio_t. The columns we display are:
*
* ADDRESS TYPE STAGE WAITER TIME_ELAPSED
*
* The 'address' column is indented by one space for each depth level as we
* descend down the tree.
*/
#define ZIO_MAXINDENT 7
#define ZIO_WALK_SELF 0
#define ZIO_WALK_CHILD 1
#define ZIO_WALK_PARENT 2
typedef struct zio_print_args {
int zpa_current_depth;
int zpa_min_depth;
int zpa_max_depth;
int zpa_type;
typedef struct mdb_zio {
void *io_waiter;
void *io_spa;
struct {
struct {
void *list_next;
} list_head;
int io_error;
} mdb_zio_t;
typedef struct mdb_zio_timestamp {
static int
{
mdb_zio_timestamp_t zio_timestamp = { 0 };
return (WALK_ERR);
if (indent > ZIO_MAXINDENT)
mdb_warn("failed to lookup zio enums");
return (WALK_ERR);
}
else
type = "?";
else
stage = "?";
} else {
stage = "FAILED";
}
} else {
else
#ifdef _KERNEL
if (zio_timestamp.io_timestamp != 0) {
1000000);
} else {
}
#else
#endif
mdb_printf("\n");
}
}
return (WALK_NEXT);
"io_parent_list");
else
"io_child_list");
zpa->zpa_current_depth++;
return (WALK_ERR);
}
zpa->zpa_current_depth--;
return (WALK_NEXT);
}
/* ARGSUSED */
static int
{
return (WALK_ERR);
}
else
}
/* ARGSUSED */
static int
{
zio_print_args_t zpa = { 0 };
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
return (DCMD_USAGE);
if (zpa.zpa_max_depth != 0) {
}
mdb_printf("%<u>%-*s %-5s %-16s %-16s %-12s%</u>\n",
"TIME_ELAPSED");
}
return (DCMD_ERR);
return (DCMD_OK);
}
/*
* [addr]::zio_state
*
* Print a summary of all zio_t structures on the system, or for a particular
* pool. This is equivalent to '::walk zio_root | ::zio'.
*/
/*ARGSUSED*/
static int
{
/*
* MDB will remember the last address of the pipeline, so if we don't
* zero this we'll end up trying to walk zio structures for a
* non-existent spa_t.
*/
if (!(flags & DCMD_ADDRSPEC))
addr = 0;
}
typedef struct txg_list_walk_data {
int lw_txgoff;
int lw_maxoff;
void *lw_obj;
static int
{
int i;
return (WALK_ERR);
}
for (i = 0; i < TXG_SIZE; i++)
return (WALK_NEXT);
}
static int
{
}
static int
{
return (txg_list_walk_init_common(wsp, 0, 0));
}
static int
{
}
static int
{
}
static int
{
}
static int
{
int status;
}
return (WALK_DONE);
return (WALK_ERR);
}
return (status);
}
/*
* ::walk spa
*
* Walk all named spa_t structures in the namespace. This is nothing more than
* a layered avl walk.
*/
static int
{
mdb_warn("spa walk only supports global walks\n");
return (WALK_ERR);
}
mdb_warn("failed to find symbol 'spa_namespace_avl'");
return (WALK_ERR);
}
mdb_warn("failed to walk 'avl'\n");
return (WALK_ERR);
}
return (WALK_NEXT);
}
static int
{
return (WALK_ERR);
}
}
/*
* [addr]::walk zio
*
* Walk all active zio_t structures on the system. This is simply a layered
* walk on top of ::walk zio_cache, with the optional ability to limit the
* structures to a particular pool.
*/
static int
{
mdb_warn("failed to walk 'zio_cache'\n");
return (WALK_ERR);
}
return (WALK_NEXT);
}
static int
{
return (WALK_ERR);
return (WALK_NEXT);
}
/*
* [addr]::walk zio_root
*
* Walk only root zio_t structures, optionally for a particular spa_t.
*/
static int
{
return (WALK_ERR);
return (WALK_NEXT);
/* If the parent list is not empty, ignore */
return (WALK_NEXT);
}
#define NICENUM_BUFLEN 6
static int
{
int mul = 1;
for (i = frac_digits; i; i--)
mul *= 10;
}
static void
{
int index = 0;
char *u;
while (n >= 1024) {
n = (n + (1024 / 2)) / 1024; /* Round up or down */
index++;
}
if (index == 0) {
(u_longlong_t)n);
} else {
(u_longlong_t)n, u);
}
}
/*
* ::zfs_blkstats
*
* -v print verbose per-level information
*
*/
static int
{
/* +10 in case it grew */
mdb_warn("failed to read 'dmu_ot'");
return (DCMD_ERR);
}
return (DCMD_USAGE);
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
mdb_printf("maybe no stats? run \"zpool scrub\" first.");
return (DCMD_ERR);
}
mdb_printf("Ganged blocks: %llu\n",
}
if (ditto != 0) {
mdb_printf("Dittoed blocks on same vdev: %llu\n",
(longlong_t)ditto);
}
mdb_printf("\nBlocks\tLSIZE\tPSIZE\tASIZE"
"\t avg\t comp\t%%Total\tType\n");
for (t = 0; t <= DMU_OT_TOTAL; t++) {
char avg[NICENUM_BUFLEN];
char typename[64];
int l;
if (t == DMU_OT_DEFERRED)
else if (t == DMU_OT_OTHER)
else if (t == DMU_OT_TOTAL)
mdb_warn("failed to read type name");
return (DCMD_ERR);
}
continue;
for (l = -1; l < DN_MAX_LEVELS; l++) {
continue;
/*
* Don't print each level unless requested.
*/
continue;
/*
* If all the space is level 0, don't print the
* level 0 separately.
*/
continue;
mdb_printf("%6s\t%5s\t%5s\t%5s\t%5s"
"\t%5s\t%6s\t",
if (level == DN_MAX_LEVELS)
else
mdb_printf(" L%d %s\n",
}
}
return (DCMD_OK);
}
/* ARGSUSED */
static int
{
static int gotid;
static mdb_ctf_id_t ref_id;
char holder_str[128];
if (!gotid) {
mdb_warn("couldn't find struct reference");
return (WALK_ERR);
}
}
return (WALK_ERR);
if (removed)
mdb_printf("removed ");
mdb_printf("reference ");
if (ref_number != 1)
if (holder_is_str)
mdb_printf(", held at:\n");
if (removed) {
mdb_printf("removed at:\n");
DCMD_ADDRSPEC, 0, NULL);
}
mdb_printf("\n");
return (WALK_NEXT);
}
/* ARGSUSED */
static int
{
static int gotid;
static mdb_ctf_id_t rc_id;
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
return (DCMD_USAGE);
if (!gotid) {
/*
* The refcount structure is different when compiled debug
* vs nondebug. Therefore, we want to make sure we get the
* refcount definition from the ZFS module, in case it has
* been compiled debug but genunix is nondebug.
*/
&rc_id) == -1) {
mdb_warn("couldn't find struct refcount");
return (DCMD_ERR);
}
}
return (DCMD_ERR);
mdb_printf("refcount_t at %p has %llu current holds\n",
return (DCMD_OK);
}
mdb_printf("refcount_t at %p has %llu current holds, "
"%llu recently released holds\n",
if (rc_count > 0)
mdb_printf("current holds:\n");
return (DCMD_ERR);
if (released) {
if (rc_removed_count > 0)
mdb_printf("released holds:\n");
return (DCMD_ERR);
}
return (DCMD_OK);
}
/* ARGSUSED */
static int
{
char *name;
int i;
return (DCMD_ERR);
}
return (DCMD_ERR);
}
mdb_printf("%<u>%-10s %-10s %-10s %-10s %s%</u>\n",
"ATTR ID", "REGISTERED", "LENGTH", "BSWAP", "NAME");
for (i = 0; i != sa_os.sa_num_attrs; i++) {
mdb_printf("%5x %8x %8x %8x %-s\n",
}
return (DCMD_OK);
}
static int
{
mdb_printf("can't find offset table in sa_idx_tab\n");
return (-1);
}
return (-1);
}
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
int attr_count;
if (argc != 1)
return (DCMD_USAGE);
else
return (DCMD_USAGE);
mdb_printf("Can't find necessary information in sa_handle "
"in sa_handle\n");
return (DCMD_ERR);
}
mdb_printf("Can't find os_sa in objset\n");
return (DCMD_ERR);
}
mdb_printf("Can't find sa_num_attrs\n");
return (DCMD_ERR);
}
if (attr_id > attr_count) {
mdb_printf("attribute id number is out of range\n");
return (DCMD_ERR);
}
if (bonus_tab) {
attr_count) == -1) {
return (DCMD_ERR);
}
mdb_printf("can't find db_data in bonus dbuf\n");
return (DCMD_ERR);
}
}
mdb_printf("Attribute does not exist\n");
return (DCMD_ERR);
attr_count) == -1) {
return (DCMD_ERR);
}
mdb_printf("can't find db_data in spill dbuf\n");
return (DCMD_ERR);
}
mdb_printf("Attribute does not exist\n");
return (DCMD_ERR);
}
}
return (DCMD_OK);
}
/* ARGSUSED */
static int
{
mdb_printf("%<u>%-?s %-8s %-8s %-8s %s%</u>\n",
"ADDR", "FLAGS", "MASK", "TYPE", "ID");
if (!verbose) {
return (DCMD_OK);
}
switch (ace_flags & ACE_TYPE_FLAGS) {
case ACE_OWNER:
mdb_printf("owner@:");
break;
case (ACE_IDENTIFIER_GROUP | ACE_GROUP):
mdb_printf("group@:");
break;
case ACE_EVERYONE:
mdb_printf("everyone@:");
break;
case ACE_IDENTIFIER_GROUP:
break;
case 0: /* User entry */
break;
}
/* print out permission mask */
if (access_mask & ACE_READ_DATA)
mdb_printf("r");
else
mdb_printf("-");
if (access_mask & ACE_WRITE_DATA)
mdb_printf("w");
else
mdb_printf("-");
if (access_mask & ACE_EXECUTE)
mdb_printf("x");
else
mdb_printf("-");
if (access_mask & ACE_APPEND_DATA)
mdb_printf("p");
else
mdb_printf("-");
if (access_mask & ACE_DELETE)
mdb_printf("d");
else
mdb_printf("-");
if (access_mask & ACE_DELETE_CHILD)
mdb_printf("D");
else
mdb_printf("-");
if (access_mask & ACE_READ_ATTRIBUTES)
mdb_printf("a");
else
mdb_printf("-");
if (access_mask & ACE_WRITE_ATTRIBUTES)
mdb_printf("A");
else
mdb_printf("-");
if (access_mask & ACE_READ_NAMED_ATTRS)
mdb_printf("R");
else
mdb_printf("-");
if (access_mask & ACE_WRITE_NAMED_ATTRS)
mdb_printf("W");
else
mdb_printf("-");
if (access_mask & ACE_READ_ACL)
mdb_printf("c");
else
mdb_printf("-");
if (access_mask & ACE_WRITE_ACL)
mdb_printf("C");
else
mdb_printf("-");
if (access_mask & ACE_WRITE_OWNER)
mdb_printf("o");
else
mdb_printf("-");
if (access_mask & ACE_SYNCHRONIZE)
mdb_printf("s");
else
mdb_printf("-");
mdb_printf(":");
/* Print out inheritance flags */
if (ace_flags & ACE_FILE_INHERIT_ACE)
mdb_printf("f");
else
mdb_printf("-");
mdb_printf("d");
else
mdb_printf("-");
if (ace_flags & ACE_INHERIT_ONLY_ACE)
mdb_printf("i");
else
mdb_printf("-");
mdb_printf("n");
else
mdb_printf("-");
mdb_printf("S");
else
mdb_printf("-");
mdb_printf("F");
else
mdb_printf("-");
if (ace_flags & ACE_INHERITED_ACE)
mdb_printf("I");
else
mdb_printf("-");
switch (ace_type) {
mdb_printf(":allow\n");
break;
mdb_printf(":deny\n");
break;
mdb_printf(":audit\n");
break;
mdb_printf(":alarm\n");
break;
default:
mdb_printf(":?\n");
}
return (DCMD_OK);
}
/* ARGSUSED */
static int
{
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
return (DCMD_USAGE);
mdb_warn("failed to read zfs_ace_t");
return (DCMD_ERR);
}
else
id = -1;
}
/* ARGSUSED */
static int
{
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
return (DCMD_USAGE);
mdb_warn("failed to read ace_t");
return (DCMD_ERR);
}
else
id = -1;
}
typedef struct acl_dump_args {
int a_argc;
int a_flags;
/* ARGSUSED */
static int
{
return (WALK_ERR);
}
} else {
return (WALK_ERR);
}
}
return (WALK_NEXT);
}
/* ARGSUSED */
static int
{
mdb_warn("can't walk ACEs");
return (DCMD_ERR);
}
} else {
mdb_warn("can't walk ACEs");
return (DCMD_ERR);
}
}
return (WALK_NEXT);
}
/* ARGSUSED */
static int
{
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
return (DCMD_USAGE);
mdb_warn("failed to read zfs_acl_t");
return (DCMD_ERR);
}
mdb_warn("can't walk ACL");
return (DCMD_ERR);
}
return (DCMD_OK);
}
/* ARGSUSED */
static int
{
mdb_warn("must supply address of zfs_acl_node_t\n");
return (WALK_ERR);
}
mdb_warn("failed to walk 'list'\n");
return (WALK_ERR);
}
return (WALK_NEXT);
}
static int
{
return (WALK_ERR);
}
}
typedef struct ace_walk_data {
int ace_count;
int ace_version;
static int
{
mdb_warn("must supply address of zfs_acl_node_t\n");
return (WALK_ERR);
}
return (WALK_NEXT);
}
static int
{
static int gotid;
static mdb_ctf_id_t acl_id;
int z_ace_count;
if (!gotid) {
if (mdb_ctf_lookup_by_name("struct zfs_acl_node",
&acl_id) == -1) {
mdb_warn("couldn't find struct zfs_acl_node");
return (DCMD_ERR);
}
}
return (DCMD_ERR);
}
return (DCMD_ERR);
}
z_ace_count, z_acldata));
}
/* ARGSUSED */
static int
{
}
/* ARGSUSED */
static int
{
return (zfs_acl_node_aces_walk_init_common(wsp, 0));
}
static int
{
int status;
int entry_type;
int allow_type;
return (WALK_DONE);
mdb_warn("failed to read zfs_ace_t at %#lx",
return (WALK_ERR);
}
switch (ace_data->ace_version) {
case 0:
break;
case 1:
break;
default:
return (WALK_ERR);
}
switch (entry_type) {
case ACE_OWNER:
case ACE_EVERYONE:
case (ACE_IDENTIFIER_GROUP | ACE_GROUP):
sizeof (ace_t) : sizeof (zfs_ace_hdr_t);
break;
case ACE_IDENTIFIER_GROUP:
default:
switch (allow_type) {
sizeof (ace_t) : sizeof (zfs_object_ace_t);
break;
default:
break;
}
}
return (status);
}
typedef struct mdb_zfs_rrwlock {
/* ARGSUSED */
static int
{
if (rrw_key == 0) {
return (DCMD_ERR);
}
0) == -1)
return (DCMD_ERR);
return (DCMD_OK);
}
if (rrw.rr_writer_wanted) {
mdb_printf("writer wanted\n");
}
mdb_printf("anonymous references:\n");
DCMD_ADDRSPEC, 0, NULL);
mdb_printf("linked references:\n");
DCMD_ADDRSPEC, 0, NULL);
/*
* XXX This should find references from
* "::walk thread | ::tsd -v <rrw_key>", but there is no support
* for programmatic consumption of dcmds, so this would be
* difficult, potentially requiring reimplementing ::tsd (both
* user and kernel versions) in this MDB module.
*/
return (DCMD_OK);
}
/*
* MDB module linkage information:
*
* We declare a list of structures describing our dcmds, and a function
* named _mdb_init to return a pointer to our module information.
*/
static const mdb_dcmd_t dcmds[] = {
{ "dbufs",
"\t[-O objset_t*] [-n objset_name | \"mos\"] "
"[-o object | \"mdn\"] \n"
"\t[-l level] [-b blkid | \"bonus\"]",
"find dmu_buf_impl_t's that match specified criteria", dbufs },
{ "abuf_find", "dva_word[0] dva_word[1]",
"find arc_buf_hdr_t of a specified DVA",
abuf_find },
{ "vdev", ":[-re]\n"
"\t-r display recursively\n"
"\t-e print statistics",
"vdev_t summary", vdev_print },
{ "zio", ":[cpr]\n"
"\t-c display children\n"
"\t-p display parents\n"
"\t-r display recursively",
"zio_t summary", zio_print },
{ "zio_state", "?", "print out all zio_t structures on system or "
"for a particular pool", zio_state },
{ "zfs_blkstats", ":[-v]",
"given a spa_t, print block type stats from last scrub",
zfs_blkstats },
{ "refcount", ":[-r]\n"
"\t-r display recently removed references",
"print refcount_t holders", refcount },
{ "zfs_aces", ":[-v]", "print all ACEs from a zfs_acl_t",
zfs_acl_dump },
{ "sa_attr_table", ":", "print SA attribute table from sa_os_t",
{ "sa_attr", ": attr_id",
"print SA attribute address when given sa_handle_t", sa_attr_print},
{ "zfs_dbgmsg", ":[-va]",
"print zfs debug log", dbgmsg},
{ "rrwlock", ":",
"print rrwlock_t, including readers", rrwlock},
{ NULL }
};
static const mdb_walker_t walkers[] = {
{ "zms_freelist", "walk ZFS metaslab freelist",
{ "txg_list", "given any txg_list_t *, walk all entries in all txgs",
{ "txg_list0", "given any txg_list_t *, walk all entries in txg 0",
{ "txg_list1", "given any txg_list_t *, walk all entries in txg 1",
{ "txg_list2", "given any txg_list_t *, walk all entries in txg 2",
{ "txg_list3", "given any txg_list_t *, walk all entries in txg 3",
{ "zio", "walk all zio structures, optionally for a particular spa_t",
{ "zio_root",
"walk all root zio_t structures, optionally for a particular spa_t",
{ "spa", "walk all spa_t entries in the namespace",
{ "metaslab", "given a spa_t *, walk all metaslab_t structures",
{ "zfs_acl_node", "given a zfs_acl_t, walk all zfs_acl_nodes",
{ "zfs_acl_node_aces", "given a zfs_acl_node_t, walk all ACEs",
{ "zfs_acl_node_aces0",
"given a zfs_acl_node_t, walk all ACEs as ace_t",
{ NULL }
};
static const mdb_modinfo_t modinfo = {
};
const mdb_modinfo_t *
_mdb_init(void)
{
return (&modinfo);
}