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