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 296 switch (cmd) { 297 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_REFRESH: 305 #if 0 306 smb_svcstate_event(SMB_SVCEVT_CONFIG, NULL); 307 #endif 308 break; 309 310 default: 311 break; 312 } 313 314 return (0); 315 } 316 317 /* ARGSUSED */ 318 static int 319 smb_drv_open(dev_t *devp, int flag, int otyp, cred_t *credp) 320 { 321 int rc = 0; 322 323 /* 324 * Only allow one open at a time 325 */ 326 mutex_enter(&smb_drv_opencount_lock); 327 if (smb_drv_busy()) { 328 mutex_exit(&smb_drv_opencount_lock); 329 return (EBUSY); 330 } 331 smb_drv_opencount++; 332 mutex_exit(&smb_drv_opencount_lock); 333 334 /* 335 * Check caller's privileges. 336 */ 337 if (secpolicy_smb(credp) != 0) { 338 mutex_enter(&smb_drv_opencount_lock); 339 smb_drv_opencount--; 340 mutex_exit(&smb_drv_opencount_lock); 341 return (EPERM); 342 } 343 344 /* 345 * Start SMB service state machine 346 */ 347 rc = smb_svcstate_sm_start(&smb_info.si_svc_sm_ctx); 348 349 if (rc != 0) { 350 mutex_enter(&smb_drv_opencount_lock); 351 smb_drv_opencount--; 352 mutex_exit(&smb_drv_opencount_lock); 353 return (rc); 354 } 355 356 return (0); 357 } 358 359 /* ARGSUSED */ 360 static int 361 smb_drv_close(dev_t dev, int flag, int otyp, cred_t *credp) 362 { 363 mutex_enter(&smb_drv_opencount_lock); 364 if (!smb_drv_busy()) { 365 mutex_exit(&smb_drv_opencount_lock); 366 return (0); 367 } 368 mutex_exit(&smb_drv_opencount_lock); 369 370 smb_svcstate_event(SMB_SVCEVT_CLOSE, NULL); 371 372 mutex_enter(&smb_drv_opencount_lock); 373 smb_drv_opencount--; 374 mutex_exit(&smb_drv_opencount_lock); 375 376 return (0); 377 } 378 379 /* 380 * Convenience function - must be called with smb_drv_opencount_lock held. 381 */ 382 static int 383 smb_drv_busy(void) 384 { 385 ASSERT(mutex_owned(&smb_drv_opencount_lock)); 386 return (smb_drv_opencount); 387 } 388 389 /* 390 * SMB Service initialization and startup functions 391 */ 392 393 int 394 smb_service_init(void) 395 { 396 int rc; 397 398 rc = smb_info_init(&smb_info); 399 if (rc != 0) { 400 return (rc); 401 } 402 403 rc = smb_svcstate_sm_init(&smb_info.si_svc_sm_ctx); 404 if (rc != 0) { 405 smb_info_fini(&smb_info); 406 return (rc); 407 } 408 409 rc = smb_kstat_init(); 410 if (rc != 0) { 411 smb_kstat_fini(); 412 return (rc); 413 } 414 415 smb_winpipe_init(); 416 417 return (0); 418 } 419 420 void 421 smb_service_fini(void) 422 { 423 smb_winpipe_fini(); 424 425 smb_kstat_fini(); 426 427 smb_svcstate_sm_fini(&smb_info.si_svc_sm_ctx); 428 429 smb_info_fini(&smb_info); 430 } 431 432 /* 433 * Progress bits for smb_info.si_open_progress. For use only by 434 * smb_service_open/smb_service_close. 435 */ 436 #define SMB_FS_STARTED 0x01 437 #define LMSHRD_KCLIENT_STARTED 0x02 438 #define SMB_KDOOR_CLNT_STARTED 0x04 439 #define SMB_KDOOR_SRV_STARTED 0x08 440 #define SMB_THREADS_STARTED 0x10 441 442 int 443 smb_service_open(struct smb_info *si) 444 { 445 int rc; 446 int size; /* XXX TEMPORARY (remove when kconfig is removed) */ 447 448 /* Track progress so we can cleanup from a partial failure */ 449 si->si_open_progress = 0; 450 si->si_connect_progress = 0; 451 452 /* XXX TEMPORARY */ 453 if (smb_get_kconfig(&si->si) == 0) { 454 if (si->si.skc_sync_enable) 455 smb_set_stability(1); 456 457 if (si->si.skc_flush_required) 458 smb_commit_required(0); 459 460 if (si->si.skc_maxconnections == 0) 461 si->si.skc_maxconnections = 0xFFFFFFFF; 462 463 size = si->si.skc_maxbufsize; 464 if (size != 0) { 465 if (size < 37 || size > 64) 466 size = 37; 467 smb_maxbufsize = SMB_NT_MAXBUF(size); 468 } 469 470 /* 471 * XXX should not override configuration. 472 * For now, this disables server side 473 * signing regardless of configuration. 474 */ 475 si->si.skc_signing_enable = 0; 476 si->si.skc_signing_required = 0; 477 si->si.skc_signing_check = 0; 478 479 smb_correct_keep_alive_values(si->si.skc_keepalive); 480 481 /* 482 * XXX The following code was pulled from smb_oplock_init. 483 * It should be combined with with the config process if 484 * this info will be stored with the configuration or with 485 * the smb_fsop_start function if the data will be stored 486 * in the root of the fs. 487 */ 488 489 /* 490 * XXX oplock enable flag. 491 * Should be stored in extended attribute in root of fs 492 * or a ZFS user-defined property. 493 */ 494 if (si->si.skc_oplock_enable == 0) { 495 cmn_err(CE_NOTE, "SmbOplocks: disabled"); 496 } 497 498 smb_oplock_timeout = si->si.skc_oplock_timeout; 499 500 /* 501 * XXX oplock timeout. Can a customer configure this? 502 */ 503 if (si->si.skc_oplock_timeout < OPLOCK_MIN_TIMEOUT) 504 smb_oplock_timeout = OPLOCK_MIN_TIMEOUT; 505 506 } else { 507 return (EIO); /* XXX Errno? */ 508 } 509 510 if ((rc = smb_fsop_start()) != 0) { 511 return (rc); 512 } 513 si->si_open_progress |= SMB_FS_STARTED; 514 515 if ((rc = lmshrd_kclient_start()) != 0) { 516 return (rc); 517 } 518 si->si_open_progress |= LMSHRD_KCLIENT_STARTED; 519 520 if ((rc = smb_kdoor_clnt_start()) != 0) { 521 return (rc); 522 } 523 si->si_open_progress |= SMB_KDOOR_CLNT_STARTED; 524 525 if ((rc = smb_kdoor_srv_start()) != 0) { 526 return (rc); 527 } 528 si->si_open_progress |= SMB_KDOOR_SRV_STARTED; 529 530 if ((rc = smb_service_start_threads(si)) != 0) { 531 return (rc); 532 } 533 si->si_open_progress |= SMB_THREADS_STARTED; 534 535 return (0); 536 } 537 538 void 539 smb_service_close(struct smb_info *si) 540 { 541 if (si->si_open_progress & SMB_THREADS_STARTED) 542 smb_service_stop_threads(si); 543 544 if (si->si_open_progress & SMB_KDOOR_SRV_STARTED) 545 smb_kdoor_srv_stop(); 546 547 if (si->si_open_progress & SMB_KDOOR_CLNT_STARTED) 548 smb_kdoor_clnt_stop(); 549 550 if (si->si_open_progress & LMSHRD_KCLIENT_STARTED) 551 lmshrd_kclient_stop(); 552 553 if (si->si_open_progress & SMB_FS_STARTED) 554 smb_fsop_stop(); 555 } 556 557 /* 558 * Start the Netbios and TCP services. 559 * 560 * Awaken arguments are not known until thread starts. 561 * 562 * XXX We give up the NET_MAC_AWARE privilege because it keeps us from 563 * re-opening the connection when there are leftover TCP connections in 564 * TCPS_TIME_WAIT state. There seem to be some security ramifications 565 * around reestablishing a connection while possessing the NET_MAC_AWARE 566 * privilege. 567 * 568 * This approach may cause problems when we try to support zones. An 569 * alternative would be to retry the connection setup for a fixed period 570 * of time until the stale connections clear up but that implies we 571 * would be offline for a couple minutes every time the service is 572 * restarted with active connections. 573 */ 574 int 575 smb_service_connect(struct smb_info *si) 576 { 577 int rc1, rc2; 578 579 if ((rc1 = setpflags(NET_MAC_AWARE, 0, CRED())) != 0) { 580 cmn_err(CE_WARN, "Cannot remove NET_MAC_AWARE privilege"); 581 smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)rc1); 582 return (rc1); 583 } 584 585 rc1 = smb_thread_start(&si->si_nbt_daemon); 586 rc2 = smb_thread_start(&si->si_tcp_daemon); 587 if (rc2 != 0) 588 rc1 = rc2; 589 return (rc1); 590 } 591 592 void 593 smb_service_disconnect(struct smb_info *si) 594 { 595 smb_thread_stop(&si->si_nbt_daemon); 596 smb_thread_stop(&si->si_tcp_daemon); 597 } 598 599 /* 600 * Start any service-related kernel threads except for the NBT and TCP 601 * daemon threads. Those service daemon threads are handled separately. 602 * 603 * Returns 0 for success, non-zero for failure. If failure is returned the 604 * caller should call smb_service_stop_threads to cleanup any threads that 605 * were successfully started. 606 */ 607 int 608 smb_service_start_threads(struct smb_info *si) 609 { 610 int rval; 611 612 si->thread_pool = taskq_create( 613 "smb_workers", 614 si->si.skc_maxworkers, 615 SMB_WORKER_PRIORITY, 616 si->si.skc_maxworkers, 617 INT_MAX, 618 TASKQ_DYNAMIC|TASKQ_PREPOPULATE); 619 ASSERT(si->thread_pool != NULL); 620 621 rval = smb_thread_start(&si->si_thread_notify_change); 622 if (rval != 0) 623 return (rval); 624 625 rval = smb_thread_start(&si->si_thread_timers); 626 if (rval != 0) { 627 smb_thread_stop(&si->si_thread_notify_change); 628 return (rval); 629 } 630 631 return (0); 632 } 633 634 void 635 smb_service_stop_threads(struct smb_info *si) 636 { 637 smb_thread_stop(&si->si_thread_timers); 638 smb_thread_stop(&si->si_thread_notify_change); 639 taskq_destroy(si->thread_pool); 640 } 641 642 static int 643 smb_info_init(struct smb_info *si) 644 { 645 int i; 646 647 bzero(si, sizeof (smb_info)); 648 649 for (i = 0; i <= SMBND_HASH_MASK; i++) { 650 smb_llist_constructor(&si->node_hash_table[i], 651 sizeof (smb_node_t), offsetof(smb_node_t, n_lnd)); 652 } 653 654 smb_llist_constructor(&si->si_vfs_list, 655 sizeof (smb_vfs_t), offsetof(smb_vfs_t, sv_lnd)); 656 657 smb_slist_constructor(&si->si_ncr_list, sizeof (smb_request_t), 658 offsetof(smb_request_t, sr_ncr.nc_lnd)); 659 660 smb_slist_constructor(&si->si_nce_list, sizeof (smb_request_t), 661 offsetof(smb_request_t, sr_ncr.nc_lnd)); 662 663 si->si_cache_vfs = kmem_cache_create("smb_vfs_cache", 664 sizeof (smb_vfs_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 665 si->si_cache_request = kmem_cache_create("smb_request_cache", 666 sizeof (smb_request_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 667 si->si_cache_session = kmem_cache_create("smb_session_cache", 668 sizeof (smb_session_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 669 si->si_cache_user = kmem_cache_create("smb_user_cache", 670 sizeof (smb_user_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 671 si->si_cache_tree = kmem_cache_create("smb_tree_cache", 672 sizeof (smb_tree_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 673 si->si_cache_ofile = kmem_cache_create("smb_ofile_cache", 674 sizeof (smb_ofile_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 675 si->si_cache_odir = kmem_cache_create("smb_odir_cache", 676 sizeof (smb_odir_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 677 si->si_cache_node = kmem_cache_create("smb_smb_node_cache", 678 sizeof (smb_node_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 679 680 smb_thread_init(&si->si_nbt_daemon, "smb_nbt_daemon", smb_nbt_daemon, 681 si, NULL, NULL); 682 smb_thread_init(&si->si_tcp_daemon, "smb_tcp_daemon", smb_tcp_daemon, 683 si, NULL, NULL); 684 smb_thread_init(&si->si_thread_notify_change, 685 "smb_notify_change_daemon", smb_notify_change_daemon, &smb_info, 686 NULL, NULL); 687 smb_thread_init(&si->si_thread_timers, "smb_timers", smb_timers, 688 si, NULL, NULL); 689 690 return (0); 691 } 692 693 static void 694 smb_info_fini(struct smb_info *si) 695 { 696 int i; 697 698 for (i = 0; i <= SMBND_HASH_MASK; i++) { 699 smb_node_t *node; 700 701 /* 702 * The following sequence is just intended for sanity check. 703 * This will have to be modified when the code goes into 704 * production. 705 * 706 * The SMB node hash table should be emtpy at this point. If the 707 * hash table is not empty all the nodes remaining are displayed 708 * (it should help figure out what actions led to this state) 709 * and "oops" will be set to B_TRUE which will trigger the 710 * ASSERT that follows. 711 * 712 * The reason why SMB nodes are still remaining in the hash 713 * table is problably due to a mismatch between calls to 714 * smb_node_lookup() and smb_node_release(). You must track that 715 * down. 716 * 717 * Now if you are reading this comment because you actually hit 718 * the ASSERT, the temptation to ignore it is going to be very 719 * strong. To help you make the right decision you should know 720 * that when the ASSERT happened a message containing you SunID 721 * has been sent to cifsgate. By now it has been logged into a 722 * special database. 723 * 724 * You are being watched... 725 */ 726 node = smb_llist_head(&si->node_hash_table[i]); 727 ASSERT(node == NULL); 728 } 729 730 for (i = 0; i <= SMBND_HASH_MASK; i++) { 731 smb_llist_destructor(&si->node_hash_table[i]); 732 } 733 734 smb_llist_destructor(&si->si_vfs_list); 735 736 kmem_cache_destroy(si->si_cache_vfs); 737 kmem_cache_destroy(si->si_cache_request); 738 kmem_cache_destroy(si->si_cache_session); 739 kmem_cache_destroy(si->si_cache_user); 740 kmem_cache_destroy(si->si_cache_tree); 741 kmem_cache_destroy(si->si_cache_ofile); 742 kmem_cache_destroy(si->si_cache_odir); 743 kmem_cache_destroy(si->si_cache_node); 744 745 smb_thread_destroy(&si->si_nbt_daemon); 746 smb_thread_destroy(&si->si_tcp_daemon); 747 smb_thread_destroy(&si->si_thread_notify_change); 748 smb_thread_destroy(&si->si_thread_timers); 749 } 750 751 static int 752 smb_kstat_init() 753 { 754 755 /* create and initialize smb kstats - smb_info stats */ 756 smbinfo_ksp = kstat_create("smb", 0, "smb_info", "misc", 757 KSTAT_TYPE_NAMED, sizeof (smbinfo_stats) / sizeof (kstat_named_t), 758 KSTAT_FLAG_VIRTUAL); 759 if (smbinfo_ksp) { 760 smbinfo_ksp->ks_data = (void *) &smbinfo_stats; 761 smbinfo_ksp->ks_update = smb_kstat_update_info; 762 kstat_install(smbinfo_ksp); 763 } 764 765 /* create and initialize smb kstats - smb_dispatch stats */ 766 smb_initialize_dispatch_kstat(); 767 768 return (0); 769 } 770 771 static void 772 smb_kstat_fini() 773 { 774 if (smbinfo_ksp != NULL) { 775 kstat_delete(smbinfo_ksp); 776 smbinfo_ksp = NULL; 777 } 778 779 smb_remove_dispatch_kstat(); 780 } 781 782 /* ARGSUSED */ 783 static int 784 smb_kstat_update_info(kstat_t *ksp, int rw) 785 { 786 if (rw == KSTAT_WRITE) { 787 return (EACCES); 788 } else { 789 smbinfo_stats.state.value.ui32 = 790 smb_info.si_svc_sm_ctx.ssc_state; 791 smbinfo_stats.open_files.value.ui32 = smb_info.open_files; 792 smbinfo_stats.open_trees.value.ui32 = smb_info.open_trees; 793 smbinfo_stats.open_users.value.ui32 = smb_info.open_users; 794 } 795 return (0); 796 } 797