usr/src/uts/common/fs/sharefs/sharetab.c
changeset 3957 86c9dda5df37
child 4543 12bb2876a62e
equal deleted inserted replaced
3956:ea75466401e7 3957:86c9dda5df37
       
     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 
       
    44 #include <sharefs/sharefs.h>
       
    45 
       
    46 /*
       
    47  * A macro to avoid cut-and-paste errors on getting a string field
       
    48  * from user-land.
       
    49  */
       
    50 #define	SHARETAB_COPYIN(field)						\
       
    51 	if (copyinstr(STRUCT_FGETP(u_sh, sh_##field),			\
       
    52 			buf,						\
       
    53 			bufsz + 1,	/* Add one for extra NUL */	\
       
    54 			&len)) {					\
       
    55 		error = EFAULT;						\
       
    56 		goto cleanup;						\
       
    57 	}								\
       
    58 	/*								\
       
    59 	 * Need to remove 1 because copyinstr() counts the NUL.		\
       
    60 	 */								\
       
    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) {						\
       
    70 		kmem_free(sh->sh_##field,				\
       
    71 			shl ? shl->shl_##field + 1 :			\
       
    72 			strlen(sh->sh_##field) + 1);			\
       
    73 	}
       
    74 
       
    75 sharetab_t	*sharefs_sharetab = NULL;	/* The incore sharetab. */
       
    76 size_t		sharetab_size;
       
    77 uint_t		sharetab_count;
       
    78 
       
    79 krwlock_t	sharetab_lock;	/* lock to protect the cached sharetab */
       
    80 
       
    81 krwlock_t	sharefs_lock;	/* lock to protect the vnode ops */
       
    82 
       
    83 timestruc_t	sharetab_mtime;
       
    84 timestruc_t	sharetab_snap_time;
       
    85 
       
    86 uint_t		sharetab_generation;	/* Only increments and wraps! */
       
    87 
       
    88 static uint_t	pkp_tab[SHARETAB_HASHES];
       
    89 
       
    90 /*
       
    91  * Initialize table in pseudo-random fashion
       
    92  * for use in Pearson's string hash algorithm.
       
    93  *
       
    94  * See: Communications of the ACM, June 1990 Vol 33 pp 677-680
       
    95  * http://www.acm.org/pubs/citations/journals/cacm/1990-33-6/p677-pearson
       
    96  */
       
    97 static void
       
    98 init_pkp_tab(void)
       
    99 {
       
   100 	int	i;
       
   101 	int	j;
       
   102 	int	k = 7;
       
   103 	uint_t	s;
       
   104 
       
   105 	for (i = 0; i < SHARETAB_HASHES; i++)
       
   106 		pkp_tab[i] = i;
       
   107 
       
   108 	for (j = 0; j < 4; j++) {
       
   109 		for (i = 0; i < SHARETAB_HASHES; i++) {
       
   110 			s = pkp_tab[i];
       
   111 			k = MOD2((k + s), SHARETAB_HASHES);
       
   112 			pkp_tab[i] = pkp_tab[k];
       
   113 			pkp_tab[k] = s;
       
   114 		}
       
   115 	}
       
   116 }
       
   117 
       
   118 /*
       
   119  * Take care of cleaning up a share.
       
   120  * If passed in a length array, use it to determine how much
       
   121  * space to clean up. Else, figure that out.
       
   122  */
       
   123 static void
       
   124 sharefree(share_t *sh, sharefs_lens_t *shl)
       
   125 {
       
   126 	if (!sh)
       
   127 		return;
       
   128 
       
   129 	SHARETAB_DELETE_FIELD(path);
       
   130 	SHARETAB_DELETE_FIELD(res);
       
   131 	SHARETAB_DELETE_FIELD(fstype);
       
   132 	SHARETAB_DELETE_FIELD(opts);
       
   133 	SHARETAB_DELETE_FIELD(descr);
       
   134 
       
   135 	kmem_free(sh, sizeof (share_t));
       
   136 }
       
   137 
       
   138 /*
       
   139  * If there is no error, then this function is responsible for
       
   140  * cleaning up the memory associated with the share argument.
       
   141  */
       
   142 static int
       
   143 sharefs_remove(share_t *sh, sharefs_lens_t *shl)
       
   144 {
       
   145 	int		iHash;
       
   146 	sharetab_t	*sht;
       
   147 	share_t		*s, *p;
       
   148 	int		iPath;
       
   149 
       
   150 	if (!sh)
       
   151 		return (ENOENT);
       
   152 
       
   153 	rw_enter(&sharetab_lock, RW_WRITER);
       
   154 	for (sht = sharefs_sharetab; sht != NULL; sht = sht->s_next) {
       
   155 		if (strcmp(sh->sh_fstype, sht->s_fstype) == 0) {
       
   156 			break;
       
   157 		}
       
   158 	}
       
   159 
       
   160 	/*
       
   161 	 * There does not exist a fstype in memory which
       
   162 	 * matches the share passed in.
       
   163 	 */
       
   164 	if (!sht) {
       
   165 		rw_exit(&sharetab_lock);
       
   166 		return (ENOENT);
       
   167 	}
       
   168 
       
   169 	iPath = shl ? shl->shl_path : strlen(sh->sh_path);
       
   170 	SHARETAB_HASH_IT(iHash, sh->sh_path);
       
   171 
       
   172 	/*
       
   173 	 * Now walk down the hash table and find the entry to free!
       
   174 	 */
       
   175 	for (p = NULL, s = sht->s_buckets[iHash].ssh_sh;
       
   176 			s != NULL;
       
   177 			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 +
       
   273 			shl->shl_descr;
       
   274 	} else {
       
   275 		sh->sh_size = strlen(sh->sh_path) +
       
   276 			strlen(sh->sh_res) +
       
   277 			strlen(sh->sh_fstype) +
       
   278 			strlen(sh->sh_opts) +
       
   279 			strlen(sh->sh_descr);
       
   280 	}
       
   281 
       
   282 	/*
       
   283 	 * We need to account for field seperators and
       
   284 	 * the EOL.
       
   285 	 */
       
   286 	sh->sh_size += 5;
       
   287 
       
   288 	/*
       
   289 	 * Now walk down the hash table and add the new entry!
       
   290 	 */
       
   291 	for (p = NULL, s = sht->s_buckets[iHash].ssh_sh;
       
   292 			s != NULL;
       
   293 			s = s->sh_next) {
       
   294 		/*
       
   295 		 * We need exact matches.
       
   296 		 *
       
   297 		 * We found a matching path. Either we have a
       
   298 		 * duplicate path in a share command or we are
       
   299 		 * being asked to replace an existing entry.
       
   300 		 */
       
   301 		if (strcmp(sh->sh_path, s->sh_path) == 0 &&
       
   302 				strlen(s->sh_path) == iPath) {
       
   303 			if (p) {
       
   304 				p->sh_next = sh;
       
   305 			} else {
       
   306 				sht->s_buckets[iHash].ssh_sh = sh;
       
   307 			}
       
   308 
       
   309 			sh->sh_next = s->sh_next;
       
   310 
       
   311 			ASSERT(sharetab_size >= s->sh_size);
       
   312 			sharetab_size -= s->sh_size;
       
   313 			sharetab_size += sh->sh_size;
       
   314 
       
   315 			/*
       
   316 			 * Get rid of the old node.
       
   317 			 */
       
   318 			sharefree(s, NULL);
       
   319 
       
   320 			gethrestime(&sharetab_mtime);
       
   321 			atomic_add_32(&sharetab_generation, 1);
       
   322 
       
   323 			ASSERT(sht->s_buckets[iHash].ssh_count != 0);
       
   324 			rw_exit(&sharetab_lock);
       
   325 
       
   326 			return (0);
       
   327 		}
       
   328 
       
   329 		p = s;
       
   330 	}
       
   331 
       
   332 	/*
       
   333 	 * Okay, we have gone through the entire hash chain and not
       
   334 	 * found a match. We just need to add this node.
       
   335 	 */
       
   336 	sh->sh_next = sht->s_buckets[iHash].ssh_sh;
       
   337 	sht->s_buckets[iHash].ssh_sh = sh;
       
   338 	atomic_add_32(&sht->s_buckets[iHash].ssh_count, 1);
       
   339 	atomic_add_32(&sht->s_count, 1);
       
   340 	atomic_add_32(&sharetab_count, 1);
       
   341 	sharetab_size += sh->sh_size;
       
   342 
       
   343 	gethrestime(&sharetab_mtime);
       
   344 	atomic_add_32(&sharetab_generation, 1);
       
   345 
       
   346 	rw_exit(&sharetab_lock);
       
   347 
       
   348 	return (0);
       
   349 }
       
   350 
       
   351 void
       
   352 sharefs_sharetab_init(void)
       
   353 {
       
   354 	init_pkp_tab();
       
   355 
       
   356 	rw_init(&sharetab_lock, NULL, RW_DEFAULT, NULL);
       
   357 	rw_init(&sharefs_lock, NULL, RW_DEFAULT, NULL);
       
   358 
       
   359 	sharetab_size = 0;
       
   360 	sharetab_count = 0;
       
   361 	sharetab_generation = 1;
       
   362 
       
   363 	gethrestime(&sharetab_mtime);
       
   364 	gethrestime(&sharetab_snap_time);
       
   365 }
       
   366 
       
   367 int
       
   368 sharefs(enum sharefs_sys_op opcode, share_t *sh_in, uint32_t iMaxLen)
       
   369 {
       
   370 	int		error = 0;
       
   371 	size_t		len;
       
   372 	size_t		bufsz;
       
   373 	share_t		*sh;
       
   374 
       
   375 	sharefs_lens_t	shl;
       
   376 
       
   377 	model_t		model;
       
   378 
       
   379 	char		*buf = NULL;
       
   380 
       
   381 	STRUCT_DECL(share, u_sh);
       
   382 
       
   383 	bufsz = iMaxLen;
       
   384 
       
   385 	/*
       
   386 	 * Before we do anything, lets make sure we have
       
   387 	 * a sharetab in memory if we need one.
       
   388 	 */
       
   389 	rw_enter(&sharetab_lock, RW_READER);
       
   390 	switch (opcode) {
       
   391 	case (SHAREFS_REMOVE) :
       
   392 	case (SHAREFS_REPLACE) :
       
   393 		if (!sharefs_sharetab) {
       
   394 			rw_exit(&sharetab_lock);
       
   395 			return (set_errno(ENOENT));
       
   396 		}
       
   397 		break;
       
   398 	case (SHAREFS_ADD) :
       
   399 	default :
       
   400 		break;
       
   401 	}
       
   402 	rw_exit(&sharetab_lock);
       
   403 
       
   404 	model = get_udatamodel();
       
   405 
       
   406 	/*
       
   407 	 * Initialize the data pointers.
       
   408 	 */
       
   409 	STRUCT_INIT(u_sh, model);
       
   410 	if (copyin(sh_in, STRUCT_BUF(u_sh),
       
   411 			STRUCT_SIZE(u_sh))) {
       
   412 		return (set_errno(EFAULT));
       
   413 	}
       
   414 
       
   415 	/*
       
   416 	 * Get the share.
       
   417 	 */
       
   418 	sh = kmem_zalloc(sizeof (share_t), KM_SLEEP);
       
   419 
       
   420 	/*
       
   421 	 * Get some storage for copying in the strings.
       
   422 	 */
       
   423 	buf = kmem_zalloc(bufsz + 1, KM_SLEEP);
       
   424 	bzero(&shl, sizeof (sharefs_lens_t));
       
   425 
       
   426 	/*
       
   427 	 * Only grab these two until we know what we want.
       
   428 	 */
       
   429 	SHARETAB_COPYIN(path);
       
   430 	SHARETAB_COPYIN(fstype);
       
   431 
       
   432 	switch (opcode) {
       
   433 	case (SHAREFS_ADD) :
       
   434 	case (SHAREFS_REPLACE) :
       
   435 		SHARETAB_COPYIN(res);
       
   436 		SHARETAB_COPYIN(opts);
       
   437 		SHARETAB_COPYIN(descr);
       
   438 
       
   439 		error = sharefs_add(sh, &shl);
       
   440 		break;
       
   441 
       
   442 	case (SHAREFS_REMOVE) :
       
   443 
       
   444 		error = sharefs_remove(sh, &shl);
       
   445 		break;
       
   446 
       
   447 	default:
       
   448 		error = EINVAL;
       
   449 		break;
       
   450 	}
       
   451 
       
   452 cleanup:
       
   453 
       
   454 	/*
       
   455 	 * If there is no error, then we have stashed the structure
       
   456 	 * away in the sharetab hash table or have deleted it.
       
   457 	 *
       
   458 	 * Either way, the only reason to blow away the data is if
       
   459 	 * there was an error.
       
   460 	 */
       
   461 	if (error != 0) {
       
   462 		sharefree(sh, &shl);
       
   463 	}
       
   464 
       
   465 	if (buf) {
       
   466 		kmem_free(buf, bufsz + 1);
       
   467 	}
       
   468 
       
   469 	return ((error != 0) ? set_errno(error) : 0);
       
   470 }