xref: /onnv-gate/usr/src/uts/common/fs/sharefs/sharetab.c (revision 12679:30c794f87c0d)
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
sharefree(share_t * sh,sharefs_lens_t * shl)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
sharefs_remove(share_t * sh,sharefs_lens_t * shl)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
sharefs_add(share_t * sh,sharefs_lens_t * shl)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
sharefs_sharetab_init(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
sharefs_impl(enum sharefs_sys_op opcode,share_t * sh_in,uint32_t iMaxLen)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
sharefs(enum sharefs_sys_op opcode,share_t * sh_in,uint32_t iMaxLen)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