zfs.c revision a2eea2e101e6a163a537dcc6d4e3c4da2a0ea5b2
/*
* 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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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/zio_compress.h>
#ifndef _KERNEL
#endif
#ifdef _KERNEL
#define ZFS_OBJ_NAME "zfs"
#else
#define ZFS_OBJ_NAME "libzpool.so.1"
#endif
static char *
local_strdup(const char *s)
{
return (s1);
}
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 int
{
static int gotid;
static mdb_ctf_id_t rc_id;
if (!gotid) {
mdb_warn("couldn't find struct refcount");
return (DCMD_ERR);
}
}
char name[64];
return (DCMD_ERR);
}
off /= 8;
}
static int
{
return (DCMD_ERR);
}
return (DCMD_ERR);
}
return (DCMD_OK);
}
static int verbose;
static int
{
mdb_warn("must supply starting address\n");
return (WALK_ERR);
}
return (WALK_NEXT);
}
static int
{
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) {
if (mdb_ctf_lookup_by_name("struct dsl_dir",
&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) {
if (mdb_ctf_lookup_by_name("struct objset_impl",
&osi_id) == -1) {
mdb_warn("couldn't find struct objset_impl");
return (DCMD_ERR);
}
if (mdb_ctf_lookup_by_name("struct dsl_dataset",
&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
{
int i;
char stage[1024];
mdb_warn("Could not find enum zio_stage");
return (DCMD_ERR);
}
for (i = 0; i < 32; i++) {
if (addr & (1U << i)) {
"ZIO_STAGE_");
}
}
return (DCMD_OK);
}
/* ARGSUSED */
static int
{
int i;
char buf[MAXPATHLEN];
mdb_warn("failed to read blkptr_t");
return (DCMD_ERR);
}
return (DCMD_ERR);
for (i = 0; i < DMU_OT_NUMTYPES; i++) {
}
return (DCMD_ERR);
for (i = 0; i < ZIO_CHECKSUM_FUNCTIONS; i++) {
}
return (DCMD_ERR);
for (i = 0; i < ZIO_COMPRESS_FUNCTIONS; i++) {
}
/*
* Super-ick warning: This code is also duplicated in
*/
for (i = 0; i < BP_GET_NDVAS(&bp); i++) {
mdb_printf("DVA[%d]: vdev_id %lld / %llx\n", i,
mdb_printf("DVA[%d]: GANG: %-5s GRID: %04x\t"
mdb_printf("DVA[%d]: :%llu:%llx:%llx:%s%s%s%s\n", i,
}
mdb_printf("LSIZE: %-16llx\t\tPSIZE: %llx\n",
mdb_printf("ENDIAN: %6s\t\t\t\t\tTYPE: %s\n",
mdb_printf("BIRTH: %-16llx LEVEL: %-2d\tFILL: %llx\n",
mdb_printf("CKFUNC: %-16s\t\tCOMP: %s\n",
mdb_printf("CKSUM: %llx:%llx:%llx:%llx\n",
return (DCMD_OK);
}
/* 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");
}
mdb_warn("couldn't find struct dmu_buf_impl_t");
return (DCMD_ERR);
}
return (WALK_ERR);
}
return (WALK_ERR);
}
else
if (blkid == DB_BONUS_BLKID)
else
return (WALK_ERR);
}
mdb_printf("%p %8s %1u %9s %2llu %s\n",
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);
}
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);
}
void
abuf_help(void)
{
mdb_printf("::abuf_find dva_word[0] dva_word[1]\n");
}
/*
* ::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
{
char poolname[MAXNAMELEN];
"UNINIT", "UNAVAIL" };
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);
}
== -1) {
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);
}
/*
* ::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);
return (DCMD_ERR);
}
mdb_printf("(none)\n");
return (DCMD_OK);
}
0, NULL));
}
void
vdev_help(void)
{
mdb_printf("[vdev_t*]::vdev [-qr]\n"
"\t-> -q display vdev_queue parameters\n"
"\t-> -r recursive (visit all children)\n");
}
/*
* ::vdev
*
* Print out a summarized vdev_t, in the following form:
*
* ADDR STATE AUX DESC
*
* or with "-q" to print out a vdev_t's vdev_queue parameters:
*
* vdev_t: c26ae4c0
* c26ae73c min pending 0x2
* c26ae744 max pending 0x23
* c26ae74c agg limit 0x20000
* c26ae754 time shift 0x4
* c26ae75c ramp rate 0x2
*
* 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;
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;
default:
aux = "UNKNOWN";
break;
}
if (queue) {
mdb_inc_indent(4);
mdb_printf("\n");
mdb_printf("%p min pending 0x%llx\n",
mdb_printf("%p max pending 0x%llx\n",
mdb_printf("%p agg limit 0x%llx\n",
mdb_printf("%p time shift 0x%llx\n",
mdb_printf("%p ramp rate 0x%llx\n",
mdb_dec_indent(4);
}
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);
}
mdb_printf("\n");
}
return (DCMD_OK);
return (DCMD_ERR);
}
for (c = 0; c < children; c++) {
return (DCMD_ERR);
}
return (DCMD_OK);
}
static int
{
int print_queue = FALSE;
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 (bits) {
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_used_bytes = %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);
}
/*
* ::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.
*/
/* ARGSUSED */
static int
{
mdb_arg_t v;
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.a_type = MDB_TYPE_STRING;
flags, 1, &v));
}
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);
}
}
/*
* 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 meet criterion", dbufs },
{ "abuf_find", "dva_word[0] dva_word[1]",
"find arc_buf_hdr_t of a specified DVA",
abuf_find },
{ NULL }
};
static const mdb_walker_t walkers[] = {
/*
* In userland, there is no generic provider of list_t walkers, so we
* need to add it.
*/
#ifndef _KERNEL
#endif
{ "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",
{ "spa", "walk all spa_t entries in the namespace",
{ "metaslab", "given a spa_t *, walk all metaslab_t structures",
{ NULL }
};
static const mdb_modinfo_t modinfo = {
};
const mdb_modinfo_t *
_mdb_init(void)
{
return (&modinfo);
}