Print this page
NEX-17095 illumos 8935 SMB ioctl fixes incomplete
8935 SMB ioctl fixes incomplete
Reviewed by: Alex Wilson <alex.wilson@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Rui Loura <rui.loura@joyent.com>
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Dominik Hassler <hasslerd@gmx.li>
Approved by: Garrett D'Amore <garrett@damore.org>
NEX-15958 panic importing CA share after failover
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Include in backports of:
  NEX-9808 SMB3 persistent handles
NEX-15958 panic importing CA share after failover
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Include in backports of:
  NEX-9808 SMB3 persistent handles
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-5273 SMB 3 Encryption
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-7490 read_kstat_data panic in smb_named_kstat_update
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexent.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-6308 namespace collision for per-share kstats when changing sharesmb property
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-6266 SMB kstats namespace collision for share names longer than 28 characters (follow-up)
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-6266 SMB kstats namespace collision for share names longer than 28 characters
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-5175 want SMB statistics separately for reads, writes, other
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-4844 assertion failed: kshare->shr_magic == SMB_SHARE_MAGIC
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-4313 want iops, bandwidth, and latency kstats for smb
Portions contributed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-3863 Would like an SMB share property to enable/disable quotas
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
SMB-74 Process oplock breaks as session requests
SMB-50 User-mode SMB server
 Includes work by these authors:
 Thomas Keiser <thomas.keiser@nexenta.com>
 Albert Lee <trisk@nexenta.com>
SMB-65 SMB server in non-global zones (data structure changes)
Many things move to the smb_server_t object, and
many functions gain an sv arg (which server).
SMB-65 SMB server in non-global zones (kmem_caches)
common kmem_cache instances across zones
separate GZ-only init from NGZ init
SMB-64 smbsrv workers run at excessively high priority
re #9812 rb3153 System panic'd with assertion failed: sl->sl_count == 0 in smb_slist_destructor after hostname change, smbd restart and attempts to rejoin active directory domain

@@ -19,26 +19,26 @@
  * CDDL HEADER END
  */
 
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  * Copyright 2017 Joyent, Inc.
  */
 
 #include <smbsrv/smb_door.h>
-#include <smbsrv/smb_kproto.h>
 #include <smbsrv/smb_ktypes.h>
+#include <smbsrv/smb2_kproto.h>
+#include <smbsrv/smb_kstat.h>
 
 typedef struct smb_unshare {
         list_node_t     us_lnd;
         char            us_sharename[MAXNAMELEN];
 } smb_unshare_t;
 
 static kmem_cache_t     *smb_kshare_cache_share;
 static kmem_cache_t     *smb_kshare_cache_unexport;
-kmem_cache_t    *smb_kshare_cache_vfs;
 
 static int smb_kshare_cmp(const void *, const void *);
 static void smb_kshare_hold(const void *);
 static boolean_t smb_kshare_rele(const void *);
 static void smb_kshare_destroy(void *);

@@ -50,10 +50,14 @@
 static void smb_kshare_unexport_thread(smb_thread_t *, void *);
 static int smb_kshare_export(smb_server_t *, smb_kshare_t *);
 static int smb_kshare_unexport(smb_server_t *, const char *);
 static int smb_kshare_export_trans(smb_server_t *, char *, char *, char *);
 static void smb_kshare_csc_flags(smb_kshare_t *, const char *);
+static int smb_named_kstat_update(kstat_t *ks, int rw);
+static int smb_kshare_kstat_update(kstat_t *, int);
+void kshare_stats_init(smb_server_t *, smb_kshare_t *);
+void kshare_stats_fini(smb_kshare_t *);
 
 static boolean_t smb_export_isready(smb_server_t *);
 
 #ifdef  _KERNEL
 static int smb_kshare_chk_dsrv_status(int, smb_dr_ctx_t *);

@@ -292,11 +296,10 @@
         }
         sv->sv_export.e_ready = B_FALSE;
         mutex_exit(&sv->sv_export.e_mutex);
 
         smb_avl_destroy(&sv->sv_export.e_share_avl);
