Print this page
NEX-15279 support NFS server in zone
NEX-15520 online NFS shares cause zoneadm halt to hang in nfs_export_zone_fini
Portions contributed by: Dan Kruchinin dan.kruchinin@nexenta.com
Portions contributed by: Stepan Zastupov stepan.zastupov@gmail.com
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>


   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 




  26 #include <sys/types.h>
  27 #include <sys/types32.h>
  28 #include <sys/param.h>
  29 #include <sys/systm.h>
  30 #include <rpc/types.h>
  31 #include <sys/vfs.h>
  32 #include <sys/siginfo.h>
  33 #include <sys/proc.h>             /* for exit() declaration */
  34 #include <sys/kmem.h>
  35 #include <sys/pathname.h>
  36 #include <sys/debug.h>
  37 #include <sys/vtrace.h>
  38 #include <sys/cmn_err.h>
  39 #include <sys/atomic.h>
  40 #include <sys/policy.h>
  41 
  42 #include <sharefs/sharefs.h>
  43 
  44 /*
  45  * A macro to avoid cut-and-paste errors on getting a string field
  46  * from user-land.
  47  */
  48 #define SHARETAB_COPYIN(field)                                          \
  49         if (copyinstr(STRUCT_FGETP(u_sh, sh_##field),                   \
  50                         buf,                                            \
  51                         bufsz + 1,      /* Add one for extra NUL */     \
  52                         &len)) {                                    \
  53                 error = EFAULT;                                         \
  54                 goto cleanup;                                           \
  55         }                                                               \
  56         /*                                                              \
  57          * Need to remove 1 because copyinstr() counts the NUL.         \
  58          */                                                             \
  59         len--;                                                          \
  60         sh->sh_##field = kmem_alloc(len + 1, KM_SLEEP);                      \
  61         bcopy(buf, sh->sh_##field, len);                             \
  62         sh->sh_##field[len] = '\0';                                  \
  63         shl.shl_##field = (int)len;                                     \
  64         sh->sh_size += shl.shl_##field;      /* Debug counting */
  65 
  66 #define SHARETAB_DELETE_FIELD(field)                                    \
  67         if (sh->sh_##field) {                                                \
  68                 kmem_free(sh->sh_##field,                            \
  69                         shl ? shl->shl_##field + 1 :                 \
  70                         strlen(sh->sh_##field) + 1);                 \
  71         }
  72 
  73 sharetab_t      *sharefs_sharetab = NULL;       /* The incore sharetab. */
  74 size_t          sharetab_size;
  75 uint_t          sharetab_count;
  76 
  77 krwlock_t       sharetab_lock;  /* lock to protect the cached sharetab */
  78 
  79 krwlock_t       sharefs_lock;   /* lock to protect the vnode ops */
  80 
  81 timestruc_t     sharetab_mtime;
  82 timestruc_t     sharetab_snap_time;
  83 
  84 uint_t          sharetab_generation;    /* Only increments and wraps! */
  85 
  86 /*
  87  * Take care of cleaning up a share.
  88  * If passed in a length array, use it to determine how much
  89  * space to clean up. Else, figure that out.
  90  */
  91 static void
  92 sharefree(share_t *sh, sharefs_lens_t *shl)
  93 {
  94         if (!sh)
  95                 return;
  96 
  97         SHARETAB_DELETE_FIELD(path);
  98         SHARETAB_DELETE_FIELD(res);
  99         SHARETAB_DELETE_FIELD(fstype);
 100         SHARETAB_DELETE_FIELD(opts);
 101         SHARETAB_DELETE_FIELD(descr);
 102 
 103         kmem_free(sh, sizeof (share_t));
 104 }
 105 
 106 /*
 107  * If there is no error, then this function is responsible for
 108  * cleaning up the memory associated with the share argument.
 109  */
 110 static int
 111 sharefs_remove(share_t *sh, sharefs_lens_t *shl)
 112 {
 113         int             iHash;
 114         sharetab_t      *sht;
 115         share_t         *s, *p;
 116         int             iPath;
 117 
 118         if (!sh)
 119                 return (ENOENT);
 120 
 121         rw_enter(&sharetab_lock, RW_WRITER);
 122         for (sht = sharefs_sharetab; sht != NULL; sht = sht->s_next) {
 123                 if (strcmp(sh->sh_fstype, sht->s_fstype) == 0) {
 124                         break;
 125                 }
 126         }
 127 
 128         /*
 129          * There does not exist a fstype in memory which
 130          * matches the share passed in.
 131          */
 132         if (!sht) {
 133                 rw_exit(&sharetab_lock);
 134                 return (ENOENT);
 135         }
 136 
 137         iPath = shl ? shl->shl_path : strlen(sh->sh_path);
 138         iHash = pkp_tab_hash(sh->sh_path, strlen(sh->sh_path));
 139 
 140         /*
 141          * Now walk down the hash table and find the entry to free!
 142          */
 143         for (p = NULL, s = sht->s_buckets[iHash].ssh_sh;
 144             s != NULL; s = s->sh_next) {
 145                 /*
 146                  * We need exact matches.
 147                  */
 148                 if (strcmp(sh->sh_path, s->sh_path) == 0 &&
 149                     strlen(s->sh_path) == iPath) {
 150                         if (p) {
 151                                 p->sh_next = s->sh_next;
 152                         } else {
 153                                 sht->s_buckets[iHash].ssh_sh = s->sh_next;
 154                         }
 155 
 156                         ASSERT(sht->s_buckets[iHash].ssh_count != 0);
 157                         atomic_dec_32(&sht->s_buckets[iHash].ssh_count);
 158                         atomic_dec_32(&sht->s_count);
 159                         atomic_dec_32(&sharetab_count);
 160 
 161                         ASSERT(sharetab_size >= s->sh_size);
 162                         sharetab_size -= s->sh_size;
 163 
 164                         gethrestime(&sharetab_mtime);
 165                         atomic_inc_32(&sharetab_generation);
 166 
 167                         break;
 168                 }
 169 
 170                 p = s;
 171         }
 172 
 173         rw_exit(&sharetab_lock);
 174 
 175         if (!s) {
 176                 return (ENOENT);
 177         }
 178 
 179         s->sh_next = NULL;
 180         sharefree(s, NULL);
 181 
 182         /*
 183          * We need to free the share for the caller.
 184          */
 185         sharefree(sh, shl);
 186 
 187         return (0);
 188 }
 189 
 190 /*
 191  * The caller must have allocated memory for us to use.
 192  */
 193 static int
 194 sharefs_add(share_t *sh, sharefs_lens_t *shl)
 195 {
 196         int             iHash;
 197         sharetab_t      *sht;
 198         share_t         *s, *p;
 199         int             iPath;
 200         int             n;
 201 
 202         if (!sh) {
 203                 return (ENOENT);
 204         }
 205 
 206         /*
 207          * We need to find the hash buckets for the fstype.
 208          */
 209         rw_enter(&sharetab_lock, RW_WRITER);
 210         for (sht = sharefs_sharetab; sht != NULL; sht = sht->s_next) {
 211                 if (strcmp(sh->sh_fstype, sht->s_fstype) == 0) {
 212                         break;
 213                 }
 214         }
 215 
 216         /*
 217          * Did not exist, so allocate one and add it to the
 218          * sharetab.
 219          */
 220         if (!sht) {
 221                 sht = kmem_zalloc(sizeof (*sht), KM_SLEEP);
 222                 n = strlen(sh->sh_fstype);
 223                 sht->s_fstype = kmem_zalloc(n + 1, KM_SLEEP);
 224                 (void) strncpy(sht->s_fstype, sh->sh_fstype, n);
 225 
 226                 sht->s_next = sharefs_sharetab;
 227                 sharefs_sharetab = sht;
 228         }
 229 
 230         /*
 231          * Now we need to find where we have to add the entry.
 232          */
 233         iHash = pkp_tab_hash(sh->sh_path, strlen(sh->sh_path));
 234 
 235         iPath = shl ? shl->shl_path : strlen(sh->sh_path);
 236 
 237         if (shl) {
 238                 sh->sh_size = shl->shl_path + shl->shl_res +
 239                     shl->shl_fstype + shl->shl_opts + shl->shl_descr;
 240         } else {
 241                 sh->sh_size = strlen(sh->sh_path) +
 242                     strlen(sh->sh_res) + strlen(sh->sh_fstype) +
 243                     strlen(sh->sh_opts) + strlen(sh->sh_descr);
 244         }
 245 
 246         /*
 247          * We need to account for field seperators and
 248          * the EOL.
 249          */
 250         sh->sh_size += 5;
 251 
 252         /*
 253          * Now walk down the hash table and add the new entry!
 254          */
 255         for (p = NULL, s = sht->s_buckets[iHash].ssh_sh;
 256             s != NULL; s = s->sh_next) {
 257                 /*
 258                  * We need exact matches.
 259                  *
 260                  * We found a matching path. Either we have a
 261                  * duplicate path in a share command or we are
 262                  * being asked to replace an existing entry.
 263                  */
 264                 if (strcmp(sh->sh_path, s->sh_path) == 0 &&
 265                     strlen(s->sh_path) == iPath) {
 266                         if (p) {
 267                                 p->sh_next = sh;
 268                         } else {
 269                                 sht->s_buckets[iHash].ssh_sh = sh;
 270                         }
 271 
 272                         sh->sh_next = s->sh_next;
 273 
 274                         ASSERT(sharetab_size >= s->sh_size);
 275                         sharetab_size -= s->sh_size;
 276                         sharetab_size += sh->sh_size;
 277 
 278                         /*
 279                          * Get rid of the old node.
 280                          */
 281                         sharefree(s, NULL);
 282 
 283                         gethrestime(&sharetab_mtime);
 284                         atomic_inc_32(&sharetab_generation);
 285 
 286                         ASSERT(sht->s_buckets[iHash].ssh_count != 0);
 287                         rw_exit(&sharetab_lock);
 288 
 289                         return (0);
 290                 }
 291 
 292                 p = s;
 293         }
 294 
 295         /*
 296          * Okay, we have gone through the entire hash chain and not
 297          * found a match. We just need to add this node.
 298          */
 299         sh->sh_next = sht->s_buckets[iHash].ssh_sh;
 300         sht->s_buckets[iHash].ssh_sh = sh;
 301         atomic_inc_32(&sht->s_buckets[iHash].ssh_count);
 302         atomic_inc_32(&sht->s_count);
 303         atomic_inc_32(&sharetab_count);
 304         sharetab_size += sh->sh_size;
 305 
 306         gethrestime(&sharetab_mtime);
 307         atomic_inc_32(&sharetab_generation);
 308 
 309         rw_exit(&sharetab_lock);
 310 
 311         return (0);
 312 }
 313 

































 314 void
 315 sharefs_sharetab_init(void)
 316 {
 317         rw_init(&sharetab_lock, NULL, RW_DEFAULT, NULL);
 318         rw_init(&sharefs_lock, NULL, RW_DEFAULT, NULL);

 319 
 320         sharetab_size = 0;
 321         sharetab_count = 0;
 322         sharetab_generation = 1;
 323 
 324         gethrestime(&sharetab_mtime);
 325         gethrestime(&sharetab_snap_time);
 326 }
 327 
 328 int
 329 sharefs_impl(enum sharefs_sys_op opcode, share_t *sh_in, uint32_t iMaxLen)
 330 {
 331         int             error = 0;
 332         size_t          len;
 333         size_t          bufsz;
 334         share_t         *sh;
 335 
 336         sharefs_lens_t  shl;
 337 
 338         model_t         model;
 339 
 340         char            *buf = NULL;

 341 
 342         STRUCT_DECL(share, u_sh);
 343 
 344         bufsz = iMaxLen;
 345 
 346         /*
 347          * Before we do anything, lets make sure we have
 348          * a sharetab in memory if we need one.
 349          */
 350         rw_enter(&sharetab_lock, RW_READER);
 351         switch (opcode) {
 352         case (SHAREFS_REMOVE) :
 353         case (SHAREFS_REPLACE) :
 354                 if (!sharefs_sharetab) {
 355                         rw_exit(&sharetab_lock);
 356                         return (set_errno(ENOENT));
 357                 }
 358                 break;
 359         case (SHAREFS_ADD) :
 360         default :
 361                 break;
 362         }
 363         rw_exit(&sharetab_lock);
 364 
 365         model = get_udatamodel();
 366 
 367         /*
 368          * Initialize the data pointers.
 369          */
 370         STRUCT_INIT(u_sh, model);
 371         if (copyin(sh_in, STRUCT_BUF(u_sh), STRUCT_SIZE(u_sh))) {
 372                 return (set_errno(EFAULT));
 373         }
 374 
 375         /*
 376          * Get the share.
 377          */
 378         sh = kmem_zalloc(sizeof (share_t), KM_SLEEP);
 379 
 380         /*
 381          * Get some storage for copying in the strings.
 382          */
 383         buf = kmem_zalloc(bufsz + 1, KM_SLEEP);
 384         bzero(&shl, sizeof (sharefs_lens_t));
 385 
 386         /*
 387          * Only grab these two until we know what we want.
 388          */
 389         SHARETAB_COPYIN(path);
 390         SHARETAB_COPYIN(fstype);
 391 
 392         switch (opcode) {
 393         case (SHAREFS_ADD) :
 394         case (SHAREFS_REPLACE) :
 395                 SHARETAB_COPYIN(res);
 396                 SHARETAB_COPYIN(opts);
 397                 SHARETAB_COPYIN(descr);
 398 
 399                 error = sharefs_add(sh, &shl);
 400                 break;
 401 
 402         case (SHAREFS_REMOVE) :
 403 
 404                 error = sharefs_remove(sh, &shl);
 405                 break;
 406 
 407         default:
 408                 error = EINVAL;
 409                 break;
 410         }
 411 
 412 cleanup:
 413 
 414         /*
 415          * If there is no error, then we have stashed the structure
 416          * away in the sharetab hash table or have deleted it.
 417          *
 418          * Either way, the only reason to blow away the data is if
 419          * there was an error.
 420          */
 421         if (error != 0) {
 422                 sharefree(sh, &shl);
 423         }
 424 
 425         if (buf) {
 426                 kmem_free(buf, bufsz + 1);
 427         }
 428 
 429         return ((error != 0) ? set_errno(error) : 0);
 430 }
 431 
 432 int
 433 sharefs(enum sharefs_sys_op opcode, share_t *sh_in, uint32_t iMaxLen)
 434 {













 435         if (secpolicy_sys_config(CRED(), B_FALSE) != 0)
 436                 return (set_errno(EPERM));




 437 

 438         return (sharefs_impl(opcode, sh_in, iMaxLen));
 439 }


   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*
  27  * Copyright 2018 Nexenta Systems, Inc.
  28  */
  29 
  30 #include <sys/types.h>
  31 #include <sys/types32.h>
  32 #include <sys/param.h>
  33 #include <sys/systm.h>
  34 #include <rpc/types.h>
  35 #include <sys/vfs.h>
  36 #include <sys/siginfo.h>
  37 #include <sys/proc.h>             /* for exit() declaration */
  38 #include <sys/kmem.h>
  39 #include <sys/pathname.h>
  40 #include <sys/debug.h>
  41 #include <sys/vtrace.h>
  42 #include <sys/cmn_err.h>
  43 #include <sys/atomic.h>
  44 #include <sys/policy.h>
  45 
  46 #include <sharefs/sharefs.h>
  47 
  48 /*
  49  * A macro to avoid cut-and-paste errors on getting a string field
  50  * from user-land.
  51  */
  52 #define SHARETAB_COPYIN(field)                                          \
  53         if (copyinstr(STRUCT_FGETP(u_sh, sh_##field),                   \
  54             buf,                                                        \
  55             bufsz + 1,  /* Add one for extra NUL */                     \
  56             &len)) {                                                        \
  57                 error = EFAULT;                                         \
  58                 goto cleanup;                                           \
  59         }                                                               \
  60         /* Need to remove 1 because copyinstr() counts the NUL */       \


  61         len--;                                                          \
  62         sh->sh_##field = kmem_alloc(len + 1, KM_SLEEP);                      \
  63         bcopy(buf, sh->sh_##field, len);                             \
  64         sh->sh_##field[len] = '\0';                                  \
  65         shl.shl_##field = (int)len;                                     \
  66         sh->sh_size += shl.shl_##field;      /* Debug counting */
  67 
  68 #define SHARETAB_DELETE_FIELD(field)                                    \
  69         if (sh->sh_##field != NULL) {                                        \
  70                 kmem_free(sh->sh_##field,                            \
  71                     shl ? shl->shl_##field + 1 :                     \
  72                     strlen(sh->sh_##field) + 1);                     \
  73         }
  74 
  75 static zone_key_t sharetab_zone_key;


  76 









  77 /*
  78  * Take care of cleaning up a share.
  79  * If passed in a length array, use it to determine how much
  80  * space to clean up. Else, figure that out.
  81  */
  82 static void
  83 sharefree(share_t *sh, sharefs_lens_t *shl)
  84 {
  85         if (sh == NULL)
  86                 return;
  87 
  88         SHARETAB_DELETE_FIELD(path);
  89         SHARETAB_DELETE_FIELD(res);
  90         SHARETAB_DELETE_FIELD(fstype);
  91         SHARETAB_DELETE_FIELD(opts);
  92         SHARETAB_DELETE_FIELD(descr);
  93 
  94         kmem_free(sh, sizeof (*sh));
  95 }
  96 
  97 /*
  98  * If there is no error, then this function is responsible for
  99  * cleaning up the memory associated with the share argument.
 100  */
 101 static int
 102 sharefs_remove(sharetab_globals_t *sg, share_t *sh, sharefs_lens_t *shl)
 103 {
 104         int             iHash;
 105         sharetab_t      *sht;
 106         share_t         *s, *p;
 107         int             iPath;
 108 
 109         if (!sh)
 110                 return (ENOENT);
 111 
 112         rw_enter(&sg->sharetab_lock, RW_WRITER);
 113         for (sht = sg->sharefs_sharetab; sht != NULL; sht = sht->s_next) {
 114                 if (strcmp(sh->sh_fstype, sht->s_fstype) == 0)
 115                         break;
 116         }

 117 
 118         /*
 119          * There does not exist a fstype in memory which
 120          * matches the share passed in.
 121          */
 122         if (sht == NULL) {
 123                 rw_exit(&sg->sharetab_lock);
 124                 return (ENOENT);
 125         }
 126 
 127         iPath = shl != NULL ? shl->shl_path : strlen(sh->sh_path);
 128         iHash = pkp_tab_hash(sh->sh_path, strlen(sh->sh_path));
 129 
 130         /*
 131          * Now walk down the hash table and find the entry to free!
 132          */
 133         for (p = NULL, s = sht->s_buckets[iHash].ssh_sh;
 134             s != NULL; s = s->sh_next) {
 135                 /*
 136                  * We need exact matches.
 137                  */
 138                 if (strcmp(sh->sh_path, s->sh_path) == 0 &&
 139                     strlen(s->sh_path) == iPath) {
 140                         if (p != NULL)
 141                                 p->sh_next = s->sh_next;
 142                         else
 143                                 sht->s_buckets[iHash].ssh_sh = s->sh_next;

 144 
 145                         ASSERT(sht->s_buckets[iHash].ssh_count != 0);
 146                         atomic_dec_32(&sht->s_buckets[iHash].ssh_count);
 147                         atomic_dec_32(&sht->s_count);
 148                         atomic_dec_32(&sg->sharetab_count);
 149 
 150                         ASSERT(sg->sharetab_size >= s->sh_size);
 151                         sg->sharetab_size -= s->sh_size;
 152 
 153                         gethrestime(&sg->sharetab_mtime);
 154                         atomic_inc_32(&sg->sharetab_generation);
 155 
 156                         break;
 157                 }
 158 
 159                 p = s;
 160         }
 161 
 162         rw_exit(&sg->sharetab_lock);
 163 
 164         if (s == NULL)
 165                 return (ENOENT);

 166 
 167         s->sh_next = NULL;
 168         sharefree(s, NULL);
 169 
 170         /* We need to free the share for the caller */


 171         sharefree(sh, shl);
 172 
 173         return (0);
 174 }
 175 
 176 /*
 177  * The caller must have allocated memory for us to use.
 178  */
 179 static int
 180 sharefs_add(sharetab_globals_t *sg, share_t *sh, sharefs_lens_t *shl)
 181 {
 182         int             iHash;
 183         sharetab_t      *sht;
 184         share_t         *s, *p;
 185         int             iPath;
 186         int             n;
 187 
 188         if (sh == NULL)
 189                 return (ENOENT);

 190 
 191         /* We need to find the hash buckets for the fstype */
 192         rw_enter(&sg->sharetab_lock, RW_WRITER);
 193         for (sht = sg->sharefs_sharetab; sht != NULL; sht = sht->s_next) {
 194                 if (strcmp(sh->sh_fstype, sht->s_fstype) == 0)


 195                         break;
 196         }

 197 
 198         /* Did not exist, so allocate one and add it to the sharetab */
 199         if (sht == NULL) {



 200                 sht = kmem_zalloc(sizeof (*sht), KM_SLEEP);
 201                 n = strlen(sh->sh_fstype);
 202                 sht->s_fstype = kmem_zalloc(n + 1, KM_SLEEP);
 203                 (void) strncpy(sht->s_fstype, sh->sh_fstype, n);
 204 
 205                 sht->s_next = sg->sharefs_sharetab;
 206                 sg->sharefs_sharetab = sht;
 207         }
 208 
 209         /* Now we need to find where we have to add the entry */
 210         iPath = shl != NULL ? shl->shl_path : strlen(sh->sh_path);

 211         iHash = pkp_tab_hash(sh->sh_path, strlen(sh->sh_path));
 212 


 213         if (shl) {
 214                 sh->sh_size = shl->shl_path + shl->shl_res +
 215                     shl->shl_fstype + shl->shl_opts + shl->shl_descr;
 216         } else {
 217                 sh->sh_size = strlen(sh->sh_path) +
 218                     strlen(sh->sh_res) + strlen(sh->sh_fstype) +
 219                     strlen(sh->sh_opts) + strlen(sh->sh_descr);
 220         }
 221 
 222         /* We need to account for field seperators and the EOL */



 223         sh->sh_size += 5;
 224 
 225         /* Now walk down the hash table and add the new entry */


 226         for (p = NULL, s = sht->s_buckets[iHash].ssh_sh;
 227             s != NULL; s = s->sh_next) {
 228                 /*
 229                  * We need exact matches.
 230                  *
 231                  * We found a matching path. Either we have a
 232                  * duplicate path in a share command or we are
 233                  * being asked to replace an existing entry.
 234                  */
 235                 if (strcmp(sh->sh_path, s->sh_path) == 0 &&
 236                     strlen(s->sh_path) == iPath) {
 237                         if (p != NULL)
 238                                 p->sh_next = sh;
 239                         else
 240                                 sht->s_buckets[iHash].ssh_sh = sh;

 241 
 242                         sh->sh_next = s->sh_next;
 243 
 244                         ASSERT(sg->sharetab_size >= s->sh_size);
 245                         sg->sharetab_size -= s->sh_size;
 246                         sg->sharetab_size += sh->sh_size;
 247 
 248                         /* Get rid of the old node */


 249                         sharefree(s, NULL);
 250 
 251                         gethrestime(&sg->sharetab_mtime);
 252                         atomic_inc_32(&sg->sharetab_generation);
 253 
 254                         ASSERT(sht->s_buckets[iHash].ssh_count != 0);
 255                         rw_exit(&sg->sharetab_lock);
 256 
 257                         return (0);
 258                 }
 259 
 260                 p = s;
 261         }
 262 
 263         /*
 264          * Okay, we have gone through the entire hash chain and not
 265          * found a match. We just need to add this node.
 266          */
 267         sh->sh_next = sht->s_buckets[iHash].ssh_sh;
 268         sht->s_buckets[iHash].ssh_sh = sh;
 269         atomic_inc_32(&sht->s_buckets[iHash].ssh_count);
 270         atomic_inc_32(&sht->s_count);
 271         atomic_inc_32(&sg->sharetab_count);
 272         sg->sharetab_size += sh->sh_size;
 273 
 274         gethrestime(&sg->sharetab_mtime);
 275         atomic_inc_32(&sg->sharetab_generation);
 276 
 277         rw_exit(&sg->sharetab_lock);
 278 
 279         return (0);
 280 }
 281 
 282 /* ARGSUSED */
 283 static void *
 284 sharetab_zone_init(zoneid_t zoneid)
 285 {
 286         sharetab_globals_t *sg;
 287 
 288         sg = kmem_zalloc(sizeof (*sg), KM_SLEEP);
 289 
 290         rw_init(&sg->sharetab_lock, NULL, RW_DEFAULT, NULL);
 291         rw_init(&sg->sharefs_lock, NULL, RW_DEFAULT, NULL);
 292 
 293         sg->sharetab_size = 0;
 294         sg->sharetab_count = 0;
 295         sg->sharetab_generation = 1;
 296 
 297         gethrestime(&sg->sharetab_mtime);
 298         gethrestime(&sg->sharetab_snap_time);
 299 
 300         return (sg);
 301 }
 302 
 303 /* ARGSUSED */
 304 static void
 305 sharetab_zone_fini(zoneid_t zoneid, void *data)
 306 {
 307         sharetab_globals_t *sg = data;
 308 
 309         rw_destroy(&sg->sharefs_lock);
 310         rw_destroy(&sg->sharetab_lock);
 311 
 312         kmem_free(sg, sizeof (*sg));
 313 }
 314 
 315 void
 316 sharefs_sharetab_init(void)
 317 {
 318         zone_key_create(&sharetab_zone_key, sharetab_zone_init,
 319             NULL, sharetab_zone_fini);
 320 }
 321 
 322 sharetab_globals_t *
 323 sharetab_get_globals(zone_t *zone)
 324 {
 325         return (zone_getspecific(sharetab_zone_key, zone));


 326 }
 327 
 328 int
 329 sharefs_impl(enum sharefs_sys_op opcode, share_t *sh_in, uint32_t iMaxLen)
 330 {
 331         int             error = 0;
 332         size_t          len;
 333         size_t          bufsz;
 334         share_t         *sh;

 335         sharefs_lens_t  shl;

 336         model_t         model;

 337         char            *buf = NULL;
 338         sharetab_globals_t *sg = sharetab_get_globals(curzone);
 339 
 340         STRUCT_DECL(share, u_sh);
 341 
 342         bufsz = iMaxLen;
 343 
 344         /*
 345          * Before we do anything, lets make sure we have
 346          * a sharetab in memory if we need one.
 347          */
 348         rw_enter(&sg->sharetab_lock, RW_READER);
 349         switch (opcode) {
 350         case SHAREFS_REMOVE:
 351         case SHAREFS_REPLACE:
 352                 if (!sg->sharefs_sharetab) {
 353                         rw_exit(&sg->sharetab_lock);
 354                         return (set_errno(ENOENT));
 355                 }
 356                 break;
 357         case SHAREFS_ADD:
 358         default:
 359                 break;
 360         }
 361         rw_exit(&sg->sharetab_lock);
 362 
 363         model = get_udatamodel();
 364 
 365         /*
 366          * Initialize the data pointers.
 367          */
 368         STRUCT_INIT(u_sh, model);
 369         if (copyin(sh_in, STRUCT_BUF(u_sh), STRUCT_SIZE(u_sh)))
 370                 return (set_errno(EFAULT));

 371 
 372         /* Get the share */


 373         sh = kmem_zalloc(sizeof (share_t), KM_SLEEP);
 374 
 375         /* Get some storage for copying in the strings */


 376         buf = kmem_zalloc(bufsz + 1, KM_SLEEP);
 377         bzero(&shl, sizeof (sharefs_lens_t));
 378 
 379         /* Only grab these two until we know what we want */


 380         SHARETAB_COPYIN(path);
 381         SHARETAB_COPYIN(fstype);
 382 
 383         switch (opcode) {
 384         case SHAREFS_ADD:
 385         case SHAREFS_REPLACE:
 386                 SHARETAB_COPYIN(res);
 387                 SHARETAB_COPYIN(opts);
 388                 SHARETAB_COPYIN(descr);
 389                 error = sharefs_add(sg, sh, &shl);

 390                 break;
 391         case SHAREFS_REMOVE:
 392                 error = sharefs_remove(sg, sh, &shl);


 393                 break;

 394         default:
 395                 error = EINVAL;
 396                 break;
 397         }
 398 
 399 cleanup:

 400         /*
 401          * If there is no error, then we have stashed the structure
 402          * away in the sharetab hash table or have deleted it.
 403          *
 404          * Either way, the only reason to blow away the data is if
 405          * there was an error.
 406          */
 407         if (error != 0)
 408                 sharefree(sh, &shl);

 409 
 410         if (buf != NULL)
 411                 kmem_free(buf, bufsz + 1);

 412 
 413         return (error != 0 ? set_errno(error) : 0);
 414 }
 415 
 416 int
 417 sharefs(enum sharefs_sys_op opcode, share_t *sh_in, uint32_t iMaxLen)
 418 {
 419         /*
 420          * If we're in the global zone PRIV_SYS_CONFIG gives us the
 421          * priviledges needed to act on sharetab. However if we're in
 422          * a non-global zone PRIV_SYS_CONFIG is not allowed. To work
 423          * around this issue PRIV_SYS_NFS is used in this case.
 424          *
 425          * TODO: This basically overloads the definition/use of
 426          * PRIV_SYS_NFS to work around the limitation of PRIV_SYS_CONFIG
 427          * in a zone. Solaris 11 solved this by implementing a PRIV_SYS_SHARE
 428          * we should do the same and replace the use of PRIV_SYS_NFS here and
 429          * in zfs_secpolicy_share.
 430          */
 431         if (INGLOBALZONE(curproc)) {
 432                 if (secpolicy_sys_config(CRED(), B_FALSE) != 0)
 433                         return (set_errno(EPERM));
 434         } else {
 435                 /* behave like zfs_secpolicy_share() */
 436                 if (secpolicy_nfs(CRED()) != 0)
 437                         return (set_errno(EPERM));
 438 
 439         }
 440         return (sharefs_impl(opcode, sh_in, iMaxLen));
 441 }