Print this page
NEX-17457 kernel share list fails to be updated after fs import
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Yuri Pankov <yuripv@yuripv.net>
NEX-16159 Time spent sharing SMB filesystems could be reduced by optimizing smb_getdataset for default mount points
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Reviewed by: Matt Barden <matt.barden@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-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-10098 Disabling SMB server service does not change the sharestate of a smb share to “offline”.(cstyle)
NEX-10098 Disabling SMB server service does not change the sharestate of a smb share to “offline”.
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@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-6949 SMB shares with no permission for root fail after restart
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexent.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-6135 Pool cannot get exported while deletes is running
Reviewed by: Alek Pinchuk <alek@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexent.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
NEX-4865 Still creating .$EXTEND directory with quotas disabled
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@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>
NEX-3673 CLONE NEX-2525 Customer cannot set Share Properties using MMC in Windows Server 2008 R2
Reviewed by: Alek Pinchuk <alek@nexenta.com>
NEX-1473 share unavailable after failover (copyright update)
NEX-1473 share unavailable after failover
@@ -17,11 +17,11 @@
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
/*
* SMB/CIFS share cache implementation.
*/
@@ -387,10 +387,11 @@
smb_shr_add(smb_share_t *si)
{
struct stat st;
smb_share_t *cached_si;
nvlist_t *shrlist;
+ boolean_t created_zfs = B_FALSE;
uint32_t status;
int rc;
assert(si != NULL);
@@ -414,19 +415,46 @@
if (STYPE_ISDSK(si->shr_type)) {
/*
* If share type is STYPE_DISKTREE then the path to the
* share should exist so that we can add the share to cache.
+ * If path is ZFS, add the .zfs/shares/<share> entry.
+ *
+ * Both actions may require privileges that main dropped,
+ * so we need to temporarily make those effective.
*/
+ if (smb_proc_takesem() == 0) {
+
+ (void) priv_set(PRIV_ON, PRIV_EFFECTIVE,
+ PRIV_FILE_DAC_READ,
+ PRIV_FILE_DAC_SEARCH,
+ PRIV_FILE_DAC_WRITE,
+ NULL);
+
rc = stat(si->shr_path, &st);
+ if (rc == 0) {
+ smb_shr_zfs_add(si);
+ created_zfs = B_TRUE;
+ }
+
+ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE,
+ PRIV_FILE_DAC_READ,
+ PRIV_FILE_DAC_SEARCH,
+ PRIV_FILE_DAC_WRITE,
+ NULL);
+ smb_proc_givesem();
+ } else {
+ rc = NERR_InternalError;
+ }
if (rc != 0) {
smb_shr_cache_unlock();
return (NERR_ItemNotFound);
}
}
if ((status = smb_shr_cache_addent(si)) != NERR_Success) {
+ /* This error should be impossible after findent above. */
smb_shr_cache_unlock();
return (status);
}
/* don't hold the lock across door call */
@@ -438,25 +466,45 @@
nvlist_free(shrlist);
if (rc == 0) {
smb_shr_publish(si->shr_name, si->shr_container);
- /* If path is ZFS, add the .zfs/shares/<share> entry. */
- smb_shr_zfs_add(si);
-
if ((si->shr_flags & SMB_SHRF_DFSROOT) != 0)
dfs_namespace_load(si->shr_name);
return (NERR_Success);
}
}
+ /*
+ * Error code path, i.e. when the kernel could not accept
+ * the new share for some reason.
+ */
if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
smb_shr_cache_delent(si->shr_name);
smb_shr_cache_unlock();
}
+ if (created_zfs && smb_proc_takesem() == 0) {
+
+ (void) priv_set(PRIV_ON, PRIV_EFFECTIVE,
+ PRIV_FILE_DAC_READ,
+ PRIV_FILE_DAC_SEARCH,
+ PRIV_FILE_DAC_WRITE,
+ NULL);
+
+ smb_shr_zfs_remove(si);
+
+ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE,
+ PRIV_FILE_DAC_READ,
+ PRIV_FILE_DAC_SEARCH,
+ PRIV_FILE_DAC_WRITE,
+ NULL);
+
+ smb_proc_givesem();
+ }
+
/*
* rc == ENOENT means the shared directory doesn't exist
*/
return ((rc == ENOENT) ? NERR_UnknownDevDir : NERR_InternalError);
}
@@ -503,13 +551,32 @@
}
}
/*
* If path is ZFS, remove the .zfs/shares/<share> entry. Need
- * to remove before cleanup of cache occurs.
+ * to remove before cleanup of cache occurs. These actions
+ * require temporary elevation of privileges.
*/
+ if (smb_proc_takesem() == 0) {
+
+ (void) priv_set(PRIV_ON, PRIV_EFFECTIVE,
+ PRIV_FILE_DAC_READ,
+ PRIV_FILE_DAC_SEARCH,
+ PRIV_FILE_DAC_WRITE,
+ NULL);
+
smb_shr_zfs_remove(si);
+
+ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE,
+ PRIV_FILE_DAC_READ,
+ PRIV_FILE_DAC_SEARCH,
+ PRIV_FILE_DAC_WRITE,
+ NULL);
+
+ smb_proc_givesem();
+ }
+
(void) smb_shr_encode(si, &shrlist);
(void) strlcpy(container, si->shr_container, sizeof (container));
dfsroot = ((si->shr_flags & SMB_SHRF_DFSROOT) != 0);
smb_shr_cache_delent(sharename);
@@ -568,14 +635,30 @@
}
bcopy(from_si, &to_si, sizeof (smb_share_t));
(void) strlcpy(to_si.shr_name, to_name, sizeof (to_si.shr_name));
-
/* If path is ZFS, rename the .zfs/shares/<share> entry. */
+ if (smb_proc_takesem() == 0) {
+
+ (void) priv_set(PRIV_ON, PRIV_EFFECTIVE,
+ PRIV_FILE_DAC_READ,
+ PRIV_FILE_DAC_SEARCH,
+ PRIV_FILE_DAC_WRITE,
+ NULL);
+
smb_shr_zfs_rename(from_si, &to_si);
+ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE,
+ PRIV_FILE_DAC_READ,
+ PRIV_FILE_DAC_SEARCH,
+ PRIV_FILE_DAC_WRITE,
+ NULL);
+
+ smb_proc_givesem();
+ }
+
if ((status = smb_shr_cache_addent(&to_si)) != NERR_Success) {
smb_shr_cache_unlock();
return (status);
}
@@ -626,18 +709,19 @@
* Modifies an existing share. Properties that can be modified are:
*
* o comment
* o AD container
* o host access
- * o abe
+ * o flags
*/
uint32_t
smb_shr_modify(smb_share_t *new_si)
{
+ smb_share_t old_si;
smb_share_t *si;
boolean_t adc_changed = B_FALSE;
- char old_container[MAXPATHLEN];
+ boolean_t quota_flag_changed = B_FALSE;
uint32_t access, flag;
nvlist_t *shrlist;
assert(new_si != NULL);
@@ -653,20 +737,24 @@
/* IPC$ share cannot be modified */
smb_shr_cache_unlock();
return (ERROR_ACCESS_DENIED);
}
+ /*
+ * Keep a copy of what the share entry looks like before we
+ * modify it. We need this for things like unpublishing
+ * from the old share container, removing the quota dir.
+ */
+ bcopy(si, &old_si, sizeof (old_si));
+
+ /* Share comment */
(void) strlcpy(si->shr_cmnt, new_si->shr_cmnt, sizeof (si->shr_cmnt));
- adc_changed = (strcmp(new_si->shr_container, si->shr_container) != 0);
- if (adc_changed) {
- /* save current container - needed for unpublishing */
- (void) strlcpy(old_container, si->shr_container,
- sizeof (old_container));
+ /* Container */
(void) strlcpy(si->shr_container, new_si->shr_container,
sizeof (si->shr_container));
- }
+ adc_changed = (strcmp(old_si.shr_container, si->shr_container) != 0);
flag = (new_si->shr_flags & SMB_SHRF_ABE);
si->shr_flags &= ~SMB_SHRF_ABE;
si->shr_flags |= flag;
@@ -680,18 +768,34 @@
flag = (new_si->shr_flags & SMB_SHRF_DFSROOT);
si->shr_flags &= ~SMB_SHRF_DFSROOT;
si->shr_flags |= flag;
+ flag = (new_si->shr_flags & SMB_SHRF_CA);
+ si->shr_flags &= ~SMB_SHRF_CA;
+ si->shr_flags |= flag;
+
+ flag = (new_si->shr_flags & SMB_SHRF_FSO);
+ si->shr_flags &= ~SMB_SHRF_FSO;
+ si->shr_flags |= flag;
+
+ flag = (new_si->shr_flags & SMB_SHRF_QUOTAS);
+ si->shr_flags &= ~SMB_SHRF_QUOTAS;
+ si->shr_flags |= flag;
+ if ((old_si.shr_flags ^ si->shr_flags) & SMB_SHRF_QUOTAS)
+ quota_flag_changed = B_TRUE;
+
flag = (new_si->shr_flags & SMB_SHRF_CSC_MASK);
si->shr_flags &= ~SMB_SHRF_CSC_MASK;
si->shr_flags |= flag;
access = (new_si->shr_flags & SMB_SHRF_ACC_ALL);
si->shr_flags &= ~SMB_SHRF_ACC_ALL;
si->shr_flags |= access;
+ si->shr_encrypt = new_si->shr_encrypt;
+
if (access & SMB_SHRF_ACC_NONE)
(void) strlcpy(si->shr_access_none, new_si->shr_access_none,
sizeof (si->shr_access_none));
if (access & SMB_SHRF_ACC_RO)
@@ -713,14 +817,35 @@
nvlist_free(shrlist);
}
}
if (adc_changed) {
- smb_shr_unpublish(new_si->shr_name, old_container);
+ smb_shr_unpublish(old_si.shr_name, old_si.shr_container);
smb_shr_publish(new_si->shr_name, new_si->shr_container);
}
+ /* The following required privileges we dropped. */
+ if (quota_flag_changed && smb_proc_takesem() == 0) {
+
+ (void) priv_set(PRIV_ON, PRIV_EFFECTIVE,
+ PRIV_FILE_DAC_READ,
+ PRIV_FILE_DAC_SEARCH,
+ PRIV_FILE_DAC_WRITE,
+ NULL);
+
+ smb_shr_zfs_remove(&old_si);
+ smb_shr_zfs_add(si);
+
+ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE,
+ PRIV_FILE_DAC_READ,
+ PRIV_FILE_DAC_SEARCH,
+ PRIV_FILE_DAC_WRITE,
+ NULL);
+
+ smb_proc_givesem();
+ }
+
return (NERR_Success);
}
/*
* smb_shr_exists
@@ -1434,11 +1559,16 @@
* All functions in this section are private
* ============================================
*/
/*
- * Load shares from sharemgr
+ * Loads the SMB shares, from sharemgr, then:
+ * - calls smb_shr_add which:
+ * - adds the share into the share cache
+ * - adds the share into in-kernel kshare table
+ * - publishes the share in ADS
+ * - updates the share list in sharefs/sharetab
*/
/*ARGSUSED*/
void *
smb_shr_load(void *args)
{
@@ -1445,14 +1575,11 @@
sa_handle_t handle;
sa_group_t group, subgroup;
char *gstate;
boolean_t gdisabled;
- (void) mutex_lock(&smb_shr_exec_mtx);
- (void) smb_config_get_execinfo(smb_shr_exec_map, smb_shr_exec_unmap,
- MAXPATHLEN);
- (void) mutex_unlock(&smb_shr_exec_mtx);
+ smb_shr_load_execinfo();
if ((handle = smb_shr_sa_enter()) == NULL) {
syslog(LOG_ERR, "smb_shr_load: load failed");
return (NULL);
}
@@ -1479,11 +1606,55 @@
}
smb_shr_sa_exit();
return (NULL);
}
+void
+smb_shr_load_execinfo()
+{
+ (void) mutex_lock(&smb_shr_exec_mtx);
+ (void) smb_config_get_execinfo(smb_shr_exec_map, smb_shr_exec_unmap,
+ MAXPATHLEN);
+ (void) mutex_unlock(&smb_shr_exec_mtx);
+}
+
/*
+ * Handles disabling shares in sharefs when stoping smbd
+ */
+void
+smb_shr_unload()
+{
+ smb_shriter_t iterator;
+ smb_share_t *si;
+ sa_handle_t handle;
+ int rc;
+
+ if ((handle = smb_shr_sa_enter()) == NULL) {
+ syslog(LOG_ERR, "smb_shr_unload: failed");
+ return;
+ }
+
+ smb_shr_iterinit(&iterator);
+
+ while ((si = smb_shr_iterate(&iterator)) != NULL) {
+
+ /* Skip transient shares, IPC$, ... */
+ if ((si->shr_flags & SMB_SHRF_TRANS) ||
+ STYPE_ISIPC(si->shr_type))
+ continue;
+
+ rc = sa_delete_sharetab(handle, si->shr_path, "smb");
+ if (rc) {
+ syslog(LOG_ERR,
+ "sharefs remove %s failed, rc=%d, err=%d",
+ si->shr_path, rc, errno);
+ }
+ }
+ smb_shr_sa_exit();
+}
+
+/*
* Load the shares contained in the specified group.
*
* Don't process groups on which the smb protocol is disabled.
* The top level ZFS group won't have the smb protocol enabled
* but sub-groups will.
@@ -1533,10 +1704,11 @@
{
smb_share_t si;
char *sharename;
uint32_t status;
boolean_t loaded;
+ int rc;
if ((sharename = sa_get_resource_attr(resource, "name")) == NULL)
return (NERR_InternalError);
loaded = smb_shr_exists(sharename);
@@ -1556,10 +1728,16 @@
syslog(LOG_DEBUG, "share: failed to cache %s (%d)",
si.shr_name, status);
return (status);
}
+ rc = sa_update_sharetab(share, "smb");
+ if (rc) {
+ syslog(LOG_ERR, "sharefs add %s failed, rc=%d, err=%d",
+ sharename, rc, errno);
+ }
+
return (NERR_Success);
}
static char *
smb_shr_sa_getprop(sa_optionset_t opts, char *propname)
@@ -1646,10 +1824,38 @@
if (val != NULL) {
smb_shr_sa_setflag(val, si, SMB_SHRF_DFSROOT);
free(val);
}
+ val = smb_shr_sa_getprop(opts, SHOPT_CA);
+ if (val != NULL) {
+ smb_shr_sa_setflag(val, si, SMB_SHRF_CA);
+ free(val);
+ }
+
+ val = smb_shr_sa_getprop(opts, SHOPT_FSO);
+ if (val != NULL) {
+ smb_shr_sa_setflag(val, si, SMB_SHRF_FSO);
+ free(val);
+ }
+
+ val = smb_shr_sa_getprop(opts, SHOPT_QUOTAS);
+ if (val != NULL) {
+ /* Turn the flag on or off */
+ smb_shr_sa_setflag(val, si, SMB_SHRF_QUOTAS);
+ free(val);
+ } else {
+ /* Default for this is enabled. */
+ si->shr_flags |= SMB_SHRF_QUOTAS;
+ }
+
+ val = smb_shr_sa_getprop(opts, SHOPT_ENCRYPT);
+ if (val != NULL) {
+ smb_cfg_set_require(val, &si->shr_encrypt);
+ free(val);
+ }
+
val = smb_shr_sa_getprop(opts, SHOPT_CSC);
if (val != NULL) {
smb_shr_sa_csc_option(val, si);
free(val);
}
@@ -2021,26 +2227,28 @@
}
}
/*
* If the share path refers to a ZFS file system, add the
- * .zfs/shares/<share> object and call smb_quota_add_fs()
- * to initialize quota support for the share.
+ * .zfs/shares/<share> object and add or remove the special
+ * directory and file telling clients about quota support.
*/
static void
smb_shr_zfs_add(smb_share_t *si)
{
libzfs_handle_t *libhd;
zfs_handle_t *zfshd;
int ret;
char buf[MAXPATHLEN]; /* dataset or mountpoint */
- if (smb_getdataset(si->shr_path, buf, MAXPATHLEN) != 0)
+ if ((libhd = libzfs_init()) == NULL)
return;
- if ((libhd = libzfs_init()) == NULL)
+ if (smb_getdataset(libhd, si->shr_path, buf, MAXPATHLEN) != 0) {
+ libzfs_fini(libhd);
return;
+ }
if ((zfshd = zfs_open(libhd, buf, ZFS_TYPE_FILESYSTEM)) == NULL) {
libzfs_fini(libhd);
return;
}
@@ -2049,40 +2257,42 @@
ret = zfs_smb_acl_add(libhd, buf, si->shr_path, si->shr_name);
if (ret != 0 && errno != EAGAIN && errno != EEXIST)
syslog(LOG_INFO, "share: failed to add ACL object: %s: %s\n",
si->shr_name, strerror(errno));
- if (zfs_prop_get(zfshd, ZFS_PROP_MOUNTPOINT, buf, MAXPATHLEN,
- NULL, NULL, 0, B_FALSE) == 0) {
+ ret = zfs_prop_get(zfshd, ZFS_PROP_MOUNTPOINT,
+ buf, MAXPATHLEN, NULL, NULL, 0, B_FALSE);
+ if (ret != 0) {
+ syslog(LOG_INFO, "share: failed to get mountpoint: "
+ "%s\n", si->shr_name);
+ } else {
+ if ((si->shr_flags & SMB_SHRF_QUOTAS) != 0) {
smb_quota_add_fs(buf);
+ } else {
+ smb_quota_remove_fs(buf);
}
+ }
-
zfs_close(zfshd);
libzfs_fini(libhd);
}
/*
* If the share path refers to a ZFS file system, remove the
- * .zfs/shares/<share> object, and call smb_quota_remove_fs()
- * to end quota support for the share.
+ * .zfs/shares/<share> object.
*/
static void
smb_shr_zfs_remove(smb_share_t *si)
{
libzfs_handle_t *libhd;
- zfs_handle_t *zfshd;
int ret;
char buf[MAXPATHLEN]; /* dataset or mountpoint */
- if (smb_getdataset(si->shr_path, buf, MAXPATHLEN) != 0)
- return;
-
if ((libhd = libzfs_init()) == NULL)
return;
- if ((zfshd = zfs_open(libhd, buf, ZFS_TYPE_FILESYSTEM)) == NULL) {
+ if (smb_getdataset(libhd, si->shr_path, buf, MAXPATHLEN) != 0) {
libzfs_fini(libhd);
return;
}
errno = 0;
@@ -2089,16 +2299,16 @@
ret = zfs_smb_acl_remove(libhd, buf, si->shr_path, si->shr_name);
if (ret != 0 && errno != EAGAIN)
syslog(LOG_INFO, "share: failed to remove ACL object: %s: %s\n",
si->shr_name, strerror(errno));
- if (zfs_prop_get(zfshd, ZFS_PROP_MOUNTPOINT, buf, MAXPATHLEN,
- NULL, NULL, 0, B_FALSE) == 0) {
- smb_quota_remove_fs(buf);
- }
+ /*
+ * We could remove the quotas directory here, but that adds
+ * significantly to the time required for a zpool export,
+ * so just leave it here and fixup when we share next.
+ */
- zfs_close(zfshd);
libzfs_fini(libhd);
}
/*
* If the share path refers to a ZFS file system, rename the
@@ -2110,15 +2320,17 @@
libzfs_handle_t *libhd;
zfs_handle_t *zfshd;
int ret;
char dataset[MAXPATHLEN];
- if (smb_getdataset(from->shr_path, dataset, MAXPATHLEN) != 0)
+ if ((libhd = libzfs_init()) == NULL)
return;
- if ((libhd = libzfs_init()) == NULL)
+ if (smb_getdataset(libhd, from->shr_path, dataset, MAXPATHLEN) != 0) {
+ libzfs_fini(libhd);
return;
+ }
if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) {
libzfs_fini(libhd);
return;
}
@@ -2413,13 +2625,26 @@
rc |= nvlist_add_string(smb, SHOPT_CATIA, "true");
if ((si->shr_flags & SMB_SHRF_GUEST_OK) != 0)
rc |= nvlist_add_string(smb, SHOPT_GUEST, "true");
if ((si->shr_flags & SMB_SHRF_DFSROOT) != 0)
rc |= nvlist_add_string(smb, SHOPT_DFSROOT, "true");
+ if ((si->shr_flags & SMB_SHRF_CA) != 0)
+ rc |= nvlist_add_string(smb, SHOPT_CA, "true");
+ if ((si->shr_flags & SMB_SHRF_FSO) != 0)
+ rc |= nvlist_add_string(smb, SHOPT_FSO, "true");
+ if ((si->shr_flags & SMB_SHRF_QUOTAS) != 0)
+ rc |= nvlist_add_string(smb, SHOPT_QUOTAS, "true");
+ if (si->shr_encrypt == SMB_CONFIG_REQUIRED)
+ rc |= nvlist_add_string(smb, SHOPT_ENCRYPT, "required");
+ else if (si->shr_encrypt == SMB_CONFIG_ENABLED)
+ rc |= nvlist_add_string(smb, SHOPT_ENCRYPT, "enabled");
+ else
+ rc |= nvlist_add_string(smb, SHOPT_ENCRYPT, "disabled");
+
if ((si->shr_flags & SMB_SHRF_AUTOHOME) != 0) {
- rc |= nvlist_add_string(smb, "Autohome", "true");
+ rc |= nvlist_add_string(smb, SHOPT_AUTOHOME, "true");
rc |= nvlist_add_uint32(smb, "uid", si->shr_uid);
rc |= nvlist_add_uint32(smb, "gid", si->shr_gid);
}
if ((csc = smb_shr_sa_csc_name(si)) != NULL)