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