summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/fs/smbsrv/smb_init.c
diff options
context:
space:
mode:
authoramw <none@none>2007-10-25 16:34:29 -0700
committeramw <none@none>2007-10-25 16:34:29 -0700
commitda6c28aaf62fa55f0fdb8004aa40f88f23bf53f0 (patch)
tree65be91fb78a6a66183197595333f2e8aafb4640a /usr/src/uts/common/fs/smbsrv/smb_init.c
parente845e33dd0d1aea22db7edaa8c7d43955d24609b (diff)
downloadillumos-joyent-da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0.tar.gz
PSARC/2007/218 caller_context_t in all VOPs
PSARC/2007/227 VFS Feature Registration and ACL on Create PSARC/2007/244 ZFS Case-insensitive support PSARC/2007/315 Extensible Attribute Interfaces PSARC/2007/394 ls(1) new command line options '-/' and '-%': CIFS system attributes support PSARC/2007/403 Modified Access Checks for CIFS PSARC/2007/410 Add system attribute support to chmod(1) PSARC/2007/432 CIFS system attributes support for cp(1), pack(1), unpack(1), compress(1) and uncompress(1) PSARC/2007/444 Rescind SETTABLE Attribute PSARC/2007/459 CIFS system attributes support for cpio(1), pax(1), tar(1) PSARC/2007/546 Update utilities to match CIFS system attributes changes. PSARC/2007/560 ZFS sharesmb property 4890717 want append-only files 6417428 Case-insensitive file system name lookup to support CIFS 6417435 DOS attributes and additional timestamps to support for CIFS 6417442 File system quarantined and modified attributes to support an integrated Anti-Virus service 6417453 FS boolean property for rejecting/allowing invalid UTF-8 sequences in file names 6473733 RFE: Need support for open-deny modes 6473755 RFE: Need ability to reconcile oplock and delegation conflicts 6494624 sharemgr needs to support CIFS shares better 6546705 All vnode operations need to pass caller_context_t 6546706 Need VOP_SETATTR/VOP_GETATTR to support new, optional attributes 6546893 Solaris system attribute support 6550962 ZFS ACL inheritance needs to be enhanced to support Automatic Inheritance 6553589 RFE: VFS Feature Registration facility 6553770 RFE: ZFS support for ACL-on-CREATE (PSARC 2007/227) 6565581 ls(1) should support file system attributes proposed in PSARC/2007/315 6566784 NTFS streams are not copied along with the files. 6576205 cp(1), pack(1) and compress(1) should support file system attributes proposed in PSARC/2007/315 6578875 RFE: kernel interfaces for nbmand need improvement 6578883 RFE: VOP_SHRLOCK needs additional access types 6578885 chmod(1) should support file system attributes proposed in PSARC/2007/315 6578886 RFE: disallow nbmand state to change on remount 6583349 ACL parser needs to support audit/alarm ACE types 6590347 tar(1) should support filesystem attributes proposed in PSARC/2007/315 6597357 *tar* xv@ doesn't show the hidden directory even though it is restored 6597360 *tar* should re-init xattr info if openat() fails during extraction of and extended attribute 6597368 *tar* cannot restore hard linked extended attributes 6597374 *tar* doesn't display "x " when hard linked attributes are restored 6597375 *tar* extended attribute header off by one 6614861 *cpio* incorrectly archives extended system attributes with -@ 6614896 *pax* incorrectly archives extended system attributes with -@ 6615225 *tar* incorrectly archives extended system attributes with -@ 6617183 CIFS Service - PSARC 2006/715
Diffstat (limited to 'usr/src/uts/common/fs/smbsrv/smb_init.c')
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_init.c796
1 files changed, 796 insertions, 0 deletions
diff --git a/usr/src/uts/common/fs/smbsrv/smb_init.c b/usr/src/uts/common/fs/smbsrv/smb_init.c
new file mode 100644
index 0000000000..1d3d8f39cb
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_init.c
@@ -0,0 +1,796 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/ddi.h>
+#include <sys/strsubr.h>
+#include <sys/socketvar.h>
+#include <sys/modctl.h>
+#include <sys/cred.h>
+#include <sys/ioccom.h>
+#include <sys/priv.h>
+#include <sys/policy.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/mlsvc.h>
+#include <smbsrv/smb_door_svc.h>
+#include <smbsrv/smb_ioctl.h>
+#include <smbsrv/smb_kproto.h>
+/*
+ * DDI entry points.
+ */
+static int smb_drv_attach(dev_info_t *, ddi_attach_cmd_t);
+static int smb_drv_detach(dev_info_t *, ddi_detach_cmd_t);
+static int smb_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
+static int smb_drv_open(dev_t *, int, int, cred_t *);
+static int smb_drv_close(dev_t, int, int, cred_t *);
+static int smb_drv_busy(void);
+static int smb_drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
+
+/*
+ * module linkage info for the kernel
+ */
+static struct cb_ops cbops = {
+ smb_drv_open, /* cb_open */
+ smb_drv_close, /* cb_close */
+ nodev, /* cb_strategy */
+ nodev, /* cb_print */
+ nodev, /* cb_dump */
+ nodev, /* cb_read */
+ nodev, /* cb_write */
+ smb_drv_ioctl, /* cb_ioctl */
+ nodev, /* cb_devmap */
+ nodev, /* cb_mmap */
+ nodev, /* cb_segmap */
+ nochpoll, /* cb_chpoll */
+ ddi_prop_op, /* cb_prop_op */
+ NULL, /* cb_streamtab */
+ D_MP, /* cb_flag */
+ CB_REV, /* cb_rev */
+ nodev, /* cb_aread */
+ nodev, /* cb_awrite */
+};
+
+static struct dev_ops devops = {
+ DEVO_REV, /* devo_rev */
+ 0, /* devo_refcnt */
+ smb_drv_getinfo, /* devo_getinfo */
+ nulldev, /* devo_identify */
+ nulldev, /* devo_probe */
+ smb_drv_attach, /* devo_attach */
+ smb_drv_detach, /* devo_detach */
+ nodev, /* devo_reset */
+ &cbops, /* devo_cb_ops */
+ NULL, /* devo_bus_ops */
+ NULL, /* devo_power */
+};
+
+static struct modldrv modldrv = {
+ &mod_driverops, /* drv_modops */
+ "CIFS Server Protocol %I%", /* drv_linkinfo */
+ &devops,
+};
+
+static struct modlinkage modlinkage = {
+
+ MODREV_1, /* revision of the module, must be: MODREV_1 */
+ &modldrv, /* ptr to linkage structures */
+ NULL,
+};
+
+static int smb_info_init(struct smb_info *si);
+static void smb_info_fini(struct smb_info *si);
+
+extern int smb_fsop_start(void);
+extern void smb_fsop_stop(void);
+
+extern int nt_mapk_start(void);
+extern void nt_mapk_stop(void);
+
+
+extern int smb_get_kconfig(smb_kmod_cfg_t *cfg);
+
+extern void smb_notify_change_daemon(smb_thread_t *thread, void *arg);
+extern void smb_nbt_daemon(smb_thread_t *thread, void *arg);
+extern void smb_tcp_daemon(smb_thread_t *thread, void *arg);
+extern void smb_timers(smb_thread_t *thread, void *arg);
+extern void smb_session_worker(void *arg);
+
+extern int smb_maxbufsize;
+
+extern time_t smb_oplock_timeout;
+
+/* Debug logging level: 0=Disabled, 1=Quiet, 2=Verbose */
+int smbsrv_debug_level;
+
+struct smb_info smb_info;
+
+static dev_info_t *smb_drv_dip = NULL;
+static kmutex_t smb_drv_opencount_lock;
+static int smb_drv_opencount = 0;
+
+/*
+ * Kstat smb_info statistics.
+ */
+static struct smbinfo_stats {
+ kstat_named_t state;
+ kstat_named_t open_files;
+ kstat_named_t open_trees;
+ kstat_named_t open_users;
+} smbinfo_stats = {
+ { "state", KSTAT_DATA_UINT32 },
+ { "open_files", KSTAT_DATA_UINT32 },
+ { "connections", KSTAT_DATA_UINT32 },
+ { "sessions", KSTAT_DATA_UINT32 }
+};
+
+static int smb_kstat_init(void);
+static void smb_kstat_fini(void);
+static int smb_kstat_update_info(kstat_t *ksp, int rw);
+extern void smb_initialize_dispatch_kstat(void);
+extern void smb_remove_dispatch_kstat(void);
+
+static kstat_t *smbinfo_ksp = NULL;
+
+/*
+ * SMB pseudo-driver entry points
+ */
+
+
+
+int
+_init(void)
+{
+ int rc;
+
+ mutex_init(&smb_drv_opencount_lock, NULL, MUTEX_DRIVER, NULL);
+
+ if ((rc = mod_install(&modlinkage)) != 0) {
+ mutex_destroy(&smb_drv_opencount_lock);
+ cmn_err(CE_NOTE, "init: %d\n", rc);
+ return (rc);
+ }
+
+ return (0);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
+int
+_fini(void)
+{
+ int rc;
+
+ mutex_enter(&smb_drv_opencount_lock);
+ if (smb_drv_busy()) {
+ mutex_exit(&smb_drv_opencount_lock);
+ return (EBUSY);
+ }
+ mutex_exit(&smb_drv_opencount_lock);
+
+ if ((rc = mod_remove(&modlinkage)) == 0)
+ mutex_destroy(&smb_drv_opencount_lock);
+
+ return (rc);
+}
+
+/*
+ * DDI entry points.
+ */
+
+/* ARGSUSED */
+static int
+smb_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
+{
+ ulong_t instance = getminor((dev_t)arg);
+
+ switch (cmd) {
+ case DDI_INFO_DEVT2DEVINFO:
+ *result = smb_drv_dip;
+ return (DDI_SUCCESS);
+
+ case DDI_INFO_DEVT2INSTANCE:
+ *result = (void *)instance;
+ return (DDI_SUCCESS);
+
+ default:
+ break;
+ }
+
+ return (DDI_FAILURE);
+}
+
+
+static int
+smb_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+ if (cmd != DDI_ATTACH) {
+ return (DDI_FAILURE);
+ }
+
+ if (ddi_get_instance(dip) != 0) {
+ /* we only allow instance 0 to attach */
+ return (DDI_FAILURE);
+ }
+
+ smb_drv_dip = dip;
+
+ /* create the minor node */
+ if (ddi_create_minor_node(dip, "smbsrv", S_IFCHR, 0,
+ DDI_PSEUDO, 0) != DDI_SUCCESS) {
+ cmn_err(CE_WARN, "smb_drv_attach: failed creating minor node");
+ ddi_remove_minor_node(dip, NULL);
+ return (DDI_FAILURE);
+ }
+
+ if (smb_service_init() != 0) {
+ ddi_remove_minor_node(dip, NULL);
+ cmn_err(CE_WARN, "smb_drv_attach: failed to initialize "
+ "SMB service");
+ return (DDI_FAILURE);
+ }
+
+ return (DDI_SUCCESS);
+}
+
+static int
+smb_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+ if (cmd != DDI_DETACH)
+ return (DDI_FAILURE);
+
+ mutex_enter(&smb_drv_opencount_lock);
+ /*
+ * Service state value is not protected by a lock in this case but
+ * it shouldn't be possible for the service state machine to transition
+ * TO a busy state at a time when smb_drv_busy() would return false.
+ */
+ if (smb_drv_busy() || smb_svcstate_sm_busy()) {
+ mutex_exit(&smb_drv_opencount_lock);
+ return (DDI_FAILURE);
+ }
+ mutex_exit(&smb_drv_opencount_lock);
+
+ smb_service_fini();
+
+ smb_drv_dip = NULL;
+ ddi_remove_minor_node(dip, NULL);
+
+ return (DDI_SUCCESS);
+}
+
+/* ARGSUSED */
+static int
+smb_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flag, cred_t *cred,
+ int *retval)
+{
+ int gmtoff;
+
+ switch (cmd) {
+
+ case SMB_IOC_GMTOFF:
+ if (ddi_copyin((int *)argp, &gmtoff, sizeof (int), flag))
+ return (EFAULT);
+ (void) smb_set_gmtoff((uint32_t)gmtoff);
+ break;
+
+ case SMB_IOC_CONFIG_REFRESH:
+#if 0
+ smb_svcstate_event(SMB_SVCEVT_CONFIG, NULL);
+#endif
+ break;
+
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+smb_drv_open(dev_t *devp, int flag, int otyp, cred_t *credp)
+{
+ int rc = 0;
+
+ /*
+ * Only allow one open at a time
+ */
+ mutex_enter(&smb_drv_opencount_lock);
+ if (smb_drv_busy()) {
+ mutex_exit(&smb_drv_opencount_lock);
+ return (EBUSY);
+ }
+ smb_drv_opencount++;
+ mutex_exit(&smb_drv_opencount_lock);
+
+ /*
+ * Check caller's privileges.
+ */
+ if (secpolicy_smb(credp) != 0) {
+ mutex_enter(&smb_drv_opencount_lock);
+ smb_drv_opencount--;
+ mutex_exit(&smb_drv_opencount_lock);
+ return (EPERM);
+ }
+
+ /*
+ * Start SMB service state machine
+ */
+ rc = smb_svcstate_sm_start(&smb_info.si_svc_sm_ctx);
+
+ if (rc != 0) {
+ mutex_enter(&smb_drv_opencount_lock);
+ smb_drv_opencount--;
+ mutex_exit(&smb_drv_opencount_lock);
+ return (rc);
+ }
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+smb_drv_close(dev_t dev, int flag, int otyp, cred_t *credp)
+{
+ mutex_enter(&smb_drv_opencount_lock);
+ if (!smb_drv_busy()) {
+ mutex_exit(&smb_drv_opencount_lock);
+ return (0);
+ }
+ mutex_exit(&smb_drv_opencount_lock);
+
+ smb_svcstate_event(SMB_SVCEVT_CLOSE, NULL);
+
+ mutex_enter(&smb_drv_opencount_lock);
+ smb_drv_opencount--;
+ mutex_exit(&smb_drv_opencount_lock);
+
+ return (0);
+}
+
+/*
+ * Convenience function - must be called with smb_drv_opencount_lock held.
+ */
+static int
+smb_drv_busy(void)
+{
+ ASSERT(mutex_owned(&smb_drv_opencount_lock));
+ return (smb_drv_opencount);
+}
+
+/*
+ * SMB Service initialization and startup functions
+ */
+
+int
+smb_service_init(void)
+{
+ int rc;
+
+ rc = smb_info_init(&smb_info);
+ if (rc != 0) {
+ return (rc);
+ }
+
+ rc = smb_svcstate_sm_init(&smb_info.si_svc_sm_ctx);
+ if (rc != 0) {
+ smb_info_fini(&smb_info);
+ return (rc);
+ }
+
+ rc = smb_kstat_init();
+ if (rc != 0) {
+ smb_kstat_fini();
+ return (rc);
+ }
+
+ smb_winpipe_init();
+
+ return (0);
+}
+
+void
+smb_service_fini(void)
+{
+ smb_winpipe_fini();
+
+ smb_kstat_fini();
+
+ smb_svcstate_sm_fini(&smb_info.si_svc_sm_ctx);
+
+ smb_info_fini(&smb_info);
+}
+
+/*
+ * Progress bits for smb_info.si_open_progress. For use only by
+ * smb_service_open/smb_service_close.
+ */
+#define SMB_FS_STARTED 0x01
+#define LMSHRD_KCLIENT_STARTED 0x02
+#define SMB_KDOOR_CLNT_STARTED 0x04
+#define SMB_KDOOR_SRV_STARTED 0x08
+#define SMB_THREADS_STARTED 0x10
+
+int
+smb_service_open(struct smb_info *si)
+{
+ int rc;
+ int size; /* XXX TEMPORARY (remove when kconfig is removed) */
+
+ /* Track progress so we can cleanup from a partial failure */
+ si->si_open_progress = 0;
+ si->si_connect_progress = 0;
+
+ /* XXX TEMPORARY */
+ if (smb_get_kconfig(&si->si) == 0) {
+ if (si->si.skc_sync_enable)
+ smb_set_stability(1);
+
+ if (si->si.skc_flush_required)
+ smb_commit_required(0);
+
+ if (si->si.skc_maxconnections == 0)
+ si->si.skc_maxconnections = 0xFFFFFFFF;
+
+ size = si->si.skc_maxbufsize;
+ if (size != 0) {
+ if (size < 37 || size > 64)
+ size = 37;
+ smb_maxbufsize = SMB_NT_MAXBUF(size);
+ }
+
+ /*
+ * XXX should not override configuration.
+ * For now, this disables server side
+ * signing regardless of configuration.
+ */
+ si->si.skc_signing_enable = 0;
+ si->si.skc_signing_required = 0;
+ si->si.skc_signing_check = 0;
+
+ smb_correct_keep_alive_values(si->si.skc_keepalive);
+
+ /*
+ * XXX The following code was pulled from smb_oplock_init.
+ * It should be combined with with the config process if
+ * this info will be stored with the configuration or with
+ * the smb_fsop_start function if the data will be stored
+ * in the root of the fs.
+ */
+
+ /*
+ * XXX oplock enable flag.
+ * Should be stored in extended attribute in root of fs
+ * or a ZFS user-defined property.
+ */
+ if (si->si.skc_oplock_enable == 0) {
+ cmn_err(CE_NOTE, "SmbOplocks: disabled");
+ }
+
+ smb_oplock_timeout = si->si.skc_oplock_timeout;
+
+ /*
+ * XXX oplock timeout. Can a customer configure this?
+ */
+ if (si->si.skc_oplock_timeout < OPLOCK_MIN_TIMEOUT)
+ smb_oplock_timeout = OPLOCK_MIN_TIMEOUT;
+
+ } else {
+ return (EIO); /* XXX Errno? */
+ }
+
+ if ((rc = smb_fsop_start()) != 0) {
+ return (rc);
+ }
+ si->si_open_progress |= SMB_FS_STARTED;
+
+ if ((rc = lmshrd_kclient_start()) != 0) {
+ return (rc);
+ }
+ si->si_open_progress |= LMSHRD_KCLIENT_STARTED;
+
+ if ((rc = smb_kdoor_clnt_start()) != 0) {
+ return (rc);
+ }
+ si->si_open_progress |= SMB_KDOOR_CLNT_STARTED;
+
+ if ((rc = smb_kdoor_srv_start()) != 0) {
+ return (rc);
+ }
+ si->si_open_progress |= SMB_KDOOR_SRV_STARTED;
+
+ if ((rc = smb_service_start_threads(si)) != 0) {
+ return (rc);
+ }
+ si->si_open_progress |= SMB_THREADS_STARTED;
+
+ return (0);
+}
+
+void
+smb_service_close(struct smb_info *si)
+{
+ if (si->si_open_progress & SMB_THREADS_STARTED)
+ smb_service_stop_threads(si);
+
+ if (si->si_open_progress & SMB_KDOOR_SRV_STARTED)
+ smb_kdoor_srv_stop();
+
+ if (si->si_open_progress & SMB_KDOOR_CLNT_STARTED)
+ smb_kdoor_clnt_stop();
+
+ if (si->si_open_progress & LMSHRD_KCLIENT_STARTED)
+ lmshrd_kclient_stop();
+
+ if (si->si_open_progress & SMB_FS_STARTED)
+ smb_fsop_stop();
+}
+
+/*
+ * Start the Netbios and TCP services.
+ *
+ * Awaken arguments are not known until thread starts.
+ *
+ * XXX We give up the NET_MAC_AWARE privilege because it keeps us from
+ * re-opening the connection when there are leftover TCP connections in
+ * TCPS_TIME_WAIT state. There seem to be some security ramifications
+ * around reestablishing a connection while possessing the NET_MAC_AWARE
+ * privilege.
+ *
+ * This approach may cause problems when we try to support zones. An
+ * alternative would be to retry the connection setup for a fixed period
+ * of time until the stale connections clear up but that implies we
+ * would be offline for a couple minutes every time the service is
+ * restarted with active connections.
+ */
+int
+smb_service_connect(struct smb_info *si)
+{
+ int rc1, rc2;
+
+ if ((rc1 = setpflags(NET_MAC_AWARE, 0, CRED())) != 0) {
+ cmn_err(CE_WARN, "Cannot remove NET_MAC_AWARE privilege");
+ smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)rc1);
+ return (rc1);
+ }
+
+ rc1 = smb_thread_start(&si->si_nbt_daemon);
+ rc2 = smb_thread_start(&si->si_tcp_daemon);
+ if (rc2 != 0)
+ rc1 = rc2;
+ return (rc1);
+}
+
+void
+smb_service_disconnect(struct smb_info *si)
+{
+ smb_thread_stop(&si->si_nbt_daemon);
+ smb_thread_stop(&si->si_tcp_daemon);
+}
+
+/*
+ * Start any service-related kernel threads except for the NBT and TCP
+ * daemon threads. Those service daemon threads are handled separately.
+ *
+ * Returns 0 for success, non-zero for failure. If failure is returned the
+ * caller should call smb_service_stop_threads to cleanup any threads that
+ * were successfully started.
+ */
+int
+smb_service_start_threads(struct smb_info *si)
+{
+ int rval;
+
+ si->thread_pool = taskq_create(
+ "smb_workers",
+ si->si.skc_maxworkers,
+ SMB_WORKER_PRIORITY,
+ si->si.skc_maxworkers,
+ INT_MAX,
+ TASKQ_DYNAMIC|TASKQ_PREPOPULATE);
+ ASSERT(si->thread_pool != NULL);
+
+ rval = smb_thread_start(&si->si_thread_notify_change);
+ if (rval != 0)
+ return (rval);
+
+ rval = smb_thread_start(&si->si_thread_timers);
+ if (rval != 0) {
+ smb_thread_stop(&si->si_thread_notify_change);
+ return (rval);
+ }
+
+ return (0);
+}
+
+void
+smb_service_stop_threads(struct smb_info *si)
+{
+ smb_thread_stop(&si->si_thread_timers);
+ smb_thread_stop(&si->si_thread_notify_change);
+ taskq_destroy(si->thread_pool);
+}
+
+static int
+smb_info_init(struct smb_info *si)
+{
+ int i;
+
+ bzero(si, sizeof (smb_info));
+
+ for (i = 0; i <= SMBND_HASH_MASK; i++) {
+ smb_llist_constructor(&si->node_hash_table[i],
+ sizeof (smb_node_t), offsetof(smb_node_t, n_lnd));
+ }
+
+ smb_llist_constructor(&si->si_vfs_list,
+ sizeof (smb_vfs_t), offsetof(smb_vfs_t, sv_lnd));
+
+ smb_slist_constructor(&si->si_ncr_list, sizeof (smb_request_t),
+ offsetof(smb_request_t, sr_ncr.nc_lnd));
+
+ smb_slist_constructor(&si->si_nce_list, sizeof (smb_request_t),
+ offsetof(smb_request_t, sr_ncr.nc_lnd));
+
+ si->si_cache_vfs = kmem_cache_create("smb_vfs_cache",
+ sizeof (smb_vfs_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ si->si_cache_request = kmem_cache_create("smb_request_cache",
+ sizeof (smb_request_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ si->si_cache_session = kmem_cache_create("smb_session_cache",
+ sizeof (smb_session_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ si->si_cache_user = kmem_cache_create("smb_user_cache",
+ sizeof (smb_user_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ si->si_cache_tree = kmem_cache_create("smb_tree_cache",
+ sizeof (smb_tree_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ si->si_cache_ofile = kmem_cache_create("smb_ofile_cache",
+ sizeof (smb_ofile_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ si->si_cache_odir = kmem_cache_create("smb_odir_cache",
+ sizeof (smb_odir_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ si->si_cache_node = kmem_cache_create("smb_smb_node_cache",
+ sizeof (smb_node_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+
+ smb_thread_init(&si->si_nbt_daemon, "smb_nbt_daemon", smb_nbt_daemon,
+ si, NULL, NULL);
+ smb_thread_init(&si->si_tcp_daemon, "smb_tcp_daemon", smb_tcp_daemon,
+ si, NULL, NULL);
+ smb_thread_init(&si->si_thread_notify_change,
+ "smb_notify_change_daemon", smb_notify_change_daemon, &smb_info,
+ NULL, NULL);
+ smb_thread_init(&si->si_thread_timers, "smb_timers", smb_timers,
+ si, NULL, NULL);
+
+ return (0);
+}
+
+static void
+smb_info_fini(struct smb_info *si)
+{
+ int i;
+
+ for (i = 0; i <= SMBND_HASH_MASK; i++) {
+ smb_node_t *node;
+
+ /*
+ * The following sequence is just intended for sanity check.
+ * This will have to be modified when the code goes into
+ * production.
+ *
+ * The SMB node hash table should be emtpy at this point. If the
+ * hash table is not empty all the nodes remaining are displayed
+ * (it should help figure out what actions led to this state)
+ * and "oops" will be set to B_TRUE which will trigger the
+ * ASSERT that follows.
+ *
+ * The reason why SMB nodes are still remaining in the hash
+ * table is problably due to a mismatch between calls to
+ * smb_node_lookup() and smb_node_release(). You must track that
+ * down.
+ *
+ * Now if you are reading this comment because you actually hit
+ * the ASSERT, the temptation to ignore it is going to be very
+ * strong. To help you make the right decision you should know
+ * that when the ASSERT happened a message containing you SunID
+ * has been sent to cifsgate. By now it has been logged into a
+ * special database.
+ *
+ * You are being watched...
+ */
+ node = smb_llist_head(&si->node_hash_table[i]);
+ ASSERT(node == NULL);
+ }
+
+ for (i = 0; i <= SMBND_HASH_MASK; i++) {
+ smb_llist_destructor(&si->node_hash_table[i]);
+ }
+
+ smb_llist_destructor(&si->si_vfs_list);
+
+ kmem_cache_destroy(si->si_cache_vfs);
+ kmem_cache_destroy(si->si_cache_request);
+ kmem_cache_destroy(si->si_cache_session);
+ kmem_cache_destroy(si->si_cache_user);
+ kmem_cache_destroy(si->si_cache_tree);
+ kmem_cache_destroy(si->si_cache_ofile);
+ kmem_cache_destroy(si->si_cache_odir);
+ kmem_cache_destroy(si->si_cache_node);
+
+ smb_thread_destroy(&si->si_nbt_daemon);
+ smb_thread_destroy(&si->si_tcp_daemon);
+ smb_thread_destroy(&si->si_thread_notify_change);
+ smb_thread_destroy(&si->si_thread_timers);
+}
+
+static int
+smb_kstat_init()
+{
+
+ /* create and initialize smb kstats - smb_info stats */
+ smbinfo_ksp = kstat_create("smb", 0, "smb_info", "misc",
+ KSTAT_TYPE_NAMED, sizeof (smbinfo_stats) / sizeof (kstat_named_t),
+ KSTAT_FLAG_VIRTUAL);
+ if (smbinfo_ksp) {
+ smbinfo_ksp->ks_data = (void *) &smbinfo_stats;
+ smbinfo_ksp->ks_update = smb_kstat_update_info;
+ kstat_install(smbinfo_ksp);
+ }
+
+ /* create and initialize smb kstats - smb_dispatch stats */
+ smb_initialize_dispatch_kstat();
+
+ return (0);
+}
+
+static void
+smb_kstat_fini()
+{
+ if (smbinfo_ksp != NULL) {
+ kstat_delete(smbinfo_ksp);
+ smbinfo_ksp = NULL;
+ }
+
+ smb_remove_dispatch_kstat();
+}
+
+/* ARGSUSED */
+static int
+smb_kstat_update_info(kstat_t *ksp, int rw)
+{
+ if (rw == KSTAT_WRITE) {
+ return (EACCES);
+ } else {
+ smbinfo_stats.state.value.ui32 =
+ smb_info.si_svc_sm_ctx.ssc_state;
+ smbinfo_stats.open_files.value.ui32 = smb_info.open_files;
+ smbinfo_stats.open_trees.value.ui32 = smb_info.open_trees;
+ smbinfo_stats.open_users.value.ui32 = smb_info.open_users;
+ }
+ return (0);
+}