xref: /titanic_41/usr/src/uts/common/fs/smbsrv/smb_init.c (revision 22337b4b3c8a2b9db615e524e0e9e1fbd3dc71bf)
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