-        smb_vfs_rele_all(&sv->sv_export);
 }
 
 void
 smb_kshare_g_init(void)
 {

@@ -303,22 +306,16 @@
         smb_kshare_cache_share = kmem_cache_create("smb_share_cache",
             sizeof (smb_kshare_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
 
         smb_kshare_cache_unexport = kmem_cache_create("smb_unexport_cache",
             sizeof (smb_unshare_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
-
-        smb_kshare_cache_vfs = kmem_cache_create("smb_vfs_cache",
-            sizeof (smb_vfs_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
 }
 
 void
 smb_kshare_init(smb_server_t *sv)
 {
 
-        smb_llist_constructor(&sv->sv_export.e_vfs_list, sizeof (smb_vfs_t),
-            offsetof(smb_vfs_t, sv_lnd));
-
         smb_slist_constructor(&sv->sv_export.e_unexport_list,
             sizeof (smb_unshare_t), offsetof(smb_unshare_t, us_lnd));
 }
 
 int

@@ -346,22 +343,17 @@
             != NULL) {
                 smb_slist_remove(&sv->sv_export.e_unexport_list, ux);
                 kmem_cache_free(smb_kshare_cache_unexport, ux);
         }
         smb_slist_destructor(&sv->sv_export.e_unexport_list);
-
-        smb_vfs_rele_all(&sv->sv_export);
-
-        smb_llist_destructor(&sv->sv_export.e_vfs_list);
 }
 
 void
 smb_kshare_g_fini(void)
 {
         kmem_cache_destroy(smb_kshare_cache_unexport);
         kmem_cache_destroy(smb_kshare_cache_share);
-        kmem_cache_destroy(smb_kshare_cache_vfs);
 }
 
 /*
  * A list of shares in nvlist format can be sent down
  * from userspace thourgh the IOCTL interface. The nvlist

@@ -681,14 +673,12 @@
         smb_avl_release(&sv->sv_export.e_share_avl, shr);
 }
 
 /*
  * Add the given share in the specified server.
- * If the share is a disk share, smb_vfs_hold() is
- * invoked to ensure that there is a hold on the
- * corresponding file system before the share is
- * added to shares AVL.
+ * If the share is a disk share, lookup the share path
+ * and hold the smb_node_t for the share root.
  *
  * If the share is an Autohome share and it is
  * already in the AVL only a reference count for
  * that share is incremented.
  */

@@ -695,11 +685,11 @@
 static int
 smb_kshare_export(smb_server_t *sv, smb_kshare_t *shr)
 {
         smb_avl_t       *share_avl;
         smb_kshare_t    *auto_shr;
-        vnode_t         *vp;
+        smb_node_t      *snode = NULL;
         int             rc = 0;
 
         share_avl = &sv->sv_export.e_share_avl;
 
         if (!STYPE_ISDSK(shr->shr_type)) {

@@ -710,44 +700,235 @@
 
                 return (rc);
         }
 
         if ((auto_shr = smb_avl_lookup(share_avl, shr)) != NULL) {
-                if ((auto_shr->shr_flags & SMB_SHRF_AUTOHOME) == 0) {
-                        smb_avl_release(share_avl, auto_shr);
-                        return (EEXIST);
-                }
-
+                rc = EEXIST;
+                if ((auto_shr->shr_flags & SMB_SHRF_AUTOHOME) != 0) {
                 mutex_enter(&auto_shr->shr_mutex);
                 auto_shr->shr_autocnt++;
                 mutex_exit(&auto_shr->shr_mutex);
+                        rc = 0;
+                }
                 smb_avl_release(share_avl, auto_shr);
-                return (0);
+                return (rc);
         }
 
-        if ((rc = smb_server_sharevp(sv, shr->shr_path, &vp)) != 0) {
-                cmn_err(CE_WARN, "export[%s(%s)]: failed obtaining vnode (%d)",
+        /*
+         * Get the root smb_node_t for this share, held.
+         * This hold is normally released during AVL destroy,
+         * via the element destructor:  smb_kshare_destroy
+         */
+        rc = smb_server_share_lookup(sv, shr->shr_path, &snode);
+        if (rc != 0) {
+                cmn_err(CE_WARN, "export[%s(%s)]: lookup failed (%d)",
                     shr->shr_name, shr->shr_path, rc);
                 return (rc);
         }
 
-        if ((rc = smb_vfs_hold(&sv->sv_export, vp->v_vfsp)) == 0) {
+        shr->shr_root_node = snode;
                 if ((rc = smb_avl_add(share_avl, shr)) != 0) {
                         cmn_err(CE_WARN, "export[%s]: failed caching (%d)",
                             shr->shr_name, rc);
-                        smb_vfs_rele(&sv->sv_export, vp->v_vfsp);
+                shr->shr_root_node = NULL;
+                smb_node_release(snode);
+                return (rc);
                 }
-        } else {
-                cmn_err(CE_WARN, "export[%s(%s)]: failed holding VFS (%d)",
-                    shr->shr_name, shr->shr_path, rc);
+
+        kshare_stats_init(sv, shr);
+
+        /*
+         * For CA shares, find or create the CA handle dir,
+         * and (if restarted) import persistent handles.
+         */
+        if ((shr->shr_flags & SMB_SHRF_CA) != 0) {
+                rc = smb2_dh_new_ca_share(sv, shr);
+                if (rc != 0) {
+                        /* Just make it a non-CA share. */
+                        mutex_enter(&shr->shr_mutex);
+                        shr->shr_flags &= ~SMB_SHRF_CA;
+                        mutex_exit(&shr->shr_mutex);
+                        rc = 0;
         }
+        }
 
-        VN_RELE(vp);
         return (rc);
 }
 
+
 /*
+ * Following a pattern somewhat similar to smb_server_kstat_init,
+ * but organized a little differently.
+ */
+void
+kshare_stats_init(smb_server_t *sv, smb_kshare_t *ks)
+{
+        static const char       *kr_names[] = SMBSRV_CLSH__NAMES;
+        char                    ks_name[KSTAT_STRLEN];
+        smbsrv_clsh_kstats_t    *ksr;
+        int                     idx;
+        smb_named_stats_t       *smbnsp;
+        kstat_t                 *kstat = NULL;
+        int                     namelen;
+
+        /*
+         * Most share names are short, and we'd like to allow consumers like
+         * the smbstat command to compose the kstat names for short share names
+         * directly.  In the (rare) case where we have longer share names, we
+         * need an indirection scheme to get around the limited (31 chars) size
+         * of kstat names. So for share names 24 chars or shorter, we compose
+         * the kstat name directly as "smbsrv:0:sh/sharename" and when the share
+         * name is longer, compose the kstat name using an arbitrary
+         * (but unique) identifier like: "smbsrv:0:sh/:ffffff0009560a98".  To
+         * find the unique identifier given a (long) share name, the consumer
+         * has to enumerate the (fake) "smbsrvshr" kstat module, looking for the
+         * kstat with the sharename element matching the one they want.  Both
+         * direct and indirect names are instantiated under the "smbsrvshr"
+         * module, so a consumer that wants all the share kstats could always
+         * lookup the kstat names using the indirection scheme if that's easier.
+         * (Nothing forces the consumer to directly compose kstat names when the
+         * share name happens to be short -- they can always enumerate to find
+         * it.)
+         *
+         * SMB share names are not allowed to contain a colon.  The naming
+         * scheme here uses a colon at the beginning of what would otherwise be
+         * the share name part of the kstat name to indicate that this name uses
+         * the "indirection" scheme.  With indirection, the part after the colon
+         * is an arbitrary (but unique per share) identifier of some other
+         * kstat, and a consumer needs to fetch that kstat to get the real share
+         * name.
+         */
+        namelen = strlen(ks->shr_name);
+        if (namelen <= 24) {
+                (void) snprintf(ks_name, sizeof (ks_name), "sh/%s",
+                    ks->shr_name);
+
+                kstat = kstat_hold_byname("smbsrvshr", 0, ks_name, sv->sv_zid);
+        }
+
+        if (namelen > 24 || kstat != NULL) {
+                (void) snprintf(ks_name, sizeof (ks_name), "sh/:%p",
+                    (void *)ks);
+
+                if (kstat != NULL)
+                        kstat_rele(kstat);
+        }
+
+        ks->shr_ksp = kstat_create_zone(SMBSRV_KSTAT_MODULE, 0,
+            ks_name, SMBSRV_KSTAT_CLASS, KSTAT_TYPE_RAW,
+            sizeof (smbsrv_clsh_kstats_t), 0, sv->sv_zid);
+
+        if (ks->shr_ksp == NULL)
+                return;
+
+        ks->stats.ksns = kstat_create_zone("smbsrvshr", 0,
+            ks_name, SMBSRV_KSTAT_CLASS, KSTAT_TYPE_NAMED,
+            0, KSTAT_FLAG_VIRTUAL, sv->sv_zid);
+
+        if (ks->stats.ksns == NULL) {
+                kstat_delete(ks->shr_ksp);
+                ks->shr_ksp = NULL;
+                return;
+        }
+
+        ks->shr_ksp->ks_update = smb_kshare_kstat_update;
+        ks->shr_ksp->ks_private = ks;
+
+        /*
+         * In-line equivalent of smb_dispatch_stats_init
+         */
+        ksr = (smbsrv_clsh_kstats_t *)ks->shr_ksp->ks_data;
+        for (idx = 0; idx < SMBSRV_CLSH__NREQ; idx++) {
+                smb_latency_init(&ks->shr_stats[idx].sdt_lat);
+                (void) strlcpy(ksr->ks_clsh[idx].kr_name, kr_names[idx],
+                    KSTAT_STRLEN);
+        }
+
+        /*
+         * SMB named kstats setup for > KSTAT_STRLEN name to short name mapping.
+         */
+        smbnsp = &ks->stats.ks_data;
+        ks->stats.ksns->ks_data = &ks->stats.ks_data;
+        ks->stats.ksns->ks_data_size = sizeof (ks->stats.ks_data);
+        ks->stats.ksns->ks_ndata = 1;
+        kstat_named_init(smbnsp->kn, "share name",
+            KSTAT_DATA_STRING);
+        ks->stats.ksns->ks_update = smb_named_kstat_update;
+        ks->stats.ksns->ks_private = (void *)ks;
+
+        kstat_install(ks->shr_ksp);
+        kstat_install(ks->stats.ksns);
+}
+
+void
+kshare_stats_fini(smb_kshare_t *ks)
+{
+        int idx;
+
+        for (idx = 0; idx < SMBSRV_CLSH__NREQ; idx++)
+                smb_latency_destroy(&ks->shr_stats[idx].sdt_lat);
+}
+
+static int
+smb_named_kstat_update(kstat_t *ks, int rw)
+{
+        smb_kshare_t            *smbksp = (smb_kshare_t *)ks->ks_private;
+        smb_named_stats_t       *smbnsp = &smbksp->stats.ks_data;
+
+        if (rw == KSTAT_READ) {
+                (void) strlcpy(smbnsp->name, smbksp->shr_name,
+                    sizeof (smbnsp->name));
+
+                kstat_named_setstr(&smbnsp->kn[0],
+                    (const char *)smbksp->shr_name);
+        }
+        return (0);
+}
+
+/*
+ * Update the kstat data from our private stats.
+ */
+static int
+smb_kshare_kstat_update(kstat_t *ksp, int rw)
+{
+        smb_kshare_t *kshare;
+        smb_disp_stats_t *sds;
+        smbsrv_clsh_kstats_t    *clsh;
+        smb_kstat_req_t *ksr;
+        int i;
+
+        if (rw == KSTAT_WRITE)
+                return (EACCES);
+
+        kshare = ksp->ks_private;
+        ASSERT(kshare->shr_magic == SMB_SHARE_MAGIC);
+        sds = kshare->shr_stats;
+
+        clsh = (smbsrv_clsh_kstats_t *)ksp->ks_data;
+        ksr = clsh->ks_clsh;
+
+        for (i = 0; i < SMBSRV_CLSH__NREQ; i++, ksr++, sds++) {
+                ksr->kr_rxb = sds->sdt_rxb;
+                ksr->kr_txb = sds->sdt_txb;
+                mutex_enter(&sds->sdt_lat.ly_mutex);
+                ksr->kr_nreq = sds->sdt_lat.ly_a_nreq;
+                ksr->kr_sum = sds->sdt_lat.ly_a_sum;
+                ksr->kr_a_mean = sds->sdt_lat.ly_a_mean;
+                ksr->kr_a_stddev = sds->sdt_lat.ly_a_stddev;
+                ksr->kr_d_mean = sds->sdt_lat.ly_d_mean;
+                ksr->kr_d_stddev = sds->sdt_lat.ly_d_stddev;
+                sds->sdt_lat.ly_d_mean = 0;
+                sds->sdt_lat.ly_d_nreq = 0;
+                sds->sdt_lat.ly_d_stddev = 0;
+                sds->sdt_lat.ly_d_sum = 0;
+                mutex_exit(&sds->sdt_lat.ly_mutex);
+        }
+
+        return (0);
+}
+
+/*
  * Removes the share specified by 'shrname' from the AVL
  * tree of the given server if it's there.
  *
  * If the share is an Autohome share, the autohome count
  * is decremented and the share is only removed if the

@@ -761,12 +942,10 @@
 smb_kshare_unexport(smb_server_t *sv, const char *shrname)
 {
         smb_avl_t       *share_avl;
         smb_kshare_t    key;
         smb_kshare_t    *shr;
-        vnode_t         *vp;
-        int             rc;
         boolean_t       auto_unexport;
 
         share_avl = &sv->sv_export.e_share_avl;
 
         key.shr_name = (char *)shrname;

@@ -782,23 +961,16 @@
                         smb_avl_release(share_avl, shr);
                         return (0);
                 }
         }
 
-        if (STYPE_ISDSK(shr->shr_type)) {
-                if ((rc = smb_server_sharevp(sv, shr->shr_path, &vp)) != 0) {
-                        smb_avl_release(share_avl, shr);
-                        cmn_err(CE_WARN, "unexport[%s]: failed obtaining vnode"
-                            " (%d)", shrname, rc);
-                        return (rc);
-                }
+        smb_avl_remove(share_avl, shr);
 
-                smb_vfs_rele(&sv->sv_export, vp->v_vfsp);
-                VN_RELE(vp);
-        }
+        mutex_enter(&shr->shr_mutex);
+        shr->shr_flags |= SMB_SHRF_REMOVED;
+        mutex_exit(&shr->shr_mutex);
 
-        smb_avl_remove(share_avl, shr);
         smb_avl_release(share_avl, shr);
 
         return (0);
 }
 

@@ -847,11 +1019,11 @@
 smb_kshare_decode(nvlist_t *share)
 {
         smb_kshare_t tmp;
         smb_kshare_t *shr;
         nvlist_t *smb;
-        char *csc_name = NULL;
+        char *csc_name = NULL, *strbuf = NULL;
         int rc;
 
         ASSERT(share);
 
         bzero(&tmp, sizeof (smb_kshare_t));

@@ -887,11 +1059,15 @@
             SMB_SHRF_CATIA);
         tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_GUEST,
             SMB_SHRF_GUEST_OK);
         tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_DFSROOT,
             SMB_SHRF_DFSROOT);
-        tmp.shr_flags |= smb_kshare_decode_bool(smb, "Autohome",
+        tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_QUOTAS,
+            SMB_SHRF_QUOTAS);
+        tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_CA, SMB_SHRF_CA);
+        tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_FSO, SMB_SHRF_FSO);
+        tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_AUTOHOME,
             SMB_SHRF_AUTOHOME);
 
         if ((tmp.shr_flags & SMB_SHRF_AUTOHOME) == SMB_SHRF_AUTOHOME) {
                 rc = nvlist_lookup_uint32(smb, "uid", &tmp.shr_uid);
                 rc |= nvlist_lookup_uint32(smb, "gid", &tmp.shr_gid);

@@ -900,10 +1076,13 @@
                             " (%d)", rc);
                         return (NULL);
                 }
         }
 
+        (void) nvlist_lookup_string(smb, SHOPT_ENCRYPT, &strbuf);
+        smb_cfg_set_require(strbuf, &tmp.shr_encrypt);
+
         (void) nvlist_lookup_string(smb, SHOPT_CSC, &csc_name);
         smb_kshare_csc_flags(&tmp, csc_name);
 
         shr = kmem_cache_alloc(smb_kshare_cache_share, KM_SLEEP);
         bzero(shr, sizeof (smb_kshare_t));

@@ -925,17 +1104,17 @@
                 shr->shr_access_rw = smb_mem_strdup(tmp.shr_access_rw);
 
         shr->shr_oemname = smb_kshare_oemname(shr->shr_name);
         shr->shr_flags = tmp.shr_flags | smb_kshare_is_admin(shr->shr_name);
         shr->shr_type = tmp.shr_type | smb_kshare_is_special(shr->shr_name);
+        shr->shr_encrypt = tmp.shr_encrypt;
 
         shr->shr_uid = tmp.shr_uid;
         shr->shr_gid = tmp.shr_gid;
 
         if ((shr->shr_flags & SMB_SHRF_AUTOHOME) == SMB_SHRF_AUTOHOME)
                 shr->shr_autocnt = 1;
-
         return (shr);
 }
 
 #if 0
 static void

@@ -1031,10 +1210,25 @@
         smb_kshare_t *shr = (smb_kshare_t *)p;
 
         ASSERT(shr);
         ASSERT(shr->shr_magic == SMB_SHARE_MAGIC);
 
+        if (shr->shr_ksp != NULL) {
+                kstat_delete(shr->shr_ksp);
+                shr->shr_ksp = NULL;
+                kshare_stats_fini(shr);
+        }
+
+        if (shr->stats.ksns != NULL) {
+                kstat_delete(shr->stats.ksns);
+        }
+
+        if (shr->shr_ca_dir != NULL)
+                smb_node_release(shr->shr_ca_dir);
+        if (shr->shr_root_node)
+                smb_node_release(shr->shr_root_node);
+
         smb_mem_free(shr->shr_name);
         smb_mem_free(shr->shr_path);
         smb_mem_free(shr->shr_cmnt);
         smb_mem_free(shr->shr_container);
         smb_mem_free(shr->shr_oemname);