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/types.h> 29 #include <sys/ddi.h> 30 #include <sys/strsubr.h> 31 #include <sys/socketvar.h> 32 #include <sys/modctl.h> 33 #include <sys/cred.h> 34 #include <sys/ioccom.h> 35 #include <sys/priv.h> 36 #include <sys/policy.h> 37 #include <smbsrv/smb_incl.h> 38 #include <smbsrv/mlsvc.h> 39 #include <smbsrv/smb_door_svc.h> 40 #include <smbsrv/smb_ioctl.h> 41 #include <smbsrv/smb_kproto.h> 42 /* 43 * DDI entry points. 44 */ 45 static int smb_drv_attach(dev_info_t *, ddi_attach_cmd_t); 46 static int smb_drv_detach(dev_info_t *, ddi_detach_cmd_t); 47 static int smb_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 48 static int smb_drv_open(dev_t *, int, int, cred_t *); 49 static int smb_drv_close(dev_t, int, int, cred_t *); 50 static int smb_drv_busy(void); 51 static int smb_drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 52 53 /* 54 * module linkage info for the kernel 55 */ 56 static struct cb_ops cbops = { 57 smb_drv_open, /* cb_open */ 58 smb_drv_close, /* cb_close */ 59 nodev, /* cb_strategy */ 60 nodev, /* cb_print */ 61 nodev, /* cb_dump */ 62 nodev, /* cb_read */ 63 nodev, /* cb_write */ 64 smb_drv_ioctl, /* cb_ioctl */ 65 nodev, /* cb_devmap */ 66 nodev, /* cb_mmap */ 67 nodev, /* cb_segmap */ 68 nochpoll, /* cb_chpoll */ 69 ddi_prop_op, /* cb_prop_op */ 70 NULL, /* cb_streamtab */ 71 D_MP, /* cb_flag */ 72 CB_REV, /* cb_rev */ 73 nodev, /* cb_aread */ 74 nodev, /* cb_awrite */ 75 }; 76 77 static struct dev_ops devops = { 78 DEVO_REV, /* devo_rev */ 79 0, /* devo_refcnt */ 80 smb_drv_getinfo, /* devo_getinfo */ 81 nulldev, /* devo_identify */ 82 nulldev, /* devo_probe */ 83 smb_drv_attach, /* devo_attach */ 84 smb_drv_detach, /* devo_detach */ 85 nodev, /* devo_reset */ 86 &cbops, /* devo_cb_ops */ 87 NULL, /* devo_bus_ops */ 88 NULL, /* devo_power */ 89 }; 90 91 static struct modldrv modldrv = { 92 &mod_driverops, /* drv_modops */ 93 "CIFS Server Protocol %I%", /* drv_linkinfo */ 94 &devops, 95 }; 96 97 static struct modlinkage modlinkage = { 98 99 MODREV_1, /* revision of the module, must be: MODREV_1 */ 100 &modldrv, /* ptr to linkage structures */ 101 NULL, 102 }; 103 104 static int smb_info_init(struct smb_info *si); 105 static void smb_info_fini(struct smb_info *si); 106 107 extern int smb_fsop_start(void); 108 extern void smb_fsop_stop(void); 109 110 extern int nt_mapk_start(void); 111 extern void nt_mapk_stop(void); 112 113 114 extern int smb_get_kconfig(smb_kmod_cfg_t *cfg); 115 116 extern void smb_notify_change_daemon(smb_thread_t *thread, void *arg); 117 extern void smb_nbt_daemon(smb_thread_t *thread, void *arg); 118 extern void smb_tcp_daemon(smb_thread_t *thread, void *arg); 119 extern void smb_timers(smb_thread_t *thread, void *arg); 120 extern void smb_session_worker(void *arg); 121 122 extern int smb_maxbufsize; 123 124 extern time_t smb_oplock_timeout; 125 126 /* Debug logging level: 0=Disabled, 1=Quiet, 2=Verbose */ 127 int smbsrv_debug_level; 128 129 struct smb_info smb_info; 130 131 static dev_info_t *smb_drv_dip = NULL; 132 static kmutex_t smb_drv_opencount_lock; 133 static int smb_drv_opencount = 0; 134 135 /* 136 * Kstat smb_info statistics. 137 */ 138 static struct smbinfo_stats { 139 kstat_named_t state; 140 kstat_named_t open_files; 141 kstat_named_t open_trees; 142 kstat_named_t open_users; 143 } smbinfo_stats = { 144 { "state", KSTAT_DATA_UINT32 }, 145 { "open_files", KSTAT_DATA_UINT32 }, 146 { "connections", KSTAT_DATA_UINT32 }, 147 { "sessions", KSTAT_DATA_UINT32 } 148 }; 149 150 static int smb_kstat_init(void); 151 static void smb_kstat_fini(void); 152 static int smb_kstat_update_info(kstat_t *ksp, int rw); 153 extern void smb_initialize_dispatch_kstat(void); 154 extern void smb_remove_dispatch_kstat(void); 155 156 static kstat_t *smbinfo_ksp = NULL; 157 158 /* 159 * SMB pseudo-driver entry points 160 */ 161 162 163 164 int 165 _init(void) 166 { 167 int rc; 168 169 mutex_init(&smb_drv_opencount_lock, NULL, MUTEX_DRIVER, NULL); 170 171 if ((rc = mod_install(&modlinkage)) != 0) { 172 mutex_destroy(&smb_drv_opencount_lock); 173 cmn_err(CE_NOTE, "init: %d\n", rc); 174 return (rc); 175 } 176 177 return (0); 178 } 179 180 int 181 _info(struct modinfo *modinfop) 182 { 183 return (mod_info(&modlinkage, modinfop)); 184 } 185 186 int 187 _fini(void) 188 { 189 int rc; 190 191 mutex_enter(&smb_drv_opencount_lock); 192 if (smb_drv_busy()) { 193 mutex_exit(&smb_drv_opencount_lock); 194 return (EBUSY); 195 } 196 mutex_exit(&smb_drv_opencount_lock); 197 198 if ((rc = mod_remove(&modlinkage)) == 0) 199 mutex_destroy(&smb_drv_opencount_lock); 200 201 return (rc); 202 } 203 204 /* 205 * DDI entry points. 206 */ 207 208 /* ARGSUSED */ 209 static int 210 smb_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 211 { 212 ulong_t instance = getminor((dev_t)arg); 213 214 switch (cmd) { 215 case DDI_INFO_DEVT2DEVINFO: 216 *result = smb_drv_dip; 217 return (DDI_SUCCESS); 218 219 case DDI_INFO_DEVT2INSTANCE: 220 *result = (void *)instance; 221 return (DDI_SUCCESS); 222 223 default: 224 break; 225 } 226 227 return (DDI_FAILURE); 228 } 229 230 231 static int 232 smb_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 233 { 234 if (cmd != DDI_ATTACH) { 235 return (DDI_FAILURE); 236 } 237 238 if (ddi_get_instance(dip) != 0) { 239 /* we only allow instance 0 to attach */ 240 return (DDI_FAILURE); 241 } 242 243 smb_drv_dip = dip; 244 245 /* create the minor node */ 246 if (ddi_create_minor_node(dip, "smbsrv", S_IFCHR, 0, 247 DDI_PSEUDO, 0) != DDI_SUCCESS) { 248 cmn_err(CE_WARN, "smb_drv_attach: failed creating minor node"); 249 ddi_remove_minor_node(dip, NULL); 250 return (DDI_FAILURE); 251 } 252 253 if (smb_service_init() != 0) { 254 ddi_remove_minor_node(dip, NULL); 255 cmn_err(CE_WARN, "smb_drv_attach: failed to initialize " 256 "SMB service"); 257 return (DDI_FAILURE); 258 } 259 260 return (DDI_SUCCESS); 261 } 262 263 static int 264 smb_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 265 { 266 if (cmd != DDI_DETACH) 267 return (DDI_FAILURE); 268 269 mutex_enter(&smb_drv_opencount_lock); 270 /* 271 * Service state value is not protected by a lock in this case but 272 * it shouldn't be possible for the service state machine to transition 273 * TO a busy state at a time when smb_drv_busy() would return false. 274 */ 275 if (smb_drv_busy() || smb_svcstate_sm_busy()) { 276 mutex_exit(&smb_drv_opencount_lock); 277 return (DDI_FAILURE); 278 } 279 mutex_exit(&smb_drv_opencount_lock); 280 281 smb_service_fini(); 282 283 smb_drv_dip = NULL; 284 ddi_remove_minor_node(dip, NULL); 285 286 return (DDI_SUCCESS); 287 } 288 289 /* ARGSUSED */ 290 static int 291 smb_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flag, cred_t *cred, 292 int *retval) 293 { 294 int gmtoff; 295 int door_id; 296 297 switch (cmd) { 298 case SMB_IOC_GMTOFF: 299 if (ddi_copyin((int *)argp, &gmtoff, sizeof (int), flag)) 300 return (EFAULT); 301 (void) smb_set_gmtoff((uint32_t)gmtoff); 302 break; 303 304 case SMB_IOC_CONFIG: 305 #if 0 306 smb_svcstate_event(SMB_SVCEVT_CONFIG, NULL); 307 #endif 308 break; 309 310 case SMB_IOC_WINPIPE: 311 if (ddi_copyin((int *)argp, &door_id, sizeof (int), flag)) 312 return (EFAULT); 313 314 if (smb_winpipe_open(door_id) != 0) 315 return (EPIPE); 316 break; 317 318 default: 319 break; 320 } 321 322 return (0); 323 } 324 325 /* ARGSUSED */ 326 static int 327 smb_drv_open(dev_t *devp, int flag, int otyp, cred_t *credp) 328 { 329 int rc = 0; 330 331 /* 332 * Only allow one open at a time 333 */ 334 mutex_enter(&smb_drv_opencount_lock); 335 if (smb_drv_busy()) { 336 mutex_exit(&smb_drv_opencount_lock); 337 return (EBUSY); 338 } 339 smb_drv_opencount++; 340 mutex_exit(&smb_drv_opencount_lock); 341 342 /* 343 * Check caller's privileges. 344 */ 345 if (secpolicy_smb(credp) != 0) { 346 mutex_enter(&smb_drv_opencount_lock); 347 smb_drv_opencount--; 348 mutex_exit(&smb_drv_opencount_lock); 349 return (EPERM); 350 } 351 352 /* 353 * Start SMB service state machine 354 */ 355 rc = smb_svcstate_sm_start(&smb_info.si_svc_sm_ctx); 356 357 if (rc != 0) { 358 mutex_enter(&smb_drv_opencount_lock); 359 smb_drv_opencount--; 360 mutex_exit(&smb_drv_opencount_lock); 361 return (rc); 362 } 363 364 return (0); 365 } 366 367 /* ARGSUSED */ 368 static int 369 smb_drv_close(dev_t dev, int flag, int otyp, cred_t *credp) 370 { 371 mutex_enter(&smb_drv_opencount_lock); 372 if (!smb_drv_busy()) { 373 mutex_exit(&smb_drv_opencount_lock); 374 return (0); 375 } 376 mutex_exit(&smb_drv_opencount_lock); 377 378 smb_svcstate_event(SMB_SVCEVT_CLOSE, NULL); 379 380 mutex_enter(&smb_drv_opencount_lock); 381 smb_drv_opencount--; 382 mutex_exit(&smb_drv_opencount_lock); 383 384 return (0); 385 } 386 387 /* 388 * Convenience function - must be called with smb_drv_opencount_lock held. 389 */ 390 static int 391 smb_drv_busy(void) 392 { 393 ASSERT(mutex_owned(&smb_drv_opencount_lock)); 394 return (smb_drv_opencount); 395 } 396 397 /* 398 * SMB Service initialization and startup functions 399 */ 400 401 int 402 smb_service_init(void) 403 { 404 int rc; 405 406 rc = smb_info_init(&smb_info); 407 if (rc != 0) { 408 return (rc); 409 } 410 411 rc = smb_svcstate_sm_init(&smb_info.si_svc_sm_ctx); 412 if (rc != 0) { 413 smb_info_fini(&smb_info); 414 return (rc); 415 } 416 417 rc = smb_kstat_init(); 418 if (rc != 0) { 419 smb_kstat_fini(); 420 return (rc); 421 } 422 423 smb_winpipe_init(); 424 425 return (0); 426 } 427 428 void 429 smb_service_fini(void) 430 { 431 smb_winpipe_fini(); 432 433 smb_kstat_fini(); 434 435 smb_svcstate_sm_fini(&smb_info.si_svc_sm_ctx); 436 437 smb_info_fini(&smb_info); 438 } 439 440 /* 441 * Progress bits for smb_info.si_open_progress. For use only by 442 * smb_service_open/smb_service_close. 443 */ 444 #define SMB_FS_STARTED 0x01 445 #define LMSHRD_KCLIENT_STARTED 0x02 446 #define SMB_KDOOR_CLNT_STARTED 0x04 447 #define SMB_KDOOR_SRV_STARTED 0x08 448 #define SMB_THREADS_STARTED 0x10 449 450 int 451 smb_service_open(struct smb_info *si) 452 { 453 int rc; 454 int size; /* XXX TEMPORARY (remove when kconfig is removed) */ 455 456 /* Track progress so we can cleanup from a partial failure */ 457 si->si_open_progress = 0; 458 si->si_connect_progress = 0; 459 460 /* XXX TEMPORARY */ 461 if (smb_get_kconfig(&si->si) == 0) { 462 if (si->si.skc_sync_enable) 463 smb_set_stability(1); 464 465 if (si->si.skc_flush_required) 466 smb_commit_required(0); 467 468 if (si->si.skc_maxconnections == 0) 469 si->si.skc_maxconnections = 0xFFFFFFFF; 470 471 size = si->si.skc_maxbufsize; 472 if (size != 0) { 473 if (size < 37 || size > 64) 474 size = 37; 475 smb_maxbufsize = SMB_NT_MAXBUF(size); 476 } 477 478 /* 479 * XXX should not override configuration. 480 * For now, this disables server side 481 * signing regardless of configuration. 482 */ 483 si->si.skc_signing_enable = 0; 484 si->si.skc_signing_required = 0; 485 si->si.skc_signing_check = 0; 486 487 smb_correct_keep_alive_values(si->si.skc_keepalive); 488 489 /* 490 * XXX The following code was pulled from smb_oplock_init. 491 * It should be combined with with the config process if 492 * this info will be stored with the configuration or with 493 * the smb_fsop_start function if the data will be stored 494 * in the root of the fs. 495 */ 496 497 /* 498 * XXX oplock enable flag. 499 * Should be stored in extended attribute in root of fs 500 * or a ZFS user-defined property. 501 */ 502 if (si->si.skc_oplock_enable == 0) { 503 cmn_err(CE_NOTE, "SmbOplocks: disabled"); 504 } 505 506 smb_oplock_timeout = si->si.skc_oplock_timeout; 507 508 /* 509 * XXX oplock timeout. Can a customer configure this? 510 */ 511 if (si->si.skc_oplock_timeout < OPLOCK_MIN_TIMEOUT) 512 smb_oplock_timeout = OPLOCK_MIN_TIMEOUT; 513 514 } else { 515 return (EIO); /* XXX Errno? */ 516 } 517 518 if ((rc = smb_fsop_start()) != 0) { 519 return (rc); 520 } 521 si->si_open_progress |= SMB_FS_STARTED; 522 523 if ((rc = lmshrd_kclient_start()) != 0) { 524 return (rc); 525 } 526 si->si_open_progress |= LMSHRD_KCLIENT_STARTED; 527 528 if ((rc = smb_kdoor_clnt_start()) != 0) { 529 return (rc); 530 } 531 si->si_open_progress |= SMB_KDOOR_CLNT_STARTED; 532 533 if ((rc = smb_kdoor_srv_start()) != 0) { 534 return (rc); 535 } 536 si->si_open_progress |= SMB_KDOOR_SRV_STARTED; 537 538 if ((rc = smb_service_start_threads(si)) != 0) { 539 return (rc); 540 } 541 si->si_open_progress |= SMB_THREADS_STARTED; 542 543 return (0); 544 } 545 546 void 547 smb_service_close(struct smb_info *si) 548 { 549 if (si->si_open_progress & SMB_THREADS_STARTED) 550 smb_service_stop_threads(si); 551 552 if (si->si_open_progress & SMB_KDOOR_SRV_STARTED) 553 smb_kdoor_srv_stop(); 554 555 if (si->si_open_progress & SMB_KDOOR_CLNT_STARTED) 556 smb_kdoor_clnt_stop(); 557 558 if (si->si_open_progress & LMSHRD_KCLIENT_STARTED) 559 lmshrd_kclient_stop(); 560 561 if (si->si_open_progress & SMB_FS_STARTED) 562 smb_fsop_stop(); 563 } 564 565 /* 566 * Start the Netbios and TCP services. 567 * 568 * Awaken arguments are not known until thread starts. 569 * 570 * XXX We give up the NET_MAC_AWARE privilege because it keeps us from 571 * re-opening the connection when there are leftover TCP connections in 572 * TCPS_TIME_WAIT state. There seem to be some security ramifications 573 * around reestablishing a connection while possessing the NET_MAC_AWARE 574 * privilege. 575 * 576 * This approach may cause problems when we try to support zones. An 577 * alternative would be to retry the connection setup for a fixed period 578 * of time until the stale connections clear up but that implies we 579 * would be offline for a couple minutes every time the service is 580 * restarted with active connections. 581 */ 582 int 583 smb_service_connect(struct smb_info *si) 584 { 585 int rc1, rc2; 586 587 if ((rc1 = setpflags(NET_MAC_AWARE, 0, CRED())) != 0) { 588 cmn_err(CE_WARN, "Cannot remove NET_MAC_AWARE privilege"); 589 smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)rc1); 590 return (rc1); 591 } 592 593 rc1 = smb_thread_start(&si->si_nbt_daemon); 594 rc2 = smb_thread_start(&si->si_tcp_daemon); 595 if (rc2 != 0) 596 rc1 = rc2; 597 return (rc1); 598 } 599 600 void 601 smb_service_disconnect(struct smb_info *si) 602 { 603 smb_thread_stop(&si->si_nbt_daemon); 604 smb_thread_stop(&si->si_tcp_daemon); 605 } 606 607 /* 608 * Start any service-related kernel threads except for the NBT and TCP 609 * daemon threads. Those service daemon threads are handled separately. 610 * 611 * Returns 0 for success, non-zero for failure. If failure is returned the 612 * caller should call smb_service_stop_threads to cleanup any threads that 613 * were successfully started. 614 */ 615 int 616 smb_service_start_threads(struct smb_info *si) 617 { 618 int rval; 619 620 si->thread_pool = taskq_create( 621 "smb_workers", 622 si->si.skc_maxworkers, 623 SMB_WORKER_PRIORITY, 624 si->si.skc_maxworkers, 625 INT_MAX, 626 TASKQ_DYNAMIC|TASKQ_PREPOPULATE); 627 ASSERT(si->thread_pool != NULL); 628 629 rval = smb_thread_start(&si->si_thread_notify_change); 630 if (rval != 0) 631 return (rval); 632 633 rval = smb_thread_start(&si->si_thread_timers); 634 if (rval != 0) { 635 smb_thread_stop(&si->si_thread_notify_change); 636 return (rval); 637 } 638 639 return (0); 640 } 641 642 void 643 smb_service_stop_threads(struct smb_info *si) 644 { 645 smb_thread_stop(&si->si_thread_timers); 646 smb_thread_stop(&si->si_thread_notify_change); 647 taskq_destroy(si->thread_pool); 648 } 649 650 static int 651 smb_info_init(struct smb_info *si) 652 { 653 int i; 654 655 bzero(si, sizeof (smb_info)); 656 657 for (i = 0; i <= SMBND_HASH_MASK; i++) { 658 smb_llist_constructor(&si->node_hash_table[i], 659 sizeof (smb_node_t), offsetof(smb_node_t, n_lnd)); 660 } 661 662 smb_llist_constructor(&si->si_vfs_list, 663 sizeof (smb_vfs_t), offsetof(smb_vfs_t, sv_lnd)); 664 665 smb_slist_constructor(&si->si_ncr_list, sizeof (smb_request_t), 666 offsetof(smb_request_t, sr_ncr.nc_lnd)); 667 668 smb_slist_constructor(&si->si_nce_list, sizeof (smb_request_t), 669 offsetof(smb_request_t, sr_ncr.nc_lnd)); 670 671 si->si_cache_vfs = kmem_cache_create("smb_vfs_cache", 672 sizeof (smb_vfs_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 673 si->si_cache_request = kmem_cache_create("smb_request_cache", 674 sizeof (smb_request_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 675 si->si_cache_session = kmem_cache_create("smb_session_cache", 676 sizeof (smb_session_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 677 si->si_cache_user = kmem_cache_create("smb_user_cache", 678 sizeof (smb_user_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 679 si->si_cache_tree = kmem_cache_create("smb_tree_cache", 680 sizeof (smb_tree_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 681 si->si_cache_ofile = kmem_cache_create("smb_ofile_cache", 682 sizeof (smb_ofile_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 683 si->si_cache_odir = kmem_cache_create("smb_odir_cache", 684 sizeof (smb_odir_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 685 si->si_cache_node = kmem_cache_create("smb_smb_node_cache", 686 sizeof (smb_node_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 687 688 smb_thread_init(&si->si_nbt_daemon, "smb_nbt_daemon", smb_nbt_daemon, 689 si, NULL, NULL); 690 smb_thread_init(&si->si_tcp_daemon, "smb_tcp_daemon", smb_tcp_daemon, 691 si, NULL, NULL); 692 smb_thread_init(&si->si_thread_notify_change, 693 "smb_notify_change_daemon", smb_notify_change_daemon, &smb_info, 694 NULL, NULL); 695 smb_thread_init(&si->si_thread_timers, "smb_timers", smb_timers, 696 si, NULL, NULL); 697 698 return (0); 699 } 700 701 static void 702 smb_info_fini(struct smb_info *si) 703 { 704 int i; 705 706 for (i = 0; i <= SMBND_HASH_MASK; i++) { 707 smb_node_t *node; 708 709 /* 710 * The following sequence is just intended for sanity check. 711 * This will have to be modified when the code goes into 712 * production. 713 * 714 * The SMB node hash table should be emtpy at this point. If the 715 * hash table is not empty all the nodes remaining are displayed 716 * (it should help figure out what actions led to this state) 717 * and "oops" will be set to B_TRUE which will trigger the 718 * ASSERT that follows. 719 * 720 * The reason why SMB nodes are still remaining in the hash 721 * table is problably due to a mismatch between calls to 722 * smb_node_lookup() and smb_node_release(). You must track that 723 * down. 724 * 725 * Now if you are reading this comment because you actually hit 726 * the ASSERT, the temptation to ignore it is going to be very 727 * strong. To help you make the right decision you should know 728 * that when the ASSERT happened a message containing you SunID 729 * has been sent to cifsgate. By now it has been logged into a 730 * special database. 731 * 732 * You are being watched... 733 */ 734 node = smb_llist_head(&si->node_hash_table[i]); 735 ASSERT(node == NULL); 736 } 737 738 for (i = 0; i <= SMBND_HASH_MASK; i++) { 739 smb_llist_destructor(&si->node_hash_table[i]); 740 } 741 742 smb_llist_destructor(&si->si_vfs_list); 743 744 kmem_cache_destroy(si->si_cache_vfs); 745 kmem_cache_destroy(si->si_cache_request); 746 kmem_cache_destroy(si->si_cache_session); 747 kmem_cache_destroy(si->si_cache_user); 748 kmem_cache_destroy(si->si_cache_tree); 749 kmem_cache_destroy(si->si_cache_ofile); 750 kmem_cache_destroy(si->si_cache_odir); 751 kmem_cache_destroy(si->si_cache_node); 752 753 smb_thread_destroy(&si->si_nbt_daemon); 754 smb_thread_destroy(&si->si_tcp_daemon); 755 smb_thread_destroy(&si->si_thread_notify_change); 756 smb_thread_destroy(&si->si_thread_timers); 757 } 758 759 static int 760 smb_kstat_init() 761 { 762 763 /* create and initialize smb kstats - smb_info stats */ 764 smbinfo_ksp = kstat_create("smb", 0, "smb_info", "misc", 765 KSTAT_TYPE_NAMED, sizeof (smbinfo_stats) / sizeof (kstat_named_t), 766 KSTAT_FLAG_VIRTUAL); 767 if (smbinfo_ksp) { 768 smbinfo_ksp->ks_data = (void *) &smbinfo_stats; 769 smbinfo_ksp->ks_update = smb_kstat_update_info; 770 kstat_install(smbinfo_ksp); 771 } 772 773 /* create and initialize smb kstats - smb_dispatch stats */ 774 smb_initialize_dispatch_kstat(); 775 776 return (0); 777 } 778 779 static void 780 smb_kstat_fini() 781 { 782 if (smbinfo_ksp != NULL) { 783 kstat_delete(smbinfo_ksp); 784 smbinfo_ksp = NULL; 785 } 786 787 smb_remove_dispatch_kstat(); 788 } 789 790 /* ARGSUSED */ 791 static int 792 smb_kstat_update_info(kstat_t *ksp, int rw) 793 { 794 if (rw == KSTAT_WRITE) { 795 return (EACCES); 796 } else { 797 smbinfo_stats.state.value.ui32 = 798 smb_info.si_svc_sm_ctx.ssc_state; 799 smbinfo_stats.open_files.value.ui32 = smb_info.open_files; 800 smbinfo_stats.open_trees.value.ui32 = smb_info.open_trees; 801 smbinfo_stats.open_users.value.ui32 = smb_info.open_users; 802 } 803 return (0); 804 } 805