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