1*3957Sth199096 /* 2*3957Sth199096 * CDDL HEADER START 3*3957Sth199096 * 4*3957Sth199096 * The contents of this file are subject to the terms of the 5*3957Sth199096 * Common Development and Distribution License (the "License"). 6*3957Sth199096 * You may not use this file except in compliance with the License. 7*3957Sth199096 * 8*3957Sth199096 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*3957Sth199096 * or http://www.opensolaris.org/os/licensing. 10*3957Sth199096 * See the License for the specific language governing permissions 11*3957Sth199096 * and limitations under the License. 12*3957Sth199096 * 13*3957Sth199096 * When distributing Covered Code, include this CDDL HEADER in each 14*3957Sth199096 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*3957Sth199096 * If applicable, add the following below this CDDL HEADER, with the 16*3957Sth199096 * fields enclosed by brackets "[]" replaced with your own identifying 17*3957Sth199096 * information: Portions Copyright [yyyy] [name of copyright owner] 18*3957Sth199096 * 19*3957Sth199096 * CDDL HEADER END 20*3957Sth199096 */ 21*3957Sth199096 22*3957Sth199096 /* 23*3957Sth199096 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24*3957Sth199096 * Use is subject to license terms. 25*3957Sth199096 */ 26*3957Sth199096 27*3957Sth199096 #pragma ident "%Z%%M% %I% %E% SMI" 28*3957Sth199096 29*3957Sth199096 #include <sys/types.h> 30*3957Sth199096 #include <sys/types32.h> 31*3957Sth199096 #include <sys/param.h> 32*3957Sth199096 #include <sys/systm.h> 33*3957Sth199096 #include <rpc/types.h> 34*3957Sth199096 #include <sys/vfs.h> 35*3957Sth199096 #include <sys/siginfo.h> 36*3957Sth199096 #include <sys/proc.h> /* for exit() declaration */ 37*3957Sth199096 #include <sys/kmem.h> 38*3957Sth199096 #include <sys/pathname.h> 39*3957Sth199096 #include <sys/debug.h> 40*3957Sth199096 #include <sys/vtrace.h> 41*3957Sth199096 #include <sys/cmn_err.h> 42*3957Sth199096 #include <sys/atomic.h> 43*3957Sth199096 44*3957Sth199096 #include <sharefs/sharefs.h> 45*3957Sth199096 46*3957Sth199096 /* 47*3957Sth199096 * A macro to avoid cut-and-paste errors on getting a string field 48*3957Sth199096 * from user-land. 49*3957Sth199096 */ 50*3957Sth199096 #define SHARETAB_COPYIN(field) \ 51*3957Sth199096 if (copyinstr(STRUCT_FGETP(u_sh, sh_##field), \ 52*3957Sth199096 buf, \ 53*3957Sth199096 bufsz + 1, /* Add one for extra NUL */ \ 54*3957Sth199096 &len)) { \ 55*3957Sth199096 error = EFAULT; \ 56*3957Sth199096 goto cleanup; \ 57*3957Sth199096 } \ 58*3957Sth199096 /* \ 59*3957Sth199096 * Need to remove 1 because copyinstr() counts the NUL. \ 60*3957Sth199096 */ \ 61*3957Sth199096 len--; \ 62*3957Sth199096 sh->sh_##field = kmem_alloc(len + 1, KM_SLEEP); \ 63*3957Sth199096 bcopy(buf, sh->sh_##field, len); \ 64*3957Sth199096 sh->sh_##field[len] = '\0'; \ 65*3957Sth199096 shl.shl_##field = (int)len; \ 66*3957Sth199096 sh->sh_size += shl.shl_##field; /* Debug counting */ 67*3957Sth199096 68*3957Sth199096 #define SHARETAB_DELETE_FIELD(field) \ 69*3957Sth199096 if (sh->sh_##field) { \ 70*3957Sth199096 kmem_free(sh->sh_##field, \ 71*3957Sth199096 shl ? shl->shl_##field + 1 : \ 72*3957Sth199096 strlen(sh->sh_##field) + 1); \ 73*3957Sth199096 } 74*3957Sth199096 75*3957Sth199096 sharetab_t *sharefs_sharetab = NULL; /* The incore sharetab. */ 76*3957Sth199096 size_t sharetab_size; 77*3957Sth199096 uint_t sharetab_count; 78*3957Sth199096 79*3957Sth199096 krwlock_t sharetab_lock; /* lock to protect the cached sharetab */ 80*3957Sth199096 81*3957Sth199096 krwlock_t sharefs_lock; /* lock to protect the vnode ops */ 82*3957Sth199096 83*3957Sth199096 timestruc_t sharetab_mtime; 84*3957Sth199096 timestruc_t sharetab_snap_time; 85*3957Sth199096 86*3957Sth199096 uint_t sharetab_generation; /* Only increments and wraps! */ 87*3957Sth199096 88*3957Sth199096 static uint_t pkp_tab[SHARETAB_HASHES]; 89*3957Sth199096 90*3957Sth199096 /* 91*3957Sth199096 * Initialize table in pseudo-random fashion 92*3957Sth199096 * for use in Pearson's string hash algorithm. 93*3957Sth199096 * 94*3957Sth199096 * See: Communications of the ACM, June 1990 Vol 33 pp 677-680 95*3957Sth199096 * http://www.acm.org/pubs/citations/journals/cacm/1990-33-6/p677-pearson 96*3957Sth199096 */ 97*3957Sth199096 static void 98*3957Sth199096 init_pkp_tab(void) 99*3957Sth199096 { 100*3957Sth199096 int i; 101*3957Sth199096 int j; 102*3957Sth199096 int k = 7; 103*3957Sth199096 uint_t s; 104*3957Sth199096 105*3957Sth199096 for (i = 0; i < SHARETAB_HASHES; i++) 106*3957Sth199096 pkp_tab[i] = i; 107*3957Sth199096 108*3957Sth199096 for (j = 0; j < 4; j++) { 109*3957Sth199096 for (i = 0; i < SHARETAB_HASHES; i++) { 110*3957Sth199096 s = pkp_tab[i]; 111*3957Sth199096 k = MOD2((k + s), SHARETAB_HASHES); 112*3957Sth199096 pkp_tab[i] = pkp_tab[k]; 113*3957Sth199096 pkp_tab[k] = s; 114*3957Sth199096 } 115*3957Sth199096 } 116*3957Sth199096 } 117*3957Sth199096 118*3957Sth199096 /* 119*3957Sth199096 * Take care of cleaning up a share. 120*3957Sth199096 * If passed in a length array, use it to determine how much 121*3957Sth199096 * space to clean up. Else, figure that out. 122*3957Sth199096 */ 123*3957Sth199096 static void 124*3957Sth199096 sharefree(share_t *sh, sharefs_lens_t *shl) 125*3957Sth199096 { 126*3957Sth199096 if (!sh) 127*3957Sth199096 return; 128*3957Sth199096 129*3957Sth199096 SHARETAB_DELETE_FIELD(path); 130*3957Sth199096 SHARETAB_DELETE_FIELD(res); 131*3957Sth199096 SHARETAB_DELETE_FIELD(fstype); 132*3957Sth199096 SHARETAB_DELETE_FIELD(opts); 133*3957Sth199096 SHARETAB_DELETE_FIELD(descr); 134*3957Sth199096 135*3957Sth199096 kmem_free(sh, sizeof (share_t)); 136*3957Sth199096 } 137*3957Sth199096 138*3957Sth199096 /* 139*3957Sth199096 * If there is no error, then this function is responsible for 140*3957Sth199096 * cleaning up the memory associated with the share argument. 141*3957Sth199096 */ 142*3957Sth199096 static int 143*3957Sth199096 sharefs_remove(share_t *sh, sharefs_lens_t *shl) 144*3957Sth199096 { 145*3957Sth199096 int iHash; 146*3957Sth199096 sharetab_t *sht; 147*3957Sth199096 share_t *s, *p; 148*3957Sth199096 int iPath; 149*3957Sth199096 150*3957Sth199096 if (!sh) 151*3957Sth199096 return (ENOENT); 152*3957Sth199096 153*3957Sth199096 rw_enter(&sharetab_lock, RW_WRITER); 154*3957Sth199096 for (sht = sharefs_sharetab; sht != NULL; sht = sht->s_next) { 155*3957Sth199096 if (strcmp(sh->sh_fstype, sht->s_fstype) == 0) { 156*3957Sth199096 break; 157*3957Sth199096 } 158*3957Sth199096 } 159*3957Sth199096 160*3957Sth199096 /* 161*3957Sth199096 * There does not exist a fstype in memory which 162*3957Sth199096 * matches the share passed in. 163*3957Sth199096 */ 164*3957Sth199096 if (!sht) { 165*3957Sth199096 rw_exit(&sharetab_lock); 166*3957Sth199096 return (ENOENT); 167*3957Sth199096 } 168*3957Sth199096 169*3957Sth199096 iPath = shl ? shl->shl_path : strlen(sh->sh_path); 170*3957Sth199096 SHARETAB_HASH_IT(iHash, sh->sh_path); 171*3957Sth199096 172*3957Sth199096 /* 173*3957Sth199096 * Now walk down the hash table and find the entry to free! 174*3957Sth199096 */ 175*3957Sth199096 for (p = NULL, s = sht->s_buckets[iHash].ssh_sh; 176*3957Sth199096 s != NULL; 177*3957Sth199096 s = s->sh_next) { 178*3957Sth199096 /* 179*3957Sth199096 * We need exact matches. 180*3957Sth199096 */ 181*3957Sth199096 if (strcmp(sh->sh_path, s->sh_path) == 0 && 182*3957Sth199096 strlen(s->sh_path) == iPath) { 183*3957Sth199096 if (p) { 184*3957Sth199096 p->sh_next = s->sh_next; 185*3957Sth199096 } else { 186*3957Sth199096 sht->s_buckets[iHash].ssh_sh = s->sh_next; 187*3957Sth199096 } 188*3957Sth199096 189*3957Sth199096 ASSERT(sht->s_buckets[iHash].ssh_count != 0); 190*3957Sth199096 atomic_add_32(&sht->s_buckets[iHash].ssh_count, -1); 191*3957Sth199096 atomic_add_32(&sht->s_count, -1); 192*3957Sth199096 atomic_add_32(&sharetab_count, -1); 193*3957Sth199096 194*3957Sth199096 ASSERT(sharetab_size >= s->sh_size); 195*3957Sth199096 sharetab_size -= s->sh_size; 196*3957Sth199096 197*3957Sth199096 gethrestime(&sharetab_mtime); 198*3957Sth199096 atomic_add_32(&sharetab_generation, 1); 199*3957Sth199096 200*3957Sth199096 break; 201*3957Sth199096 } 202*3957Sth199096 203*3957Sth199096 p = s; 204*3957Sth199096 } 205*3957Sth199096 206*3957Sth199096 rw_exit(&sharetab_lock); 207*3957Sth199096 208*3957Sth199096 if (!s) { 209*3957Sth199096 return (ENOENT); 210*3957Sth199096 } 211*3957Sth199096 212*3957Sth199096 s->sh_next = NULL; 213*3957Sth199096 sharefree(s, NULL); 214*3957Sth199096 215*3957Sth199096 /* 216*3957Sth199096 * We need to free the share for the caller. 217*3957Sth199096 */ 218*3957Sth199096 sharefree(sh, shl); 219*3957Sth199096 220*3957Sth199096 return (0); 221*3957Sth199096 } 222*3957Sth199096 223*3957Sth199096 /* 224*3957Sth199096 * The caller must have allocated memory for us to use. 225*3957Sth199096 */ 226*3957Sth199096 static int 227*3957Sth199096 sharefs_add(share_t *sh, sharefs_lens_t *shl) 228*3957Sth199096 { 229*3957Sth199096 int iHash; 230*3957Sth199096 sharetab_t *sht; 231*3957Sth199096 share_t *s, *p; 232*3957Sth199096 int iPath; 233*3957Sth199096 int n; 234*3957Sth199096 235*3957Sth199096 if (!sh) { 236*3957Sth199096 return (ENOENT); 237*3957Sth199096 } 238*3957Sth199096 239*3957Sth199096 /* 240*3957Sth199096 * We need to find the hash buckets for the fstype. 241*3957Sth199096 */ 242*3957Sth199096 rw_enter(&sharetab_lock, RW_WRITER); 243*3957Sth199096 for (sht = sharefs_sharetab; sht != NULL; sht = sht->s_next) { 244*3957Sth199096 if (strcmp(sh->sh_fstype, sht->s_fstype) == 0) { 245*3957Sth199096 break; 246*3957Sth199096 } 247*3957Sth199096 } 248*3957Sth199096 249*3957Sth199096 /* 250*3957Sth199096 * Did not exist, so allocate one and add it to the 251*3957Sth199096 * sharetab. 252*3957Sth199096 */ 253*3957Sth199096 if (!sht) { 254*3957Sth199096 sht = kmem_zalloc(sizeof (*sht), KM_SLEEP); 255*3957Sth199096 n = strlen(sh->sh_fstype); 256*3957Sth199096 sht->s_fstype = kmem_zalloc(n + 1, KM_SLEEP); 257*3957Sth199096 (void) strncpy(sht->s_fstype, sh->sh_fstype, n); 258*3957Sth199096 259*3957Sth199096 sht->s_next = sharefs_sharetab; 260*3957Sth199096 sharefs_sharetab = sht; 261*3957Sth199096 } 262*3957Sth199096 263*3957Sth199096 /* 264*3957Sth199096 * Now we need to find where we have to add the entry. 265*3957Sth199096 */ 266*3957Sth199096 SHARETAB_HASH_IT(iHash, sh->sh_path); 267*3957Sth199096 268*3957Sth199096 iPath = shl ? shl->shl_path : strlen(sh->sh_path); 269*3957Sth199096 270*3957Sth199096 if (shl) { 271*3957Sth199096 sh->sh_size = shl->shl_path + shl->shl_res + 272*3957Sth199096 shl->shl_fstype + shl->shl_opts + 273*3957Sth199096 shl->shl_descr; 274*3957Sth199096 } else { 275*3957Sth199096 sh->sh_size = strlen(sh->sh_path) + 276*3957Sth199096 strlen(sh->sh_res) + 277*3957Sth199096 strlen(sh->sh_fstype) + 278*3957Sth199096 strlen(sh->sh_opts) + 279*3957Sth199096 strlen(sh->sh_descr); 280*3957Sth199096 } 281*3957Sth199096 282*3957Sth199096 /* 283*3957Sth199096 * We need to account for field seperators and 284*3957Sth199096 * the EOL. 285*3957Sth199096 */ 286*3957Sth199096 sh->sh_size += 5; 287*3957Sth199096 288*3957Sth199096 /* 289*3957Sth199096 * Now walk down the hash table and add the new entry! 290*3957Sth199096 */ 291*3957Sth199096 for (p = NULL, s = sht->s_buckets[iHash].ssh_sh; 292*3957Sth199096 s != NULL; 293*3957Sth199096 s = s->sh_next) { 294*3957Sth199096 /* 295*3957Sth199096 * We need exact matches. 296*3957Sth199096 * 297*3957Sth199096 * We found a matching path. Either we have a 298*3957Sth199096 * duplicate path in a share command or we are 299*3957Sth199096 * being asked to replace an existing entry. 300*3957Sth199096 */ 301*3957Sth199096 if (strcmp(sh->sh_path, s->sh_path) == 0 && 302*3957Sth199096 strlen(s->sh_path) == iPath) { 303*3957Sth199096 if (p) { 304*3957Sth199096 p->sh_next = sh; 305*3957Sth199096 } else { 306*3957Sth199096 sht->s_buckets[iHash].ssh_sh = sh; 307*3957Sth199096 } 308*3957Sth199096 309*3957Sth199096 sh->sh_next = s->sh_next; 310*3957Sth199096 311*3957Sth199096 ASSERT(sharetab_size >= s->sh_size); 312*3957Sth199096 sharetab_size -= s->sh_size; 313*3957Sth199096 sharetab_size += sh->sh_size; 314*3957Sth199096 315*3957Sth199096 /* 316*3957Sth199096 * Get rid of the old node. 317*3957Sth199096 */ 318*3957Sth199096 sharefree(s, NULL); 319*3957Sth199096 320*3957Sth199096 gethrestime(&sharetab_mtime); 321*3957Sth199096 atomic_add_32(&sharetab_generation, 1); 322*3957Sth199096 323*3957Sth199096 ASSERT(sht->s_buckets[iHash].ssh_count != 0); 324*3957Sth199096 rw_exit(&sharetab_lock); 325*3957Sth199096 326*3957Sth199096 return (0); 327*3957Sth199096 } 328*3957Sth199096 329*3957Sth199096 p = s; 330*3957Sth199096 } 331*3957Sth199096 332*3957Sth199096 /* 333*3957Sth199096 * Okay, we have gone through the entire hash chain and not 334*3957Sth199096 * found a match. We just need to add this node. 335*3957Sth199096 */ 336*3957Sth199096 sh->sh_next = sht->s_buckets[iHash].ssh_sh; 337*3957Sth199096 sht->s_buckets[iHash].ssh_sh = sh; 338*3957Sth199096 atomic_add_32(&sht->s_buckets[iHash].ssh_count, 1); 339*3957Sth199096 atomic_add_32(&sht->s_count, 1); 340*3957Sth199096 atomic_add_32(&sharetab_count, 1); 341*3957Sth199096 sharetab_size += sh->sh_size; 342*3957Sth199096 343*3957Sth199096 gethrestime(&sharetab_mtime); 344*3957Sth199096 atomic_add_32(&sharetab_generation, 1); 345*3957Sth199096 346*3957Sth199096 rw_exit(&sharetab_lock); 347*3957Sth199096 348*3957Sth199096 return (0); 349*3957Sth199096 } 350*3957Sth199096 351*3957Sth199096 void 352*3957Sth199096 sharefs_sharetab_init(void) 353*3957Sth199096 { 354*3957Sth199096 init_pkp_tab(); 355*3957Sth199096 356*3957Sth199096 rw_init(&sharetab_lock, NULL, RW_DEFAULT, NULL); 357*3957Sth199096 rw_init(&sharefs_lock, NULL, RW_DEFAULT, NULL); 358*3957Sth199096 359*3957Sth199096 sharetab_size = 0; 360*3957Sth199096 sharetab_count = 0; 361*3957Sth199096 sharetab_generation = 1; 362*3957Sth199096 363*3957Sth199096 gethrestime(&sharetab_mtime); 364*3957Sth199096 gethrestime(&sharetab_snap_time); 365*3957Sth199096 } 366*3957Sth199096 367*3957Sth199096 int 368*3957Sth199096 sharefs(enum sharefs_sys_op opcode, share_t *sh_in, uint32_t iMaxLen) 369*3957Sth199096 { 370*3957Sth199096 int error = 0; 371*3957Sth199096 size_t len; 372*3957Sth199096 size_t bufsz; 373*3957Sth199096 share_t *sh; 374*3957Sth199096 375*3957Sth199096 sharefs_lens_t shl; 376*3957Sth199096 377*3957Sth199096 model_t model; 378*3957Sth199096 379*3957Sth199096 char *buf = NULL; 380*3957Sth199096 381*3957Sth199096 STRUCT_DECL(share, u_sh); 382*3957Sth199096 383*3957Sth199096 bufsz = iMaxLen; 384*3957Sth199096 385*3957Sth199096 /* 386*3957Sth199096 * Before we do anything, lets make sure we have 387*3957Sth199096 * a sharetab in memory if we need one. 388*3957Sth199096 */ 389*3957Sth199096 rw_enter(&sharetab_lock, RW_READER); 390*3957Sth199096 switch (opcode) { 391*3957Sth199096 case (SHAREFS_REMOVE) : 392*3957Sth199096 case (SHAREFS_REPLACE) : 393*3957Sth199096 if (!sharefs_sharetab) { 394*3957Sth199096 rw_exit(&sharetab_lock); 395*3957Sth199096 return (set_errno(ENOENT)); 396*3957Sth199096 } 397*3957Sth199096 break; 398*3957Sth199096 case (SHAREFS_ADD) : 399*3957Sth199096 default : 400*3957Sth199096 break; 401*3957Sth199096 } 402*3957Sth199096 rw_exit(&sharetab_lock); 403*3957Sth199096 404*3957Sth199096 model = get_udatamodel(); 405*3957Sth199096 406*3957Sth199096 /* 407*3957Sth199096 * Initialize the data pointers. 408*3957Sth199096 */ 409*3957Sth199096 STRUCT_INIT(u_sh, model); 410*3957Sth199096 if (copyin(sh_in, STRUCT_BUF(u_sh), 411*3957Sth199096 STRUCT_SIZE(u_sh))) { 412*3957Sth199096 return (set_errno(EFAULT)); 413*3957Sth199096 } 414*3957Sth199096 415*3957Sth199096 /* 416*3957Sth199096 * Get the share. 417*3957Sth199096 */ 418*3957Sth199096 sh = kmem_zalloc(sizeof (share_t), KM_SLEEP); 419*3957Sth199096 420*3957Sth199096 /* 421*3957Sth199096 * Get some storage for copying in the strings. 422*3957Sth199096 */ 423*3957Sth199096 buf = kmem_zalloc(bufsz + 1, KM_SLEEP); 424*3957Sth199096 bzero(&shl, sizeof (sharefs_lens_t)); 425*3957Sth199096 426*3957Sth199096 /* 427*3957Sth199096 * Only grab these two until we know what we want. 428*3957Sth199096 */ 429*3957Sth199096 SHARETAB_COPYIN(path); 430*3957Sth199096 SHARETAB_COPYIN(fstype); 431*3957Sth199096 432*3957Sth199096 switch (opcode) { 433*3957Sth199096 case (SHAREFS_ADD) : 434*3957Sth199096 case (SHAREFS_REPLACE) : 435*3957Sth199096 SHARETAB_COPYIN(res); 436*3957Sth199096 SHARETAB_COPYIN(opts); 437*3957Sth199096 SHARETAB_COPYIN(descr); 438*3957Sth199096 439*3957Sth199096 error = sharefs_add(sh, &shl); 440*3957Sth199096 break; 441*3957Sth199096 442*3957Sth199096 case (SHAREFS_REMOVE) : 443*3957Sth199096 444*3957Sth199096 error = sharefs_remove(sh, &shl); 445*3957Sth199096 break; 446*3957Sth199096 447*3957Sth199096 default: 448*3957Sth199096 error = EINVAL; 449*3957Sth199096 break; 450*3957Sth199096 } 451*3957Sth199096 452*3957Sth199096 cleanup: 453*3957Sth199096 454*3957Sth199096 /* 455*3957Sth199096 * If there is no error, then we have stashed the structure 456*3957Sth199096 * away in the sharetab hash table or have deleted it. 457*3957Sth199096 * 458*3957Sth199096 * Either way, the only reason to blow away the data is if 459*3957Sth199096 * there was an error. 460*3957Sth199096 */ 461*3957Sth199096 if (error != 0) { 462*3957Sth199096 sharefree(sh, &shl); 463*3957Sth199096 } 464*3957Sth199096 465*3957Sth199096 if (buf) { 466*3957Sth199096 kmem_free(buf, bufsz + 1); 467*3957Sth199096 } 468*3957Sth199096 469*3957Sth199096 return ((error != 0) ? set_errno(error) : 0); 470*3957Sth199096 } 471