xref: /illumos-gate/usr/src/uts/common/fs/sharefs/sharetab.c (revision e82e447ac83da0082df4f3e07829e533342ff9ef)
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 }
471