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 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/mdb_modapi.h> 29 #include <smbsrv/smb_vops.h> 30 #include <smbsrv/smb.h> 31 #include <smbsrv/mlsvc.h> 32 #include <smbsrv/smbvar.h> 33 34 #define SMB_DCMD_INDENT 4 35 36 static void smb_lookup_svc_state_str(smb_svcstate_t state, char *dst_str, 37 int slen); 38 39 /* 40 * Initialize the smb_session_t walker by reading the value of smb_info 41 * object in the kernel's symbol table. Only global walk supported. 42 */ 43 static int 44 smb_session_walk_init(mdb_walk_state_t *wsp) 45 { 46 GElf_Sym sym; 47 uintptr_t svcsm_addr; 48 49 if (wsp->walk_addr == NULL) { 50 if (mdb_lookup_by_name("smb_info", &sym) == -1) { 51 mdb_warn("failed to find 'smb_info'"); 52 return (WALK_ERR); 53 } 54 svcsm_addr = (uintptr_t)(sym.st_value + 55 offsetof(struct smb_info, si_svc_sm_ctx)); 56 wsp->walk_addr = svcsm_addr + 57 offsetof(smb_svc_sm_ctx_t, ssc_active_sessions); 58 } else { 59 mdb_printf("smb_session walk only supports global walks\n"); 60 return (WALK_ERR); 61 } 62 63 if (mdb_layered_walk("list", wsp) == -1) { 64 mdb_warn("failed to walk 'list'"); 65 return (WALK_ERR); 66 } 67 68 return (WALK_NEXT); 69 } 70 71 static int 72 smb_session_walk_step(mdb_walk_state_t *wsp) 73 { 74 return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer, 75 wsp->walk_cbdata)); 76 } 77 78 /* 79 * Initialize the smb_node_t walker by reading the value of smb_info 80 * object in the kernel's symbol table. Only global walk supported. 81 */ 82 static int 83 smb_node_walk_init(mdb_walk_state_t *wsp) 84 { 85 GElf_Sym sym; 86 int i; 87 uintptr_t node_hash_table_addr; 88 89 if (wsp->walk_addr == NULL) { 90 if (mdb_lookup_by_name("smb_info", &sym) == -1) { 91 mdb_warn("failed to find 'smb_info'"); 92 return (WALK_ERR); 93 } 94 node_hash_table_addr = (uintptr_t)(sym.st_value + 95 offsetof(struct smb_info, node_hash_table)); 96 } else { 97 mdb_printf("smb_node walk only supports global walks\n"); 98 return (WALK_ERR); 99 } 100 101 for (i = 0; i < SMBND_HASH_MASK + 1; i++) { 102 wsp->walk_addr = node_hash_table_addr + 103 (i * sizeof (smb_llist_t)) + 104 offsetof(smb_llist_t, ll_list); 105 if (mdb_layered_walk("list", wsp) == -1) { 106 mdb_warn("failed to walk 'list'"); 107 return (WALK_ERR); 108 } 109 } 110 111 return (WALK_NEXT); 112 } 113 114 static int 115 smb_node_walk_step(mdb_walk_state_t *wsp) 116 { 117 return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer, 118 wsp->walk_cbdata)); 119 } 120 121 /* 122 * ::smb_info 123 * 124 * smb_info dcmd - Print out the smb_info structure. 125 */ 126 /*ARGSUSED*/ 127 static int 128 smb_information(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 129 { 130 int print_config = FALSE; 131 struct smb_info smb_info; 132 GElf_Sym smb_info_sym; 133 char state_name[40]; 134 char last_state_name[40]; 135 136 if (mdb_getopts(argc, argv, 137 'c', MDB_OPT_SETBITS, TRUE, &print_config, 138 NULL) != argc) 139 return (DCMD_USAGE); 140 141 if (flags & DCMD_ADDRSPEC) 142 return (DCMD_USAGE); 143 144 if (mdb_lookup_by_obj(MDB_OBJ_EVERY, "smb_info", &smb_info_sym)) { 145 mdb_warn("failed to find symbol smb_info"); 146 return (DCMD_ERR); 147 } 148 149 if (mdb_readvar(&smb_info, "smb_info") == -1) { 150 mdb_warn("failed to read smb_info structure"); 151 return (DCMD_ERR); 152 } 153 154 /* Lookup state string */ 155 smb_lookup_svc_state_str(smb_info.si_svc_sm_ctx.ssc_state, 156 state_name, 40); 157 smb_lookup_svc_state_str(smb_info.si_svc_sm_ctx.ssc_last_state, 158 last_state_name, 40); 159 160 mdb_printf("SMB information:\n\n"); 161 mdb_printf(" SMB state :\t%s (%d)\n", state_name, 162 smb_info.si_svc_sm_ctx.ssc_state); 163 mdb_printf(" SMB last state :\t%s (%d)\n", last_state_name, 164 smb_info.si_svc_sm_ctx.ssc_last_state); 165 mdb_printf(" Active Sessions :\t%d\n", 166 smb_info.si_svc_sm_ctx.ssc_active_session_count); 167 mdb_printf("Deferred Sessions :\t%d\n", 168 smb_info.si_svc_sm_ctx.ssc_deferred_session_count); 169 mdb_printf(" SMB Open Files :\t%d\n", smb_info.open_files); 170 mdb_printf(" SMB Open Trees :\t%d\n", smb_info.open_trees); 171 mdb_printf(" SMB Open Users :\t%d\n\n", smb_info.open_users); 172 173 if (print_config) { 174 mdb_printf("Configuration:\n\n"); 175 (void) mdb_inc_indent(SMB_DCMD_INDENT); 176 mdb_printf("Max Buffer Size %d\n", 177 smb_info.si.skc_maxbufsize); 178 mdb_printf("Max Worker Thread %d\n", 179 smb_info.si.skc_maxworkers); 180 mdb_printf("Max Connections %d\n", 181 smb_info.si.skc_maxconnections); 182 mdb_printf("Keep Alive Timeout %d\n", 183 smb_info.si.skc_keepalive); 184 mdb_printf("%sRestrict Anonymous Access\n", 185 (smb_info.si.skc_restrict_anon) ? "" : "Do Not "); 186 mdb_printf("Signing %s\n", 187 (smb_info.si.skc_signing_enable) ? "Enabled" : "Disabled"); 188 mdb_printf("Signing %sRequired\n", 189 (smb_info.si.skc_signing_required) ? "" : "Not "); 190 mdb_printf("Signing Check %s\n", 191 (smb_info.si.skc_signing_check) ? "Enabled" : "Disabled"); 192 mdb_printf("Oplocks %s\n", 193 (smb_info.si.skc_oplock_enable) ? "Enabled" : "Disabled"); 194 mdb_printf("Oplock Timeout %d millisec\n", 195 smb_info.si.skc_oplock_timeout); 196 mdb_printf("Flush %sRequired\n", 197 (smb_info.si.skc_flush_required) ? "" : "Not "); 198 mdb_printf("Sync %s\n", 199 (smb_info.si.skc_sync_enable) ? "Enabled" : "Disabled"); 200 mdb_printf("Dir Symlink %s\n", 201 (smb_info.si.skc_dirsymlink_enable) ? 202 "Enabled" : "Disabled"); 203 mdb_printf("%sAnnounce Quota\n", 204 (smb_info.si.skc_announce_quota) ? "" : "Do Not "); 205 mdb_printf("Security Mode %d\n", smb_info.si.skc_secmode); 206 mdb_printf("LM Level %d\n", smb_info.si.skc_lmlevel); 207 mdb_printf("Domain %s\n", smb_info.si.skc_resource_domain); 208 mdb_printf("Hostname %s\n", smb_info.si.skc_hostname); 209 mdb_printf("Comment %s\n", smb_info.si.skc_system_comment); 210 (void) mdb_dec_indent(SMB_DCMD_INDENT); 211 mdb_printf("\n"); 212 } 213 214 return (DCMD_OK); 215 } 216 217 static void 218 smb_lookup_svc_state_str(smb_svcstate_t state, char *dst_str, int slen) 219 { 220 GElf_Sym smb_statename_table_sym; 221 uintptr_t statename_addr_addr, statename_addr; 222 223 if (mdb_lookup_by_name("smb_svcstate_state_name", 224 &smb_statename_table_sym)) { 225 (void) mdb_snprintf(dst_str, slen, "UNKNOWN"); 226 return; 227 } 228 229 /* Lookup state string */ 230 statename_addr_addr = smb_statename_table_sym.st_value + 231 (state * sizeof (uintptr_t)); 232 if (mdb_vread(&statename_addr, sizeof (uintptr_t), 233 statename_addr_addr) == -1) { 234 (void) mdb_snprintf(dst_str, slen, "UNKNOWN"); 235 return; 236 } else { 237 if (mdb_readstr(dst_str, slen, statename_addr) == -1) { 238 (void) mdb_snprintf(dst_str, slen, "UNKNOWN"); 239 return; 240 } 241 } 242 } 243 244 static void 245 smb_node_help(void) 246 { 247 mdb_printf( 248 "Display the contents of smb_node_t, with optional filtering.\n\n"); 249 mdb_dec_indent(2); 250 mdb_printf("%<b>OPTIONS%</b>\n"); 251 mdb_inc_indent(2); 252 mdb_printf( 253 "-v\tDisplay verbose smb_node information\n" 254 "-p\tDisplay the full path of the vnode associated\n" 255 "-s\tDisplay the stack of the last 16 calls that modified the " 256 "reference\n\tcount\n"); 257 } 258 259 /* 260 * ::smb_node 261 * 262 * smb_node dcmd - Print out smb_node structure. 263 */ 264 /*ARGSUSED*/ 265 static int 266 smb_node(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 267 { 268 smb_node_t node; 269 int verbose = FALSE; 270 int print_full_path = FALSE; 271 int stack_trace = FALSE; 272 vnode_t vnode; 273 char od_name[MAXNAMELEN]; 274 char path_name[1024]; 275 uintptr_t list_addr; 276 277 if (mdb_getopts(argc, argv, 278 'v', MDB_OPT_SETBITS, TRUE, &verbose, 279 'p', MDB_OPT_SETBITS, TRUE, &print_full_path, 280 's', MDB_OPT_SETBITS, TRUE, &stack_trace, 281 NULL) != argc) 282 return (DCMD_USAGE); 283 284 /* 285 * If no smb_node address was specified on the command line, we can 286 * print out all smb nodes by invoking the smb_node walker, using 287 * this dcmd itself as the callback. 288 */ 289 if (!(flags & DCMD_ADDRSPEC)) { 290 if (mdb_walk_dcmd("smb_node", "smb_node", 291 argc, argv) == -1) { 292 mdb_warn("failed to walk 'smb_node'"); 293 return (DCMD_ERR); 294 } 295 return (DCMD_OK); 296 } 297 298 /* 299 * If this is the first invocation of the command, print a nice 300 * header line for the output that will follow. 301 */ 302 if (DCMD_HDRSPEC(flags)) { 303 if (verbose) 304 mdb_printf("SMB node information:\n\n"); 305 else 306 mdb_printf("%<u>%?s %?s %18s %6s %5s %4s%</u>\n", 307 "SMB Nodes:", "VP", "NODE NAME", 308 "OFILES", "LOCKS", "REF"); 309 } 310 311 /* 312 * For each smb_node, we just need to read the smb_node_t struct, 313 * read and then print out the following fields. 314 */ 315 if (mdb_vread(&node, sizeof (node), addr) == sizeof (node)) { 316 (void) mdb_snprintf(od_name, MAXNAMELEN, "%s", node.od_name); 317 if (print_full_path) { 318 if (mdb_vread(&vnode, sizeof (vnode_t), 319 (uintptr_t)node.vp) == 320 sizeof (vnode_t)) { 321 if (mdb_readstr(path_name, 1024, 322 (uintptr_t)vnode.v_path) != 0) { 323 (void) mdb_snprintf(od_name, 324 MAXNAMELEN, "N/A"); 325 } 326 } 327 } 328 if (verbose) { 329 mdb_printf("VP :\t%p\n", 330 node.vp); 331 mdb_printf("Name :\t%s\n", 332 od_name); 333 if (print_full_path) { 334 mdb_printf("V-node Path :\t%s\n", 335 path_name); 336 } 337 mdb_printf("Ofiles :\t%u\n", 338 node.n_ofile_list.ll_count); 339 mdb_printf("Range Locks :\t%u\n", 340 node.n_lock_list.ll_count); 341 if (node.n_lock_list.ll_count != 0) { 342 (void) mdb_inc_indent(SMB_DCMD_INDENT); 343 list_addr = addr + 344 offsetof(smb_node_t, n_lock_list) + 345 offsetof(smb_llist_t, ll_list); 346 if (mdb_pwalk_dcmd("list", "smb_lock", 347 0, NULL, list_addr)) { 348 mdb_warn("failed to walk node's active" 349 " locks"); 350 } 351 (void) mdb_dec_indent(SMB_DCMD_INDENT); 352 } 353 mdb_printf("Reference Count :\t%u\n", 354 node.n_refcnt); 355 mdb_printf("\n"); 356 } else { 357 mdb_printf("%?p %?p %18s %5d %5d %4d\n", 358 addr, node.vp, od_name, node.n_ofile_list.ll_count, 359 node.n_lock_list.ll_count, node.n_refcnt); 360 if (print_full_path) { 361 if (mdb_vread(&vnode, sizeof (vnode_t), 362 (uintptr_t)node.vp) == 363 sizeof (vnode_t)) { 364 if (mdb_readstr(path_name, 1024, 365 (uintptr_t)vnode.v_path)) { 366 mdb_printf("\t%s\n", 367 path_name); 368 } 369 } 370 } 371 } 372 if (stack_trace && node.n_audit_buf) { 373 int ctr; 374 smb_audit_buf_node_t *anb; 375 376 anb = mdb_alloc(sizeof (smb_audit_buf_node_t), 377 UM_SLEEP); 378 379 if (mdb_vread(anb, sizeof (*anb), 380 (uintptr_t)node.n_audit_buf) != sizeof (*anb)) { 381 mdb_free(anb, sizeof (smb_audit_buf_node_t)); 382 mdb_warn("failed to read audit buffer"); 383 return (DCMD_ERR); 384 } 385 ctr = anb->anb_max_index + 1; 386 anb->anb_index--; 387 anb->anb_index &= anb->anb_max_index; 388 389 while (ctr) { 390 smb_audit_record_node_t *anr; 391 392 anr = anb->anb_records + anb->anb_index; 393 394 if (anr->anr_depth) { 395 char c[MDB_SYM_NAMLEN]; 396 GElf_Sym sym; 397 int i; 398 399 mdb_printf("\nRefCnt: %u\t", 400 anr->anr_refcnt); 401 402 for (i = 0; 403 i < anr->anr_depth; 404 i++) { 405 if (mdb_lookup_by_addr( 406 anr->anr_stack[i], 407 MDB_SYM_FUZZY, 408 c, sizeof (c), 409 &sym) == -1) { 410 continue; 411 } 412 mdb_printf("%s+0x%1x", 413 c, 414 anr->anr_stack[i] - 415 (uintptr_t)sym.st_value); 416 ++i; 417 break; 418 } 419 420 while (i < anr->anr_depth) { 421 if (mdb_lookup_by_addr( 422 anr->anr_stack[i], 423 MDB_SYM_FUZZY, 424 c, sizeof (c), 425 &sym) == -1) { 426 ++i; 427 continue; 428 } 429 mdb_printf("\n\t\t%s+0x%1x", 430 c, 431 anr->anr_stack[i] - 432 (uintptr_t)sym.st_value); 433 ++i; 434 } 435 mdb_printf("\n"); 436 } 437 anb->anb_index--; 438 anb->anb_index &= anb->anb_max_index; 439 ctr--; 440 } 441 mdb_free(anb, sizeof (smb_audit_buf_node_t)); 442 } 443 } else { 444 mdb_warn("failed to read struct smb_node at %p", addr); 445 return (DCMD_ERR); 446 } 447 448 return (DCMD_OK); 449 } 450 451 static void 452 smb_session_help(void) 453 { 454 mdb_printf( 455 "Display the contents of smb_session_t, with optional" 456 " filtering.\n\n"); 457 mdb_dec_indent(2); 458 mdb_printf("%<b>OPTIONS%</b>\n"); 459 mdb_inc_indent(2); 460 mdb_printf( 461 "-v\tDisplay verbose smb_session information\n" 462 "-r\tDisplay the list of smb requests attached\n" 463 "-u\tDisplay the list of users attached\n"); 464 } 465 466 /* 467 * ::smb_session 468 * 469 * smb_session dcmd - Print out the smb_session structure. 470 */ 471 /*ARGSUSED*/ 472 static int 473 smb_session(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 474 { 475 smb_session_t session; 476 int print_requests = FALSE; 477 int print_users = FALSE; 478 int verbose = FALSE; 479 uintptr_t list_addr; 480 481 if (mdb_getopts(argc, argv, 482 'v', MDB_OPT_SETBITS, TRUE, &verbose, 483 'r', MDB_OPT_SETBITS, TRUE, &print_requests, 484 'u', MDB_OPT_SETBITS, TRUE, &print_users, 485 NULL) != argc) 486 return (DCMD_USAGE); 487 488 /* 489 * If no smb_session address was specified on the command line, we can 490 * print out all smb sessions by invoking the smb_session walker, using 491 * this dcmd itself as the callback. 492 */ 493 if (!(flags & DCMD_ADDRSPEC)) { 494 if (mdb_walk_dcmd("smb_session", "smb_session", 495 argc, argv) == -1) { 496 mdb_warn("failed to walk 'smb_session'"); 497 return (DCMD_ERR); 498 } 499 return (DCMD_OK); 500 } 501 502 /* 503 * If this is the first invocation of the command, print a nice 504 * header line for the output that will follow. 505 */ 506 if (DCMD_HDRSPEC(flags)) { 507 if (verbose) 508 mdb_printf("SMB session information:\n\n"); 509 else 510 mdb_printf("%<u>%-?s %16s %16s %5s %10s%</u>\n", 511 "Sessions:", "CLIENT_IP_ADDR", "LOCAL_IP_ADDR", 512 "KID", "STATE"); 513 } 514 515 /* 516 * For each smb_session, we just need to read the smb_session_t struct, 517 * read and then print out the following fields. 518 */ 519 if (mdb_vread(&session, sizeof (session), addr) == sizeof (session)) { 520 if (verbose) { 521 mdb_printf("IP address :\t%I\n", 522 session.ipaddr); 523 mdb_printf("Local IP Address:\t%I\n", 524 session.local_ipaddr); 525 mdb_printf("Session KID :\t%u\n", 526 session.s_kid); 527 mdb_printf("Workstation Name:\t%s\n", 528 session.workstation); 529 mdb_printf("Session state :\t%u\n", 530 session.s_state); 531 mdb_printf("users :\t%u\n", 532 session.s_user_list.ll_count); 533 mdb_printf("trees :\t%u\n", 534 session.s_tree_cnt); 535 mdb_printf("files :\t%u\n", 536 session.s_file_cnt); 537 mdb_printf("shares :\t%u\n", 538 session.s_dir_cnt); 539 mdb_printf("xa count :\t%u\n\n", 540 session.s_xa_list.ll_count); 541 mdb_printf("\n"); 542 } else { 543 mdb_printf("%?p %16I %16I %5u %10u\n", addr, 544 session.ipaddr, session.local_ipaddr, 545 session.s_kid, session.s_state); 546 } 547 } else { 548 mdb_warn("failed to read struct smb_session at %p", &session); 549 return (DCMD_ERR); 550 } 551 552 if (print_requests) { 553 (void) mdb_inc_indent(SMB_DCMD_INDENT); 554 list_addr = addr + offsetof(smb_session_t, s_req_list) + 555 offsetof(smb_slist_t, sl_list); 556 if (mdb_pwalk_dcmd("list", "smb_request", 0, NULL, list_addr)) { 557 mdb_warn("failed to walk request list\n"); 558 (void) mdb_dec_indent(SMB_DCMD_INDENT); 559 return (DCMD_ERR); 560 } 561 (void) mdb_dec_indent(SMB_DCMD_INDENT); 562 } 563 564 if (print_users) { 565 (void) mdb_inc_indent(SMB_DCMD_INDENT); 566 list_addr = addr + offsetof(smb_session_t, s_user_list) + 567 offsetof(smb_llist_t, ll_list); 568 if (mdb_pwalk_dcmd("list", "smb_user", 0, NULL, list_addr)) { 569 mdb_warn("failed to walk user list\n"); 570 (void) mdb_dec_indent(SMB_DCMD_INDENT); 571 return (DCMD_ERR); 572 } 573 (void) mdb_dec_indent(SMB_DCMD_INDENT); 574 } 575 576 return (DCMD_OK); 577 } 578 579 static int 580 smb_request(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 581 { 582 smb_request_t request; 583 int verbose = FALSE; 584 585 if (mdb_getopts(argc, argv, 586 'v', MDB_OPT_SETBITS, TRUE, &verbose, 587 NULL) != argc) 588 return (DCMD_USAGE); 589 590 /* 591 * An smb_requets_t address must be specified. 592 */ 593 if (!(flags & DCMD_ADDRSPEC)) 594 return (DCMD_USAGE); 595 596 /* 597 * If this is the first invocation of the command, print a nice 598 * header line for the output that will follow. 599 */ 600 if (DCMD_HDRSPEC(flags)) { 601 if (verbose) 602 mdb_printf("SMB request information:\n\n"); 603 else 604 mdb_printf("%<u>%-?s %4s %6s %4s %4s %4s %4s%</u>\n", 605 "Requests: ", "COM", "STATE", 606 "TID", "PID", "UID", "MID"); 607 } 608 609 if (mdb_vread(&request, sizeof (request), addr) == sizeof (request)) { 610 if (verbose) { 611 mdb_printf("First SMB COM :\t%I\n", 612 request.first_smb_com); 613 mdb_printf("State :\t%I\n", 614 request.sr_state); 615 mdb_printf("Tree ID :\t%u\n", 616 request.smb_tid); 617 mdb_printf("Process ID :\t%u\n", 618 request.smb_pid); 619 mdb_printf("User ID :\t%u\n", 620 request.smb_uid); 621 mdb_printf("Multiplex ID :\t%u\n", 622 request.smb_mid); 623 mdb_printf("\n"); 624 } else { 625 mdb_printf("%?p %04x %6x %04x %04x %04x" 626 " %04x\n", addr, 627 request.first_smb_com, request.sr_state, 628 request.smb_tid, request.smb_pid, 629 request.smb_uid, request.smb_mid); 630 } 631 } else { 632 mdb_warn("failed to read struct smb_request at %p", addr); 633 return (DCMD_ERR); 634 } 635 636 return (DCMD_OK); 637 } 638 639 static int 640 smb_lock(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 641 { 642 smb_lock_t lock; 643 int verbose = FALSE; 644 uintptr_t list_addr; 645 char *lock_type; 646 647 if (mdb_getopts(argc, argv, 648 'v', MDB_OPT_SETBITS, TRUE, &verbose, 649 NULL) != argc) 650 return (DCMD_USAGE); 651 652 /* 653 * An smb_lock_t address must be specified. 654 */ 655 if (!(flags & DCMD_ADDRSPEC)) 656 return (DCMD_USAGE); 657 658 /* 659 * If this is the first invocation of the command, print a nice 660 * header line for the output that will follow. 661 */ 662 if (DCMD_HDRSPEC(flags)) { 663 if (verbose) 664 mdb_printf("SMB lock information:\n\n"); 665 else 666 mdb_printf("%<u>%-?s %4s %16s %8s %9s%</u>\n", 667 "Locks: ", "TYPE", "START", "LENGTH", 668 "CONFLICTS"); 669 } 670 671 if (mdb_vread(&lock, sizeof (lock), addr) == sizeof (lock)) { 672 switch (lock.l_type) { 673 case SMB_LOCK_TYPE_READWRITE: 674 lock_type = "RW"; 675 break; 676 case SMB_LOCK_TYPE_READONLY: 677 lock_type = "RO"; 678 break; 679 default: 680 lock_type = "N/A"; 681 break; 682 } 683 if (verbose) { 684 mdb_printf("Type :\t%s (%u)\n", 685 lock_type, lock.l_type); 686 mdb_printf("Start :\t%llx\n", 687 lock.l_start); 688 mdb_printf("Length :\t%lx\n", 689 lock.l_length); 690 mdb_printf("Session :\t%p\n", 691 lock.l_session); 692 mdb_printf("File :\t%p\n", 693 lock.l_file); 694 mdb_printf("User ID :\t%u\n", 695 lock.l_uid); 696 mdb_printf("Process ID :\t%u\n", 697 lock.l_pid); 698 mdb_printf("Conflicts :\t%u\n", 699 lock.l_conflict_list.sl_count); 700 if (lock.l_conflict_list.sl_count != 0) { 701 (void) mdb_inc_indent(SMB_DCMD_INDENT); 702 list_addr = addr + 703 offsetof(smb_lock_t, l_conflict_list) + 704 offsetof(smb_slist_t, sl_list); 705 if (mdb_pwalk_dcmd("list", "smb_lock", 706 0, NULL, list_addr)) { 707 mdb_warn("failed to walk conflict " 708 "locks "); 709 } 710 (void) mdb_dec_indent(SMB_DCMD_INDENT); 711 } 712 mdb_printf("Blocked by :\t%p\n", 713 lock.l_blocked_by); 714 mdb_printf("Flags :\t0x%x\n", 715 lock.l_flags); 716 mdb_printf("\n"); 717 } else { 718 mdb_printf("%?p %4s %16llx %08lx %9x", addr, 719 lock_type, lock.l_start, lock.l_length, 720 lock.l_conflict_list.sl_count); 721 } 722 } else { 723 mdb_warn("failed to read struct smb_request at %p", addr); 724 return (DCMD_ERR); 725 } 726 727 return (DCMD_OK); 728 } 729 730 static void 731 smb_user_help(void) 732 { 733 mdb_printf( 734 "Display the contents of smb_user_t, with optional filtering.\n\n"); 735 mdb_dec_indent(2); 736 mdb_printf("%<b>OPTIONS%</b>\n"); 737 mdb_inc_indent(2); 738 mdb_printf( 739 "-v\tDisplay verbose smb_user information\n" 740 "-q\tDon't Display the contents of the smb_user. This option " 741 "should be\n\tused in conjunction with -d or -f\n" 742 "-d\tDisplay the list of smb_odirs attached\n" 743 "-f\tDisplay the list of smb_ofiles attached\n" 744 "-t\tDisplay the list of smb_trees attached\n"); 745 } 746 747 static int 748 smb_user(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 749 { 750 smb_user_t user; 751 int print_odir = FALSE; 752 int print_ofile = FALSE; 753 int print_tree = FALSE; 754 int verbose = FALSE; 755 int quiet = FALSE; 756 uintptr_t list_addr; 757 int new_argc; 758 mdb_arg_t new_argv[3]; 759 760 if (mdb_getopts(argc, argv, 761 'v', MDB_OPT_SETBITS, TRUE, &verbose, 762 'q', MDB_OPT_SETBITS, TRUE, &quiet, 763 'd', MDB_OPT_SETBITS, TRUE, &print_odir, 764 'f', MDB_OPT_SETBITS, TRUE, &print_ofile, 765 't', MDB_OPT_SETBITS, TRUE, &print_tree, 766 NULL) != argc) 767 return (DCMD_USAGE); 768 769 /* 770 * An smb_user address must be specified on the command line. 771 */ 772 if (!(flags & DCMD_ADDRSPEC)) 773 return (DCMD_USAGE); 774 775 /* 776 * If this is the first invocation of the command, print a nice 777 * header line for the output that will follow. 778 */ 779 if (DCMD_HDRSPEC(flags) && !quiet) { 780 if (verbose) 781 mdb_printf("SMB user information:\n\n"); 782 else 783 mdb_printf("%<u>%-?s %4s %6s %8s %16s %8s %s%</u>\n", 784 "Users:", "UID", "STATE", "FLAGS", "CRED", 785 "REFCNT", "ACCOUNT"); 786 } 787 788 if (mdb_vread(&user, sizeof (user), addr) != sizeof (user)) { 789 mdb_warn("failed to read struct smb_user at %?p", addr); 790 return (DCMD_ERR); 791 } 792 793 if (!quiet) { 794 char domain[SMB_PI_MAX_DOMAIN]; 795 char account[SMB_PI_MAX_USERNAME]; 796 int valid_domain = 0, valid_account = 0; 797 798 if (mdb_vread(domain, user.u_domain_len, 799 (uintptr_t)user.u_domain) == user.u_domain_len) 800 valid_domain = 1; 801 if (mdb_vread(account, user.u_name_len, 802 (uintptr_t)user.u_name) == user.u_name_len) 803 valid_account = 1; 804 805 if (verbose) { 806 mdb_printf("User ID :\t%04x\n", 807 user.u_uid); 808 mdb_printf("State :\t%d\n", 809 user.u_state); 810 mdb_printf("Flags :\t%08x\n", 811 user.u_flags); 812 mdb_printf("Privileges :\t%08x\n", 813 user.u_privileges); 814 mdb_printf("Credential :\t%llx\n", 815 user.u_cred); 816 mdb_printf("Reference Count :\t%d\n", 817 user.u_refcnt); 818 if (valid_domain && valid_account) 819 mdb_printf("User Account :\t%s\\%s\n", 820 domain, account); 821 mdb_printf("\n"); 822 } else { 823 mdb_printf("%?p %04x %6d %08x %?p %8d %s\\%s\n", 824 addr, user.u_uid, user.u_state, user.u_flags, 825 user.u_cred, user.u_refcnt, 826 valid_domain ? domain : "UNKNOWN", 827 valid_account ? account : "UNKNOWN"); 828 } 829 } 830 831 new_argc = 0; 832 if (!print_tree) { 833 new_argv[new_argc].a_type = MDB_TYPE_STRING; 834 new_argv[new_argc].a_un.a_str = "-q"; 835 new_argc++; 836 } 837 if (print_ofile) { 838 new_argv[new_argc].a_type = MDB_TYPE_STRING; 839 new_argv[new_argc].a_un.a_str = "-f"; 840 new_argc++; 841 } 842 if (print_odir) { 843 new_argv[new_argc].a_type = MDB_TYPE_STRING; 844 new_argv[new_argc].a_un.a_str = "-d"; 845 new_argc++; 846 } 847 848 if (print_tree || print_ofile || print_odir) { 849 (void) mdb_inc_indent(SMB_DCMD_INDENT); 850 list_addr = addr + offsetof(smb_user_t, u_tree_list) + 851 offsetof(smb_llist_t, ll_list); 852 if (mdb_pwalk_dcmd("list", "smb_tree", new_argc, new_argv, 853 list_addr)) { 854 mdb_warn("failed to walk tree list\n"); 855 (void) mdb_dec_indent(SMB_DCMD_INDENT); 856 return (DCMD_ERR); 857 } 858 (void) mdb_dec_indent(SMB_DCMD_INDENT); 859 } 860 861 return (DCMD_OK); 862 } 863 864 static void 865 smb_tree_help(void) 866 { 867 mdb_printf( 868 "Display the contents of smb_tree_t, with optional filtering.\n\n"); 869 mdb_dec_indent(2); 870 mdb_printf("%<b>OPTIONS%</b>\n"); 871 mdb_inc_indent(2); 872 mdb_printf( 873 "-v\tDisplay verbose smb_tree information\n" 874 "-q\tDon't Display the contents of the smb_tree. This option " 875 "should be\n\tused in conjunction with -d or -f\n" 876 "-d\tDisplay the list of smb_odirs attached\n" 877 "-f\tDisplay the list of smb_ofiles attached\n"); 878 } 879 880 static int 881 smb_tree(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 882 { 883 smb_tree_t tree; 884 int print_odir = FALSE; 885 int print_ofile = FALSE; 886 int verbose = FALSE; 887 int quiet = FALSE; 888 uintptr_t list_addr; 889 890 if (mdb_getopts(argc, argv, 891 'v', MDB_OPT_SETBITS, TRUE, &verbose, 892 'd', MDB_OPT_SETBITS, TRUE, &print_odir, 893 'f', MDB_OPT_SETBITS, TRUE, &print_ofile, 894 'q', MDB_OPT_SETBITS, TRUE, &quiet, 895 NULL) != argc) 896 return (DCMD_USAGE); 897 898 /* 899 * If no smb_session address was specified on the command line, we can 900 * print out all smb sessions by invoking the smb_session walker, using 901 * this dcmd itself as the callback. 902 */ 903 if (!(flags & DCMD_ADDRSPEC)) 904 return (DCMD_USAGE); 905 906 /* 907 * If this is the first invocation of the command, print a nice 908 * header line for the output that will follow. 909 */ 910 if (DCMD_HDRSPEC(flags)) { 911 if (verbose) 912 mdb_printf("SMB tree information:\n\n"); 913 else 914 mdb_printf("%<u>%-?s %4s %6s %16s %10s%</u>\n", 915 "Trees:", "TID", "STATE", "SMB NODE", 916 "SHARE NAME"); 917 } 918 919 /* 920 * Read tree and print some of the fields 921 */ 922 if (mdb_vread(&tree, sizeof (tree), addr) != sizeof (tree)) { 923 mdb_warn("failed to read struct smb_tree at %p", addr); 924 return (DCMD_ERR); 925 } 926 if (!quiet) { 927 if (verbose) { 928 mdb_printf("Tree ID :\t%04x\n", 929 tree.t_tid); 930 mdb_printf("State :\t%d\n", 931 tree.t_state); 932 mdb_printf("Share name :\t%s\n", 933 tree.t_sharename); 934 mdb_printf("Resource :\t%s\n", 935 tree.t_resource); 936 mdb_printf("Umask :\t%04x\n", 937 tree.t_umask); 938 mdb_printf("Access :\t%04x\n", 939 tree.t_access); 940 mdb_printf("Flags :\t%08x\n", 941 tree.t_flags); 942 mdb_printf("SMB Node :\t%llx\n", 943 tree.t_snode); 944 mdb_printf("Reference Count :\t%d\n", 945 tree.t_refcnt); 946 mdb_printf("\n"); 947 } else { 948 mdb_printf("%?p %04x %6d %16llx %s\n", addr, 949 tree.t_tid, tree.t_state, tree.t_snode, 950 tree.t_sharename); 951 } 952 } 953 954 if (print_odir) { 955 (void) mdb_inc_indent(SMB_DCMD_INDENT); 956 list_addr = addr + offsetof(smb_tree_t, t_odir_list) + 957 offsetof(smb_llist_t, ll_list); 958 if (mdb_pwalk_dcmd("list", "smb_odir", 0, NULL, list_addr)) { 959 mdb_warn("failed to walk odir list\n"); 960 (void) mdb_dec_indent(SMB_DCMD_INDENT); 961 return (DCMD_ERR); 962 } 963 (void) mdb_dec_indent(SMB_DCMD_INDENT); 964 } 965 966 if (print_ofile) { 967 (void) mdb_inc_indent(SMB_DCMD_INDENT); 968 list_addr = addr + offsetof(smb_tree_t, t_ofile_list) + 969 offsetof(smb_llist_t, ll_list); 970 if (mdb_pwalk_dcmd("list", "smb_ofile", 0, NULL, list_addr)) { 971 mdb_warn("failed to walk ofile list\n"); 972 (void) mdb_dec_indent(SMB_DCMD_INDENT); 973 return (DCMD_ERR); 974 } 975 (void) mdb_dec_indent(SMB_DCMD_INDENT); 976 } 977 978 return (DCMD_OK); 979 } 980 981 static int 982 smb_odir(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 983 { 984 smb_odir_t odir; 985 int verbose = FALSE; 986 987 if (mdb_getopts(argc, argv, 988 'v', MDB_OPT_SETBITS, TRUE, &verbose, 989 NULL) != argc) 990 return (DCMD_USAGE); 991 992 /* 993 * If no smb_session address was specified on the command line, we can 994 * print out all smb sessions by invoking the smb_session walker, using 995 * this dcmd itself as the callback. 996 */ 997 if (!(flags & DCMD_ADDRSPEC)) 998 return (DCMD_USAGE); 999 1000 /* 1001 * If this is the first invocation of the command, print a nice 1002 * header line for the output that will follow. 1003 */ 1004 if (DCMD_HDRSPEC(flags)) { 1005 if (verbose) 1006 mdb_printf("SMB odir information:\n\n"); 1007 else 1008 mdb_printf("%<u>%-?s %8s %?s %10s%</u>\n", 1009 "odir:", "STATE", "SMB NODE", "PATTERN"); 1010 } 1011 1012 /* 1013 * For each smb_session, we just need to read the smb_session_t struct, 1014 * read and then print out the following fields. 1015 */ 1016 if (mdb_vread(&odir, sizeof (odir), addr) == sizeof (odir)) { 1017 if (verbose) { 1018 mdb_printf("State :\t%d\n", 1019 odir.d_state); 1020 mdb_printf("Pattern :\t%s\n", 1021 odir.d_pattern); 1022 mdb_printf("SMB Node :\t%s\n", 1023 odir.d_dir_snode); 1024 mdb_printf("\n"); 1025 } else { 1026 mdb_printf("%?p %8d %16llx %s\n", addr, 1027 odir.d_state, odir.d_dir_snode, odir.d_pattern); 1028 } 1029 } else { 1030 mdb_warn("failed to read struct smb_odir at %p", addr); 1031 return (DCMD_ERR); 1032 } 1033 1034 return (DCMD_OK); 1035 } 1036 1037 static int 1038 smb_ofile(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1039 { 1040 smb_ofile_t ofile; 1041 int verbose = FALSE; 1042 1043 if (mdb_getopts(argc, argv, 1044 'v', MDB_OPT_SETBITS, TRUE, &verbose, 1045 NULL) != argc) 1046 return (DCMD_USAGE); 1047 1048 /* 1049 * If no smb_session address was specified on the command line, we can 1050 * print out all smb sessions by invoking the smb_session walker, using 1051 * this dcmd itself as the callback. 1052 */ 1053 if (!(flags & DCMD_ADDRSPEC)) 1054 return (DCMD_USAGE); 1055 1056 /* 1057 * If this is the first invocation of the command, print a nice 1058 * header line for the output that will follow. 1059 */ 1060 if (DCMD_HDRSPEC(flags)) { 1061 if (verbose) 1062 mdb_printf("SMB ofile information:\n\n"); 1063 else 1064 mdb_printf("%<u>%-?s %04s %8s %?s %8s %?s%</u>\n", 1065 "ofiles:", "FID", "STATE", "SMB NODE", "FLAGS", 1066 "CRED"); 1067 } 1068 1069 /* 1070 * For each smb_session, we just need to read the smb_session_t struct, 1071 * read and then print out the following fields. 1072 */ 1073 if (mdb_vread(&ofile, sizeof (ofile), addr) == sizeof (ofile)) { 1074 if (verbose) { 1075 mdb_printf("Ofile ID :\t%04x\n", 1076 ofile.f_fid); 1077 mdb_printf("State :\t%d\n", 1078 ofile.f_state); 1079 mdb_printf("SMB Node :\t%llx\n", 1080 ofile.f_node); 1081 mdb_printf("LLF Offset :\t%llx (%s)\n", 1082 ofile.f_llf_pos, 1083 ((ofile.f_flags & SMB_OFLAGS_LLF_POS_VALID) ? 1084 "Valid" : "Invalid")); 1085 mdb_printf("FLAGS :\t%08x\n", 1086 ofile.f_flags); 1087 mdb_printf("Credential :\t%llx\n", 1088 ofile.f_cr); 1089 mdb_printf("\n"); 1090 } else { 1091 mdb_printf("%?p %04x %8d %16llx %08x %?\n", addr, 1092 ofile.f_fid, ofile.f_state, ofile.f_node, 1093 ofile.f_flags, ofile.f_cr); 1094 } 1095 } else { 1096 mdb_warn("failed to read struct smb_odir at %p", addr); 1097 return (DCMD_ERR); 1098 } 1099 1100 return (DCMD_OK); 1101 } 1102 1103 1104 /* 1105 * ::smb_dispatch_stats 1106 * 1107 * smb_dispatch_stats dcmd - Prints all dispatched SMB requests statistics. 1108 */ 1109 /*ARGSUSED*/ 1110 static int 1111 smb_stats(uintptr_t addr, uint_t flags, int argc, 1112 const mdb_arg_t *argv) 1113 { 1114 smb_dispatch_table_t *disp; 1115 GElf_Sym sym; 1116 int nstats = 0, i; 1117 1118 if ((flags & DCMD_ADDRSPEC) || argc != 0) 1119 return (DCMD_USAGE); 1120 1121 if (mdb_lookup_by_obj(MDB_OBJ_EVERY, "dispatch", &sym)) { 1122 mdb_warn("failed to find dispatch object"); 1123 return (DCMD_ERR); 1124 } 1125 1126 disp = mdb_alloc(sym.st_size, UM_SLEEP | UM_GC); 1127 if (mdb_vread(disp, sym.st_size, sym.st_value) == -1) { 1128 mdb_warn("failed to read from dispatch object"); 1129 return (DCMD_ERR); 1130 } 1131 1132 nstats = sym.st_size / sizeof (smb_dispatch_table_t); 1133 1134 mdb_printf("All dispatched SMB requests statistics:\n\n"); 1135 for (i = 0; i < nstats; i++) { 1136 if (disp[i].sdt_function) 1137 mdb_printf(" %40s\t: %lld\n", 1138 disp[i].sdt_dispatch_stats.name, 1139 disp[i].sdt_dispatch_stats.value.ui64); 1140 } 1141 return (DCMD_OK); 1142 } 1143 1144 /* 1145 * MDB module linkage information: 1146 * 1147 * We declare a list of structures describing our dcmds, a list of structures 1148 * describing our walkers and a function named _mdb_init to return a pointer 1149 * to our module information. 1150 */ 1151 static const mdb_dcmd_t dcmds[] = { 1152 { "smb_info", "[-c]", 1153 "print smb_info information", smb_information }, 1154 { "smb_node", "?[-vps]", 1155 "print smb_node_t information", smb_node, smb_node_help }, 1156 { "smb_session", "?[-vru]", 1157 "print smb_session_t information", smb_session, smb_session_help}, 1158 { "smb_request", ":[-v]", 1159 "print smb_request_t information", smb_request }, 1160 { "smb_lock", ":[-v]", 1161 "print smb_lock_t information", smb_lock }, 1162 { "smb_user", ":[-vdftq]", 1163 "print smb_user_t information", smb_user, smb_user_help }, 1164 { "smb_tree", ":[-vdfq]", 1165 "print smb_tree_t information", smb_tree, smb_tree_help }, 1166 { "smb_odir", ":[-v]", 1167 "print smb_odir_t information", smb_odir }, 1168 { "smb_ofile", "[-v]", 1169 "print smb_odir_t information", smb_ofile }, 1170 { "smb_stats", NULL, 1171 "print all smb dispatched requests statistics", 1172 smb_stats }, 1173 { NULL } 1174 }; 1175 1176 static const mdb_walker_t walkers[] = { 1177 { "smb_session", "walk list of smb_session_t structures", 1178 smb_session_walk_init, smb_session_walk_step, 1179 NULL }, 1180 { "smb_node", "walk list of smb_node_t structures", 1181 smb_node_walk_init, smb_node_walk_step, 1182 NULL }, 1183 { NULL } 1184 }; 1185 1186 static const mdb_modinfo_t modinfo = { 1187 MDB_API_VERSION, dcmds, walkers 1188 }; 1189 1190 const mdb_modinfo_t * 1191 _mdb_init(void) 1192 { 1193 return (&modinfo); 1194 } 1195