/* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright 2021 Tintri by DDN, Inc. All rights reserved. */ #include #include #include #include #include #include #include #include #include "nfs_clnt.h" #include "common.h" /* * Common functions */ static void nfs_print_io_stat(uintptr_t kstat_addr) { kstat_t kstat; kstat_io_t kstat_io; mdb_printf("IO statistics for this mount:\n"); mdb_inc_indent(2); if (mdb_vread(&kstat, sizeof (kstat), kstat_addr) == -1 || mdb_vread(&kstat_io, sizeof (kstat_io), (uintptr_t)KSTAT_IO_PTR(&kstat)) == -1) { mdb_printf("No. of bytes read: %9s\n", "??"); mdb_printf("No. of read operations: %9s\n", "??"); mdb_printf("No. of bytes written: %9s\n", "??"); mdb_printf("No. of write operations: %9s\n", "??"); } else { mdb_printf("No. of bytes read: %9llu\n", kstat_io.nread); mdb_printf("No. of read operations: %9lu\n", kstat_io.reads); mdb_printf("No. of bytes written: %9llu\n", kstat_io.nwritten); mdb_printf("No. of write operations: %9lu\n", kstat_io.writes); } mdb_dec_indent(2); } static int walk_count_cb(uintptr_t addr, const void *data, void *cb_data) { (*(size_t *)cb_data)++; return (WALK_NEXT); } #define TBL_ENTRY(e) {#e, e} static const struct { const char *str; nfs_opnum4 op; } nfs4_op_tbl[] = { TBL_ENTRY(OP_ACCESS), TBL_ENTRY(OP_CLOSE), TBL_ENTRY(OP_COMMIT), TBL_ENTRY(OP_CREATE), TBL_ENTRY(OP_DELEGPURGE), TBL_ENTRY(OP_DELEGRETURN), TBL_ENTRY(OP_GETATTR), TBL_ENTRY(OP_GETFH), TBL_ENTRY(OP_LINK), TBL_ENTRY(OP_LOCK), TBL_ENTRY(OP_LOCKT), TBL_ENTRY(OP_LOCKU), TBL_ENTRY(OP_LOOKUP), TBL_ENTRY(OP_LOOKUPP), TBL_ENTRY(OP_NVERIFY), TBL_ENTRY(OP_OPEN), TBL_ENTRY(OP_OPENATTR), TBL_ENTRY(OP_OPEN_CONFIRM), TBL_ENTRY(OP_OPEN_DOWNGRADE), TBL_ENTRY(OP_PUTFH), TBL_ENTRY(OP_PUTPUBFH), TBL_ENTRY(OP_PUTROOTFH), TBL_ENTRY(OP_READ), TBL_ENTRY(OP_READDIR), TBL_ENTRY(OP_READLINK), TBL_ENTRY(OP_REMOVE), TBL_ENTRY(OP_RENAME), TBL_ENTRY(OP_RENEW), TBL_ENTRY(OP_RESTOREFH), TBL_ENTRY(OP_SAVEFH), TBL_ENTRY(OP_SECINFO), TBL_ENTRY(OP_SETATTR), TBL_ENTRY(OP_SETCLIENTID), TBL_ENTRY(OP_SETCLIENTID_CONFIRM), TBL_ENTRY(OP_VERIFY), TBL_ENTRY(OP_WRITE), TBL_ENTRY(OP_RELEASE_LOCKOWNER), TBL_ENTRY(OP_ILLEGAL), TBL_ENTRY(OP_CCREATE), TBL_ENTRY(OP_CLINK), TBL_ENTRY(OP_CLOOKUP), TBL_ENTRY(OP_COPEN), TBL_ENTRY(OP_CPUTFH), TBL_ENTRY(OP_CREMOVE), TBL_ENTRY(OP_CRENAME), TBL_ENTRY(OP_CSECINFO), {NULL} }; static const char * nfs4_op_str(nfs_opnum4 op) { int i; for (i = 0; nfs4_op_tbl[i].str != NULL; i++) if (nfs4_op_tbl[i].op == op) return (nfs4_op_tbl[i].str); return ("??"); } static const struct { const char *str; nfs4_recov_t action; } nfs4_recov_tbl[] = { TBL_ENTRY(NR_UNUSED), TBL_ENTRY(NR_CLIENTID), TBL_ENTRY(NR_OPENFILES), TBL_ENTRY(NR_FHEXPIRED), TBL_ENTRY(NR_FAILOVER), TBL_ENTRY(NR_WRONGSEC), TBL_ENTRY(NR_EXPIRED), TBL_ENTRY(NR_BAD_STATEID), TBL_ENTRY(NR_BADHANDLE), TBL_ENTRY(NR_BAD_SEQID), TBL_ENTRY(NR_OLDSTATEID), TBL_ENTRY(NR_GRACE), TBL_ENTRY(NR_DELAY), TBL_ENTRY(NR_LOST_LOCK), TBL_ENTRY(NR_LOST_STATE_RQST), TBL_ENTRY(NR_STALE), TBL_ENTRY(NR_MOVED), {NULL} }; static const char * nfs4_recov_str(nfs4_recov_t action) { int i; for (i = 0; nfs4_recov_tbl[i].str != NULL; i++) if (nfs4_recov_tbl[i].action == action) return (nfs4_recov_tbl[i].str); return ("??"); } static const struct { const char *str; nfsstat4 stat; } nfs4_stat_tbl[] = { TBL_ENTRY(NFS4_OK), TBL_ENTRY(NFS4ERR_PERM), TBL_ENTRY(NFS4ERR_NOENT), TBL_ENTRY(NFS4ERR_IO), TBL_ENTRY(NFS4ERR_NXIO), TBL_ENTRY(NFS4ERR_ACCESS), TBL_ENTRY(NFS4ERR_EXIST), TBL_ENTRY(NFS4ERR_XDEV), TBL_ENTRY(NFS4ERR_NOTDIR), TBL_ENTRY(NFS4ERR_ISDIR), TBL_ENTRY(NFS4ERR_INVAL), TBL_ENTRY(NFS4ERR_FBIG), TBL_ENTRY(NFS4ERR_NOSPC), TBL_ENTRY(NFS4ERR_ROFS), TBL_ENTRY(NFS4ERR_MLINK), TBL_ENTRY(NFS4ERR_NAMETOOLONG), TBL_ENTRY(NFS4ERR_NOTEMPTY), TBL_ENTRY(NFS4ERR_DQUOT), TBL_ENTRY(NFS4ERR_STALE), TBL_ENTRY(NFS4ERR_BADHANDLE), TBL_ENTRY(NFS4ERR_BAD_COOKIE), TBL_ENTRY(NFS4ERR_NOTSUPP), TBL_ENTRY(NFS4ERR_TOOSMALL), TBL_ENTRY(NFS4ERR_SERVERFAULT), TBL_ENTRY(NFS4ERR_BADTYPE), TBL_ENTRY(NFS4ERR_DELAY), TBL_ENTRY(NFS4ERR_SAME), TBL_ENTRY(NFS4ERR_DENIED), TBL_ENTRY(NFS4ERR_EXPIRED), TBL_ENTRY(NFS4ERR_LOCKED), TBL_ENTRY(NFS4ERR_GRACE), TBL_ENTRY(NFS4ERR_FHEXPIRED), TBL_ENTRY(NFS4ERR_SHARE_DENIED), TBL_ENTRY(NFS4ERR_WRONGSEC), TBL_ENTRY(NFS4ERR_CLID_INUSE), TBL_ENTRY(NFS4ERR_RESOURCE), TBL_ENTRY(NFS4ERR_MOVED), TBL_ENTRY(NFS4ERR_NOFILEHANDLE), TBL_ENTRY(NFS4ERR_MINOR_VERS_MISMATCH), TBL_ENTRY(NFS4ERR_STALE_CLIENTID), TBL_ENTRY(NFS4ERR_STALE_STATEID), TBL_ENTRY(NFS4ERR_OLD_STATEID), TBL_ENTRY(NFS4ERR_BAD_STATEID), TBL_ENTRY(NFS4ERR_BAD_SEQID), TBL_ENTRY(NFS4ERR_NOT_SAME), TBL_ENTRY(NFS4ERR_LOCK_RANGE), TBL_ENTRY(NFS4ERR_SYMLINK), TBL_ENTRY(NFS4ERR_RESTOREFH), TBL_ENTRY(NFS4ERR_LEASE_MOVED), TBL_ENTRY(NFS4ERR_ATTRNOTSUPP), TBL_ENTRY(NFS4ERR_NO_GRACE), TBL_ENTRY(NFS4ERR_RECLAIM_BAD), TBL_ENTRY(NFS4ERR_RECLAIM_CONFLICT), TBL_ENTRY(NFS4ERR_BADXDR), TBL_ENTRY(NFS4ERR_LOCKS_HELD), TBL_ENTRY(NFS4ERR_OPENMODE), TBL_ENTRY(NFS4ERR_BADOWNER), TBL_ENTRY(NFS4ERR_BADCHAR), TBL_ENTRY(NFS4ERR_BADNAME), TBL_ENTRY(NFS4ERR_BAD_RANGE), TBL_ENTRY(NFS4ERR_LOCK_NOTSUPP), TBL_ENTRY(NFS4ERR_OP_ILLEGAL), TBL_ENTRY(NFS4ERR_DEADLOCK), TBL_ENTRY(NFS4ERR_FILE_OPEN), TBL_ENTRY(NFS4ERR_ADMIN_REVOKED), TBL_ENTRY(NFS4ERR_CB_PATH_DOWN), {NULL} }; static const char * nfs4_stat_str(nfsstat4 stat) { int i; for (i = 0; nfs4_stat_tbl[i].str != NULL; i++) if (nfs4_stat_tbl[i].stat == stat) return (nfs4_stat_tbl[i].str); return ("??"); } static const struct { const char *str; nfs4_tag_type_t tt; } nfs4_tag_tbl[] = { {"", TAG_NONE}, {"access", TAG_ACCESS}, {"close", TAG_CLOSE}, {"lost close", TAG_CLOSE_LOST}, {"undo close", TAG_CLOSE_UNDO}, {"commit", TAG_COMMIT}, {"delegreturn", TAG_DELEGRETURN}, {"fsinfo", TAG_FSINFO}, {"get symlink text", TAG_GET_SYMLINK}, {"getattr", TAG_GETATTR}, {"getattr fslocation", TAG_GETATTR_FSLOCATION}, {"inactive", TAG_INACTIVE}, {"link", TAG_LINK}, {"lock", TAG_LOCK}, {"reclaim lock", TAG_LOCK_RECLAIM}, {"resend lock", TAG_LOCK_RESEND}, {"reinstate lock", TAG_LOCK_REINSTATE}, {"unknown lock", TAG_LOCK_UNKNOWN}, {"lock test", TAG_LOCKT}, {"unlock", TAG_LOCKU}, {"resend locku", TAG_LOCKU_RESEND}, {"reinstate unlock", TAG_LOCKU_REINSTATE}, {"lookup", TAG_LOOKUP}, {"lookup parent", TAG_LOOKUP_PARENT}, {"lookup valid", TAG_LOOKUP_VALID}, {"lookup valid parent", TAG_LOOKUP_VPARENT}, {"mkdir", TAG_MKDIR}, {"mknod", TAG_MKNOD}, {"mount", TAG_MOUNT}, {"open", TAG_OPEN}, {"open confirm", TAG_OPEN_CONFIRM}, {"lost open confirm", TAG_OPEN_CONFIRM_LOST}, {"open downgrade", TAG_OPEN_DG}, {"lost open downgrade", TAG_OPEN_DG_LOST}, {"lost open", TAG_OPEN_LOST}, {"openattr", TAG_OPENATTR}, {"pathconf", TAG_PATHCONF}, {"putrootfh", TAG_PUTROOTFH}, {"read", TAG_READ}, {"readahead", TAG_READAHEAD}, {"readdir", TAG_READDIR}, {"readlink", TAG_READLINK}, {"relock", TAG_RELOCK}, {"remap lookup", TAG_REMAP_LOOKUP}, {"remap lookup attr dir", TAG_REMAP_LOOKUP_AD}, {"remap lookup named attrs", TAG_REMAP_LOOKUP_NA}, {"remap mount", TAG_REMAP_MOUNT}, {"rmdir", TAG_RMDIR}, {"remove", TAG_REMOVE}, {"rename", TAG_RENAME}, {"rename volatile fh", TAG_RENAME_VFH}, {"renew", TAG_RENEW}, {"reopen", TAG_REOPEN}, {"lost reopen", TAG_REOPEN_LOST}, {"secinfo", TAG_SECINFO}, {"setattr", TAG_SETATTR}, {"setclientid", TAG_SETCLIENTID}, {"setclientid_confirm", TAG_SETCLIENTID_CF}, {"symlink", TAG_SYMLINK}, {"write", TAG_WRITE}, {NULL, 0} }; static const char * nfs4_tag_str(nfs4_tag_type_t tt) { int i; for (i = 0; nfs4_tag_tbl[i].str != NULL; i++) if (nfs4_tag_tbl[i].tt == tt) return (nfs4_tag_tbl[i].str); return ("??"); } /* * nfs_mntinfo dcmd implementation */ static const mdb_bitmask_t nfs_mi_flags[] = { {"MI_HARD", MI_HARD, MI_HARD}, {"MI_PRINTED", MI_PRINTED, MI_PRINTED}, {"MI_INT", MI_INT, MI_INT}, {"MI_DOWN", MI_DOWN, MI_DOWN}, {"MI_NOAC", MI_NOAC, MI_NOAC}, {"MI_NOCTO", MI_NOCTO, MI_NOCTO}, {"MI_DYNAMIC", MI_DYNAMIC, MI_DYNAMIC}, {"MI_LLOCK", MI_LLOCK, MI_LLOCK}, {"MI_GRPID", MI_GRPID, MI_GRPID}, {"MI_RPCTIMESYNC", MI_RPCTIMESYNC, MI_RPCTIMESYNC}, {"MI_LINK", MI_LINK, MI_LINK}, {"MI_SYMLINK", MI_SYMLINK, MI_SYMLINK}, {"MI_READDIRONLY", MI_READDIRONLY, MI_READDIRONLY}, {"MI_ACL", MI_ACL, MI_ACL}, {"MI_BINDINPROG", MI_BINDINPROG, MI_BINDINPROG}, {"MI_LOOPBACK", MI_LOOPBACK, MI_LOOPBACK}, {"MI_SEMISOFT", MI_SEMISOFT, MI_SEMISOFT}, {"MI_NOPRINT", MI_NOPRINT, MI_NOPRINT}, {"MI_DIRECTIO", MI_DIRECTIO, MI_DIRECTIO}, {"MI_EXTATTR", MI_EXTATTR, MI_EXTATTR}, {"MI_ASYNC_MGR_STOP", MI_ASYNC_MGR_STOP, MI_ASYNC_MGR_STOP}, {"MI_DEAD", MI_DEAD, MI_DEAD}, {NULL, 0, 0} }; static int nfs_print_mntinfo_cb(uintptr_t addr, const void *data, void *cb_data) { const mntinfo_t *mi = data; uintptr_t nfs3_ops; vfs_t vfs; char buf[MAXPATHLEN]; uint_t opt_v = *(uint_t *)cb_data; int i; if (mdb_readvar(&nfs3_ops, "nfs3_vfsops") == -1) { mdb_warn("failed to read %s", "nfs3_vfsops"); return (WALK_ERR); } if (mdb_vread(&vfs, sizeof (vfs), (uintptr_t)mi->mi_vfsp) == -1) { mdb_warn("failed to read vfs_t at %p", mi->mi_vfsp); return (WALK_ERR); } mdb_printf("NFS Version: %d\n", nfs3_ops == (uintptr_t)vfs.vfs_op ? 3 : 2); mdb_inc_indent(2); mdb_printf("mi_flags: %b\n", mi->mi_flags, nfs_mi_flags); if (mdb_read_refstr((uintptr_t)vfs.vfs_mntpt, buf, sizeof (buf)) == -1) strcpy(buf, "??"); mdb_printf("mount point: %s\n", buf); if (mdb_read_refstr((uintptr_t)vfs.vfs_resource, buf, sizeof (buf)) == -1) strcpy(buf, "??"); mdb_printf("mount from: %s\n", buf); mdb_dec_indent(2); mdb_printf("\n"); if (!opt_v) return (WALK_NEXT); mdb_inc_indent(2); mdb_printf("mi_zone = %p\n", mi->mi_zone); mdb_printf("mi_curread = %i, mi_curwrite = %i, mi_retrans = %i, " "mi_timeo = %i\n", mi->mi_curread, mi->mi_curwrite, mi->mi_retrans, mi->mi_timeo); mdb_printf("mi_acregmin = %lu, mi_acregmax = %lu, mi_acdirmin = %lu, " "mi_acdirmax = %lu\n", mi->mi_acregmin, mi->mi_acregmax, mi->mi_acdirmin, mi->mi_acdirmax); mdb_printf("\nServer list: %p\n", mi->mi_servers); mdb_inc_indent(2); if (mdb_pwalk_dcmd("nfs_serv", "nfs_servinfo", 0, NULL, (uintptr_t)mi->mi_servers) == -1) mdb_printf("??\n"); mdb_dec_indent(2); mdb_printf("Current Server: %p ", mi->mi_curr_serv); if (mdb_call_dcmd("nfs_servinfo", (uintptr_t)mi->mi_curr_serv, DCMD_ADDRSPEC, 0, NULL) == -1) mdb_printf("??\n"); mdb_printf( "\nTotal: Server Non-responses = %u, Server Failovers = %u\n", mi->mi_noresponse, mi->mi_failover); if (mi->mi_io_kstats != NULL) nfs_print_io_stat((uintptr_t)mi->mi_io_kstats); mdb_printf("\nAsync Request queue:\n"); mdb_inc_indent(2); mdb_printf("max threads = %u, active threads = %u\n", mi->mi_max_threads, mi->mi_threads[NFS_ASYNC_QUEUE]); mdb_printf("Async reserved page operation only active threads = %u\n", mi->mi_threads[NFS_ASYNC_PGOPS_QUEUE]); mdb_printf("number requests queued:\n"); for (i = 0; i < NFS_ASYNC_TYPES; i++) { const char *opname; size_t count = 0; switch (i) { case NFS_PUTAPAGE: opname = "PUTAPAGE"; break; case NFS_PAGEIO: opname = "PAGEIO"; break; case NFS_COMMIT: opname = "COMMIT"; break; case NFS_READ_AHEAD: opname = "READ_AHEAD"; break; case NFS_READDIR: opname = "READDIR"; break; case NFS_INACTIVE: opname = "INACTIVE"; break; default: opname = "??"; break; } if (mi->mi_async_reqs[i] == NULL || mdb_pwalk("nfs_async", walk_count_cb, &count, (uintptr_t)mi->mi_async_reqs[i]) == -1) mdb_printf("\t%s = ??", opname); else mdb_printf("\t%s = %llu", opname, count); } mdb_printf("\n"); mdb_dec_indent(2); if (mi->mi_printftime) mdb_printf("\nLast error report time = %Y\n", mi->mi_printftime); mdb_dec_indent(2); mdb_printf("\n"); return (WALK_NEXT); } int nfs_mntinfo_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { mntinfo_t mi; uint_t opt_v = FALSE; if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc) return (DCMD_USAGE); if ((flags & DCMD_ADDRSPEC) == 0) { if (mdb_walk("nfs_mnt", nfs_print_mntinfo_cb, &opt_v) == -1) { mdb_warn("failed to walk nfs_mnt"); return (DCMD_ERR); } return (DCMD_OK); } if (mdb_vread(&mi, sizeof (mi), addr) == -1) { mdb_warn("failed to read mntinfo_t"); return (DCMD_ERR); } return (nfs_print_mntinfo_cb(addr, &mi, &opt_v) == WALK_ERR ? DCMD_ERR : DCMD_OK); } void nfs_mntinfo_help(void) { mdb_printf("-v verbose information\n"); } /* * nfs_servinfo dcmd implementation */ int nfs_servinfo_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { servinfo_t si; uint_t opt_v = FALSE; const char *addr_str; struct knetconfig knconf; char *hostname; int i; if ((flags & DCMD_ADDRSPEC) == 0) { mdb_printf("requires address of servinfo_t\n"); return (DCMD_USAGE); } if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc) return (DCMD_USAGE); if (mdb_vread(&si, sizeof (si), addr) == -1) { mdb_warn("can't read servinfo_t"); return (DCMD_ERR); } addr_str = common_netbuf_str(&si.sv_addr); if (!opt_v) { mdb_printf("%s\n", addr_str); return (DCMD_OK); } mdb_printf("secdata ptr = %p\n", si.sv_secdata); mdb_printf("address = "); if (mdb_vread(&knconf, sizeof (knconf), (uintptr_t)si.sv_knconf) == -1) { mdb_printf("?\?/?\?/??"); } else { char knc_str[KNC_STRSIZE]; mdb_printf("%u", knconf.knc_semantics); if (mdb_readstr(knc_str, sizeof (knc_str), (uintptr_t)knconf.knc_protofmly) == -1) mdb_printf("/??"); else mdb_printf("/%s", knc_str); if (mdb_readstr(knc_str, sizeof (knc_str), (uintptr_t)knconf.knc_proto) == -1) mdb_printf("/??"); else mdb_printf("/%s", knc_str); } mdb_printf("/%s\n", addr_str); if (si.sv_hostnamelen <= 0 || (hostname = mdb_alloc(si.sv_hostnamelen, UM_NOSLEEP | UM_GC)) == NULL || mdb_readstr(hostname, si.sv_hostnamelen, (uintptr_t)si.sv_hostname) == -1) mdb_printf("hostname = ??\n"); else mdb_printf("hostname = %s\n", hostname); mdb_printf("filehandle = "); if (si.sv_fhandle.fh_len >= 0 && si.sv_fhandle.fh_len <= NFS_FHANDLE_LEN) for (i = 0; i < si.sv_fhandle.fh_len; i++) mdb_printf("%02x", (unsigned char)si.sv_fhandle.fh_buf[i]); else mdb_printf("??"); mdb_printf("\n\n"); return (DCMD_OK); } void nfs_servinfo_help(void) { mdb_printf("-v verbose information\n"); } /* * nfs4_mntinfo dcmd implementation */ static const mdb_bitmask_t nfs_mi4_flags[] = { {"MI4_HARD", MI4_HARD, MI4_HARD}, {"MI4_PRINTED", MI4_PRINTED, MI4_PRINTED}, {"MI4_INT", MI4_INT, MI4_INT}, {"MI4_DOWN", MI4_DOWN, MI4_DOWN}, {"MI4_NOAC", MI4_NOAC, MI4_NOAC}, {"MI4_NOCTO", MI4_NOCTO, MI4_NOCTO}, {"MI4_LLOCK", MI4_LLOCK, MI4_LLOCK}, {"MI4_GRPID", MI4_GRPID, MI4_GRPID}, {"MI4_SHUTDOWN", MI4_SHUTDOWN, MI4_SHUTDOWN}, {"MI4_LINK", MI4_LINK, MI4_LINK}, {"MI4_SYMLINK", MI4_SYMLINK, MI4_SYMLINK}, {"MI4_EPHEMERAL_RECURSED", MI4_EPHEMERAL_RECURSED, MI4_EPHEMERAL_RECURSED}, {"MI4_ACL", MI4_ACL, MI4_ACL}, {"MI4_MIRRORMOUNT", MI4_MIRRORMOUNT, MI4_MIRRORMOUNT}, {"MI4_REFERRAL", MI4_REFERRAL, MI4_REFERRAL}, {"MI4_EPHEMERAL", MI4_EPHEMERAL, MI4_EPHEMERAL}, {"MI4_NOPRINT", MI4_NOPRINT, MI4_NOPRINT}, {"MI4_DIRECTIO", MI4_DIRECTIO, MI4_DIRECTIO}, {"MI4_RECOV_ACTIV", MI4_RECOV_ACTIV, MI4_RECOV_ACTIV}, {"MI4_REMOVE_ON_LAST_CLOSE", MI4_REMOVE_ON_LAST_CLOSE, MI4_REMOVE_ON_LAST_CLOSE}, {"MI4_RECOV_FAIL", MI4_RECOV_FAIL, MI4_RECOV_FAIL}, {"MI4_PUBLIC", MI4_PUBLIC, MI4_PUBLIC}, {"MI4_MOUNTING", MI4_MOUNTING, MI4_MOUNTING}, {"MI4_POSIX_LOCK", MI4_POSIX_LOCK, MI4_POSIX_LOCK}, {"MI4_LOCK_DEBUG", MI4_LOCK_DEBUG, MI4_LOCK_DEBUG}, {"MI4_DEAD", MI4_DEAD, MI4_DEAD}, {"MI4_INACTIVE_IDLE", MI4_INACTIVE_IDLE, MI4_INACTIVE_IDLE}, {"MI4_BADOWNER_DEBUG", MI4_BADOWNER_DEBUG, MI4_BADOWNER_DEBUG}, {"MI4_ASYNC_MGR_STOP", MI4_ASYNC_MGR_STOP, MI4_ASYNC_MGR_STOP}, {"MI4_TIMEDOUT", MI4_TIMEDOUT, MI4_TIMEDOUT}, {NULL, 0, 0} }; static const mdb_bitmask_t nfs_mi4_recovflags[] = { {"MI4R_NEED_CLIENTID", MI4R_NEED_CLIENTID, MI4R_NEED_CLIENTID}, {"MI4R_REOPEN_FILES", MI4R_REOPEN_FILES, MI4R_REOPEN_FILES}, {"MI4R_NEED_SECINFO", MI4R_NEED_SECINFO, MI4R_NEED_SECINFO}, {"MI4R_NEED_NEW_SERVER", MI4R_NEED_NEW_SERVER, MI4R_NEED_NEW_SERVER}, {"MI4R_REMAP_FILES", MI4R_REMAP_FILES, MI4R_REMAP_FILES}, {"MI4R_SRV_REBOOT", MI4R_SRV_REBOOT, MI4R_SRV_REBOOT}, {"MI4R_LOST_STATE", MI4R_LOST_STATE, MI4R_LOST_STATE}, {"MI4R_BAD_SEQID", MI4R_BAD_SEQID, MI4R_BAD_SEQID}, {"MI4R_MOVED", MI4R_MOVED, MI4R_MOVED}, {NULL, 0, 0} }; int nfs4_mntinfo_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { mntinfo4_t mi; vfs_t vfs; char buf[MAXPATHLEN]; uint_t opt_m = FALSE; uint_t opt_v = FALSE; if ((flags & DCMD_ADDRSPEC) == 0) { if (mdb_walk_dcmd("nfs4_mnt", "nfs4_mntinfo", argc, argv) == -1) { mdb_warn("failed to walk nfs4_mnt"); return (DCMD_ERR); } return (DCMD_OK); } if (mdb_getopts(argc, argv, 'm', MDB_OPT_SETBITS, TRUE, &opt_m, 'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc) return (DCMD_USAGE); if (mdb_vread(&mi, sizeof (mi), addr) == -1) { mdb_warn("failed to read mntinfo4_t at %p", addr); return (DCMD_ERR); } if (mdb_vread(&vfs, sizeof (vfs), (uintptr_t)mi.mi_vfsp) == -1) { mdb_warn("failed to read vfs_t at %p", mi.mi_vfsp); return (DCMD_ERR); } mdb_printf("+--------------------------------------+\n"); mdb_printf(" mntinfo4_t: 0x%p\n", addr); mdb_printf(" NFS Version: 4\n"); mdb_printf(" mi_flags: %b\n", mi.mi_flags, nfs_mi4_flags); mdb_printf(" mi_error: %u\n", mi.mi_error); mdb_printf(" mi_open_files: %i\n", mi.mi_open_files); mdb_printf(" mi_msg_count: %i\n", mi.mi_msg_count); mdb_printf(" mi_recovflags: %b\n", mi.mi_recovflags, nfs_mi4_recovflags); mdb_printf("mi_recovthread: 0x%p\n", mi.mi_recovthread); mdb_printf("mi_in_recovery: %i\n", mi.mi_in_recovery); if (mdb_read_refstr((uintptr_t)vfs.vfs_mntpt, buf, sizeof (buf)) == -1) strcpy(buf, "??"); mdb_printf(" mount point: %s\n", buf); if (mdb_read_refstr((uintptr_t)vfs.vfs_resource, buf, sizeof (buf)) == -1) strcpy(buf, "??"); mdb_printf(" mount from: %s\n", buf); if (opt_v) { int i; mdb_printf("\n"); mdb_inc_indent(2); mdb_printf("mi_zone = %p\n", mi.mi_zone); mdb_printf("mi_curread = %i, mi_curwrite = %i, " "mi_retrans = %i, mi_timeo = %i\n", mi.mi_curread, mi.mi_curwrite, mi.mi_retrans, mi.mi_timeo); mdb_printf("mi_acregmin = %lu, mi_acregmax = %lu, " "mi_acdirmin = %lu, mi_acdirmax = %lu\n", mi.mi_acregmin, mi.mi_acregmax, mi.mi_acdirmin, mi.mi_acdirmax); mdb_printf("\nServer list: %p\n", mi.mi_servers); mdb_inc_indent(2); if (mdb_pwalk_dcmd("nfs4_serv", "nfs4_servinfo", 0, NULL, (uintptr_t)mi.mi_servers) == -1) mdb_printf("??\n"); mdb_dec_indent(2); mdb_printf("Current Server: %p ", mi.mi_curr_serv); if (mdb_call_dcmd("nfs4_servinfo", (uintptr_t)mi.mi_curr_serv, DCMD_ADDRSPEC, 0, NULL) == -1) mdb_printf("??\n"); mdb_printf("\nTotal: Server Non-responses = %u, " "Server Failovers = %u\n", mi.mi_noresponse, mi.mi_failover); if (mi.mi_io_kstats != NULL) nfs_print_io_stat((uintptr_t)mi.mi_io_kstats); mdb_printf("\nAsync Request queue:\n"); mdb_inc_indent(2); mdb_printf("max threads = %u, active threads = %u\n", mi.mi_max_threads, mi.mi_threads[NFS4_ASYNC_QUEUE]); mdb_printf("Async reserved page operation only active " "threads = %u\n", mi.mi_threads[NFS4_ASYNC_PGOPS_QUEUE]); mdb_printf("number requests queued:\n"); for (i = 0; i < NFS4_ASYNC_TYPES; i++) { const char *opname; size_t count = 0; switch (i) { case NFS4_PUTAPAGE: opname = "PUTAPAGE"; break; case NFS4_PAGEIO: opname = "PAGEIO"; break; case NFS4_COMMIT: opname = "COMMIT"; break; case NFS4_READ_AHEAD: opname = "READ_AHEAD"; break; case NFS4_READDIR: opname = "READDIR"; break; case NFS4_INACTIVE: opname = "INACTIVE"; break; default: opname = "??"; break; } if (mi.mi_async_reqs[i] != NULL && mdb_pwalk("nfs4_async", walk_count_cb, &count, (uintptr_t)mi.mi_async_reqs[i]) == -1) mdb_printf("\t%s = ??", opname); else mdb_printf("\t%s = %llu", opname, count); } mdb_printf("\n"); mdb_dec_indent(2); mdb_dec_indent(2); } return (DCMD_OK); } void nfs4_mntinfo_help(void) { mdb_printf("::nfs4_mntinfo -> gives mntinfo4_t information\n" " ::nfs4_mntinfo -> walks thru all NFSv4 mntinfo4_t\n" "Each of these formats also takes the following argument\n" " -v -> Verbose output\n"); } /* * nfs4_servinfo dcmd implementation */ int nfs4_servinfo_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { servinfo4_t si; uint_t opt_v = FALSE; const char *addr_str; struct knetconfig knconf; char *hostname; int i; if ((flags & DCMD_ADDRSPEC) == 0) { mdb_printf("requires address of servinfo4_t\n"); return (DCMD_USAGE); } if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc) return (DCMD_USAGE); if (mdb_vread(&si, sizeof (si), addr) == -1) { mdb_warn("can't read servinfo_t"); return (DCMD_ERR); } addr_str = common_netbuf_str(&si.sv_addr); if (!opt_v) { mdb_printf("%s\n", addr_str); return (DCMD_OK); } mdb_printf("secdata ptr = %p\n", si.sv_secdata); mdb_printf("address = "); if (mdb_vread(&knconf, sizeof (knconf), (uintptr_t)si.sv_knconf) == -1) { mdb_printf("?\?/?\?/??"); } else { char knc_str[KNC_STRSIZE]; mdb_printf("%u", knconf.knc_semantics); if (mdb_readstr(knc_str, sizeof (knc_str), (uintptr_t)knconf.knc_protofmly) == -1) mdb_printf("/??"); else mdb_printf("/%s", knc_str); if (mdb_readstr(knc_str, sizeof (knc_str), (uintptr_t)knconf.knc_proto) == -1) mdb_printf("/??"); else mdb_printf("/%s", knc_str); } mdb_printf("/%s\n", addr_str); if (si.sv_hostnamelen <= 0 || (hostname = mdb_alloc(si.sv_hostnamelen, UM_NOSLEEP | UM_GC)) == NULL || mdb_readstr(hostname, si.sv_hostnamelen, (uintptr_t)si.sv_hostname) == -1) mdb_printf("hostname = ??\n"); else mdb_printf("hostname = %s\n", hostname); mdb_printf("server filehandle = "); if (si.sv_fhandle.fh_len >= 0 && si.sv_fhandle.fh_len <= NFS4_FHSIZE) for (i = 0; i < si.sv_fhandle.fh_len; i++) mdb_printf("%02x", (unsigned char)si.sv_fhandle.fh_buf[i]); else mdb_printf("??"); mdb_printf("\nparent dir filehandle = "); if (si.sv_pfhandle.fh_len >= 0 && si.sv_pfhandle.fh_len <= NFS4_FHSIZE) for (i = 0; i < si.sv_pfhandle.fh_len; i++) mdb_printf("%02x", (unsigned char)si.sv_pfhandle.fh_buf[i]); else mdb_printf("??"); mdb_printf("\n\n"); return (DCMD_OK); } void nfs4_servinfo_help(void) { mdb_printf("-v verbose information\n"); } /* * nfs4_server_info dcmd implementation */ static const mdb_bitmask_t nfs4_si_flags[] = { {"N4S_CLIENTID_SET", N4S_CLIENTID_SET, N4S_CLIENTID_SET}, {"N4S_CLIENTID_PEND", N4S_CLIENTID_PEND, N4S_CLIENTID_PEND}, {"N4S_CB_PINGED", N4S_CB_PINGED, N4S_CB_PINGED}, {"N4S_CB_WAITER", N4S_CB_WAITER, N4S_CB_WAITER}, {"N4S_INSERTED", N4S_INSERTED, N4S_INSERTED}, {"N4S_BADOWNER_DEBUG", N4S_BADOWNER_DEBUG, N4S_BADOWNER_DEBUG}, {NULL, 0, 0} }; int nfs4_server_info_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { nfs4_server_t srv; char *id_val; uint_t opt_c = FALSE; uint_t opt_s = FALSE; if ((flags & DCMD_ADDRSPEC) == 0) { if (mdb_walk_dcmd("nfs4_server", "nfs4_server_info", argc, argv) == -1) { mdb_warn("nfs4_server walker failed"); return (DCMD_ERR); } return (DCMD_OK); } if (mdb_getopts(argc, argv, 'c', MDB_OPT_SETBITS, TRUE, &opt_c, 's', MDB_OPT_SETBITS, TRUE, &opt_s, NULL) != argc) return (DCMD_USAGE); if (mdb_vread(&srv, sizeof (srv), addr) == -1) { mdb_warn("failed to read nfs4_server_t at %p", addr); return (DCMD_ERR); } if (srv.saddr.len == 0) return (DCMD_OK); mdb_printf("Address: %p Zone: %i Server: %s\n", addr, srv.zoneid, common_netbuf_str(&srv.saddr)); mdb_printf("Program: %x Flags: %b\n", srv.s_program, srv.s_flags, nfs4_si_flags); mdb_printf("Client ID: %#llx", srv.clientid); if (opt_s) { struct { uint32_t start_time; uint32_t c_id; } *impl_id = (void *)&srv.clientid; mdb_printf(" (srvrboot: %Y, c_id: %u)", impl_id->start_time, impl_id->c_id); } mdb_printf("\nCLIDtoSend: [verifier: %llx", srv.clidtosend.verifier); if (opt_c) { struct { uint32_t sec; uint32_t subsec; } *curtime = (void *)&srv.clidtosend.verifier; mdb_printf(" (%Y + %u nsec)", curtime->sec, curtime->subsec); } mdb_printf(", client identifier: "); id_val = mdb_alloc(srv.clidtosend.id_len, UM_NOSLEEP | UM_GC); if (id_val != NULL && mdb_vread(id_val, srv.clidtosend.id_len, (uintptr_t)srv.clidtosend.id_val) == srv.clidtosend.id_len) { uint_t i; if (opt_c) { size_t l; struct netbuf nb; l = strlen(id_val) + 1; nb.len = nb.maxlen = srv.clidtosend.id_len - l; nb.buf = srv.clidtosend.id_val + l; mdb_printf("(%s/%s) ", id_val, common_netbuf_str(&nb)); } for (i = 0; i < srv.clidtosend.id_len; i++) mdb_printf("%02x", (unsigned char)id_val[i]); } else { mdb_printf("??"); } mdb_printf(" ]\n"); mdb_printf("mntinfo4 list: %p\n", srv.mntinfo4_list); mdb_printf("Deleg list: %p ::walk list\n", addr + OFFSETOF(nfs4_server_t, s_deleg_list)); mdb_printf("Lease Valid: "); switch (srv.lease_valid) { case NFS4_LEASE_INVALID: mdb_printf("INVALID\n"); break; case NFS4_LEASE_VALID: mdb_printf("VALID\n"); break; case NFS4_LEASE_UNINITIALIZED: mdb_printf("UNINIT\n"); break; case NFS4_LEASE_NOT_STARTED: mdb_printf("NOT_STARTED\n"); break; default: mdb_printf("??\n"); break; } mdb_printf("Lease Time: %i sec\n", srv.s_lease_time); mdb_printf("Last renewal: %Y\n", srv.last_renewal_time); mdb_printf("Propgn Delay: %li sec : %li nsec\n", srv.propagation_delay.tv_sec, srv.propagation_delay.tv_nsec); mdb_printf("Credential: %p\n\n", srv.s_cred); return (DCMD_OK); } void nfs4_server_info_help(void) { mdb_printf( "-c assumes client is an illumos NFSv4 Client\n" "-s assumes server is an illumos NFSv4 Server\n" "\n" "The -c option enables the dcmd to decode the client generated\n" "structure CLIDtoSend that is normally opaque to the server.\n" "The -s option enables the dcmd to decode the server generated\n" "structure Client ID that is normally opaque to the client.\n"); } /* * nfs4_mimsg dcmd implementation */ static const struct { const char *str; nfs4_event_type_t et; } nfs4_event_type_tbl[] = { TBL_ENTRY(RE_BAD_SEQID), TBL_ENTRY(RE_BADHANDLE), TBL_ENTRY(RE_CLIENTID), TBL_ENTRY(RE_DEAD_FILE), TBL_ENTRY(RE_END), TBL_ENTRY(RE_FAIL_RELOCK), TBL_ENTRY(RE_FAIL_REMAP_LEN), TBL_ENTRY(RE_FAIL_REMAP_OP), TBL_ENTRY(RE_FAILOVER), TBL_ENTRY(RE_FILE_DIFF), TBL_ENTRY(RE_LOST_STATE), TBL_ENTRY(RE_OPENS_CHANGED), TBL_ENTRY(RE_SIGLOST), TBL_ENTRY(RE_SIGLOST_NO_DUMP), TBL_ENTRY(RE_START), TBL_ENTRY(RE_UNEXPECTED_ACTION), TBL_ENTRY(RE_UNEXPECTED_ERRNO), TBL_ENTRY(RE_UNEXPECTED_STATUS), TBL_ENTRY(RE_WRONGSEC), TBL_ENTRY(RE_LOST_STATE_BAD_OP), TBL_ENTRY(RE_REFERRAL), {NULL} }; static const struct { const char *str; nfs4_fact_type_t ft; } nfs4_fact_type_tbl[] = { TBL_ENTRY(RF_BADOWNER), TBL_ENTRY(RF_ERR), TBL_ENTRY(RF_RENEW_EXPIRED), TBL_ENTRY(RF_SRV_NOT_RESPOND), TBL_ENTRY(RF_SRV_OK), TBL_ENTRY(RF_SRVS_NOT_RESPOND), TBL_ENTRY(RF_SRVS_OK), TBL_ENTRY(RF_DELMAP_CB_ERR), TBL_ENTRY(RF_SENDQ_FULL), {NULL} }; static void mimsg_print_event(const nfs4_debug_msg_t *msg) { const nfs4_revent_t *ep = &msg->rmsg_u.msg_event; char msg_srv[MAXPATHLEN]; char msg_mntpt[MAXPATHLEN]; char char1[MAXPATHLEN]; char *char1p = char1; char char2[MAXPATHLEN]; char *char2p = char2; if (mdb_readstr(msg_srv, sizeof (msg_srv), (uintptr_t)msg->msg_srv) == -1) strcpy(msg_srv, "??"); if (mdb_readstr(msg_mntpt, sizeof (msg_mntpt), (uintptr_t)msg->msg_mntpt) == -1) strcpy(msg_mntpt, "??"); if (ep->re_char1 != NULL) { if (mdb_readstr(char1, sizeof (char1), (uintptr_t)ep->re_char1) == -1) strcpy(char1, "??"); } else { char1[0] = '\0'; char1p = NULL; } if (ep->re_char2 != NULL) { if (mdb_readstr(char2, sizeof (char2), (uintptr_t)ep->re_char2) == -1) strcpy(char2, "??"); } else { char2[0] = '\0'; char2p = NULL; } switch (ep->re_type) { case RE_BAD_SEQID: mdb_printf("Operation %s for file %s (rnode_pt 0x%p), pid %d " "using seqid %u got %s on server %s. Last good seqid was " "%u for operation %s.", nfs4_tag_str(ep->re_tag1), char1p, ep->re_rp1, ep->re_pid, ep->re_seqid1, nfs4_stat_str(ep->re_stat4), msg_srv, ep->re_seqid2, nfs4_tag_str(ep->re_tag2)); break; case RE_BADHANDLE: if (ep->re_char1 != NULL) { mdb_printf("server %s said filehandle was invalid for " "file: %s (rnode_pt %p) on mount %s", msg_srv, char1, ep->re_rp1, msg_mntpt); } else { mdb_printf("server %s said filehandle was invalid for " "file: (rnode_pt %p) on mount %s", msg_srv, ep->re_rp1, msg_mntpt); } break; case RE_CLIENTID: mdb_printf("Can't recover clientid on mi 0x%p due to error %u " "(%s), for server %s. Marking file system as unusable.", ep->re_mi, ep->re_uint, nfs4_stat_str(ep->re_stat4), msg_srv); break; case RE_DEAD_FILE: mdb_printf("File %s (rnode_pt %p) on server %s could not be " "recovered and was closed. %s %s.", char1p, ep->re_rp1, msg_srv, char2, ep->re_stat4 ? nfs4_stat_str(ep->re_stat4) : ""); break; case RE_END: mdb_printf("Recovery done for mount %s (0x%p) on server %s, " "rnode_pt1 %s (0x%p), rnode_pt2 %s (0x%p)", msg_mntpt, ep->re_mi, msg_srv, char1p, ep->re_rp1, char2p, ep->re_rp2); break; case RE_FAIL_RELOCK: mdb_printf("Couldn't reclaim lock for pid %d for file %s " "(rnode_pt %p) on (server %s): error %u", ep->re_pid, char1p, ep->re_rp1, msg_srv, ep->re_uint ? ep->re_uint : ep->re_stat4); break; case RE_FAIL_REMAP_LEN: mdb_printf("remap_lookup: server %s returned bad fhandle " "length (%u)", msg_srv, ep->re_uint); break; case RE_FAIL_REMAP_OP: mdb_printf("remap_lookup: didn't get expected OP_GETFH for " "server %s", msg_srv); break; case RE_FAILOVER: if (ep->re_char1) mdb_printf("Failing over from %s to %s", msg_srv, char1p); else mdb_printf("Failing over: selecting original server %s", msg_srv); break; case RE_FILE_DIFF: mdb_printf("Replicas %s and %s: file %s(%p) not same", msg_srv, msg_mntpt, ep->re_char1, (void *)ep->re_rp1); break; case RE_LOST_STATE: /* * if char1 is null you should use ::nfs4_fname for re_rp1 */ mdb_printf("client has a lost %s request for rnode_pt1 %s " "(0x%p), rnode_pt2 %s (0x%p) on fs %s, server %s.", nfs4_op_str(ep->re_uint), char1p, ep->re_rp1, char2p, ep->re_rp2, msg_mntpt, msg_srv); break; case RE_OPENS_CHANGED: mdb_printf("Recovery: number of open files changed " "for mount %s (0x%p) (old %d, new %d) on server %s\n", msg_mntpt, (void *)ep->re_mi, ep->re_uint, ep->re_pid, msg_srv); break; case RE_SIGLOST: case RE_SIGLOST_NO_DUMP: mdb_printf("Process %d lost its locks on file %s (rnode_pt %p) " "due to a NFS error (%u) on server %s", ep->re_pid, char1p, ep->re_rp1, ep->re_uint ? ep->re_uint : ep->re_stat4, msg_srv); break; case RE_START: mdb_printf("Starting recovery for mount %s (0x%p, flags %#x) " "on server %s, rnode_pt1 %s (0x%p), rnode_pt2 %s (0x%p)", msg_mntpt, ep->re_mi, ep->re_uint, msg_srv, char1p, ep->re_rp1, char2p, ep->re_rp2); break; case RE_UNEXPECTED_ACTION: mdb_printf("Recovery, unexpected action (%d) on server %s\n", ep->re_uint, msg_srv); break; case RE_UNEXPECTED_ERRNO: mdb_printf("Recovery, unexpected errno (%d) on server %s\n", ep->re_uint, msg_srv); break; case RE_UNEXPECTED_STATUS: mdb_printf("Recovery, unexpected NFS status code (%s) " "on server %s\n", nfs4_stat_str(ep->re_stat4), msg_srv); break; case RE_WRONGSEC: mdb_printf("Recovery, can't recover from NFS4ERR_WRONGSEC." " error %d for mount %s server %s: rnode_pt1 %s (0x%p)" " rnode_pt2 %s (0x%p)", ep->re_uint, msg_mntpt, msg_srv, ep->re_char1, (void *)ep->re_rp1, ep->re_char2, (void *)ep->re_rp2); break; case RE_LOST_STATE_BAD_OP: mdb_printf("NFS lost state with unrecognized op (%d)." " fs %s, server %s, pid %d, file %s (rnode_pt: 0x%p), " "dir %s (0x%p)", ep->re_uint, msg_mntpt, msg_srv, ep->re_pid, ep->re_char1, (void *)ep->re_rp1, ep->re_char2, (void *)ep->re_rp2); break; case RE_REFERRAL: if (ep->re_char1) mdb_printf("Referal, Server: %s on Mntpt: %s" "being referred from %s to %s", msg_srv, msg_mntpt, msg_srv, ep->re_char1); else mdb_printf("Referal, Server: %s on Mntpt: %s" "NFS4: being referred from %s to unknown server", msg_srv, msg_mntpt, msg->msg_srv); break; default: mdb_printf("illegal event %d", ep->re_type); break; } } static void mimsg_print_fact(const nfs4_debug_msg_t *msg) { const nfs4_rfact_t *fp = &msg->rmsg_u.msg_fact; char msg_srv[MAXPATHLEN]; char file[MAXPATHLEN]; if (mdb_readstr(msg_srv, sizeof (msg_srv), (uintptr_t)msg->msg_srv) == -1) strcpy(msg_srv, "??"); switch (fp->rf_type) { case RF_BADOWNER: mdb_printf("NFSMAPID_DOMAIN does not match server: %s's " "domain.", msg_srv); break; case RF_ERR: mdb_printf("Op %s got error ", nfs4_op_str(fp->rf_op)); if (fp->rf_error) mdb_printf("%d", fp->rf_error); else mdb_printf("%s", nfs4_stat_str(fp->rf_stat4)); mdb_printf(" causing recovery action %s.", nfs4_recov_str(fp->rf_action)); if (fp->rf_reboot) mdb_printf(" Client also suspects server rebooted"); break; case RF_RENEW_EXPIRED: mdb_printf("Client's lease expired on server %s.", msg_srv); break; case RF_SRV_NOT_RESPOND: mdb_printf("Server %s not responding, still trying", msg_srv); break; case RF_SRV_OK: mdb_printf("Server %s ok", msg_srv); break; case RF_SRVS_NOT_RESPOND: mdb_printf("Servers %s not responding, still trying", msg_srv); break; case RF_SRVS_OK: mdb_printf("Servers %s ok", msg_srv); break; case RF_DELMAP_CB_ERR: if (mdb_readstr(file, sizeof (file), (uintptr_t)fp->rf_char1) == -1) strcpy(file, "??"); mdb_printf("Op %s got error %s when executing delmap on file " "%s (rnode_pt 0x%p).", nfs4_op_str(fp->rf_op), nfs4_stat_str(fp->rf_stat4), file, fp->rf_rp1); break; case RF_SENDQ_FULL: mdb_printf("Send queue to NFS server %s is full; still trying", msg_srv); break; default: mdb_printf("??"); break; } } static int print_mimsg_cb(uintptr_t addr, const void *data, void *cb_data) { nfs4_debug_msg_t msg; uint_t opt_s = *(uint_t *)cb_data; if (mdb_vread(&msg, sizeof (msg), addr) == -1) { mdb_warn("failed to read nfs4_debug_msg_t at %p", addr); return (WALK_ERR); } if (opt_s) { const char *msg_type = "??"; const char *ef_type = "??"; int i; switch (msg.msg_type) { case RM_EVENT: msg_type = "event"; for (i = 0; nfs4_event_type_tbl[i].str != NULL; i++) if (nfs4_event_type_tbl[i].et == msg.rmsg_u.msg_event.re_type) { ef_type = nfs4_event_type_tbl[i].str; break; } break; case RM_FACT: msg_type = "fact"; for (i = 0; nfs4_fact_type_tbl[i].str != NULL; i++) if (nfs4_fact_type_tbl[i].ft == msg.rmsg_u.msg_fact.rf_type) { ef_type = nfs4_fact_type_tbl[i].str; break; } break; } mdb_printf("%Y: %s %s\n", msg.msg_time.tv_sec, msg_type, ef_type); return (WALK_NEXT); } mdb_printf("[NFS4]%Y: ", msg.msg_time.tv_sec); switch (msg.msg_type) { case RM_EVENT: mimsg_print_event(&msg); break; case RM_FACT: mimsg_print_fact(&msg); break; default: mdb_printf("??"); break; } mdb_printf("\n"); return (WALK_NEXT); } int nfs4_mimsg_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { uint_t opt_s = FALSE; if ((flags & DCMD_ADDRSPEC) == 0) { mdb_printf("requires address of mi_msg_list\n"); return (DCMD_USAGE); } if (mdb_getopts(argc, argv, 's', MDB_OPT_SETBITS, TRUE, &opt_s, NULL) != argc) return (DCMD_USAGE); if (mdb_pwalk("list", print_mimsg_cb, &opt_s, addr) == -1) { mdb_warn("failed to walk mi_msg_list list"); return (DCMD_ERR); } return (DCMD_OK); } void nfs4_mimsg_help(void) { mdb_printf( "-c assumes client is an illumos NFSv4 Client\n" "-s assumes server is an illumos NFSv4 Server\n" "\n" "The -c option enables the dcmd to decode the client generated\n" "structure CLIDtoSend that is normally opaque to the server.\n" "The -s option enables the dcmd to decode the server generated\n" "structure Client ID that is normally opaque to the client.\n"); } /* * nfs4_fname dcmd implementation */ static void print_nfs4_fname(uintptr_t addr) { char path[MAXPATHLEN]; char *p = path + sizeof (path) - 1; *p = '\0'; while (addr != 0) { nfs4_fname_t fn; char name[MAXNAMELEN]; if (mdb_vread(&fn, sizeof (fn), addr) == -1 || fn.fn_len >= sizeof (name) || fn.fn_len < 0 || p - fn.fn_len - 1 < path || mdb_readstr(name, sizeof (name), (uintptr_t)fn.fn_name) != fn.fn_len) { mdb_printf("??"); break; } bcopy(name, p -= fn.fn_len, fn.fn_len); if ((addr = (uintptr_t)fn.fn_parent) != 0) *--p = '/'; } mdb_printf("%s", p); } int nfs4_fname_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { if ((flags & DCMD_ADDRSPEC) == 0) { mdb_printf("requires address of nfs4_fname_t \n"); return (DCMD_USAGE); } if (argc != 0) return (DCMD_USAGE); print_nfs4_fname(addr); mdb_printf("\n"); return (DCMD_OK); } /* * Open Owner commands and walkers */ int nfs4_oo_cb(uintptr_t addr, const void *data, void *varg) { nfs4_open_owner_t oop; if (mdb_vread(&oop, sizeof (nfs4_open_owner_t), addr) == -1) { mdb_warn("failed to read nfs4_open_onwer at %p", addr); return (WALK_ERR); } mdb_printf("%p %p %d %d %s %s\n", addr, oop.oo_cred, oop.oo_ref_count, oop.oo_seqid, oop.oo_just_created ? "True" : "False", oop.oo_seqid_inuse ? "True" : "False"); return (WALK_NEXT); } /* * nfs4_foo dcmd implementation */ int nfs4_foo_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { int foo_off; uintptr_t list_addr; mntinfo4_t mi; foo_off = offsetof(mntinfo4_t, mi_foo_list); if ((flags & DCMD_ADDRSPEC) == 0) { mdb_printf("requires address of mntinfo4_t\n"); return (DCMD_USAGE); } if (argc != 0) return (DCMD_USAGE); if (mdb_vread(&mi, sizeof (mntinfo4_t), addr) == -1) { mdb_warn("Failed to read mntinfo at %p", addr); return (DCMD_ERR); } list_addr = addr + foo_off; mdb_printf("mntinfo4: %p, mi_foo_num=%d, mi_foo_max=%d \n", addr, mi.mi_foo_num, mi.mi_foo_max); mdb_printf("Address Cred RefCnt SeqID "); mdb_printf("JustCre SeqInUse BadSeqid\n"); if (mdb_pwalk("list", nfs4_oo_cb, NULL, list_addr) == -1) { mdb_warn("failed to walk 'nfs4_foo'"); return (DCMD_ERR); } return (DCMD_OK); } /* * nfs4_oob_dcmd dcmd */ int nfs4_oob_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { int oo_off; uintptr_t list_addr; uintptr_t list_inst; int i; if ((flags & DCMD_ADDRSPEC) == 0) { mdb_printf("requires address of mntinfo4_t\n"); return (DCMD_USAGE); } if (argc != 0) return (DCMD_USAGE); oo_off = offsetof(mntinfo4_t, mi_oo_list); list_addr = addr + oo_off; mdb_printf("Address Cred RefCnt SeqID "); mdb_printf("JustCre SeqInUse BadSeqid\n"); for (i = 0; i < NFS4_NUM_OO_BUCKETS; i++) { list_inst = list_addr + (sizeof (nfs4_oo_hash_bucket_t) * i); if (mdb_pwalk("list", nfs4_oo_cb, NULL, list_inst) == -1) { mdb_warn("failed to walk 'nfs4_oob'"); return (DCMD_ERR); } } return (DCMD_OK); } /* * print out open stream entry */ int nfs4_openstream_print(uintptr_t addr, void *buf, int *opts) { nfs4_open_stream_t os; if (mdb_vread(&os, sizeof (nfs4_open_stream_t), addr) == -1) { mdb_warn("Failed to read open stream at %p", addr); return (DCMD_ERR); } mdb_printf("%p\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t" "%d\t%d\t%d\n", addr, os.os_ref_count, os.os_share_acc_read, os.os_share_acc_write, os.os_mmap_read, os.os_mmap_write, os.os_share_deny_none, os.os_share_deny_read, os.os_share_deny_write, os.os_open_ref_count, os.os_dc_openacc, os.os_mapcnt); if (opts && *opts & TRUE) { mdb_printf(" "); if (os.os_valid) mdb_printf("os_valid "); if (os.os_delegation) mdb_printf("os_delegation "); if (os.os_final_close) mdb_printf("os_final_close "); if (os.os_pending_close) mdb_printf("os_pending_close "); if (os.os_failed_reopen) mdb_printf("os_failed_reopen "); if (os.os_force_close) mdb_printf("os_force_close "); mdb_printf("os_orig_oo_name: %s\n", (uchar_t *)&os.os_orig_oo_name); } return (DCMD_OK); } /* * nfs4_svnode dcmd implementation */ int nfs4_openstreams_cb(uintptr_t addr, void *private, int *opts) { mdb_ctf_id_t ctfid; ulong_t offset; uintptr_t os_list_ptr; /* * Walk the rnode4 ptr's r_open_streams list. */ if ((mdb_ctf_lookup_by_name("rnode4_t", &ctfid) == 0) && (mdb_ctf_offsetof(ctfid, "r_open_streams", &offset) == 0) && (offset % (sizeof (uintptr_t) * NBBY) == 0)) { offset /= NBBY; } else { offset = offsetof(rnode4_t, r_open_streams); } os_list_ptr = addr + offset; if (mdb_pwalk("list", (mdb_walk_cb_t)nfs4_openstream_print, opts, os_list_ptr) == -1) { mdb_warn("Failed to walk r_open_streams"); return (DCMD_ERR); } return (DCMD_OK); } /* * nfs4_os_dcmd list open streams */ int nfs4_os_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { int opts = 0; if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &opts, NULL) != argc) { return (DCMD_USAGE); } mdb_printf(" ref\t| os_share | os_mmap | " "os_share_deny | open | deleg |\t|\n"); mdb_printf("%%-?s %-s|%s %s|%s %s|%s %s %s|" "%s |%s |%s |%\n", "Address", "count", "acc_read", "acc_write", "read", "write", "none", "read", "write", "count", "access", "mapcnt"); /* * Walk the rnode4 cache if no address is specified */ if (!(flags & DCMD_ADDRSPEC)) { if (mdb_walk("nfs_rtable4", (mdb_walk_cb_t)nfs4_openstreams_cb, &opts) == -1) { mdb_warn("unable to walk nfs_rtable4"); return (DCMD_ERR); } return (DCMD_OK); } return (nfs4_openstreams_cb(addr, NULL, &opts)); } int nfs4_svnode_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { svnode_t sn; if ((flags & DCMD_ADDRSPEC) == 0) { mdb_printf("requires address of svnode_t\n"); return (DCMD_USAGE); } if (argc != 0) return (DCMD_USAGE); if (mdb_vread(&sn, sizeof (sn), addr) == -1) { mdb_warn("can't read svnode_t at %p", addr); return (DCMD_ERR); } if (DCMD_HDRSPEC(flags)) mdb_printf("%%%-?s %-?s %-20s%%\n", "SVNODE", "VNODE", "PATH"); mdb_printf("%-?p %-?p ", addr, sn.sv_r_vnode); print_nfs4_fname((uintptr_t)sn.sv_name); mdb_printf("\n"); return (DCMD_OK); } /* * nfs_rtable walker implementation */ hash_table_walk_arg_t nfs_rtable_arg = { 0, /* will be set in the init */ 0, /* will be set in the init */ sizeof (rhashq_t), "r_hashf", OFFSETOF(rhashq_t, r_hashf), "rnode_t", sizeof (rnode_t), OFFSETOF(struct rnode, r_hashf) }; static int nfs_rtable_common_init(mdb_walk_state_t *wsp, const char *tabname, const char *sizename) { hash_table_walk_arg_t *arg = wsp->walk_arg; int rtsize; uintptr_t rtaddr; if (mdb_readsym(&rtsize, sizeof (rtsize), sizename) == -1) { mdb_warn("failed to get %s", sizename); return (WALK_ERR); } if (rtsize < 0) { mdb_warn("%s is negative: %d", sizename, rtsize); return (WALK_ERR); } if (mdb_readsym(&rtaddr, sizeof (rtaddr), tabname) == -1) { mdb_warn("failed to get %s", tabname); return (WALK_ERR); } arg->array_addr = rtaddr; arg->array_len = rtsize; return (hash_table_walk_init(wsp)); } int nfs_rtable_walk_init(mdb_walk_state_t *wsp) { if (wsp->walk_addr != 0) { mdb_warn("nfs_rtable supports only global walks"); return (WALK_ERR); } return (nfs_rtable_common_init(wsp, "rtable", "rtablesize")); } /* * nfs_rtable4 walker implementation */ hash_table_walk_arg_t nfs_rtable4_arg = { 0, /* will be set in the init */ 0, /* will be set in the init */ sizeof (r4hashq_t), "r_hashf", OFFSETOF(r4hashq_t, r_hashf), "rnode4_t", sizeof (rnode4_t), OFFSETOF(struct rnode4, r_hashf) }; int nfs_rtable4_walk_init(mdb_walk_state_t *wsp) { if (wsp->walk_addr != 0) { mdb_warn("nfs_rtable4 supports only global walks"); return (WALK_ERR); } return (nfs_rtable_common_init(wsp, "rtable4", "rtable4size")); } /* * nfs_vfs walker implementation */ typedef struct nfs_vfs_walk { uintptr_t nfs2_ops; uintptr_t nfs3_ops; uintptr_t nfs4_ops; void *data; /* walker specific data */ } nfs_vfs_walk_t; int nfs_vfs_walk_init(mdb_walk_state_t *wsp) { nfs_vfs_walk_t data; nfs_vfs_walk_t *datap; if (mdb_readvar(&data.nfs2_ops, "nfs_vfsops") == -1) { mdb_warn("failed to read %s", "nfs_vfsops"); return (WALK_ERR); } if (mdb_readvar(&data.nfs3_ops, "nfs3_vfsops") == -1) { mdb_warn("failed to read %s", "nfs3_vfsops"); return (WALK_ERR); } if (mdb_readvar(&data.nfs4_ops, "nfs4_vfsops") == -1) { mdb_warn("failed to read %s", "nfs4_vfsops"); return (WALK_ERR); } if (mdb_layered_walk("genunix`vfs", wsp) == -1) { mdb_warn("failed to walk vfs"); return (WALK_ERR); } datap = mdb_alloc(sizeof (data), UM_SLEEP); *datap = data; wsp->walk_data = datap; return (WALK_NEXT); } int nfs_vfs_walk_step(mdb_walk_state_t *wsp) { nfs_vfs_walk_t *data = (nfs_vfs_walk_t *)wsp->walk_data; vfs_t *vfs = (vfs_t *)wsp->walk_layer; if (data->nfs2_ops != (uintptr_t)vfs->vfs_op && data->nfs3_ops != (uintptr_t)vfs->vfs_op && data->nfs4_ops != (uintptr_t)vfs->vfs_op) return (WALK_NEXT); return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer, wsp->walk_cbdata)); } void nfs_vfs_walk_fini(mdb_walk_state_t *wsp) { mdb_free(wsp->walk_data, sizeof (nfs_vfs_walk_t)); } /* * nfs_mnt walker implementation */ int nfs_mnt_walk_init(mdb_walk_state_t *wsp) { int status; nfs_vfs_walk_t *data; status = nfs_vfs_walk_init(wsp); if (status != WALK_NEXT) return (status); data = wsp->walk_data; data->data = mdb_alloc(sizeof (mntinfo_t), UM_SLEEP); return (WALK_NEXT); } int nfs_mnt_walk_step(mdb_walk_state_t *wsp) { nfs_vfs_walk_t *data = (nfs_vfs_walk_t *)wsp->walk_data; vfs_t *vfs = (vfs_t *)wsp->walk_layer; if (data->nfs2_ops != (uintptr_t)vfs->vfs_op && data->nfs3_ops != (uintptr_t)vfs->vfs_op) return (WALK_NEXT); if (mdb_vread(data->data, sizeof (mntinfo_t), (uintptr_t)VFTOMI(vfs)) == -1) { mdb_warn("can't read mntinfo"); return (WALK_ERR); } return (wsp->walk_callback((uintptr_t)VFTOMI(vfs), data->data, wsp->walk_cbdata)); } void nfs_mnt_walk_fini(mdb_walk_state_t *wsp) { nfs_vfs_walk_t *data = (nfs_vfs_walk_t *)wsp->walk_data; mdb_free(data->data, sizeof (mntinfo_t)); nfs_vfs_walk_fini(wsp); } /* * nfs4_mnt walker implementation */ int nfs4_mnt_walk_init(mdb_walk_state_t *wsp) { int status; nfs_vfs_walk_t *data; status = nfs_vfs_walk_init(wsp); if (status != WALK_NEXT) return (status); data = wsp->walk_data; data->data = mdb_alloc(sizeof (mntinfo4_t), UM_SLEEP); return (WALK_NEXT); } int nfs4_mnt_walk_step(mdb_walk_state_t *wsp) { nfs_vfs_walk_t *data = (nfs_vfs_walk_t *)wsp->walk_data; vfs_t *vfs = (vfs_t *)wsp->walk_layer; if (data->nfs4_ops != (uintptr_t)vfs->vfs_op) return (WALK_NEXT); if (mdb_vread(data->data, sizeof (mntinfo4_t), (uintptr_t)VFTOMI4(vfs)) == -1) { mdb_warn("can't read mntinfo4"); return (WALK_ERR); } return (wsp->walk_callback((uintptr_t)VFTOMI4(vfs), data->data, wsp->walk_cbdata)); } void nfs4_mnt_walk_fini(mdb_walk_state_t *wsp) { nfs_vfs_walk_t *data = (nfs_vfs_walk_t *)wsp->walk_data; mdb_free(data->data, sizeof (mntinfo4_t)); nfs_vfs_walk_fini(wsp); } /* * nfs_serv walker implementation */ int nfs_serv_walk_init(mdb_walk_state_t *wsp) { if (wsp->walk_addr == 0) { mdb_warn("global walk not supported"); return (WALK_ERR); } return (WALK_NEXT); } int nfs_serv_walk_step(mdb_walk_state_t *wsp) { servinfo_t si; uintptr_t addr = wsp->walk_addr; if (addr == 0) return (WALK_DONE); if (mdb_vread(&si, sizeof (si), addr) == -1) { mdb_warn("can't read servinfo_t"); return (WALK_ERR); } wsp->walk_addr = (uintptr_t)si.sv_next; return (wsp->walk_callback(addr, &si, wsp->walk_cbdata)); } /* * nfs4_serv walker implementation */ int nfs4_serv_walk_init(mdb_walk_state_t *wsp) { if (wsp->walk_addr == 0) { mdb_warn("global walk not supported"); return (WALK_ERR); } return (WALK_NEXT); } int nfs4_serv_walk_step(mdb_walk_state_t *wsp) { servinfo4_t si; uintptr_t addr = wsp->walk_addr; if (addr == 0) return (WALK_DONE); if (mdb_vread(&si, sizeof (si), addr) == -1) { mdb_warn("can't read servinfo4_t"); return (WALK_ERR); } wsp->walk_addr = (uintptr_t)si.sv_next; return (wsp->walk_callback(addr, &si, wsp->walk_cbdata)); } /* * nfs4_svnode walker implementation */ int nfs4_svnode_walk_init(mdb_walk_state_t *wsp) { if (wsp->walk_addr == 0) { mdb_warn("global walk not supported"); return (WALK_ERR); } wsp->walk_data = (void *)wsp->walk_addr; return (WALK_NEXT); } int nfs4_svnode_walk_step(mdb_walk_state_t *wsp) { svnode_t sn; uintptr_t addr = wsp->walk_addr; int status; if (mdb_vread(&sn, sizeof (sn), addr) == -1) { mdb_warn("can't read svnode_t"); return (WALK_ERR); } wsp->walk_addr = (uintptr_t)sn.sv_forw; status = wsp->walk_callback(addr, &sn, wsp->walk_cbdata); if (status != WALK_NEXT) return (status); return (((void *)wsp->walk_addr == wsp->walk_data) ? WALK_DONE : WALK_NEXT); } /* * nfs4_server walker implementation */ int nfs4_server_walk_init(mdb_walk_state_t *wsp) { if (wsp->walk_addr == 0) { GElf_Sym sym; if (mdb_lookup_by_name("nfs4_server_lst", &sym) == -1) { mdb_warn("failed to find 'nfs4_server_lst'"); return (WALK_ERR); } wsp->walk_addr = sym.st_value; } wsp->walk_data = (void *)wsp->walk_addr; return (WALK_NEXT); } int nfs4_server_walk_step(mdb_walk_state_t *wsp) { nfs4_server_t srv; uintptr_t addr = wsp->walk_addr; int status; if (mdb_vread(&srv, sizeof (srv), addr) == -1) { mdb_warn("can't read nfs4_server_t"); return (WALK_ERR); } wsp->walk_addr = (uintptr_t)srv.forw; status = wsp->walk_callback(addr, &srv, wsp->walk_cbdata); if (status != WALK_NEXT) return (status); return (((void *)wsp->walk_addr == wsp->walk_data) ? WALK_DONE : WALK_NEXT); } /* * nfs_async walker implementation */ int nfs_async_walk_init(mdb_walk_state_t *wsp) { if (wsp->walk_addr == 0) { mdb_warn("global walk not supported"); return (WALK_ERR); } return (WALK_NEXT); } int nfs_async_walk_step(mdb_walk_state_t *wsp) { struct nfs_async_reqs areq; uintptr_t addr = wsp->walk_addr; if (addr == 0) return (WALK_DONE); if (mdb_vread(&areq, sizeof (areq), addr) == -1) { mdb_warn("can't read struct nfs_async_reqs"); return (WALK_ERR); } wsp->walk_addr = (uintptr_t)areq.a_next; return (wsp->walk_callback(addr, &areq, wsp->walk_cbdata)); } /* * nfs4_async walker implementation */ int nfs4_async_walk_init(mdb_walk_state_t *wsp) { if (wsp->walk_addr == 0) { mdb_warn("global walk not supported"); return (WALK_ERR); } return (WALK_NEXT); } int nfs4_async_walk_step(mdb_walk_state_t *wsp) { struct nfs4_async_reqs areq; uintptr_t addr = wsp->walk_addr; if (addr == 0) return (WALK_DONE); if (mdb_vread(&areq, sizeof (areq), addr) == -1) { mdb_warn("can't read struct nfs4_async_reqs"); return (WALK_ERR); } wsp->walk_addr = (uintptr_t)areq.a_next; return (wsp->walk_callback(addr, &areq, wsp->walk_cbdata)); } /* * nfs_acache_rnode walker implementation */ int nfs_acache_rnode_walk_init(mdb_walk_state_t *wsp) { rnode_t rn; if (wsp->walk_addr == 0) { mdb_warn("global walk not supported"); return (WALK_ERR); } if (mdb_vread(&rn, sizeof (rn), wsp->walk_addr) == -1) { mdb_warn("can't read rnode_t at %p", wsp->walk_addr); return (WALK_ERR); } wsp->walk_addr = (uintptr_t)rn.r_acache; return (WALK_NEXT); } int nfs_acache_rnode_walk_step(mdb_walk_state_t *wsp) { acache_t ac; uintptr_t addr = wsp->walk_addr; if (addr == 0) return (WALK_DONE); if (mdb_vread(&ac, sizeof (ac), addr) == -1) { mdb_warn("can't read acache_t at %p", addr); return (WALK_ERR); } wsp->walk_addr = (uintptr_t)ac.list; return (wsp->walk_callback(addr, &ac, wsp->walk_cbdata)); } /* * nfs_acache walker implementation */ static const hash_table_walk_arg_t nfs_acache_arg = { 0, /* placeholder */ 0, /* placeholder */ sizeof (acache_hash_t), "next", OFFSETOF(acache_hash_t, next), "acache_t", sizeof (acache_t), OFFSETOF(acache_t, next) }; int nfs_acache_walk_init(mdb_walk_state_t *wsp) { hash_table_walk_arg_t *arg; int size; uintptr_t addr; int status; if (wsp->walk_addr != 0) { mdb_warn("local walk not supported"); return (WALK_ERR); } if (mdb_readsym(&size, sizeof (size), "acachesize") == -1) { mdb_warn("failed to get %s", "acachesize"); return (WALK_ERR); } if (size < 0) { mdb_warn("%s is negative: %d", "acachesize", size); return (WALK_ERR); } if (mdb_readsym(&addr, sizeof (addr), "acache") == -1) { mdb_warn("failed to get %s", "acache"); return (WALK_ERR); } arg = mdb_alloc(sizeof (*arg), UM_SLEEP); bcopy(&nfs_acache_arg, arg, sizeof (*arg)); arg->array_addr = addr; arg->array_len = size; wsp->walk_arg = arg; status = hash_table_walk_init(wsp); if (status != WALK_NEXT) mdb_free(wsp->walk_arg, sizeof (hash_table_walk_arg_t)); return (status); } void nfs_acache_walk_fini(mdb_walk_state_t *wsp) { hash_table_walk_fini(wsp); mdb_free(wsp->walk_arg, sizeof (hash_table_walk_arg_t)); } /* * nfs_acache4_rnode walker implementation */ int nfs_acache4_rnode_walk_init(mdb_walk_state_t *wsp) { rnode4_t rn; if (wsp->walk_addr == 0) { mdb_warn("global walk not supported"); return (WALK_ERR); } if (mdb_vread(&rn, sizeof (rn), wsp->walk_addr) == -1) { mdb_warn("can't read rnode4_t at %p", wsp->walk_addr); return (WALK_ERR); } wsp->walk_addr = (uintptr_t)rn.r_acache; return (WALK_NEXT); } int nfs_acache4_rnode_walk_step(mdb_walk_state_t *wsp) { acache4_t ac; uintptr_t addr = wsp->walk_addr; if (addr == 0) return (WALK_DONE); if (mdb_vread(&ac, sizeof (ac), addr) == -1) { mdb_warn("can't read acache4_t at %p", addr); return (WALK_ERR); } wsp->walk_addr = (uintptr_t)ac.list; return (wsp->walk_callback(addr, &ac, wsp->walk_cbdata)); } /* * nfs_acache4 walker implementation */ static const hash_table_walk_arg_t nfs_acache4_arg = { 0, /* placeholder */ 0, /* placeholder */ sizeof (acache4_hash_t), "next", OFFSETOF(acache4_hash_t, next), "acache4_t", sizeof (acache4_t), OFFSETOF(acache4_t, next) }; int nfs_acache4_walk_init(mdb_walk_state_t *wsp) { hash_table_walk_arg_t *arg; int size; uintptr_t addr; int status; if (wsp->walk_addr != 0) { mdb_warn("local walk not supported"); return (WALK_ERR); } if (mdb_readsym(&size, sizeof (size), "acache4size") == -1) { mdb_warn("failed to get %s", "acache4size"); return (WALK_ERR); } if (size < 0) { mdb_warn("%s is negative: %d\n", "acache4size", size); return (WALK_ERR); } if (mdb_readsym(&addr, sizeof (addr), "acache4") == -1) { mdb_warn("failed to get %s", "acache4"); return (WALK_ERR); } arg = mdb_alloc(sizeof (*arg), UM_SLEEP); bcopy(&nfs_acache4_arg, arg, sizeof (*arg)); arg->array_addr = addr; arg->array_len = size; wsp->walk_arg = arg; status = hash_table_walk_init(wsp); if (status != WALK_NEXT) mdb_free(wsp->walk_arg, sizeof (hash_table_walk_arg_t)); return (status); } void nfs_acache4_walk_fini(mdb_walk_state_t *wsp) { hash_table_walk_fini(wsp); mdb_free(wsp->walk_arg, sizeof (hash_table_walk_arg_t)); }