1*6007Sthurlow /* 2*6007Sthurlow * CDDL HEADER START 3*6007Sthurlow * 4*6007Sthurlow * The contents of this file are subject to the terms of the 5*6007Sthurlow * Common Development and Distribution License (the "License"). 6*6007Sthurlow * You may not use this file except in compliance with the License. 7*6007Sthurlow * 8*6007Sthurlow * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*6007Sthurlow * or http://www.opensolaris.org/os/licensing. 10*6007Sthurlow * See the License for the specific language governing permissions 11*6007Sthurlow * and limitations under the License. 12*6007Sthurlow * 13*6007Sthurlow * When distributing Covered Code, include this CDDL HEADER in each 14*6007Sthurlow * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*6007Sthurlow * If applicable, add the following below this CDDL HEADER, with the 16*6007Sthurlow * fields enclosed by brackets "[]" replaced with your own identifying 17*6007Sthurlow * information: Portions Copyright [yyyy] [name of copyright owner] 18*6007Sthurlow * 19*6007Sthurlow * CDDL HEADER END 20*6007Sthurlow */ 21*6007Sthurlow 22*6007Sthurlow /* 23*6007Sthurlow * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24*6007Sthurlow * Use is subject to license terms. 25*6007Sthurlow */ 26*6007Sthurlow 27*6007Sthurlow 28*6007Sthurlow #pragma ident "%Z%%M% %I% %E% SMI" 29*6007Sthurlow 30*6007Sthurlow #include <sys/mdb_modapi.h> 31*6007Sthurlow #include <sys/types.h> 32*6007Sthurlow #include <sys/refstr_impl.h> 33*6007Sthurlow #include <sys/vnode.h> 34*6007Sthurlow #include <sys/vfs.h> 35*6007Sthurlow 36*6007Sthurlow #include "smbfs.h" 37*6007Sthurlow #include "smbfs_node.h" 38*6007Sthurlow 39*6007Sthurlow #define OPT_VERBOSE 0x0001 /* Be [-v]erbose in dcmd's */ 40*6007Sthurlow 41*6007Sthurlow /* 42*6007Sthurlow * This macro lets us easily use both sizeof (typename) 43*6007Sthurlow * and the string-ified typename for the error message. 44*6007Sthurlow */ 45*6007Sthurlow #define SMBFS_OBJ_FETCH(obj_addr, obj_type, dest, err) \ 46*6007Sthurlow if (mdb_vread(dest, sizeof (obj_type), ((uintptr_t)obj_addr)) \ 47*6007Sthurlow != sizeof (obj_type)) { \ 48*6007Sthurlow mdb_warn("error reading "#obj_type" at %p", obj_addr); \ 49*6007Sthurlow return (err); \ 50*6007Sthurlow } 51*6007Sthurlow 52*6007Sthurlow /* 53*6007Sthurlow * We need to read in a private copy 54*6007Sthurlow * of every string we want to print out. 55*6007Sthurlow */ 56*6007Sthurlow void 57*6007Sthurlow print_str(uintptr_t addr) 58*6007Sthurlow { 59*6007Sthurlow char buf[64]; 60*6007Sthurlow int len, mx = sizeof (buf) - 4; 61*6007Sthurlow 62*6007Sthurlow if ((len = mdb_readstr(buf, sizeof (buf), addr)) <= 0) { 63*6007Sthurlow mdb_printf(" (%p)", addr); 64*6007Sthurlow } else { 65*6007Sthurlow if (len > mx) 66*6007Sthurlow strcpy(&buf[mx], "..."); 67*6007Sthurlow mdb_printf(" %s", buf); 68*6007Sthurlow } 69*6007Sthurlow } 70*6007Sthurlow 71*6007Sthurlow /* 72*6007Sthurlow * Dcmd (and callback function) to print a summary of 73*6007Sthurlow * all "smbfs" entries in the VFS list. 74*6007Sthurlow */ 75*6007Sthurlow 76*6007Sthurlow typedef struct smbfs_vfs_cbdata { 77*6007Sthurlow int flags; 78*6007Sthurlow int printed_header; 79*6007Sthurlow uintptr_t vfsops; /* filter by vfs ops pointer */ 80*6007Sthurlow smbmntinfo_t smi; /* scratch space for smbfs_vfs_cb */ 81*6007Sthurlow } smbfs_vfs_cbdata_t; 82*6007Sthurlow 83*6007Sthurlow int 84*6007Sthurlow smbfs_vfs_cb(uintptr_t addr, const void *data, void *arg) 85*6007Sthurlow { 86*6007Sthurlow const vfs_t *vfs = data; 87*6007Sthurlow smbfs_vfs_cbdata_t *cbd = arg; 88*6007Sthurlow uintptr_t ta; 89*6007Sthurlow 90*6007Sthurlow /* Filter by matching smbfs ops vector. */ 91*6007Sthurlow if (cbd->vfsops && cbd->vfsops != (uintptr_t)vfs->vfs_op) { 92*6007Sthurlow return (WALK_NEXT); 93*6007Sthurlow } 94*6007Sthurlow 95*6007Sthurlow if (cbd->printed_header == 0) { 96*6007Sthurlow cbd->printed_header = 1; 97*6007Sthurlow mdb_printf("// vfs_t smbmntinfo_t mnt_path\n"); 98*6007Sthurlow } 99*6007Sthurlow 100*6007Sthurlow mdb_printf(" %-p", addr); /* vfs_t */ 101*6007Sthurlow mdb_printf(" %-p", (uintptr_t)vfs->vfs_data); 102*6007Sthurlow /* 103*6007Sthurlow * Note: vfs_mntpt is a refstr_t. 104*6007Sthurlow * Advance to string member. 105*6007Sthurlow */ 106*6007Sthurlow ta = (uintptr_t)vfs->vfs_mntpt; 107*6007Sthurlow ta += OFFSETOF(struct refstr, rs_string); 108*6007Sthurlow print_str(ta); 109*6007Sthurlow mdb_printf("\n"); 110*6007Sthurlow 111*6007Sthurlow if (cbd->flags & OPT_VERBOSE) { 112*6007Sthurlow mdb_inc_indent(2); 113*6007Sthurlow /* Don't fail the walk if this fails. */ 114*6007Sthurlow if (mdb_vread(&cbd->smi, sizeof (cbd->smi), 115*6007Sthurlow (uintptr_t)vfs->vfs_data) == -1) { 116*6007Sthurlow mdb_warn("error reading smbmntinfo_t at %p", 117*6007Sthurlow (uintptr_t)vfs->vfs_data); 118*6007Sthurlow } else { 119*6007Sthurlow /* Interesting parts of smbmntinfo_t */ 120*6007Sthurlow mdb_printf("smi_share: %p, smi_root: %p\n", 121*6007Sthurlow cbd->smi.smi_share, cbd->smi.smi_root); 122*6007Sthurlow } 123*6007Sthurlow mdb_dec_indent(2); 124*6007Sthurlow } 125*6007Sthurlow 126*6007Sthurlow return (WALK_NEXT); 127*6007Sthurlow } 128*6007Sthurlow 129*6007Sthurlow int 130*6007Sthurlow smbfs_vfs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 131*6007Sthurlow { 132*6007Sthurlow smbfs_vfs_cbdata_t *cbd; 133*6007Sthurlow vfs_t *vfs; 134*6007Sthurlow 135*6007Sthurlow cbd = mdb_zalloc(sizeof (*cbd), UM_SLEEP | UM_GC); 136*6007Sthurlow 137*6007Sthurlow /* 138*6007Sthurlow * Get the ops address here, so things work 139*6007Sthurlow * even if the smbfs module is loaded later 140*6007Sthurlow * than this mdb module. 141*6007Sthurlow */ 142*6007Sthurlow if (mdb_readvar(&cbd->vfsops, "smbfs_vfsops") == -1) { 143*6007Sthurlow mdb_warn("failed to find 'smbfs_vfsops'\n"); 144*6007Sthurlow return (DCMD_ERR); 145*6007Sthurlow } 146*6007Sthurlow 147*6007Sthurlow if (mdb_getopts(argc, argv, 148*6007Sthurlow 'v', MDB_OPT_SETBITS, OPT_VERBOSE, &cbd->flags, 149*6007Sthurlow NULL) != argc) { 150*6007Sthurlow return (DCMD_USAGE); 151*6007Sthurlow } 152*6007Sthurlow 153*6007Sthurlow if (!(flags & DCMD_ADDRSPEC)) { 154*6007Sthurlow if (mdb_walk("genunix`vfs", smbfs_vfs_cb, cbd) 155*6007Sthurlow == -1) { 156*6007Sthurlow mdb_warn("can't walk smbfs vfs"); 157*6007Sthurlow return (DCMD_ERR); 158*6007Sthurlow } 159*6007Sthurlow return (DCMD_OK); 160*6007Sthurlow } 161*6007Sthurlow 162*6007Sthurlow vfs = mdb_alloc(sizeof (*vfs), UM_SLEEP | UM_GC); 163*6007Sthurlow SMBFS_OBJ_FETCH(addr, vfs_t, vfs, DCMD_ERR); 164*6007Sthurlow smbfs_vfs_cb(addr, vfs, cbd); 165*6007Sthurlow return (DCMD_OK); 166*6007Sthurlow } 167*6007Sthurlow 168*6007Sthurlow void 169*6007Sthurlow smbfs_vfs_help(void) 170*6007Sthurlow { 171*6007Sthurlow mdb_printf( 172*6007Sthurlow "Display addresses of the mounted smbfs structures\n" 173*6007Sthurlow "and the pathname of the mountpoint\n" 174*6007Sthurlow "\nOptions:\n" 175*6007Sthurlow " -v display details of the smbmntinfo\n"); 176*6007Sthurlow } 177*6007Sthurlow 178*6007Sthurlow /* 179*6007Sthurlow * Walker for the smbnode hash table. 180*6007Sthurlow */ 181*6007Sthurlow 182*6007Sthurlow typedef struct smbnode_walk_data { 183*6007Sthurlow rhashq_t *smbtab; /* (our copy of) the smbtable */ 184*6007Sthurlow int tabsize; /* size of table */ 185*6007Sthurlow int nextidx; /* next bucket index */ 186*6007Sthurlow uintptr_t buckptr; /* target addr of current bucket */ 187*6007Sthurlow uintptr_t nodeptr; /* target addr of current smbnode */ 188*6007Sthurlow smbnode_t node; /* scratch space for _step */ 189*6007Sthurlow } smbnode_walk_data_t; 190*6007Sthurlow 191*6007Sthurlow int 192*6007Sthurlow smbnode_walk_init(mdb_walk_state_t *wsp) 193*6007Sthurlow { 194*6007Sthurlow size_t tabsz_bytes; 195*6007Sthurlow int tabsize; 196*6007Sthurlow uintptr_t smbtab; 197*6007Sthurlow smbnode_walk_data_t *smbw; 198*6007Sthurlow 199*6007Sthurlow if (wsp->walk_addr != NULL) { 200*6007Sthurlow mdb_warn("smbnode only supports global walks\n"); 201*6007Sthurlow return (WALK_ERR); 202*6007Sthurlow } 203*6007Sthurlow 204*6007Sthurlow if (mdb_readvar(&tabsize, "smbtablesize") == -1) { 205*6007Sthurlow mdb_warn("failed to read `smbtablesize'\n"); 206*6007Sthurlow return (WALK_ERR); 207*6007Sthurlow } 208*6007Sthurlow 209*6007Sthurlow if (tabsize == 0) { 210*6007Sthurlow return (WALK_DONE); 211*6007Sthurlow } 212*6007Sthurlow 213*6007Sthurlow if (mdb_readvar(&smbtab, "smbtable") == -1) { 214*6007Sthurlow mdb_warn("failed to read `smbtable'\n"); 215*6007Sthurlow return (WALK_ERR); 216*6007Sthurlow } 217*6007Sthurlow 218*6007Sthurlow smbw = mdb_alloc(sizeof (*smbw), UM_SLEEP | UM_GC); 219*6007Sthurlow 220*6007Sthurlow tabsz_bytes = tabsize * sizeof (rhashq_t); 221*6007Sthurlow smbw->smbtab = mdb_alloc(tabsz_bytes, UM_SLEEP | UM_GC); 222*6007Sthurlow if (mdb_vread(smbw->smbtab, tabsz_bytes, smbtab) != tabsz_bytes) { 223*6007Sthurlow mdb_warn("failed to read in smbtable from %p", smbtab); 224*6007Sthurlow return (WALK_ERR); 225*6007Sthurlow } 226*6007Sthurlow smbw->tabsize = tabsize; 227*6007Sthurlow smbw->nextidx = 1; 228*6007Sthurlow smbw->buckptr = smbtab; 229*6007Sthurlow smbw->nodeptr = (uintptr_t)smbw->smbtab[0].r_hashf; 230*6007Sthurlow wsp->walk_data = smbw; 231*6007Sthurlow 232*6007Sthurlow return (WALK_NEXT); 233*6007Sthurlow } 234*6007Sthurlow 235*6007Sthurlow int 236*6007Sthurlow smbnode_walk_step(mdb_walk_state_t *wsp) 237*6007Sthurlow { 238*6007Sthurlow smbnode_walk_data_t *smbw = wsp->walk_data; 239*6007Sthurlow int status; 240*6007Sthurlow 241*6007Sthurlow next_bucket: 242*6007Sthurlow while (smbw->nodeptr == smbw->buckptr && 243*6007Sthurlow smbw->nextidx < smbw->tabsize) { 244*6007Sthurlow 245*6007Sthurlow /* Skip an empty bucket */ 246*6007Sthurlow rhashq_t *h = &smbw->smbtab[smbw->nextidx]; 247*6007Sthurlow smbw->nodeptr = (uintptr_t)h->r_hashf; 248*6007Sthurlow smbw->nextidx++; 249*6007Sthurlow smbw->buckptr += sizeof (rhashq_t); 250*6007Sthurlow } 251*6007Sthurlow 252*6007Sthurlow if (smbw->nodeptr == smbw->buckptr) 253*6007Sthurlow return (WALK_DONE); 254*6007Sthurlow 255*6007Sthurlow if (mdb_vread(&smbw->node, sizeof (smbw->node), 256*6007Sthurlow smbw->nodeptr) != sizeof (smbw->node)) { 257*6007Sthurlow mdb_warn("failed to read smbnode at %p in bucket %p\n", 258*6007Sthurlow smbw->nodeptr, smbw->buckptr); 259*6007Sthurlow /* Proceed with next bucket. */ 260*6007Sthurlow smbw->nodeptr = smbw->buckptr; 261*6007Sthurlow goto next_bucket; 262*6007Sthurlow } 263*6007Sthurlow 264*6007Sthurlow status = wsp->walk_callback(smbw->nodeptr, 265*6007Sthurlow &smbw->node, wsp->walk_cbdata); 266*6007Sthurlow 267*6007Sthurlow /* Move to next node in this bucket */ 268*6007Sthurlow smbw->nodeptr = (uintptr_t)smbw->node.r_hashf; 269*6007Sthurlow 270*6007Sthurlow return (status); 271*6007Sthurlow } 272*6007Sthurlow 273*6007Sthurlow /*ARGSUSED*/ 274*6007Sthurlow void 275*6007Sthurlow smbnode_walk_fini(mdb_walk_state_t *wsp) 276*6007Sthurlow { 277*6007Sthurlow /* UM_GC takes care of it all. */ 278*6007Sthurlow } 279*6007Sthurlow 280*6007Sthurlow /* 281*6007Sthurlow * Dcmd (and callback function) to print a summary of 282*6007Sthurlow * all smbnodes in the node hash table. 283*6007Sthurlow */ 284*6007Sthurlow 285*6007Sthurlow typedef struct smbnode_cbdata { 286*6007Sthurlow int flags; 287*6007Sthurlow int printed_header; 288*6007Sthurlow uintptr_t smi; /* optional filtering by VFS */ 289*6007Sthurlow /* TODO: only nodes with a given [-h]ash */ 290*6007Sthurlow vnode_t vn; /* scratch space for smbnode_cb */ 291*6007Sthurlow } smbnode_cbdata_t; 292*6007Sthurlow 293*6007Sthurlow int 294*6007Sthurlow smbnode_cb(uintptr_t addr, const void *data, void *arg) 295*6007Sthurlow { 296*6007Sthurlow const smbnode_t *np = data; 297*6007Sthurlow smbnode_cbdata_t *cbd = arg; 298*6007Sthurlow 299*6007Sthurlow /* Optional filtering by mount point. */ 300*6007Sthurlow if (cbd->smi && cbd->smi != (uintptr_t)np->n_mount) { 301*6007Sthurlow return (WALK_NEXT); 302*6007Sthurlow } 303*6007Sthurlow 304*6007Sthurlow if (cbd->printed_header == 0) { 305*6007Sthurlow cbd->printed_header = 1; 306*6007Sthurlow mdb_printf("// smbnode vnode rpath\n"); 307*6007Sthurlow } 308*6007Sthurlow 309*6007Sthurlow mdb_printf(" %-p", addr); /* smbnode */ 310*6007Sthurlow mdb_printf(" %-p", (uintptr_t)np->r_vnode); 311*6007Sthurlow print_str((uintptr_t)np->n_rpath); 312*6007Sthurlow mdb_printf("\n"); 313*6007Sthurlow 314*6007Sthurlow if (cbd->flags & OPT_VERBOSE) { 315*6007Sthurlow mdb_inc_indent(2); 316*6007Sthurlow /* Don't fail the walk if this fails. */ 317*6007Sthurlow if (mdb_vread(&cbd->vn, sizeof (cbd->vn), 318*6007Sthurlow (uintptr_t)np->r_vnode) == -1) { 319*6007Sthurlow mdb_warn("error reading vnode_t at %p", 320*6007Sthurlow (uintptr_t)np->r_vnode); 321*6007Sthurlow } else { 322*6007Sthurlow /* Interesting parts of vnode_t */ 323*6007Sthurlow mdb_printf("v_type: %d v_path:", 324*6007Sthurlow cbd->vn.v_type); 325*6007Sthurlow print_str((uintptr_t)cbd->vn.v_path); 326*6007Sthurlow mdb_printf("\n"); 327*6007Sthurlow } 328*6007Sthurlow mdb_dec_indent(2); 329*6007Sthurlow } 330*6007Sthurlow 331*6007Sthurlow return (WALK_NEXT); 332*6007Sthurlow } 333*6007Sthurlow 334*6007Sthurlow int 335*6007Sthurlow smbnode_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 336*6007Sthurlow { 337*6007Sthurlow smbnode_cbdata_t *cbd; 338*6007Sthurlow smbnode_t *np; 339*6007Sthurlow 340*6007Sthurlow cbd = mdb_zalloc(sizeof (*cbd), UM_SLEEP | UM_GC); 341*6007Sthurlow 342*6007Sthurlow if (mdb_getopts(argc, argv, 343*6007Sthurlow 'v', MDB_OPT_SETBITS, OPT_VERBOSE, &cbd->flags, 344*6007Sthurlow 'm', MDB_OPT_UINTPTR, &cbd->smi, NULL) != argc) { 345*6007Sthurlow return (DCMD_USAGE); 346*6007Sthurlow } 347*6007Sthurlow 348*6007Sthurlow if (!(flags & DCMD_ADDRSPEC)) { 349*6007Sthurlow if (mdb_walk("smbnode", smbnode_cb, cbd) 350*6007Sthurlow == -1) { 351*6007Sthurlow mdb_warn("cannot walk smbnodes"); 352*6007Sthurlow return (DCMD_ERR); 353*6007Sthurlow } 354*6007Sthurlow return (DCMD_OK); 355*6007Sthurlow } 356*6007Sthurlow 357*6007Sthurlow np = mdb_alloc(sizeof (*np), UM_SLEEP | UM_GC); 358*6007Sthurlow SMBFS_OBJ_FETCH(addr, smbnode_t, np, DCMD_ERR); 359*6007Sthurlow smbnode_cb(addr, np, cbd); 360*6007Sthurlow 361*6007Sthurlow return (DCMD_OK); 362*6007Sthurlow } 363*6007Sthurlow 364*6007Sthurlow void 365*6007Sthurlow smbnode_help(void) 366*6007Sthurlow { 367*6007Sthurlow mdb_printf("Options:\n" 368*6007Sthurlow " -m mntinfo only show smbnodes belonging to mntinfo\n" 369*6007Sthurlow " -v be verbose when displaying smbnodes\n"); 370*6007Sthurlow } 371*6007Sthurlow 372*6007Sthurlow static const mdb_dcmd_t dcmds[] = { 373*6007Sthurlow { "smbfs_vfs", "?[-v]", 374*6007Sthurlow "show smbfs-mounted vfs structs", 375*6007Sthurlow smbfs_vfs_dcmd, smbfs_vfs_help }, 376*6007Sthurlow { "smbnode", "?[-v] [-m mntinfo]", 377*6007Sthurlow "show smbnodes", smbnode_dcmd, smbnode_help }, 378*6007Sthurlow {NULL} 379*6007Sthurlow }; 380*6007Sthurlow 381*6007Sthurlow static const mdb_walker_t walkers[] = { 382*6007Sthurlow { "smbnode", "walk smbnode hash table", 383*6007Sthurlow smbnode_walk_init, smbnode_walk_step, smbnode_walk_fini }, 384*6007Sthurlow {NULL} 385*6007Sthurlow }; 386*6007Sthurlow 387*6007Sthurlow static const mdb_modinfo_t modinfo = { 388*6007Sthurlow MDB_API_VERSION, 389*6007Sthurlow dcmds, 390*6007Sthurlow walkers 391*6007Sthurlow }; 392*6007Sthurlow 393*6007Sthurlow const mdb_modinfo_t * 394*6007Sthurlow _mdb_init(void) 395*6007Sthurlow { 396*6007Sthurlow return (&modinfo); 397*6007Sthurlow } 398