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,27 ****
   * 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.
   */
  
  /*
   * SMB/CIFS share cache implementation.
   */
--- 17,27 ----
   * information: Portions Copyright [yyyy] [name of copyright owner]
   *
   * CDDL HEADER END
   *
   * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
!  * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
   */
  
  /*
   * SMB/CIFS share cache implementation.
   */
*** 387,396 ****
--- 387,397 ----
  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,432 ****
--- 415,460 ----
  
          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,462 ****
                  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);
                  }
          }
  
          if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
                  smb_shr_cache_delent(si->shr_name);
                  smb_shr_cache_unlock();
          }
  
          /*
           * rc == ENOENT means the shared directory doesn't exist
           */
          return ((rc == ENOENT) ? NERR_UnknownDevDir : NERR_InternalError);
  }
--- 466,510 ----
                  nvlist_free(shrlist);
  
                  if (rc == 0) {
                          smb_shr_publish(si->shr_name, si->shr_container);
  
                          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,515 ****
                  }
          }
  
          /*
           * If path is ZFS, remove the .zfs/shares/<share> entry.  Need
!          * to remove before cleanup of cache occurs.
           */
          smb_shr_zfs_remove(si);
          (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);
--- 551,582 ----
                  }
          }
  
          /*
           * If path is ZFS, remove the .zfs/shares/<share> entry.  Need
!          * 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,581 ****
          }
  
          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. */
          smb_shr_zfs_rename(from_si, &to_si);
  
          if ((status = smb_shr_cache_addent(&to_si)) != NERR_Success) {
                  smb_shr_cache_unlock();
                  return (status);
          }
  
--- 635,664 ----
          }
  
          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,643 ****
   * Modifies an existing share. Properties that can be modified are:
   *
   *   o comment
   *   o AD container
   *   o host access
!  *   o abe
   */
  uint32_t
  smb_shr_modify(smb_share_t *new_si)
  {
          smb_share_t *si;
          boolean_t adc_changed = B_FALSE;
!         char old_container[MAXPATHLEN];
          uint32_t access, flag;
          nvlist_t *shrlist;
  
          assert(new_si != NULL);
  
--- 709,727 ----
   * Modifies an existing share. Properties that can be modified are:
   *
   *   o comment
   *   o AD container
   *   o host access
!  *   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;
!         boolean_t quota_flag_changed = B_FALSE;
          uint32_t access, flag;
          nvlist_t *shrlist;
  
          assert(new_si != NULL);
  
*** 653,672 ****
                  /* IPC$ share cannot be modified */
                  smb_shr_cache_unlock();
                  return (ERROR_ACCESS_DENIED);
          }
  
          (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));
                  (void) strlcpy(si->shr_container, new_si->shr_container,
                      sizeof (si->shr_container));
!         }
  
          flag = (new_si->shr_flags & SMB_SHRF_ABE);
          si->shr_flags &= ~SMB_SHRF_ABE;
          si->shr_flags |= flag;
  
--- 737,760 ----
                  /* 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));
  
!         /* 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,697 ****
--- 768,801 ----
  
          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,726 ****
                          nvlist_free(shrlist);
                  }
          }
  
          if (adc_changed) {
!                 smb_shr_unpublish(new_si->shr_name, old_container);
                  smb_shr_publish(new_si->shr_name, new_si->shr_container);
          }
  
          return (NERR_Success);
  }
  
  /*
   * smb_shr_exists
--- 817,851 ----
                          nvlist_free(shrlist);
                  }
          }
  
          if (adc_changed) {
!                 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,1444 ****
   * All functions in this section are private
   * ============================================
   */
  
  /*
!  * Load shares from sharemgr
   */
  /*ARGSUSED*/
  void *
  smb_shr_load(void *args)
  {
--- 1559,1574 ----
   * All functions in this section are private
   * ============================================
   */
  
  /*
!  * 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,1458 ****
          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);
  
          if ((handle = smb_shr_sa_enter()) == NULL) {
                  syslog(LOG_ERR, "smb_shr_load: load failed");
                  return (NULL);
          }
--- 1575,1585 ----
          sa_handle_t handle;
          sa_group_t group, subgroup;
          char *gstate;
          boolean_t gdisabled;
  
!         smb_shr_load_execinfo();
  
          if ((handle = smb_shr_sa_enter()) == NULL) {
                  syslog(LOG_ERR, "smb_shr_load: load failed");
                  return (NULL);
          }
*** 1479,1489 ****
--- 1606,1660 ----
          }
          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,1542 ****
--- 1704,1714 ----
  {
          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,1565 ****
--- 1728,1743 ----
                  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,1655 ****
--- 1824,1861 ----
          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,2046 ****
          }
  }
  
  /*
   * 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.
   */
  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)
                  return;
  
!         if ((libhd = libzfs_init()) == NULL)
                  return;
  
          if ((zfshd = zfs_open(libhd, buf, ZFS_TYPE_FILESYSTEM)) == NULL) {
                  libzfs_fini(libhd);
                  return;
          }
--- 2227,2254 ----
          }
  }
  
  /*
   * If the share path refers to a ZFS file system, add the
!  * .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 ((libhd = libzfs_init()) == NULL)
                  return;
  
!         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,2088 ****
          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) {
                  smb_quota_add_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.
   */
  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) {
                  libzfs_fini(libhd);
                  return;
          }
  
          errno = 0;
--- 2257,2298 ----
          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));
  
!         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.
   */
  static void
  smb_shr_zfs_remove(smb_share_t *si)
  {
          libzfs_handle_t *libhd;
          int ret;
          char buf[MAXPATHLEN];   /* dataset or mountpoint */
  
          if ((libhd = libzfs_init()) == NULL)
                  return;
  
!         if (smb_getdataset(libhd, si->shr_path, buf, MAXPATHLEN) != 0) {
                  libzfs_fini(libhd);
                  return;
          }
  
          errno = 0;
*** 2089,2104 ****
          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);
!         }
  
-         zfs_close(zfshd);
          libzfs_fini(libhd);
  }
  
  /*
   * If the share path refers to a ZFS file system, rename the
--- 2299,2314 ----
          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));
  
!         /*
!          * 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.
!          */
  
          libzfs_fini(libhd);
  }
  
  /*
   * If the share path refers to a ZFS file system, rename the
*** 2110,2124 ****
          libzfs_handle_t *libhd;
          zfs_handle_t *zfshd;
          int ret;
          char dataset[MAXPATHLEN];
  
!         if (smb_getdataset(from->shr_path, dataset, MAXPATHLEN) != 0)
                  return;
  
!         if ((libhd = libzfs_init()) == NULL)
                  return;
  
          if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) {
                  libzfs_fini(libhd);
                  return;
          }
--- 2320,2336 ----
          libzfs_handle_t *libhd;
          zfs_handle_t *zfshd;
          int ret;
          char dataset[MAXPATHLEN];
  
!         if ((libhd = libzfs_init()) == NULL)
                  return;
  
!         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,2425 ****
                  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_AUTOHOME) != 0) {
!                 rc |= nvlist_add_string(smb, "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)
--- 2625,2650 ----
                  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, 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)