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);