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