13957Sth199096 /* 23957Sth199096 * CDDL HEADER START 33957Sth199096 * 43957Sth199096 * The contents of this file are subject to the terms of the 53957Sth199096 * Common Development and Distribution License (the "License"). 63957Sth199096 * You may not use this file except in compliance with the License. 73957Sth199096 * 83957Sth199096 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93957Sth199096 * or http://www.opensolaris.org/os/licensing. 103957Sth199096 * See the License for the specific language governing permissions 113957Sth199096 * and limitations under the License. 123957Sth199096 * 133957Sth199096 * When distributing Covered Code, include this CDDL HEADER in each 143957Sth199096 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153957Sth199096 * If applicable, add the following below this CDDL HEADER, with the 163957Sth199096 * fields enclosed by brackets "[]" replaced with your own identifying 173957Sth199096 * information: Portions Copyright [yyyy] [name of copyright owner] 183957Sth199096 * 193957Sth199096 * CDDL HEADER END 203957Sth199096 */ 213957Sth199096 223957Sth199096 /* 23*12679SPavel.Filipensky@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 243957Sth199096 */ 253957Sth199096 263957Sth199096 #include <sys/types.h> 273957Sth199096 #include <sys/types32.h> 283957Sth199096 #include <sys/param.h> 293957Sth199096 #include <sys/systm.h> 303957Sth199096 #include <rpc/types.h> 313957Sth199096 #include <sys/vfs.h> 323957Sth199096 #include <sys/siginfo.h> 333957Sth199096 #include <sys/proc.h> /* for exit() declaration */ 343957Sth199096 #include <sys/kmem.h> 353957Sth199096 #include <sys/pathname.h> 363957Sth199096 #include <sys/debug.h> 373957Sth199096 #include <sys/vtrace.h> 383957Sth199096 #include <sys/cmn_err.h> 393957Sth199096 #include <sys/atomic.h> 404543Smarks #include <sys/policy.h> 413957Sth199096 423957Sth199096 #include <sharefs/sharefs.h> 433957Sth199096 443957Sth199096 /* 453957Sth199096 * A macro to avoid cut-and-paste errors on getting a string field 463957Sth199096 * from user-land. 473957Sth199096 */ 483957Sth199096 #define SHARETAB_COPYIN(field) \ 493957Sth199096 if (copyinstr(STRUCT_FGETP(u_sh, sh_##field), \ 503957Sth199096 buf, \ 513957Sth199096 bufsz + 1, /* Add one for extra NUL */ \ 523957Sth199096 &len)) { \ 533957Sth199096 error = EFAULT; \ 543957Sth199096 goto cleanup; \ 553957Sth199096 } \ 563957Sth199096 /* \ 573957Sth199096 * Need to remove 1 because copyinstr() counts the NUL. \ 583957Sth199096 */ \ 593957Sth199096 len--; \ 603957Sth199096 sh->sh_##field = kmem_alloc(len + 1, KM_SLEEP); \ 613957Sth199096 bcopy(buf, sh->sh_##field, len); \ 623957Sth199096 sh->sh_##field[len] = '\0'; \ 633957Sth199096 shl.shl_##field = (int)len; \ 643957Sth199096 sh->sh_size += shl.shl_##field; /* Debug counting */ 653957Sth199096 663957Sth199096 #define SHARETAB_DELETE_FIELD(field) \ 673957Sth199096 if (sh->sh_##field) { \ 683957Sth199096 kmem_free(sh->sh_##field, \ 693957Sth199096 shl ? shl->shl_##field + 1 : \ 703957Sth199096 strlen(sh->sh_##field) + 1); \ 713957Sth199096 } 723957Sth199096 733957Sth199096 sharetab_t *sharefs_sharetab = NULL; /* The incore sharetab. */ 743957Sth199096 size_t sharetab_size; 753957Sth199096 uint_t sharetab_count; 763957Sth199096 773957Sth199096 krwlock_t sharetab_lock; /* lock to protect the cached sharetab */ 783957Sth199096 793957Sth199096 krwlock_t sharefs_lock; /* lock to protect the vnode ops */ 803957Sth199096 813957Sth199096 timestruc_t sharetab_mtime; 823957Sth199096 timestruc_t sharetab_snap_time; 833957Sth199096 843957Sth199096 uint_t sharetab_generation; /* Only increments and wraps! */ 853957Sth199096 863957Sth199096 /* 873957Sth199096 * Take care of cleaning up a share. 883957Sth199096 * If passed in a length array, use it to determine how much 893957Sth199096 * space to clean up. Else, figure that out. 903957Sth199096 */ 913957Sth199096 static void 923957Sth199096 sharefree(share_t *sh, sharefs_lens_t *shl) 933957Sth199096 { 943957Sth199096 if (!sh) 953957Sth199096 return; 963957Sth199096 973957Sth199096 SHARETAB_DELETE_FIELD(path); 983957Sth199096 SHARETAB_DELETE_FIELD(res); 993957Sth199096 SHARETAB_DELETE_FIELD(fstype); 1003957Sth199096 SHARETAB_DELETE_FIELD(opts); 1013957Sth199096 SHARETAB_DELETE_FIELD(descr); 1023957Sth199096 1033957Sth199096 kmem_free(sh, sizeof (share_t)); 1043957Sth199096 } 1053957Sth199096 1063957Sth199096 /* 1073957Sth199096 * If there is no error, then this function is responsible for 1083957Sth199096 * cleaning up the memory associated with the share argument. 1093957Sth199096 */ 1103957Sth199096 static int 1113957Sth199096 sharefs_remove(share_t *sh, sharefs_lens_t *shl) 1123957Sth199096 { 1133957Sth199096 int iHash; 1143957Sth199096 sharetab_t *sht; 1153957Sth199096 share_t *s, *p; 1163957Sth199096 int iPath; 1173957Sth199096 1183957Sth199096 if (!sh) 1193957Sth199096 return (ENOENT); 1203957Sth199096 1213957Sth199096 rw_enter(&sharetab_lock, RW_WRITER); 1223957Sth199096 for (sht = sharefs_sharetab; sht != NULL; sht = sht->s_next) { 1233957Sth199096 if (strcmp(sh->sh_fstype, sht->s_fstype) == 0) { 1243957Sth199096 break; 1253957Sth199096 } 1263957Sth199096 } 1273957Sth199096 1283957Sth199096 /* 1293957Sth199096 * There does not exist a fstype in memory which 1303957Sth199096 * matches the share passed in. 1313957Sth199096 */ 1323957Sth199096 if (!sht) { 1333957Sth199096 rw_exit(&sharetab_lock); 1343957Sth199096 return (ENOENT); 1353957Sth199096 } 1363957Sth199096 1373957Sth199096 iPath = shl ? shl->shl_path : strlen(sh->sh_path); 138*12679SPavel.Filipensky@Sun.COM iHash = pkp_tab_hash(sh->sh_path, strlen(sh->sh_path)); 1393957Sth199096 1403957Sth199096 /* 1413957Sth199096 * Now walk down the hash table and find the entry to free! 1423957Sth199096 */ 1433957Sth199096 for (p = NULL, s = sht->s_buckets[iHash].ssh_sh; 1444543Smarks s != NULL; s = s->sh_next) { 1453957Sth199096 /* 1463957Sth199096 * We need exact matches. 1473957Sth199096 */ 1483957Sth199096 if (strcmp(sh->sh_path, s->sh_path) == 0 && 1494543Smarks strlen(s->sh_path) == iPath) { 1503957Sth199096 if (p) { 1513957Sth199096 p->sh_next = s->sh_next; 1523957Sth199096 } else { 1533957Sth199096 sht->s_buckets[iHash].ssh_sh = s->sh_next; 1543957Sth199096 } 1553957Sth199096 1563957Sth199096 ASSERT(sht->s_buckets[iHash].ssh_count != 0); 1573957Sth199096 atomic_add_32(&sht->s_buckets[iHash].ssh_count, -1); 1583957Sth199096 atomic_add_32(&sht->s_count, -1); 1593957Sth199096 atomic_add_32(&sharetab_count, -1); 1603957Sth199096 1613957Sth199096 ASSERT(sharetab_size >= s->sh_size); 1623957Sth199096 sharetab_size -= s->sh_size; 1633957Sth199096 1643957Sth199096 gethrestime(&sharetab_mtime); 1653957Sth199096 atomic_add_32(&sharetab_generation, 1); 1663957Sth199096 1673957Sth199096 break; 1683957Sth199096 } 1693957Sth199096 1703957Sth199096 p = s; 1713957Sth199096 } 1723957Sth199096 1733957Sth199096 rw_exit(&sharetab_lock); 1743957Sth199096 1753957Sth199096 if (!s) { 1763957Sth199096 return (ENOENT); 1773957Sth199096 } 1783957Sth199096 1793957Sth199096 s->sh_next = NULL; 1803957Sth199096 sharefree(s, NULL); 1813957Sth199096 1823957Sth199096 /* 1833957Sth199096 * We need to free the share for the caller. 1843957Sth199096 */ 1853957Sth199096 sharefree(sh, shl); 1863957Sth199096 1873957Sth199096 return (0); 1883957Sth199096 } 1893957Sth199096 1903957Sth199096 /* 1913957Sth199096 * The caller must have allocated memory for us to use. 1923957Sth199096 */ 1933957Sth199096 static int 1943957Sth199096 sharefs_add(share_t *sh, sharefs_lens_t *shl) 1953957Sth199096 { 1963957Sth199096 int iHash; 1973957Sth199096 sharetab_t *sht; 1983957Sth199096 share_t *s, *p; 1993957Sth199096 int iPath; 2003957Sth199096 int n; 2013957Sth199096 2023957Sth199096 if (!sh) { 2033957Sth199096 return (ENOENT); 2043957Sth199096 } 2053957Sth199096 2063957Sth199096 /* 2073957Sth199096 * We need to find the hash buckets for the fstype. 2083957Sth199096 */ 2093957Sth199096 rw_enter(&sharetab_lock, RW_WRITER); 2103957Sth199096 for (sht = sharefs_sharetab; sht != NULL; sht = sht->s_next) { 2113957Sth199096 if (strcmp(sh->sh_fstype, sht->s_fstype) == 0) { 2123957Sth199096 break; 2133957Sth199096 } 2143957Sth199096 } 2153957Sth199096 2163957Sth199096 /* 2173957Sth199096 * Did not exist, so allocate one and add it to the 2183957Sth199096 * sharetab. 2193957Sth199096 */ 2203957Sth199096 if (!sht) { 2213957Sth199096 sht = kmem_zalloc(sizeof (*sht), KM_SLEEP); 2223957Sth199096 n = strlen(sh->sh_fstype); 2233957Sth199096 sht->s_fstype = kmem_zalloc(n + 1, KM_SLEEP); 2243957Sth199096 (void) strncpy(sht->s_fstype, sh->sh_fstype, n); 2253957Sth199096 2263957Sth199096 sht->s_next = sharefs_sharetab; 2273957Sth199096 sharefs_sharetab = sht; 2283957Sth199096 } 2293957Sth199096 2303957Sth199096 /* 2313957Sth199096 * Now we need to find where we have to add the entry. 2323957Sth199096 */ 233*12679SPavel.Filipensky@Sun.COM iHash = pkp_tab_hash(sh->sh_path, strlen(sh->sh_path)); 2343957Sth199096 2353957Sth199096 iPath = shl ? shl->shl_path : strlen(sh->sh_path); 2363957Sth199096 2373957Sth199096 if (shl) { 2383957Sth199096 sh->sh_size = shl->shl_path + shl->shl_res + 2394543Smarks shl->shl_fstype + shl->shl_opts + shl->shl_descr; 2403957Sth199096 } else { 2413957Sth199096 sh->sh_size = strlen(sh->sh_path) + 2424543Smarks strlen(sh->sh_res) + strlen(sh->sh_fstype) + 2434543Smarks strlen(sh->sh_opts) + strlen(sh->sh_descr); 2443957Sth199096 } 2453957Sth199096 2463957Sth199096 /* 2473957Sth199096 * We need to account for field seperators and 2483957Sth199096 * the EOL. 2493957Sth199096 */ 2503957Sth199096 sh->sh_size += 5; 2513957Sth199096 2523957Sth199096 /* 2533957Sth199096 * Now walk down the hash table and add the new entry! 2543957Sth199096 */ 2553957Sth199096 for (p = NULL, s = sht->s_buckets[iHash].ssh_sh; 2564543Smarks s != NULL; s = s->sh_next) { 2573957Sth199096 /* 2583957Sth199096 * We need exact matches. 2593957Sth199096 * 2603957Sth199096 * We found a matching path. Either we have a 2613957Sth199096 * duplicate path in a share command or we are 2623957Sth199096 * being asked to replace an existing entry. 2633957Sth199096 */ 2643957Sth199096 if (strcmp(sh->sh_path, s->sh_path) == 0 && 2654543Smarks strlen(s->sh_path) == iPath) { 2663957Sth199096 if (p) { 2673957Sth199096 p->sh_next = sh; 2683957Sth199096 } else { 2693957Sth199096 sht->s_buckets[iHash].ssh_sh = sh; 2703957Sth199096 } 2713957Sth199096 2723957Sth199096 sh->sh_next = s->sh_next; 2733957Sth199096 2743957Sth199096 ASSERT(sharetab_size >= s->sh_size); 2753957Sth199096 sharetab_size -= s->sh_size; 2763957Sth199096 sharetab_size += sh->sh_size; 2773957Sth199096 2783957Sth199096 /* 2793957Sth199096 * Get rid of the old node. 2803957Sth199096 */ 2813957Sth199096 sharefree(s, NULL); 2823957Sth199096 2833957Sth199096 gethrestime(&sharetab_mtime); 2843957Sth199096 atomic_add_32(&sharetab_generation, 1); 2853957Sth199096 2863957Sth199096 ASSERT(sht->s_buckets[iHash].ssh_count != 0); 2873957Sth199096 rw_exit(&sharetab_lock); 2883957Sth199096 2893957Sth199096 return (0); 2903957Sth199096 } 2913957Sth199096 2923957Sth199096 p = s; 2933957Sth199096 } 2943957Sth199096 2953957Sth199096 /* 2963957Sth199096 * Okay, we have gone through the entire hash chain and not 2973957Sth199096 * found a match. We just need to add this node. 2983957Sth199096 */ 2993957Sth199096 sh->sh_next = sht->s_buckets[iHash].ssh_sh; 3003957Sth199096 sht->s_buckets[iHash].ssh_sh = sh; 3013957Sth199096 atomic_add_32(&sht->s_buckets[iHash].ssh_count, 1); 3023957Sth199096 atomic_add_32(&sht->s_count, 1); 3033957Sth199096 atomic_add_32(&sharetab_count, 1); 3043957Sth199096 sharetab_size += sh->sh_size; 3053957Sth199096 3063957Sth199096 gethrestime(&sharetab_mtime); 3073957Sth199096 atomic_add_32(&sharetab_generation, 1); 3083957Sth199096 3093957Sth199096 rw_exit(&sharetab_lock); 3103957Sth199096 3113957Sth199096 return (0); 3123957Sth199096 } 3133957Sth199096 3143957Sth199096 void 3153957Sth199096 sharefs_sharetab_init(void) 3163957Sth199096 { 3173957Sth199096 rw_init(&sharetab_lock, NULL, RW_DEFAULT, NULL); 3183957Sth199096 rw_init(&sharefs_lock, NULL, RW_DEFAULT, NULL); 3193957Sth199096 3203957Sth199096 sharetab_size = 0; 3213957Sth199096 sharetab_count = 0; 3223957Sth199096 sharetab_generation = 1; 3233957Sth199096 3243957Sth199096 gethrestime(&sharetab_mtime); 3253957Sth199096 gethrestime(&sharetab_snap_time); 3263957Sth199096 } 3273957Sth199096 3283957Sth199096 int 3294543Smarks sharefs_impl(enum sharefs_sys_op opcode, share_t *sh_in, uint32_t iMaxLen) 3303957Sth199096 { 3313957Sth199096 int error = 0; 3323957Sth199096 size_t len; 3333957Sth199096 size_t bufsz; 3343957Sth199096 share_t *sh; 3353957Sth199096 3363957Sth199096 sharefs_lens_t shl; 3373957Sth199096 3383957Sth199096 model_t model; 3393957Sth199096 3403957Sth199096 char *buf = NULL; 3413957Sth199096 3423957Sth199096 STRUCT_DECL(share, u_sh); 3433957Sth199096 3443957Sth199096 bufsz = iMaxLen; 3453957Sth199096 3463957Sth199096 /* 3473957Sth199096 * Before we do anything, lets make sure we have 3483957Sth199096 * a sharetab in memory if we need one. 3493957Sth199096 */ 3503957Sth199096 rw_enter(&sharetab_lock, RW_READER); 3513957Sth199096 switch (opcode) { 3523957Sth199096 case (SHAREFS_REMOVE) : 3533957Sth199096 case (SHAREFS_REPLACE) : 3543957Sth199096 if (!sharefs_sharetab) { 3553957Sth199096 rw_exit(&sharetab_lock); 3563957Sth199096 return (set_errno(ENOENT)); 3573957Sth199096 } 3583957Sth199096 break; 3593957Sth199096 case (SHAREFS_ADD) : 3603957Sth199096 default : 3613957Sth199096 break; 3623957Sth199096 } 3633957Sth199096 rw_exit(&sharetab_lock); 3643957Sth199096 3653957Sth199096 model = get_udatamodel(); 3663957Sth199096 3673957Sth199096 /* 3683957Sth199096 * Initialize the data pointers. 3693957Sth199096 */ 3703957Sth199096 STRUCT_INIT(u_sh, model); 3714543Smarks if (copyin(sh_in, STRUCT_BUF(u_sh), STRUCT_SIZE(u_sh))) { 3723957Sth199096 return (set_errno(EFAULT)); 3733957Sth199096 } 3743957Sth199096 3753957Sth199096 /* 3763957Sth199096 * Get the share. 3773957Sth199096 */ 3783957Sth199096 sh = kmem_zalloc(sizeof (share_t), KM_SLEEP); 3793957Sth199096 3803957Sth199096 /* 3813957Sth199096 * Get some storage for copying in the strings. 3823957Sth199096 */ 3833957Sth199096 buf = kmem_zalloc(bufsz + 1, KM_SLEEP); 3843957Sth199096 bzero(&shl, sizeof (sharefs_lens_t)); 3853957Sth199096 3863957Sth199096 /* 3873957Sth199096 * Only grab these two until we know what we want. 3883957Sth199096 */ 3893957Sth199096 SHARETAB_COPYIN(path); 3903957Sth199096 SHARETAB_COPYIN(fstype); 3913957Sth199096 3923957Sth199096 switch (opcode) { 3933957Sth199096 case (SHAREFS_ADD) : 3943957Sth199096 case (SHAREFS_REPLACE) : 3953957Sth199096 SHARETAB_COPYIN(res); 3963957Sth199096 SHARETAB_COPYIN(opts); 3973957Sth199096 SHARETAB_COPYIN(descr); 3983957Sth199096 3993957Sth199096 error = sharefs_add(sh, &shl); 4003957Sth199096 break; 4013957Sth199096 4023957Sth199096 case (SHAREFS_REMOVE) : 4033957Sth199096 4043957Sth199096 error = sharefs_remove(sh, &shl); 4053957Sth199096 break; 4063957Sth199096 4073957Sth199096 default: 4083957Sth199096 error = EINVAL; 4093957Sth199096 break; 4103957Sth199096 } 4113957Sth199096 4123957Sth199096 cleanup: 4133957Sth199096 4143957Sth199096 /* 4153957Sth199096 * If there is no error, then we have stashed the structure 4163957Sth199096 * away in the sharetab hash table or have deleted it. 4173957Sth199096 * 4183957Sth199096 * Either way, the only reason to blow away the data is if 4193957Sth199096 * there was an error. 4203957Sth199096 */ 4213957Sth199096 if (error != 0) { 4223957Sth199096 sharefree(sh, &shl); 4233957Sth199096 } 4243957Sth199096 4253957Sth199096 if (buf) { 4263957Sth199096 kmem_free(buf, bufsz + 1); 4273957Sth199096 } 4283957Sth199096 4293957Sth199096 return ((error != 0) ? set_errno(error) : 0); 4303957Sth199096 } 4314543Smarks 4324543Smarks int 4334543Smarks sharefs(enum sharefs_sys_op opcode, share_t *sh_in, uint32_t iMaxLen) 4344543Smarks { 4354543Smarks if (secpolicy_sys_config(CRED(), B_FALSE) != 0) 4364543Smarks return (set_errno(EPERM)); 4374543Smarks 4384543Smarks return (sharefs_impl(opcode, sh_in, iMaxLen)); 4394543Smarks } 440