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