diff options
author | amw <none@none> | 2007-10-25 16:34:29 -0700 |
---|---|---|
committer | amw <none@none> | 2007-10-25 16:34:29 -0700 |
commit | da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0 (patch) | |
tree | 65be91fb78a6a66183197595333f2e8aafb4640a /usr/src/uts/common/fs/smbsrv/smb_init.c | |
parent | e845e33dd0d1aea22db7edaa8c7d43955d24609b (diff) | |
download | illumos-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.c | 796 |
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); +} |