xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_init.c (revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0)
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