xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs_export.c (revision a7123019ed2e4decef929dc2e426f3f310788fa1)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  *  	Copyright 1983, 1984, 1985, 1986, 1987, 1988, 1989  AT&T.
29  *		All rights reserved.
30  */
31 
32 
33 #pragma ident	"%Z%%M%	%I%	%E% SMI"
34 
35 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <sys/time.h>
38 #include <sys/vfs.h>
39 #include <sys/vnode.h>
40 #include <sys/socket.h>
41 #include <sys/errno.h>
42 #include <sys/uio.h>
43 #include <sys/proc.h>
44 #include <sys/user.h>
45 #include <sys/file.h>
46 #include <sys/tiuser.h>
47 #include <sys/kmem.h>
48 #include <sys/pathname.h>
49 #include <sys/debug.h>
50 #include <sys/vtrace.h>
51 #include <sys/cmn_err.h>
52 #include <sys/acl.h>
53 #include <sys/utsname.h>
54 #include <netinet/in.h>
55 
56 #include <rpc/types.h>
57 #include <rpc/auth.h>
58 #include <rpc/svc.h>
59 
60 #include <nfs/nfs.h>
61 #include <nfs/export.h>
62 #include <nfs/nfssys.h>
63 #include <nfs/nfs_clnt.h>
64 #include <nfs/nfs_acl.h>
65 #include <nfs/nfs_log.h>
66 #include <nfs/lm.h>
67 
68 #define	EXPTABLESIZE 16
69 
70 struct exportinfo *exptable[EXPTABLESIZE];
71 
72 static int	unexport(fsid_t *, fid_t *, vnode_t *);
73 static void	exportfree(struct exportinfo *);
74 static int	loadindex(struct exportdata *);
75 
76 extern void	nfsauth_cache_free(struct exportinfo *);
77 extern int	sec_svc_loadrootnames(int, int, caddr_t **, model_t);
78 extern void	sec_svc_freerootnames(int, int, caddr_t *);
79 
80 #ifdef VOLATILE_FH_TEST
81 static struct ex_vol_rename *find_volrnm_fh(struct exportinfo *, nfs_fh4 *);
82 static uint32_t find_volrnm_fh_id(struct exportinfo *, nfs_fh4 *);
83 static void free_volrnm_list(struct exportinfo *);
84 #endif /* VOLATILE_FH_TEST */
85 
86 /*
87  * exported_lock	Read/Write lock that protects the exportinfo list.
88  *			This lock must be held when searching or modifiying
89  *			the exportinfo list.
90  */
91 krwlock_t exported_lock;
92 
93 /*
94  * "public" and default (root) location for public filehandle
95  */
96 struct exportinfo *exi_public, *exi_root;
97 
98 fid_t exi_rootfid;	/* for checking the default public file handle */
99 
100 fhandle_t nullfh2;	/* for comparing V2 filehandles */
101 
102 #define	exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1))
103 
104 /*
105  * File handle hash function, good for producing hash values 16 bits wide.
106  */
107 int
108 nfs_fhhash(fsid_t *fsid, fid_t *fid)
109 {
110 	short *data;
111 	int i, len;
112 	short h;
113 
114 	ASSERT(fid != NULL);
115 
116 	data = (short *)fid->fid_data;
117 
118 	/* fid_data must be aligned on a short */
119 	ASSERT((((uintptr_t)data) & (sizeof (short) - 1)) == 0);
120 
121 	if (fid->fid_len == 10) {
122 		/*
123 		 * probably ufs: hash on bytes 4,5 and 8,9
124 		 */
125 		return (fsid->val[0] ^ data[2] ^ data[4]);
126 	}
127 
128 	if (fid->fid_len == 6) {
129 		/*
130 		 * probably hsfs: hash on bytes 0,1 and 4,5
131 		 */
132 		return ((fsid->val[0] ^ data[0] ^ data[2]));
133 	}
134 
135 	/*
136 	 * Some other file system. Assume that every byte is
137 	 * worth hashing.
138 	 */
139 	h = (short)fsid->val[0];
140 
141 	/*
142 	 * Sanity check the length before using it
143 	 * blindly in case the client trashed it.
144 	 */
145 	if (fid->fid_len > NFS_FHMAXDATA)
146 		len = 0;
147 	else
148 		len = fid->fid_len / sizeof (short);
149 
150 	/*
151 	 * This will ignore one byte if len is not a multiple of
152 	 * of sizeof (short). No big deal since we at least get some
153 	 * variation with fsid->val[0];
154 	 */
155 	for (i = 0; i < len; i++)
156 		h ^= data[i];
157 
158 	return ((int)h);
159 }
160 
161 /*
162  * Counted byte string compare routine, optimized for file ids.
163  */
164 int
165 nfs_fhbcmp(char *d1, char *d2, int l)
166 {
167 	int k;
168 
169 	if (l > NFS_FHMAXDATA)
170 		return (1);
171 
172 	/*
173 	 * We are always passed pointers to the data portions of
174 	 * two fids, where pointers are always 2 bytes from 32 bit
175 	 * alignment. If the length is also 2 bytes off word alignment,
176 	 * we can do word compares, because the two bytes before the fid
177 	 * data are always the length packed into a 16 bit short, so we
178 	 * can safely start our comparisons at d1-2 and d2-2.
179 	 * If the length is 2 bytes off word alignment, that probably
180 	 * means that first two bytes are zeroes. This means that
181 	 * first word in each fid, including the length are going to be
182 	 * equal (we wouldn't call fhbcmp if the lengths weren't the
183 	 * same). Thus it makes the most sense to start comparing the
184 	 * last words of each data portion.
185 	 */
186 
187 	if ((l & 0x3) == 2) {
188 		/*
189 		 * We are going move the data pointers to the
190 		 * last word. Adding just the length, puts us to the
191 		 * word past end of the data. So reduce length by one
192 		 * word length.
193 		 */
194 		k = l - 4;
195 		/*
196 		 * Both adjusted length and the data pointer are offset two
197 		 * bytes from word alignment. Adding them together gives
198 		 * us word alignment.
199 		 */
200 		d1 += k;
201 		d2 += k;
202 		l += 2;
203 		while (l -= 4) {
204 			if (*(int *)d1 != *(int *)d2)
205 				return (1);
206 			d1 -= 4;
207 			d2 -= 4;
208 		}
209 	} else {
210 		while (l--) {
211 			if (*d1++ != *d2++)
212 				return (1);
213 		}
214 	}
215 	return (0);
216 }
217 
218 /*
219  * Free the memory allocated within a secinfo entry.
220  */
221 void
222 srv_secinfo_entry_free(struct secinfo *secp)
223 {
224 	if (secp->s_rootcnt > 0 && secp->s_rootnames != NULL) {
225 		sec_svc_freerootnames(secp->s_secinfo.sc_rpcnum,
226 				secp->s_rootcnt, secp->s_rootnames);
227 		secp->s_rootcnt = 0;
228 	}
229 
230 	if ((secp->s_secinfo.sc_rpcnum == RPCSEC_GSS) &&
231 	    (secp->s_secinfo.sc_gss_mech_type)) {
232 		kmem_free(secp->s_secinfo.sc_gss_mech_type->elements,
233 			secp->s_secinfo.sc_gss_mech_type->length);
234 		kmem_free(secp->s_secinfo.sc_gss_mech_type,
235 			sizeof (rpc_gss_OID_desc));
236 		secp->s_secinfo.sc_gss_mech_type = NULL;
237 	}
238 
239 }
240 
241 /*
242  * Free a list of secinfo allocated in the exportdata structure.
243  */
244 void
245 srv_secinfo_list_free(struct secinfo *secinfo, int cnt)
246 {
247 	int i;
248 
249 	if (cnt == 0)
250 		return;
251 
252 	for (i = 0; i < cnt; i++)
253 		srv_secinfo_entry_free(&secinfo[i]);
254 
255 	kmem_free(secinfo, cnt * sizeof (struct secinfo));
256 }
257 
258 /*
259  * Allocate and copy a secinfo data from "from" to "to".
260  *
261  * This routine is used by srv_secinfo_add() to add a new flavor to an
262  * ancestor's export node. The rootnames are not copied because the
263  * allowable rootname access only applies to the explicit exported node,
264  * not its ancestor's.
265  *
266  * "to" should have already been allocated and zeroed before calling
267  * this routine.
268  *
269  * This routine is used under the protection of exported_lock (RW_WRITER).
270  */
271 void
272 srv_secinfo_copy(struct secinfo *from, struct secinfo *to)
273 {
274 	to->s_secinfo.sc_nfsnum = from->s_secinfo.sc_nfsnum;
275 	to->s_secinfo.sc_rpcnum = from->s_secinfo.sc_rpcnum;
276 
277 	if (from->s_secinfo.sc_rpcnum == RPCSEC_GSS) {
278 		to->s_secinfo.sc_service = from->s_secinfo.sc_service;
279 		bcopy(from->s_secinfo.sc_name, to->s_secinfo.sc_name,
280 			strlen(from->s_secinfo.sc_name));
281 		bcopy(from->s_secinfo.sc_gss_mech, to->s_secinfo.sc_gss_mech,
282 			strlen(from->s_secinfo.sc_gss_mech));
283 
284 		/* copy mechanism oid */
285 		to->s_secinfo.sc_gss_mech_type =
286 			kmem_alloc(sizeof (rpc_gss_OID_desc), KM_SLEEP);
287 		to->s_secinfo.sc_gss_mech_type->length =
288 			from->s_secinfo.sc_gss_mech_type->length;
289 		to->s_secinfo.sc_gss_mech_type->elements =
290 			kmem_alloc(from->s_secinfo.sc_gss_mech_type->length,
291 					KM_SLEEP);
292 		bcopy(from->s_secinfo.sc_gss_mech_type->elements,
293 			to->s_secinfo.sc_gss_mech_type->elements,
294 			from->s_secinfo.sc_gss_mech_type->length);
295 	}
296 
297 	to->s_refcnt = from->s_refcnt;
298 	to->s_window = from->s_window;
299 	/* no need to copy the mode bits - s_flags */
300 }
301 
302 /*
303  * Add the new security flavors from newdata to the current list, curdata.
304  * Upon return, curdata has the newly merged secinfo list.
305  *
306  * There should be at least 1 secinfo entry in newdata.
307  *
308  * This routine is used under the protection of exported_lock (RW_WRITER).
309  */
310 void
311 srv_secinfo_add(struct exportdata *curdata, struct exportdata *newdata)
312 {
313 	int ccnt, c;		/* sec count in current data - curdata */
314 	int ncnt, n;		/* sec count in new data - newdata */
315 	int tcnt, mcnt;		/* total sec count after merge */
316 	struct secinfo *msec;	/* merged secinfo list */
317 
318 	ccnt = curdata->ex_seccnt;
319 	ncnt = newdata->ex_seccnt;
320 
321 	ASSERT(ncnt > 0);
322 	tcnt = ccnt + ncnt;
323 
324 	for (n = 0; n < ncnt; n++) {
325 		for (c = 0; c < ccnt; c++) {
326 		    if (newdata->ex_secinfo[n].s_secinfo.sc_nfsnum ==
327 			curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) {
328 
329 			/*
330 			 * add the reference count of the newdata
331 			 * to the curdata for this nfs flavor.
332 			 */
333 			curdata->ex_secinfo[c].s_refcnt +=
334 				newdata->ex_secinfo[n].s_refcnt;
335 
336 			tcnt--;
337 			break;
338 		    }
339 		}
340 	}
341 
342 	if (tcnt == ccnt)
343 		return; /* no change; no new flavors */
344 
345 	msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
346 
347 	/* move current secinfo list data to the new list */
348 	for (c = 0; c < ccnt; c++) {
349 
350 		bcopy(&curdata->ex_secinfo[c], &msec[c],
351 			sizeof (struct secinfo));
352 	}
353 
354 	/* Add the flavor that's not in the current data */
355 	mcnt = ccnt;
356 	for (n = 0; n < ncnt; n++) {
357 		for (c = 0; c < ccnt; c++) {
358 		    if (newdata->ex_secinfo[n].s_secinfo.sc_nfsnum ==
359 			curdata->ex_secinfo[c].s_secinfo.sc_nfsnum)
360 				break;
361 		}
362 
363 		/* This is the one. Add it. */
364 		if (c == ccnt) {
365 		    srv_secinfo_copy(&newdata->ex_secinfo[n], &msec[mcnt]);
366 		    if (curdata->ex_flags & EX_PSEUDO)
367 			msec[mcnt].s_flags = M_RO;
368 		    mcnt++;
369 		}
370 	}
371 
372 	ASSERT(mcnt == tcnt);
373 	/*
374 	 * Done. Update curdata.
375 	 * Free up the existing secinfo list in curdata and
376 	 * set the new value.
377 	 */
378 	if (ccnt > 0)
379 		kmem_free(curdata->ex_secinfo, ccnt * sizeof (struct secinfo));
380 	curdata->ex_seccnt = tcnt;
381 	curdata->ex_secinfo = msec;
382 }
383 
384 /*
385  * For NFS V4.
386  * Remove the security data of the unexported node from its ancestors.
387  * Assume there is at least one flavor entry in the current data, curdata.
388  *
389  * This routine is used under the protection of exported_lock (RW_WRITER).
390  */
391 void
392 srv_secinfo_remove(struct exportdata *curdata, struct exportdata *remdata)
393 {
394 	int ccnt, c;		/* sec count in current data - curdata */
395 	int rcnt, r;		/* sec count in removal data - remdata */
396 	int tcnt, mcnt;		/* total sec count after removing */
397 	struct secinfo *msec;	/* final secinfo list after removing */
398 
399 	ASSERT(curdata->ex_seccnt > 0);
400 	ccnt = curdata->ex_seccnt;
401 	rcnt = remdata->ex_seccnt;
402 	tcnt = ccnt;
403 
404 	for (r = 0; r < rcnt; r++) {
405 
406 	    if (SEC_REF_EXPORTED(&remdata->ex_secinfo[r])) {
407 		/*
408 		 * Remove a flavor only if the flavor was a shared flavor for
409 		 * the remdata exported node that's being unshared. Otherwise,
410 		 * this flavor is for the children of remdata, need to keep it.
411 		 */
412 		for (c = 0; c < ccnt; c++) {
413 		    if (remdata->ex_secinfo[r].s_secinfo.sc_nfsnum ==
414 			curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) {
415 
416 			/*
417 			 * Decrement secinfo reference count by 1.
418 			 * If this entry is invalid after decrementing
419 			 * the count (i.e. count < 1), this entry will
420 			 * be removed.
421 			 */
422 			curdata->ex_secinfo[c].s_refcnt--;
423 			if (SEC_REF_INVALID(&curdata->ex_secinfo[c]))
424 				tcnt--;
425 
426 			break;
427 		    }
428 		}
429 	    }
430 	}
431 
432 	ASSERT(tcnt >= 0);
433 	if (tcnt == ccnt)
434 		return; /* no change; no flavors to remove */
435 
436 	if (tcnt == 0) {
437 		srv_secinfo_list_free(curdata->ex_secinfo, ccnt);
438 		curdata->ex_seccnt = 0;
439 		curdata->ex_secinfo = NULL;
440 		return;
441 	}
442 
443 	msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
444 
445 	/* walk thru the given secinfo list to remove the flavors */
446 	mcnt = 0;
447 	for (c = 0; c < ccnt; c++) {
448 
449 		if (SEC_REF_INVALID(&curdata->ex_secinfo[c])) {
450 			srv_secinfo_entry_free(&curdata->ex_secinfo[c]);
451 		} else {
452 			bcopy(&curdata->ex_secinfo[c], &msec[mcnt],
453 				sizeof (struct secinfo));
454 			mcnt++;
455 		}
456 	}
457 
458 	ASSERT(mcnt == tcnt);
459 	/*
460 	 * Done. Update curdata.
461 	 * Free the existing secinfo list in curdata. All pointers
462 	 * within the list have either been moved to msec or freed
463 	 * if it's invalid.
464 	 */
465 	kmem_free(curdata->ex_secinfo, ccnt * sizeof (struct secinfo));
466 	curdata->ex_seccnt = tcnt;
467 	curdata->ex_secinfo = msec;
468 }
469 
470 /*
471  * Upon re-sharing an export node, if there is more than 1 export reference
472  * to an old flavor (i.e. some of its children shared with this flavor), this
473  * flavor information needs to be transfered to the new shared node.
474  *
475  * Expect at least 1 secinfo entry in the old shared node - olddata.
476  * Expect both curdata and olddata are not pseudo nodes.
477  *
478  * This routine is used under the protection of exported_lock (RW_WRITER).
479  */
480 void
481 srv_secinfo_exp2exp(struct exportdata *curdata, struct exportdata *olddata)
482 {
483 	int ccnt, c;		/* sec count in current data - curdata */
484 	int ocnt, o;		/* sec count in old data - olddata */
485 	int tcnt, mcnt;		/* total sec count after the transfer */
486 	struct secinfo *msec;	/* merged secinfo list */
487 
488 	ccnt = curdata->ex_seccnt;
489 	ocnt = olddata->ex_seccnt;
490 
491 	ASSERT(ocnt > 0);
492 	ASSERT(!(olddata->ex_flags & EX_PSEUDO));
493 	ASSERT(!(curdata->ex_flags & EX_PSEUDO));
494 
495 	/*
496 	 * If the olddata has flavors with more than 1 reference count,
497 	 * transfer the information to the curdata.
498 	 */
499 	tcnt = ccnt + ocnt;
500 
501 	for (o = 0; o < ocnt; o++) {
502 
503 	    if (SEC_REF_SELF(&olddata->ex_secinfo[o])) {
504 		tcnt--;
505 	    } else {
506 		for (c = 0; c < ccnt; c++) {
507 		    if (olddata->ex_secinfo[o].s_secinfo.sc_nfsnum ==
508 			curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) {
509 
510 			/* add old reference to the current secinfo count */
511 			curdata->ex_secinfo[c].s_refcnt +=
512 				olddata->ex_secinfo[o].s_refcnt;
513 
514 			/* delete the old export flavor reference */
515 			if (SEC_REF_EXPORTED(&olddata->ex_secinfo[o]))
516 				curdata->ex_secinfo[c].s_refcnt--;
517 			tcnt--;
518 			break;
519 		    }
520 		}
521 	    }
522 	}
523 
524 	if (tcnt == ccnt)
525 		return; /* no more transfer to do */
526 
527 	/*
528 	 * olddata has flavors refered by its children that are not
529 	 * in the current (new) export flavor list. Add these flavors.
530 	 */
531 	msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
532 
533 	/* move current secinfo list data to the new list */
534 	for (c = 0; c < ccnt; c++) {
535 		bcopy(&curdata->ex_secinfo[c], &msec[c],
536 			sizeof (struct secinfo));
537 	}
538 
539 	/*
540 	 * Add the flavor that's not in the new export, but still
541 	 * referred by its children.
542 	 */
543 	mcnt = ccnt;
544 	for (o = 0; o < ocnt; o++) {
545 	    if (! SEC_REF_SELF(&olddata->ex_secinfo[o])) {
546 		for (c = 0; c < ccnt; c++) {
547 		    if (olddata->ex_secinfo[o].s_secinfo.sc_nfsnum ==
548 			curdata->ex_secinfo[c].s_secinfo.sc_nfsnum)
549 				break;
550 		}
551 
552 		/*
553 		 * This is the one. Add it. Decrement the reference count
554 		 * by 1 if the flavor is an explicitly shared flavor for
555 		 * the olddata export node.
556 		 */
557 		if (c == ccnt) {
558 		    srv_secinfo_copy(&olddata->ex_secinfo[o], &msec[mcnt]);
559 		    if (SEC_REF_EXPORTED(&olddata->ex_secinfo[o]))
560 			msec[mcnt].s_refcnt--;
561 		    mcnt++;
562 		}
563 	    }
564 	}
565 
566 	ASSERT(mcnt == tcnt);
567 	/*
568 	 * Done. Update curdata.
569 	 * Free up the existing secinfo list in curdata and
570 	 * set the new value.
571 	 */
572 	if (ccnt > 0)
573 		kmem_free(curdata->ex_secinfo, ccnt * sizeof (struct secinfo));
574 	curdata->ex_seccnt = tcnt;
575 	curdata->ex_secinfo = msec;
576 }
577 
578 /*
579  * When unsharing an old export node and the old node becomes a pseudo node,
580  * if there is more than 1 export reference to an old flavor (i.e. some of
581  * its children shared with this flavor), this flavor information needs to
582  * be transfered to the new shared node.
583  *
584  * This routine is used under the protection of exported_lock (RW_WRITER).
585  */
586 void
587 srv_secinfo_exp2pseu(struct exportdata *curdata, struct exportdata *olddata)
588 {
589 	int ocnt, o;		/* sec count in transfer data - trandata */
590 	int tcnt, mcnt;		/* total sec count after transfer */
591 	struct secinfo *msec;	/* merged secinfo list */
592 
593 	ASSERT(curdata->ex_flags & EX_PSEUDO);
594 	ASSERT(curdata->ex_seccnt == 0);
595 
596 	ocnt = olddata->ex_seccnt;
597 
598 	/*
599 	 * If the olddata has flavors with more than 1 reference count,
600 	 * transfer the information to the curdata.
601 	 */
602 	tcnt = ocnt;
603 
604 	for (o = 0; o < ocnt; o++) {
605 	    if (SEC_REF_SELF(&olddata->ex_secinfo[o]))
606 		tcnt--;
607 	}
608 
609 	if (tcnt == 0)
610 		return; /* no transfer to do */
611 
612 	msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
613 
614 	mcnt = 0;
615 	for (o = 0; o < ocnt; o++) {
616 	    if (! SEC_REF_SELF(&olddata->ex_secinfo[o])) {
617 
618 		/*
619 		 * Decrement the reference count by 1 if the flavor is
620 		 * an explicitly shared flavor for the olddata export node.
621 		 */
622 		srv_secinfo_copy(&olddata->ex_secinfo[o], &msec[mcnt]);
623 		msec[mcnt].s_flags = M_RO; /* for a pseudo node */
624 		if (SEC_REF_EXPORTED(&olddata->ex_secinfo[o]))
625 			msec[mcnt].s_refcnt--;
626 		mcnt++;
627 	    }
628 	}
629 
630 	ASSERT(mcnt == tcnt);
631 	/*
632 	 * Done. Update curdata.
633 	 * Free up the existing secinfo list in curdata and
634 	 * set the new value.
635 	 */
636 	curdata->ex_seccnt = tcnt;
637 	curdata->ex_secinfo = msec;
638 }
639 
640 /*
641  * For NFS V4.
642  * Add or remove the newly exported or unexported security flavors of the
643  * given exportinfo from its ancestors upto the system root.
644  */
645 int
646 srv_secinfo_treeclimb(struct exportinfo *exip, bool_t isadd)
647 {
648 	vnode_t *dvp, *vp;
649 	fid_t fid;
650 	int error = 0;
651 	int exportdir;
652 	struct exportinfo *exi;
653 	struct exportdata *exdata;
654 
655 	ASSERT(RW_WRITE_HELD(&exported_lock));
656 
657 	exdata = &exip->exi_export;
658 	if (exdata->ex_seccnt == 0)
659 		return (0);
660 
661 	vp = exip->exi_vp;
662 	VN_HOLD(vp);
663 	exportdir = 1;
664 
665 	for (;;) {
666 
667 		bzero(&fid, sizeof (fid));
668 		fid.fid_len = MAXFIDSZ;
669 		error = vop_fid_pseudo(vp, &fid);
670 		if (error)
671 			break;
672 
673 		if (! exportdir) {
674 
675 			exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
676 
677 			if (exi != NULL) {
678 
679 			    if (isadd) {
680 				/*
681 				 * Add the new security flavors to the
682 				 * export entry of the current directory.
683 				 */
684 				srv_secinfo_add(&exi->exi_export, exdata);
685 			    } else {
686 				/*
687 				 * Remove the unexported secinfo entries.
688 				 */
689 				srv_secinfo_remove(&exi->exi_export, exdata);
690 			    }
691 			}
692 		}
693 
694 		/*
695 		 * If at the root of the filesystem, need
696 		 * to traverse across the mountpoint
697 		 * and continue the climb on the mounted-on
698 		 * filesystem.
699 		 */
700 		if (vp->v_flag & VROOT) {
701 
702 			if (VN_CMP(vp, rootdir)) {
703 				/* at system root */
704 				break;
705 			}
706 
707 			vp = untraverse(vp);
708 			exportdir = 0;
709 			continue;
710 		}
711 
712 		/*
713 		 * Now, do a ".." to find parent dir of vp.
714 		 */
715 		error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED());
716 
717 		if (error == ENOTDIR && exportdir) {
718 			dvp = exip->exi_dvp;
719 			ASSERT(dvp != NULL);
720 			VN_HOLD(dvp);
721 			error = 0;
722 		}
723 
724 		if (error)
725 			break;
726 
727 		exportdir = 0;
728 		VN_RELE(vp);
729 		vp = dvp;
730 	}
731 
732 	VN_RELE(vp);
733 	return (error);
734 }
735 
736 void
737 export_link(struct exportinfo *exi) {
738 	int exporthash;
739 
740 	exporthash = exptablehash(&exi->exi_fsid, &exi->exi_fid);
741 	exi->exi_hash = exptable[exporthash];
742 	exptable[exporthash] = exi;
743 }
744 
745 /*
746  * Initialization routine for export routines. Should only be called once.
747  */
748 int
749 nfs_exportinit(void)
750 {
751 	int error;
752 
753 	rw_init(&exported_lock, NULL, RW_DEFAULT, NULL);
754 
755 	/*
756 	 * Allocate the place holder for the public file handle, which
757 	 * is all zeroes. It is initially set to the root filesystem.
758 	 */
759 	exi_root = kmem_zalloc(sizeof (*exi_root), KM_SLEEP);
760 	exi_public = exi_root;
761 
762 	exi_root->exi_export.ex_flags = EX_PUBLIC;
763 	exi_root->exi_export.ex_pathlen = 2;	/* length of "/" */
764 	exi_root->exi_export.ex_path =
765 		kmem_alloc(exi_root->exi_export.ex_pathlen, KM_SLEEP);
766 	exi_root->exi_export.ex_path[0] = '/';
767 	exi_root->exi_export.ex_path[1] = '\0';
768 
769 	exi_root->exi_count = 1;
770 	mutex_init(&exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
771 
772 	exi_root->exi_vp = rootdir;
773 	exi_rootfid.fid_len = MAXFIDSZ;
774 	error = vop_fid_pseudo(exi_root->exi_vp, &exi_rootfid);
775 	if (error) {
776 		mutex_destroy(&exi_root->exi_lock);
777 		kmem_free(exi_root, sizeof (*exi_root));
778 		return (error);
779 	}
780 
781 	/* setup the fhandle template */
782 	exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid;
783 	exi_root->exi_fh.fh_xlen = exi_rootfid.fid_len;
784 	bcopy(exi_rootfid.fid_data, exi_root->exi_fh.fh_xdata,
785 			exi_rootfid.fid_len);
786 	exi_root->exi_fh.fh_len = sizeof (exi_root->exi_fh.fh_data);
787 
788 	/*
789 	 * Publish the exportinfo in the hash table
790 	 */
791 	export_link(exi_root);
792 
793 	nfslog_init();
794 
795 	return (0);
796 }
797 
798 /*
799  * Finalization routine for export routines. Called to cleanup previoulsy
800  * initializtion work when the NFS server module could not be loaded correctly.
801  */
802 void
803 nfs_exportfini(void)
804 {
805 	/*
806 	 * Deallocate the place holder for the public file handle.
807 	 */
808 	srv_secinfo_list_free(exi_root->exi_export.ex_secinfo,
809 				exi_root->exi_export.ex_seccnt);
810 	mutex_destroy(&exi_root->exi_lock);
811 	kmem_free(exi_root, sizeof (*exi_root));
812 
813 	rw_destroy(&exported_lock);
814 }
815 
816 /*
817  *  Check if 2 gss mechanism identifiers are the same.
818  *
819  *  return FALSE if not the same.
820  *  return TRUE if the same.
821  */
822 static bool_t
823 nfs_mech_equal(rpc_gss_OID mech1, rpc_gss_OID mech2)
824 {
825 	if ((mech1->length == 0) && (mech2->length == 0))
826 		return (TRUE);
827 
828 	if (mech1->length != mech2->length)
829 		return (FALSE);
830 
831 	return (bcmp(mech1->elements, mech2->elements, mech1->length) == 0);
832 }
833 
834 /*
835  *  This routine is used by rpc to map rpc security number
836  *  to nfs specific security flavor number.
837  *
838  *  The gss callback prototype is
839  *  callback(struct svc_req *, gss_cred_id_t *, gss_ctx_id_t *,
840  *				rpc_gss_lock_t *, void **),
841  *  since nfs does not use the gss_cred_id_t/gss_ctx_id_t arguments
842  *  we cast them to void.
843  */
844 /*ARGSUSED*/
845 bool_t
846 rfs_gsscallback(struct svc_req *req, gss_cred_id_t deleg, void *gss_context,
847     rpc_gss_lock_t *lock, void **cookie)
848 {
849 	int i, j;
850 	rpc_gss_rawcred_t *raw_cred;
851 	struct exportinfo *exi;
852 
853 	/*
854 	 * We don't deal with delegated credentials.
855 	 */
856 	if (deleg != GSS_C_NO_CREDENTIAL)
857 		return (FALSE);
858 
859 	raw_cred = lock->raw_cred;
860 	*cookie = NULL;
861 
862 	rw_enter(&exported_lock, RW_READER);
863 	for (i = 0; i < EXPTABLESIZE; i++) {
864 	    exi = exptable[i];
865 	    while (exi) {
866 		if (exi->exi_export.ex_seccnt > 0) {
867 		    struct secinfo *secp;
868 
869 		    secp = exi->exi_export.ex_secinfo;
870 		    for (j = 0; j < exi->exi_export.ex_seccnt; j++) {
871 			/*
872 			 *  If there is a map of the triplet
873 			 *  (mechanism, service, qop) between raw_cred and
874 			 *  the exported flavor, get the psudo flavor number.
875 			 *  Also qop should not be NULL, it should be "default"
876 			 *  or something else.
877 			 */
878 			if ((secp[j].s_secinfo.sc_rpcnum == RPCSEC_GSS) &&
879 			(nfs_mech_equal(secp[j].s_secinfo.sc_gss_mech_type,
880 			raw_cred->mechanism)) &&
881 			(secp[j].s_secinfo.sc_service == raw_cred->service) &&
882 			(raw_cred->qop == secp[j].s_secinfo.sc_qop)) {
883 				*cookie = (void *)(uintptr_t)
884 				    secp[j].s_secinfo.sc_nfsnum;
885 				goto done;
886 			}
887 		    }
888 		}
889 		exi = exi->exi_hash;
890 	    }
891 	}
892 done:
893 	rw_exit(&exported_lock);
894 
895 	/*
896 	 * If no nfs pseudo number mapping can be found in the export
897 	 * table, assign the nfsflavor to NFS_FLAVOR_NOMAP. In V4, we may
898 	 * recover the flavor mismatch from NFS layer (NFS4ERR_WRONGSEC).
899 	 *
900 	 * For example:
901 	 *	server first shares with krb5i;
902 	 *	client mounts with krb5i;
903 	 *	server re-shares with krb5p;
904 	 *	client tries with krb5i, but no mapping can be found;
905 	 *	rpcsec_gss module calls this routine to do the mapping,
906 	 *		if this routine fails, request is rejected from
907 	 *		the rpc layer.
908 	 *	What we need is to let the nfs layer rejects the request.
909 	 *	For V4, we can reject with NFS4ERR_WRONGSEC and the client
910 	 *	may recover from it by getting the new flavor via SECINFO.
911 	 *
912 	 * nfs pseudo number for RPCSEC_GSS mapping (see nfssec.conf)
913 	 * is owned by IANA (see RFC 2623).
914 	 *
915 	 * XXX NFS_FLAVOR_NOMAP is defined in Solaris to work around
916 	 * the implementation issue. This number should not overlap with
917 	 * any new IANA defined pseudo flavor numbers.
918 	 */
919 	if (*cookie == NULL)
920 		*cookie = (void *)NFS_FLAVOR_NOMAP;
921 
922 	lock->locked = TRUE;
923 
924 	return (TRUE);
925 }
926 
927 
928 /*
929  * Exportfs system call; credentials should be checked before
930  * calling this function.
931  */
932 int
933 exportfs(struct exportfs_args *args, model_t model, cred_t *cr)
934 {
935 	vnode_t *vp;
936 	vnode_t *dvp;
937 	struct exportdata *kex;
938 	struct exportinfo *exi;
939 	struct exportinfo *ex, *prev;
940 	fid_t fid;
941 	fsid_t fsid;
942 	int error;
943 	size_t allocsize;
944 	struct secinfo *sp;
945 	struct secinfo *exs;
946 	rpc_gss_callback_t cb;
947 	char *pathbuf;
948 	char *log_buffer;
949 	char *tagbuf;
950 	int callback;
951 	int allocd_seccnt;
952 	STRUCT_HANDLE(exportfs_args, uap);
953 	STRUCT_DECL(exportdata, uexi);
954 	int i;
955 
956 	STRUCT_SET_HANDLE(uap, model, args);
957 
958 	error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
959 	    FOLLOW, &dvp, &vp);
960 	if (error == EINVAL) {
961 		/*
962 		 * if fname resolves to / we get EINVAL error
963 		 * since we wanted the parent vnode. Try again
964 		 * with NULL dvp.
965 		 */
966 		error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
967 		    FOLLOW, NULL, &vp);
968 		dvp = NULL;
969 	}
970 	if (!error && vp == NULL) {
971 		/*
972 		 * Last component of fname not found
973 		 */
974 		if (dvp != NULL) {
975 			VN_RELE(dvp);
976 		}
977 		error = ENOENT;
978 	}
979 	if (error)
980 		return (error);
981 
982 	/*
983 	 * 'vp' may be an AUTOFS node, so we perform a
984 	 * VOP_ACCESS() to trigger the mount of the
985 	 * intended filesystem, so we can share the intended
986 	 * filesystem instead of the AUTOFS filesystem.
987 	 */
988 	(void) VOP_ACCESS(vp, 0, 0, cr);
989 
990 	/*
991 	 * We're interested in the top most filesystem.
992 	 * This is specially important when uap->dname is a trigger
993 	 * AUTOFS node, since we're really interested in sharing the
994 	 * filesystem AUTOFS mounted as result of the VOP_ACCESS()
995 	 * call not the AUTOFS node itself.
996 	 */
997 	if (vn_mountedvfs(vp) != NULL) {
998 		if (error = traverse(&vp)) {
999 			VN_RELE(vp);
1000 			if (dvp != NULL)
1001 				VN_RELE(dvp);
1002 			return (error);
1003 		}
1004 	}
1005 
1006 	/*
1007 	 * Get the vfs id
1008 	 */
1009 	bzero(&fid, sizeof (fid));
1010 	fid.fid_len = MAXFIDSZ;
1011 	error = VOP_FID(vp, &fid);
1012 	fsid = vp->v_vfsp->vfs_fsid;
1013 	if (error) {
1014 		VN_RELE(vp);
1015 		if (dvp != NULL)
1016 			VN_RELE(dvp);
1017 		/*
1018 		 * If VOP_FID returns ENOSPC then the fid supplied
1019 		 * is too small.  For now we simply return EREMOTE.
1020 		 */
1021 		if (error == ENOSPC)
1022 			error = EREMOTE;
1023 		return (error);
1024 	}
1025 
1026 	if (STRUCT_FGETP(uap, uex) == NULL) {
1027 		error = unexport(&fsid, &fid, vp);
1028 		VN_RELE(vp);
1029 		if (dvp != NULL)
1030 			VN_RELE(dvp);
1031 		return (error);
1032 	}
1033 	exi = kmem_zalloc(sizeof (*exi), KM_SLEEP);
1034 	exi->exi_fsid = fsid;
1035 	exi->exi_fid = fid;
1036 	exi->exi_vp = vp;
1037 	exi->exi_count = 1;
1038 	exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
1039 				VSW_VOLATILEDEV) ? 1 : 0;
1040 	mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
1041 	exi->exi_dvp = dvp;
1042 
1043 	/*
1044 	 * Initialize auth cache lock
1045 	 */
1046 	rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL);
1047 
1048 	/*
1049 	 * Build up the template fhandle
1050 	 */
1051 	exi->exi_fh.fh_fsid = fsid;
1052 	if (exi->exi_fid.fid_len > sizeof (exi->exi_fh.fh_xdata)) {
1053 		error = EREMOTE;
1054 		goto out1;
1055 	}
1056 	exi->exi_fh.fh_xlen = exi->exi_fid.fid_len;
1057 	bcopy(exi->exi_fid.fid_data, exi->exi_fh.fh_xdata,
1058 	    exi->exi_fid.fid_len);
1059 
1060 	exi->exi_fh.fh_len = sizeof (exi->exi_fh.fh_data);
1061 
1062 	kex = &exi->exi_export;
1063 
1064 	/*
1065 	 * Load in everything, and do sanity checking
1066 	 */
1067 	STRUCT_INIT(uexi, model);
1068 	if (copyin(STRUCT_FGETP(uap, uex), STRUCT_BUF(uexi),
1069 	    STRUCT_SIZE(uexi))) {
1070 		error = EFAULT;
1071 		goto out1;
1072 	}
1073 
1074 	kex->ex_version = STRUCT_FGET(uexi, ex_version);
1075 	if (kex->ex_version != EX_CURRENT_VERSION) {
1076 		error = EINVAL;
1077 		cmn_err(CE_WARN,
1078 		"NFS: exportfs requires export struct version 2 - got %d\n",
1079 		kex->ex_version);
1080 		goto out1;
1081 	}
1082 
1083 	/*
1084 	 * Must have at least one security entry
1085 	 */
1086 	kex->ex_seccnt = STRUCT_FGET(uexi, ex_seccnt);
1087 	if (kex->ex_seccnt < 1) {
1088 		error = EINVAL;
1089 		goto out1;
1090 	}
1091 
1092 	kex->ex_path = STRUCT_FGETP(uexi, ex_path);
1093 	kex->ex_pathlen = STRUCT_FGET(uexi, ex_pathlen);
1094 	kex->ex_flags = STRUCT_FGET(uexi, ex_flags);
1095 	kex->ex_anon = STRUCT_FGET(uexi, ex_anon);
1096 	kex->ex_secinfo = STRUCT_FGETP(uexi, ex_secinfo);
1097 	kex->ex_index = STRUCT_FGETP(uexi, ex_index);
1098 	kex->ex_log_buffer = STRUCT_FGETP(uexi, ex_log_buffer);
1099 	kex->ex_log_bufferlen = STRUCT_FGET(uexi, ex_log_bufferlen);
1100 	kex->ex_tag = STRUCT_FGETP(uexi, ex_tag);
1101 	kex->ex_taglen = STRUCT_FGET(uexi, ex_taglen);
1102 
1103 	/*
1104 	 * Copy the exported pathname into
1105 	 * an appropriately sized buffer.
1106 	 */
1107 	pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1108 	if (copyinstr(kex->ex_path, pathbuf, MAXPATHLEN, &kex->ex_pathlen)) {
1109 		kmem_free(pathbuf, MAXPATHLEN);
1110 		error = EFAULT;
1111 		goto out1;
1112 	}
1113 	kex->ex_path = kmem_alloc(kex->ex_pathlen + 1, KM_SLEEP);
1114 	bcopy(pathbuf, kex->ex_path, kex->ex_pathlen);
1115 	kex->ex_path[kex->ex_pathlen] = '\0';
1116 	kmem_free(pathbuf, MAXPATHLEN);
1117 
1118 	/*
1119 	 * Get the path to the logging buffer and the tag
1120 	 */
1121 	if (kex->ex_flags & EX_LOG) {
1122 		log_buffer = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1123 		if (copyinstr(kex->ex_log_buffer, log_buffer, MAXPATHLEN,
1124 		    &kex->ex_log_bufferlen)) {
1125 			kmem_free(log_buffer, MAXPATHLEN);
1126 			error = EFAULT;
1127 			goto out2;
1128 		}
1129 		kex->ex_log_buffer =
1130 			kmem_alloc(kex->ex_log_bufferlen + 1, KM_SLEEP);
1131 		bcopy(log_buffer, kex->ex_log_buffer, kex->ex_log_bufferlen);
1132 		kex->ex_log_buffer[kex->ex_log_bufferlen] = '\0';
1133 		kmem_free(log_buffer, MAXPATHLEN);
1134 
1135 		tagbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1136 		if (copyinstr(kex->ex_tag, tagbuf, MAXPATHLEN,
1137 		    &kex->ex_taglen)) {
1138 			kmem_free(tagbuf, MAXPATHLEN);
1139 			error = EFAULT;
1140 			goto out3;
1141 		}
1142 		kex->ex_tag = kmem_alloc(kex->ex_taglen + 1, KM_SLEEP);
1143 		bcopy(tagbuf, kex->ex_tag, kex->ex_taglen);
1144 		kex->ex_tag[kex->ex_taglen] = '\0';
1145 		kmem_free(tagbuf, MAXPATHLEN);
1146 	}
1147 
1148 	/*
1149 	 * Load the security information for each flavor
1150 	 */
1151 	allocsize = kex->ex_seccnt * SIZEOF_STRUCT(secinfo, model);
1152 	sp = kmem_zalloc(allocsize, KM_SLEEP);
1153 	if (copyin(kex->ex_secinfo, sp, allocsize)) {
1154 		kmem_free(sp, allocsize);
1155 		error = EFAULT;
1156 		goto out4;
1157 	}
1158 
1159 	/*
1160 	 * All of these nested structures need to be converted to
1161 	 * the kernel native format.
1162 	 */
1163 	if (model != DATAMODEL_NATIVE) {
1164 		size_t allocsize2;
1165 		struct secinfo *sp2;
1166 
1167 		allocsize2 = kex->ex_seccnt * sizeof (struct secinfo);
1168 		sp2 = kmem_zalloc(allocsize2, KM_SLEEP);
1169 
1170 		for (i = 0; i < kex->ex_seccnt; i++) {
1171 			STRUCT_HANDLE(secinfo, usi);
1172 
1173 			STRUCT_SET_HANDLE(usi, model,
1174 			    (struct secinfo *)((caddr_t)sp +
1175 			    (i * SIZEOF_STRUCT(secinfo, model))));
1176 			bcopy(STRUCT_FGET(usi, s_secinfo.sc_name),
1177 			    sp2[i].s_secinfo.sc_name, MAX_NAME_LEN);
1178 			sp2[i].s_secinfo.sc_nfsnum =
1179 			    STRUCT_FGET(usi, s_secinfo.sc_nfsnum);
1180 			sp2[i].s_secinfo.sc_rpcnum =
1181 			    STRUCT_FGET(usi, s_secinfo.sc_rpcnum);
1182 			bcopy(STRUCT_FGET(usi, s_secinfo.sc_gss_mech),
1183 			    sp2[i].s_secinfo.sc_gss_mech, MAX_NAME_LEN);
1184 			sp2[i].s_secinfo.sc_gss_mech_type =
1185 			    STRUCT_FGETP(usi, s_secinfo.sc_gss_mech_type);
1186 			sp2[i].s_secinfo.sc_qop =
1187 			    STRUCT_FGET(usi, s_secinfo.sc_qop);
1188 			sp2[i].s_secinfo.sc_service =
1189 			    STRUCT_FGET(usi, s_secinfo.sc_service);
1190 
1191 			sp2[i].s_flags = STRUCT_FGET(usi, s_flags);
1192 			sp2[i].s_window = STRUCT_FGET(usi, s_window);
1193 			sp2[i].s_rootcnt = STRUCT_FGET(usi, s_rootcnt);
1194 			sp2[i].s_rootnames = STRUCT_FGETP(usi, s_rootnames);
1195 		}
1196 		kmem_free(sp, allocsize);
1197 		sp = sp2;
1198 		allocsize = allocsize2;
1199 	}
1200 
1201 	kex->ex_secinfo = sp;
1202 
1203 	/*
1204 	 * And now copy rootnames for each individual secinfo.
1205 	 */
1206 	callback = 0;
1207 	allocd_seccnt = 0;
1208 	while (allocd_seccnt < kex->ex_seccnt) {
1209 
1210 		exs = &sp[allocd_seccnt];
1211 		if (exs->s_rootcnt > 0) {
1212 			if (!sec_svc_loadrootnames(exs->s_secinfo.sc_rpcnum,
1213 			    exs->s_rootcnt, &exs->s_rootnames, model)) {
1214 				error = EFAULT;
1215 				goto out5;
1216 			}
1217 		}
1218 
1219 		if (exs->s_secinfo.sc_rpcnum == RPCSEC_GSS) {
1220 			rpc_gss_OID mech_tmp;
1221 			STRUCT_DECL(rpc_gss_OID_s, umech_tmp);
1222 			caddr_t elements_tmp;
1223 
1224 			/* Copyin mechanism type */
1225 			STRUCT_INIT(umech_tmp, model);
1226 			mech_tmp = kmem_alloc(sizeof (*mech_tmp), KM_SLEEP);
1227 			if (copyin(exs->s_secinfo.sc_gss_mech_type,
1228 			    STRUCT_BUF(umech_tmp), STRUCT_SIZE(umech_tmp))) {
1229 				kmem_free(mech_tmp, sizeof (*mech_tmp));
1230 				error = EFAULT;
1231 				goto out5;
1232 			}
1233 			mech_tmp->length = STRUCT_FGET(umech_tmp, length);
1234 			mech_tmp->elements = STRUCT_FGETP(umech_tmp, elements);
1235 
1236 			elements_tmp = kmem_alloc(mech_tmp->length, KM_SLEEP);
1237 			if (copyin(mech_tmp->elements, elements_tmp,
1238 			    mech_tmp->length)) {
1239 				kmem_free(elements_tmp, mech_tmp->length);
1240 				kmem_free(mech_tmp, sizeof (*mech_tmp));
1241 				error = EFAULT;
1242 				goto out5;
1243 			}
1244 			mech_tmp->elements = elements_tmp;
1245 			exs->s_secinfo.sc_gss_mech_type = mech_tmp;
1246 			allocd_seccnt++;
1247 
1248 			callback = 1;
1249 		} else
1250 			allocd_seccnt++;
1251 	}
1252 
1253 	/*
1254 	 * Init the secinfo reference count and mark these flavors
1255 	 * explicitly exported flavors.
1256 	 */
1257 	for (i = 0; i < kex->ex_seccnt; i++) {
1258 		kex->ex_secinfo[i].s_flags |= M_4SEC_EXPORTED;
1259 		kex->ex_secinfo[i].s_refcnt++;  /* 1 reference count */
1260 	}
1261 
1262 	/*
1263 	 *  Set up rpcsec_gss callback routine entry if any.
1264 	 */
1265 	if (callback) {
1266 		cb.callback = rfs_gsscallback;
1267 		cb.program = NFS_ACL_PROGRAM;
1268 		for (cb.version = NFS_ACL_VERSMIN;
1269 		    cb.version <= NFS_ACL_VERSMAX; cb.version++) {
1270 			(void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK,
1271 			    (void *)&cb);
1272 		}
1273 
1274 		cb.program = NFS_PROGRAM;
1275 		for (cb.version = NFS_VERSMIN;
1276 		    cb.version <= NFS_VERSMAX; cb.version++) {
1277 			(void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK,
1278 			    (void *)&cb);
1279 		}
1280 	}
1281 
1282 	/*
1283 	 * Check the index flag. Do this here to avoid holding the
1284 	 * lock while dealing with the index option (as we do with
1285 	 * the public option).
1286 	 */
1287 	if (kex->ex_flags & EX_INDEX) {
1288 		if (!kex->ex_index) {	/* sanity check */
1289 			error = EINVAL;
1290 			goto out5;
1291 		}
1292 		if (error = loadindex(kex))
1293 			goto out5;
1294 	}
1295 
1296 	if (kex->ex_flags & EX_LOG) {
1297 		if (error = nfslog_setup(exi))
1298 			goto out6;
1299 	}
1300 
1301 	/*
1302 	 * Insert the new entry at the front of the export list
1303 	 */
1304 	rw_enter(&exported_lock, RW_WRITER);
1305 
1306 	export_link(exi);
1307 
1308 	/*
1309 	 * Check the rest of the list for an old entry for the fs.
1310 	 * If one is found then unlink it, wait until this is the
1311 	 * only reference and then free it.
1312 	 */
1313 	prev = exi;
1314 	for (ex = prev->exi_hash; ex != NULL; prev = ex, ex = ex->exi_hash) {
1315 		if (ex != exi_root && VN_CMP(ex->exi_vp, vp)) {
1316 			prev->exi_hash = ex->exi_hash;
1317 			break;
1318 		}
1319 	}
1320 
1321 	/*
1322 	 * If the public filehandle is pointing at the
1323 	 * old entry, then point it back at the root.
1324 	 */
1325 	if (ex != NULL && ex == exi_public)
1326 		exi_public = exi_root;
1327 
1328 	/*
1329 	 * If the public flag is on, make the global exi_public
1330 	 * point to this entry and turn off the public bit so that
1331 	 * we can distinguish it from the place holder export.
1332 	 */
1333 	if (kex->ex_flags & EX_PUBLIC) {
1334 		exi_public = exi;
1335 		kex->ex_flags &= ~EX_PUBLIC;
1336 	}
1337 
1338 #ifdef VOLATILE_FH_TEST
1339 	/*
1340 	 * Set up the volatile_id value if volatile on share.
1341 	 * The list of volatile renamed filehandles is always destroyed,
1342 	 * if the fs was reshared.
1343 	 */
1344 	if (kex->ex_flags & EX_VOLFH)
1345 		exi->exi_volatile_id = gethrestime_sec();
1346 
1347 	mutex_init(&exi->exi_vol_rename_lock, NULL, MUTEX_DEFAULT, NULL);
1348 #endif /* VOLATILE_FH_TEST */
1349 
1350 	/*
1351 	 * If this is a new export, then climb up
1352 	 * the tree and check if any pseudo exports
1353 	 * need to be created to provide a path for
1354 	 * NFS v4 clients.
1355 	 */
1356 	if (ex == NULL)
1357 		error = treeclimb_export(exi);
1358 
1359 	if (!error)
1360 		error = srv_secinfo_treeclimb(exi, TRUE);
1361 
1362 	/*
1363 	 * If re-sharing an old export entry, update the secinfo data
1364 	 * depending on if the old entry is a pseudo node or not.
1365 	 */
1366 	if (!error && ex != NULL) {
1367 		if (PSEUDO(ex)) {
1368 		    srv_secinfo_add(&exi->exi_export, &ex->exi_export);
1369 		} else {
1370 		    srv_secinfo_exp2exp(&exi->exi_export, &ex->exi_export);
1371 		    error = srv_secinfo_treeclimb(ex, FALSE);
1372 		}
1373 	}
1374 
1375 	if (error)
1376 		goto out7;
1377 
1378 	/*
1379 	 * If it's a re-export and the old entry has a visible list,
1380 	 * then transfer its visible list to the new export.
1381 	 * Note: only VROOT node may have a visible list either
1382 	 * it is a PSEUDO node or a real export node.
1383 	 */
1384 	if (ex != NULL && (ex->exi_visible != NULL)) {
1385 		exi->exi_visible = ex->exi_visible;
1386 		ex->exi_visible = NULL;
1387 	}
1388 
1389 	rw_exit(&exported_lock);
1390 
1391 	if (exi_public == exi || kex->ex_flags & EX_LOG) {
1392 		/*
1393 		 * Log share operation to this buffer only.
1394 		 */
1395 		nfslog_share_record(exi, cr);
1396 	}
1397 
1398 	if (ex != NULL)
1399 		exi_rele(ex);
1400 
1401 	return (0);
1402 
1403 out7:
1404 	/*
1405 	 * Cleaning up the tree. Assuming *treeclimb* routines
1406 	 * will fail at the same place in the tree.
1407 	 */
1408 	(void) treeclimb_unexport(exi);
1409 	(void) srv_secinfo_treeclimb(exi, FALSE);
1410 
1411 	/*
1412 	 * Unlink and re-link the new and old export in exptable.
1413 	 */
1414 	(void) export_unlink(&exi->exi_fsid, &exi->exi_fid, exi->exi_vp, NULL);
1415 	if (ex != NULL)
1416 		export_link(ex);
1417 
1418 	rw_exit(&exported_lock);
1419 out6:
1420 	if (kex->ex_flags & EX_INDEX)
1421 		kmem_free(kex->ex_index, strlen(kex->ex_index) + 1);
1422 out5:
1423 	/* free partially completed allocation */
1424 	while (--allocd_seccnt >= 0) {
1425 		exs = &kex->ex_secinfo[allocd_seccnt];
1426 		srv_secinfo_entry_free(exs);
1427 	}
1428 
1429 	if (kex->ex_secinfo) {
1430 		kmem_free(kex->ex_secinfo,
1431 			kex->ex_seccnt * sizeof (struct secinfo));
1432 	}
1433 
1434 out4:
1435 	if ((kex->ex_flags & EX_LOG) && kex->ex_tag != NULL)
1436 		kmem_free(kex->ex_tag, kex->ex_taglen + 1);
1437 out3:
1438 	if ((kex->ex_flags & EX_LOG) && kex->ex_log_buffer != NULL)
1439 		kmem_free(kex->ex_log_buffer, kex->ex_log_bufferlen + 1);
1440 out2:
1441 	kmem_free(kex->ex_path, kex->ex_pathlen + 1);
1442 out1:
1443 	VN_RELE(vp);
1444 	if (dvp != NULL)
1445 		VN_RELE(dvp);
1446 	mutex_destroy(&exi->exi_lock);
1447 	rw_destroy(&exi->exi_cache_lock);
1448 	kmem_free(exi, sizeof (*exi));
1449 	return (error);
1450 }
1451 
1452 /*
1453  * Remove the exportinfo from the export list
1454  */
1455 int
1456 export_unlink(fsid_t *fsid, fid_t *fid, vnode_t *vp, struct exportinfo **exip)
1457 {
1458 	struct exportinfo **tail;
1459 
1460 	ASSERT(RW_WRITE_HELD(&exported_lock));
1461 
1462 	tail = &exptable[exptablehash(fsid, fid)];
1463 	while (*tail != NULL) {
1464 		if (exportmatch(*tail, fsid, fid)) {
1465 			/*
1466 			 * If vp is given, check if vp is the
1467 			 * same vnode as the exported node.
1468 			 *
1469 			 * Since VOP_FID of a lofs node returns the
1470 			 * fid of its real node (ufs), the exported
1471 			 * node for lofs and (pseudo) ufs may have
1472 			 * the same fsid and fid.
1473 			 */
1474 			if (vp == NULL || vp == (*tail)->exi_vp) {
1475 
1476 				if (exip != NULL)
1477 					*exip = *tail;
1478 				*tail = (*tail)->exi_hash;
1479 
1480 				return (0);
1481 			}
1482 		}
1483 		tail = &(*tail)->exi_hash;
1484 	}
1485 
1486 	return (EINVAL);
1487 }
1488 
1489 /*
1490  * Unexport an exported filesystem
1491  */
1492 int
1493 unexport(fsid_t *fsid, fid_t *fid, vnode_t *vp)
1494 {
1495 	struct exportinfo *exi = NULL;
1496 	int error;
1497 
1498 	rw_enter(&exported_lock, RW_WRITER);
1499 
1500 	error = export_unlink(fsid, fid, vp, &exi);
1501 
1502 	if (error) {
1503 		rw_exit(&exported_lock);
1504 		return (error);
1505 	}
1506 
1507 	/* pseudo node is not a real exported filesystem */
1508 	if (PSEUDO(exi)) {
1509 		/*
1510 		 * Put the pseudo node back into the export table
1511 		 * before erroring out.
1512 		 */
1513 		export_link(exi);
1514 		rw_exit(&exported_lock);
1515 		return (EINVAL);
1516 	}
1517 
1518 	/*
1519 	 * If there's a visible list, then need to leave
1520 	 * a pseudo export here to retain the visible list
1521 	 * for paths to exports below.
1522 	 */
1523 	if (exi->exi_visible) {
1524 		error = pseudo_exportfs(exi->exi_vp, exi->exi_visible,
1525 						&exi->exi_export);
1526 		if (error)
1527 			goto done;
1528 
1529 		exi->exi_visible = NULL;
1530 	} else {
1531 		error = treeclimb_unexport(exi);
1532 		if (error)
1533 			goto done;
1534 	}
1535 
1536 	error = srv_secinfo_treeclimb(exi, FALSE);
1537 	if (error)
1538 		goto done;
1539 
1540 	rw_exit(&exported_lock);
1541 
1542 	/*
1543 	 * Need to call into the NFSv4 server and release all data
1544 	 * held on this particular export.  This is important since
1545 	 * the v4 server may be holding file locks or vnodes under
1546 	 * this export.
1547 	 */
1548 	rfs4_clean_state_exi(exi);
1549 
1550 	/*
1551 	 * Notify the lock manager that the filesystem is being
1552 	 * unexported.
1553 	 */
1554 	lm_unexport(exi);
1555 
1556 	/*
1557 	 * If this was a public export, restore
1558 	 * the public filehandle to the root.
1559 	 */
1560 	if (exi == exi_public) {
1561 		exi_public = exi_root;
1562 
1563 		nfslog_share_record(exi_public, CRED());
1564 	}
1565 
1566 	if (exi->exi_export.ex_flags & EX_LOG) {
1567 		nfslog_unshare_record(exi, CRED());
1568 	}
1569 
1570 	exi_rele(exi);
1571 	return (error);
1572 
1573 done:
1574 	rw_exit(&exported_lock);
1575 	exi_rele(exi);
1576 	return (error);
1577 }
1578 
1579 /*
1580  * Get file handle system call.
1581  * Takes file name and returns a file handle for it.
1582  * Credentials must be verified before calling.
1583  */
1584 int
1585 nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr)
1586 {
1587 	fhandle_t fh;
1588 	vnode_t *vp;
1589 	vnode_t *dvp;
1590 	struct exportinfo *exi;
1591 	int error;
1592 	STRUCT_HANDLE(nfs_getfh_args, uap);
1593 
1594 #ifdef lint
1595 	model = model;		/* STRUCT macros don't always use it */
1596 #endif
1597 
1598 	STRUCT_SET_HANDLE(uap, model, args);
1599 
1600 	error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE,
1601 	    FOLLOW, &dvp, &vp);
1602 	if (error == EINVAL) {
1603 		/*
1604 		 * if fname resolves to / we get EINVAL error
1605 		 * since we wanted the parent vnode. Try again
1606 		 * with NULL dvp.
1607 		 */
1608 		error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE,
1609 		    FOLLOW, NULL, &vp);
1610 		dvp = NULL;
1611 	}
1612 	if (!error && vp == NULL) {
1613 		/*
1614 		 * Last component of fname not found
1615 		 */
1616 		if (dvp != NULL) {
1617 			VN_RELE(dvp);
1618 		}
1619 		error = ENOENT;
1620 	}
1621 	if (error)
1622 		return (error);
1623 
1624 	/*
1625 	 * 'vp' may be an AUTOFS node, so we perform a
1626 	 * VOP_ACCESS() to trigger the mount of the
1627 	 * intended filesystem, so we can share the intended
1628 	 * filesystem instead of the AUTOFS filesystem.
1629 	 */
1630 	(void) VOP_ACCESS(vp, 0, 0, cr);
1631 
1632 	/*
1633 	 * We're interested in the top most filesystem.
1634 	 * This is specially important when uap->dname is a trigger
1635 	 * AUTOFS node, since we're really interested in sharing the
1636 	 * filesystem AUTOFS mounted as result of the VOP_ACCESS()
1637 	 * call not the AUTOFS node itself.
1638 	 */
1639 	if (vn_mountedvfs(vp) != NULL) {
1640 		if (error = traverse(&vp)) {
1641 			VN_RELE(vp);
1642 			if (dvp != NULL)
1643 				VN_RELE(dvp);
1644 			return (error);
1645 		}
1646 	}
1647 
1648 	exi = nfs_vptoexi(dvp, vp, cr, NULL, &error, FALSE);
1649 	if (!error) {
1650 		error = makefh(&fh, vp, exi);
1651 		if (!error && exi->exi_export.ex_flags & EX_LOG) {
1652 			nfslog_getfh(exi, &fh, STRUCT_FGETP(uap, fname),
1653 				UIO_USERSPACE, cr);
1654 		}
1655 		exi_rele(exi);
1656 		if (!error) {
1657 			if (copyout(&fh, STRUCT_FGETP(uap, fhp), sizeof (fh)))
1658 				error = EFAULT;
1659 		}
1660 	}
1661 	VN_RELE(vp);
1662 	if (dvp != NULL) {
1663 		VN_RELE(dvp);
1664 	}
1665 	return (error);
1666 }
1667 
1668 /*
1669  * Strategy: if vp is in the export list, then
1670  * return the associated file handle. Otherwise, ".."
1671  * once up the vp and try again, until the root of the
1672  * filesystem is reached.
1673  */
1674 struct   exportinfo *
1675 nfs_vptoexi(vnode_t *dvp, vnode_t *vp, cred_t *cr, int *walk,
1676 	int *err,  bool_t v4srv)
1677 {
1678 	fid_t fid;
1679 	int error;
1680 	struct exportinfo *exi;
1681 
1682 	ASSERT(vp);
1683 	VN_HOLD(vp);
1684 	if (dvp != NULL) {
1685 		VN_HOLD(dvp);
1686 	}
1687 	if (walk != NULL)
1688 		*walk = 0;
1689 
1690 	for (;;) {
1691 		bzero(&fid, sizeof (fid));
1692 		fid.fid_len = MAXFIDSZ;
1693 		error = vop_fid_pseudo(vp, &fid);
1694 		if (error) {
1695 			/*
1696 			 * If vop_fid_pseudo returns ENOSPC then the fid
1697 			 * supplied is too small. For now we simply
1698 			 * return EREMOTE.
1699 			 */
1700 			if (error == ENOSPC)
1701 				error = EREMOTE;
1702 			break;
1703 		}
1704 
1705 		if (v4srv)
1706 			exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
1707 		else
1708 			exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid);
1709 
1710 		if (exi != NULL) {
1711 			/*
1712 			 * Found the export info
1713 			 */
1714 			break;
1715 		}
1716 
1717 		/*
1718 		 * We have just failed finding a matching export.
1719 		 * If we're at the root of this filesystem, then
1720 		 * it's time to stop (with failure).
1721 		 */
1722 		if (vp->v_flag & VROOT) {
1723 			error = EINVAL;
1724 			break;
1725 		}
1726 
1727 		if (walk != NULL)
1728 			(*walk)++;
1729 
1730 		/*
1731 		 * Now, do a ".." up vp. If dvp is supplied, use it,
1732 		 * otherwise, look it up.
1733 		 */
1734 		if (dvp == NULL) {
1735 			error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr);
1736 			if (error)
1737 				break;
1738 		}
1739 		VN_RELE(vp);
1740 		vp = dvp;
1741 		dvp = NULL;
1742 	}
1743 	VN_RELE(vp);
1744 	if (dvp != NULL) {
1745 		VN_RELE(dvp);
1746 	}
1747 	if (error != 0) {
1748 		if (err != NULL)
1749 			*err = error;
1750 		return (NULL);
1751 	}
1752 	return (exi);
1753 }
1754 
1755 bool_t
1756 chk_clnt_sec(struct exportinfo *exi, struct svc_req *req)
1757 {
1758 	int i, nfsflavor;
1759 	struct secinfo *sp;
1760 	bool_t sec_found = FALSE;
1761 
1762 	/*
1763 	 *  Get the nfs flavor number from xprt.
1764 	 */
1765 	nfsflavor = (int)(uintptr_t)req->rq_xprt->xp_cookie;
1766 
1767 	sp = exi->exi_export.ex_secinfo;
1768 	for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
1769 		if (nfsflavor == sp[i].s_secinfo.sc_nfsnum) {
1770 			sec_found = TRUE;
1771 			break;
1772 		}
1773 	}
1774 	return (sec_found);
1775 }
1776 
1777 /*
1778  * Make an fhandle from a vnode
1779  */
1780 int
1781 makefh(fhandle_t *fh, vnode_t *vp, struct exportinfo *exi)
1782 {
1783 	int error;
1784 
1785 	*fh = exi->exi_fh;	/* struct copy */
1786 
1787 	error = VOP_FID(vp, (fid_t *)&fh->fh_len);
1788 	if (error) {
1789 		/*
1790 		 * Should be something other than EREMOTE
1791 		 */
1792 		return (EREMOTE);
1793 	}
1794 	return (0);
1795 }
1796 
1797 /*
1798  * This routine makes an overloaded V2 fhandle which contains
1799  * sec modes.
1800  *
1801  * Note that the first four octets contain the length octet,
1802  * the status octet, and two padded octets to make them XDR
1803  * four-octet aligned.
1804  *
1805  *   1   2   3   4                                          32
1806  * +---+---+---+---+---+---+---+---+   +---+---+---+---+   +---+
1807  * | l | s |   |   |     sec_1     |...|     sec_n     |...|   |
1808  * +---+---+---+---+---+---+---+---+   +---+---+---+---+   +---+
1809  *
1810  * where
1811  *
1812  *   the status octet s indicates whether there are more security
1813  *   flavors (1 means yes, 0 means no) that require the client to
1814  *   perform another 0x81 LOOKUP to get them,
1815  *
1816  *   the length octet l is the length describing the number of
1817  *   valid octets that follow.  (l = 4 * n, where n is the number
1818  *   of security flavors sent in the current overloaded filehandle.)
1819  */
1820 int
1821 makefh_ol(fhandle_t *fh, struct exportinfo *exi, uint_t sec_index)
1822 {
1823 	static int max_cnt = (NFS_FHSIZE/sizeof (int)) - 1;
1824 	int totalcnt, i, *ipt, cnt;
1825 	char *c;
1826 
1827 	if (fh == (fhandle_t *)NULL ||
1828 		exi == (struct exportinfo *)NULL ||
1829 		sec_index > exi->exi_export.ex_seccnt ||
1830 		sec_index < 1)
1831 		return (EREMOTE);
1832 
1833 	totalcnt = exi->exi_export.ex_seccnt-sec_index+1;
1834 	cnt = totalcnt > max_cnt? max_cnt : totalcnt;
1835 
1836 	c = (char *)fh;
1837 	/*
1838 	 * Encode the length octet representing the number of
1839 	 * security flavors (in bytes) in this overloaded fh.
1840 	 */
1841 	*c = cnt * sizeof (int);
1842 
1843 	/*
1844 	 * Encode the status octet that indicates whether there
1845 	 * are more security flavors the client needs to get.
1846 	 */
1847 	*(c+1) = totalcnt > max_cnt;
1848 
1849 	/*
1850 	 * put security flavors in the overloaded fh
1851 	 */
1852 	ipt = (int *)(c + sizeof (int32_t));
1853 	for (i = 0; i < cnt; i++) {
1854 		*ipt++ = htonl(exi->exi_export.ex_secinfo[i+sec_index-1].
1855 				s_secinfo.sc_nfsnum);
1856 	}
1857 	return (0);
1858 }
1859 
1860 /*
1861  * Make an nfs_fh3 from a vnode
1862  */
1863 int
1864 makefh3(nfs_fh3 *fh, vnode_t *vp, struct exportinfo *exi)
1865 {
1866 	int error;
1867 
1868 	fh->fh3_length = sizeof (fh->fh3_u.nfs_fh3_i);
1869 	fh->fh3_u.nfs_fh3_i.fh3_i = exi->exi_fh;	/* struct copy */
1870 
1871 	error = VOP_FID(vp, (fid_t *)&fh->fh3_len);
1872 
1873 	if (error) {
1874 		/*
1875 		 * Should be something other than EREMOTE
1876 		 */
1877 		return (EREMOTE);
1878 	}
1879 	return (0);
1880 }
1881 
1882 /*
1883  * This routine makes an overloaded V3 fhandle which contains
1884  * sec modes.
1885  *
1886  *  1        4
1887  * +--+--+--+--+
1888  * |    len    |
1889  * +--+--+--+--+
1890  *                                               up to 64
1891  * +--+--+--+--+--+--+--+--+--+--+--+--+     +--+--+--+--+
1892  * |s |  |  |  |   sec_1   |   sec_2   | ... |   sec_n   |
1893  * +--+--+--+--+--+--+--+--+--+--+--+--+     +--+--+--+--+
1894  *
1895  * len = 4 * (n+1), where n is the number of security flavors
1896  * sent in the current overloaded filehandle.
1897  *
1898  * the status octet s indicates whether there are more security
1899  * mechanisms (1 means yes, 0 means no) that require the client
1900  * to perform another 0x81 LOOKUP to get them.
1901  *
1902  * Three octets are padded after the status octet.
1903  */
1904 int
1905 makefh3_ol(nfs_fh3 *fh, struct exportinfo *exi, uint_t sec_index)
1906 {
1907 	static int max_cnt = NFS3_FHSIZE/sizeof (int) - 1;
1908 	int totalcnt, cnt, *ipt, i;
1909 	char *c;
1910 
1911 	if (fh == (nfs_fh3 *)NULL ||
1912 		exi == (struct exportinfo *)NULL ||
1913 		sec_index > exi->exi_export.ex_seccnt ||
1914 		sec_index < 1) {
1915 		return (EREMOTE);
1916 	}
1917 
1918 	totalcnt = exi->exi_export.ex_seccnt-sec_index+1;
1919 	cnt = totalcnt > max_cnt? max_cnt : totalcnt;
1920 
1921 	/*
1922 	 * Place the length in fh3_length representing the number
1923 	 * of security flavors (in bytes) in this overloaded fh.
1924 	 */
1925 	fh->fh3_length = (cnt+1) * sizeof (int32_t);
1926 
1927 	c = (char *)&fh->fh3_u.nfs_fh3_i.fh3_i;
1928 	/*
1929 	 * Encode the status octet that indicates whether there
1930 	 * are more security flavors the client needs to get.
1931 	 */
1932 	*c = totalcnt > max_cnt;
1933 
1934 	/*
1935 	 * put security flavors in the overloaded fh
1936 	 */
1937 	ipt = (int *)(c + sizeof (int32_t));
1938 	for (i = 0; i < cnt; i++) {
1939 		*(ipt+i) = htonl(
1940 		exi->exi_export.ex_secinfo[i+sec_index-1].s_secinfo.sc_nfsnum);
1941 	}
1942 	return (0);
1943 }
1944 
1945 /*
1946  * Make an nfs_fh4 from a vnode
1947  */
1948 int
1949 makefh4(nfs_fh4 *fh, vnode_t *vp, struct exportinfo *exi)
1950 {
1951 	int error;
1952 	nfs_fh4_fmt_t *fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val;
1953 	fid_t fid;
1954 
1955 	bzero(&fid, sizeof (fid));
1956 	fid.fid_len = MAXFIDSZ;
1957 	/*
1958 	 * vop_fid_pseudo() is used to set up NFSv4 namespace, so
1959 	 * use vop_fid_pseudo() here to get the fid instead of VOP_FID.
1960 	 */
1961 	error = vop_fid_pseudo(vp, &fid);
1962 	if (error)
1963 		return (error);
1964 
1965 	fh->nfs_fh4_len = NFS_FH4_LEN;
1966 
1967 	fh_fmtp->fh4_i = exi->exi_fh;	/* copy the fhandle template */
1968 	fh_fmtp->fh4_len = fid.fid_len;
1969 	ASSERT(fid.fid_len <= sizeof (fh_fmtp->fh4_data));
1970 	bcopy(fid.fid_data, fh_fmtp->fh4_data, fid.fid_len);
1971 	fh_fmtp->fh4_flag = 0;
1972 
1973 #ifdef VOLATILE_FH_TEST
1974 	/*
1975 	 * XXX (temporary?)
1976 	 * Use the rnode volatile_id value to add volatility to the fh.
1977 	 *
1978 	 * For testing purposes there are currently two scenarios, based
1979 	 * on whether the filesystem was shared with "volatile_fh"
1980 	 * or "expire_on_rename". In the first case, use the value of
1981 	 * export struct share_time as the volatile_id. In the second
1982 	 * case use the vnode volatile_id value (which is set to the
1983 	 * time in which the file was renamed).
1984 	 *
1985 	 * Note that the above are temporary constructs for testing only
1986 	 * XXX
1987 	 */
1988 	if (exi->exi_export.ex_flags & EX_VOLRNM) {
1989 		fh_fmtp->fh4_volatile_id = find_volrnm_fh_id(exi, fh);
1990 	} else if (exi->exi_export.ex_flags & EX_VOLFH) {
1991 		fh_fmtp->fh4_volatile_id = exi->exi_volatile_id;
1992 	} else {
1993 		fh_fmtp->fh4_volatile_id = 0;
1994 	}
1995 #endif /* VOLATILE_FH_TEST */
1996 
1997 	return (0);
1998 }
1999 
2000 /*
2001  * Convert an fhandle into a vnode.
2002  * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode.
2003  * WARNING: users of this routine must do a VN_RELE on the vnode when they
2004  * are done with it.
2005  */
2006 vnode_t *
2007 nfs_fhtovp(fhandle_t *fh, struct exportinfo *exi)
2008 {
2009 	vfs_t *vfsp;
2010 	vnode_t *vp;
2011 	int error;
2012 	fid_t *fidp;
2013 
2014 	TRACE_0(TR_FAC_NFS, TR_FHTOVP_START,
2015 		"fhtovp_start");
2016 
2017 	if (exi == NULL) {
2018 		TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2019 			"fhtovp_end:(%S)", "exi NULL");
2020 		return (NULL);	/* not exported */
2021 	}
2022 
2023 	ASSERT(exi->exi_vp != NULL);
2024 
2025 	if (PUBLIC_FH2(fh)) {
2026 		if (exi->exi_export.ex_flags & EX_PUBLIC) {
2027 			TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2028 				"fhtovp_end:(%S)", "root not exported");
2029 			return (NULL);
2030 		}
2031 		vp = exi->exi_vp;
2032 		VN_HOLD(vp);
2033 		return (vp);
2034 	}
2035 
2036 	vfsp = exi->exi_vp->v_vfsp;
2037 	ASSERT(vfsp != NULL);
2038 	fidp = (fid_t *)&fh->fh_len;
2039 
2040 	error = VFS_VGET(vfsp, &vp, fidp);
2041 	if (error || vp == NULL) {
2042 		TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2043 			"fhtovp_end:(%S)", "VFS_GET failed or vp NULL");
2044 		return (NULL);
2045 	}
2046 	TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2047 		"fhtovp_end:(%S)", "end");
2048 	return (vp);
2049 }
2050 
2051 /*
2052  * Convert an fhandle into a vnode.
2053  * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode.
2054  * WARNING: users of this routine must do a VN_RELE on the vnode when they
2055  * are done with it.
2056  * This is just like nfs_fhtovp() but without the exportinfo argument.
2057  */
2058 
2059 vnode_t *
2060 lm_fhtovp(fhandle_t *fh)
2061 {
2062 	register vfs_t *vfsp;
2063 	vnode_t *vp;
2064 	int error;
2065 
2066 	vfsp = getvfs(&fh->fh_fsid);
2067 	if (vfsp == NULL)
2068 		return (NULL);
2069 
2070 	error = VFS_VGET(vfsp, &vp, (fid_t *)&(fh->fh_len));
2071 	VFS_RELE(vfsp);
2072 	if (error || vp == NULL)
2073 		return (NULL);
2074 
2075 	return (vp);
2076 }
2077 
2078 /*
2079  * Convert an nfs_fh3 into a vnode.
2080  * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2081  * WARNING: users of this routine must do a VN_RELE on the vnode when they
2082  * are done with it.
2083  */
2084 vnode_t *
2085 nfs3_fhtovp(nfs_fh3 *fh, struct exportinfo *exi)
2086 {
2087 	vfs_t *vfsp;
2088 	vnode_t *vp;
2089 	int error;
2090 	fid_t *fidp;
2091 
2092 	if (exi == NULL)
2093 		return (NULL);	/* not exported */
2094 
2095 	ASSERT(exi->exi_vp != NULL);
2096 
2097 	if (PUBLIC_FH3(fh)) {
2098 		if (exi->exi_export.ex_flags & EX_PUBLIC)
2099 			return (NULL);
2100 		vp = exi->exi_vp;
2101 		VN_HOLD(vp);
2102 		return (vp);
2103 	}
2104 
2105 	if (fh->fh3_length != NFS3_CURFHSIZE)
2106 		return (NULL);
2107 
2108 	vfsp = exi->exi_vp->v_vfsp;
2109 	ASSERT(vfsp != NULL);
2110 	fidp = (fid_t *)&fh->fh3_len;
2111 
2112 	error = VFS_VGET(vfsp, &vp, fidp);
2113 	if (error || vp == NULL)
2114 		return (NULL);
2115 
2116 	return (vp);
2117 }
2118 
2119 /*
2120  * Convert an nfs_fh3 into a vnode.
2121  * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2122  * WARNING: users of this routine must do a VN_RELE on the vnode when they
2123  * are done with it.
2124  * BTW: This is just like nfs3_fhtovp() but without the exportinfo arg.
2125  * Also, vfsp is accessed through getvfs() rather using exportinfo !!
2126  */
2127 
2128 vnode_t *
2129 lm_nfs3_fhtovp(nfs_fh3 *fh)
2130 {
2131 	vfs_t *vfsp;
2132 	vnode_t *vp;
2133 	int error;
2134 
2135 	if (fh->fh3_length != NFS3_CURFHSIZE)
2136 		return (NULL);
2137 
2138 	vfsp = getvfs(&fh->fh3_fsid);
2139 	if (vfsp == NULL)
2140 		return (NULL);
2141 
2142 	error = VFS_VGET(vfsp, &vp, (fid_t *)&(fh->fh3_len));
2143 	VFS_RELE(vfsp);
2144 	if (error || vp == NULL)
2145 		return (NULL);
2146 
2147 	return (vp);
2148 }
2149 
2150 /*
2151  * Convert an nfs_fh4 into a vnode.
2152  * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2153  * WARNING: users of this routine must do a VN_RELE on the vnode when they
2154  * are done with it.
2155  */
2156 vnode_t *
2157 nfs4_fhtovp(nfs_fh4 *fh, struct exportinfo *exi, nfsstat4 *statp)
2158 {
2159 	vfs_t *vfsp;
2160 	vnode_t *vp = NULL;
2161 	int error;
2162 	fid_t *fidp;
2163 	nfs_fh4_fmt_t *fh_fmtp;
2164 #ifdef VOLATILE_FH_TEST
2165 	uint32_t volatile_id = 0;
2166 #endif /* VOLATILE_FH_TEST */
2167 
2168 	if (exi == NULL) {
2169 		*statp = NFS4ERR_STALE;
2170 		return (NULL);	/* not exported */
2171 	}
2172 	ASSERT(exi->exi_vp != NULL);
2173 
2174 	/* caller should have checked this */
2175 	ASSERT(fh->nfs_fh4_len >= NFS_FH4_LEN);
2176 
2177 	fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val;
2178 	vfsp = exi->exi_vp->v_vfsp;
2179 	ASSERT(vfsp != NULL);
2180 	fidp = (fid_t *)&fh_fmtp->fh4_len;
2181 
2182 #ifdef VOLATILE_FH_TEST
2183 	/* XXX check if volatile - should be changed later */
2184 	if (exi->exi_export.ex_flags & (EX_VOLRNM | EX_VOLFH)) {
2185 		/*
2186 		 * Filesystem is shared with volatile filehandles
2187 		 */
2188 		if (exi->exi_export.ex_flags & EX_VOLRNM)
2189 			volatile_id = find_volrnm_fh_id(exi, fh);
2190 		else
2191 			volatile_id = exi->exi_volatile_id;
2192 
2193 		if (fh_fmtp->fh4_volatile_id != volatile_id) {
2194 			*statp = NFS4ERR_FHEXPIRED;
2195 			return (NULL);
2196 		}
2197 	}
2198 	/*
2199 	 * XXX even if test_volatile_fh false, the fh may contain a
2200 	 * volatile id if obtained when the test was set.
2201 	 */
2202 	fh_fmtp->fh4_volatile_id = (uchar_t)0;
2203 #endif /* VOLATILE_FH_TEST */
2204 
2205 	error = VFS_VGET(vfsp, &vp, fidp);
2206 	/*
2207 	 * If we can not get vp from VFS_VGET, perhaps this is
2208 	 * an nfs v2/v3/v4 node in an nfsv4 pseudo filesystem.
2209 	 * Check it out.
2210 	 */
2211 	if (error && PSEUDO(exi))
2212 		error = nfs4_vget_pseudo(exi, &vp, fidp);
2213 
2214 	if (error || vp == NULL) {
2215 		*statp = NFS4ERR_STALE;
2216 		return (NULL);
2217 	}
2218 	/* XXX - disgusting hack */
2219 	if (vp->v_type == VNON && vp->v_flag & V_XATTRDIR)
2220 		vp->v_type = VDIR;
2221 	*statp = NFS4_OK;
2222 	return (vp);
2223 }
2224 
2225 /*
2226  * Find the export structure associated with the given filesystem.
2227  * If found, then increment the ref count (exi_count).
2228  */
2229 struct exportinfo *
2230 checkexport(fsid_t *fsid, fid_t *fid)
2231 {
2232 	struct exportinfo *exi;
2233 
2234 	rw_enter(&exported_lock, RW_READER);
2235 	for (exi = exptable[exptablehash(fsid, fid)];
2236 	    exi != NULL;
2237 	    exi = exi->exi_hash) {
2238 		if (exportmatch(exi, fsid, fid)) {
2239 			/*
2240 			 * If this is the place holder for the
2241 			 * public file handle, then return the
2242 			 * real export entry for the public file
2243 			 * handle.
2244 			 */
2245 			if (exi->exi_export.ex_flags & EX_PUBLIC) {
2246 				exi = exi_public;
2247 			}
2248 			mutex_enter(&exi->exi_lock);
2249 			exi->exi_count++;
2250 			mutex_exit(&exi->exi_lock);
2251 			rw_exit(&exported_lock);
2252 			return (exi);
2253 		}
2254 	}
2255 	rw_exit(&exported_lock);
2256 	return (NULL);
2257 }
2258 
2259 
2260 /*
2261  * "old school" version of checkexport() for NFS4.  NFS4
2262  * rfs4_compound holds exported_lock for duration of compound
2263  * processing.  This version doesn't manipulate exi_count
2264  * since NFS4 breaks fundamental assumptions in the exi_count
2265  * design.
2266  */
2267 struct exportinfo *
2268 checkexport4(fsid_t *fsid, fid_t *fid, vnode_t *vp)
2269 {
2270 	struct exportinfo *exi;
2271 
2272 	ASSERT(RW_LOCK_HELD(&exported_lock));
2273 
2274 	for (exi = exptable[exptablehash(fsid, fid)];
2275 	    exi != NULL;
2276 	    exi = exi->exi_hash) {
2277 		if (exportmatch(exi, fsid, fid)) {
2278 			/*
2279 			 * If this is the place holder for the
2280 			 * public file handle, then return the
2281 			 * real export entry for the public file
2282 			 * handle.
2283 			 */
2284 			if (exi->exi_export.ex_flags & EX_PUBLIC) {
2285 				exi = exi_public;
2286 			}
2287 
2288 			/*
2289 			 * If vp is given, check if vp is the
2290 			 * same vnode as the exported node.
2291 			 *
2292 			 * Since VOP_FID of a lofs node returns the
2293 			 * fid of its real node (ufs), the exported
2294 			 * node for lofs and (pseudo) ufs may have
2295 			 * the same fsid and fid.
2296 			 */
2297 			if (vp == NULL || vp == exi->exi_vp)
2298 				return (exi);
2299 		}
2300 	}
2301 
2302 	return (NULL);
2303 }
2304 
2305 /*
2306  * Free an entire export list node
2307  */
2308 void
2309 exportfree(struct exportinfo *exi)
2310 {
2311 	struct exportdata *ex;
2312 
2313 	ex = &exi->exi_export;
2314 
2315 	ASSERT(exi->exi_vp != NULL && !(exi->exi_export.ex_flags & EX_PUBLIC));
2316 	VN_RELE(exi->exi_vp);
2317 	if (exi->exi_dvp != NULL)
2318 		VN_RELE(exi->exi_dvp);
2319 
2320 	if (ex->ex_flags & EX_INDEX)
2321 		kmem_free(ex->ex_index, strlen(ex->ex_index) + 1);
2322 
2323 	kmem_free(ex->ex_path, ex->ex_pathlen + 1);
2324 	nfsauth_cache_free(exi);
2325 
2326 	if (exi->exi_logbuffer != NULL)
2327 		nfslog_disable(exi);
2328 
2329 	if (ex->ex_flags & EX_LOG) {
2330 		kmem_free(ex->ex_log_buffer, ex->ex_log_bufferlen + 1);
2331 		kmem_free(ex->ex_tag, ex->ex_taglen + 1);
2332 	}
2333 
2334 	if (exi->exi_visible)
2335 		free_visible(exi->exi_visible);
2336 
2337 	srv_secinfo_list_free(ex->ex_secinfo, ex->ex_seccnt);
2338 
2339 #ifdef VOLATILE_FH_TEST
2340 	free_volrnm_list(exi);
2341 	mutex_destroy(&exi->exi_vol_rename_lock);
2342 #endif /* VOLATILE_FH_TEST */
2343 
2344 	mutex_destroy(&exi->exi_lock);
2345 	rw_destroy(&exi->exi_cache_lock);
2346 
2347 	kmem_free(exi, sizeof (*exi));
2348 }
2349 
2350 /*
2351  * load the index file from user space into kernel space.
2352  */
2353 static int
2354 loadindex(struct exportdata *kex)
2355 {
2356 	int error;
2357 	char index[MAXNAMELEN+1];
2358 	size_t len;
2359 
2360 	/*
2361 	 * copyinstr copies the complete string including the NULL and
2362 	 * returns the len with the NULL byte included in the calculation
2363 	 * as long as the max length is not exceeded.
2364 	 */
2365 	if (error = copyinstr(kex->ex_index, index, sizeof (index), &len))
2366 		return (error);
2367 
2368 	kex->ex_index = kmem_alloc(len, KM_SLEEP);
2369 	bcopy(index, kex->ex_index, len);
2370 
2371 	return (0);
2372 }
2373 
2374 /*
2375  * When a thread completes using exi, it should call exi_rele().
2376  * exi_rele() decrements exi_count. It releases exi if exi_count == 0, i.e.
2377  * if this is the last user of exi and exi is not on exportinfo list anymore
2378  */
2379 void
2380 exi_rele(struct exportinfo *exi)
2381 {
2382 	mutex_enter(&exi->exi_lock);
2383 	exi->exi_count--;
2384 	if (exi->exi_count == 0) {
2385 		mutex_exit(&exi->exi_lock);
2386 		exportfree(exi);
2387 	} else
2388 		mutex_exit(&exi->exi_lock);
2389 }
2390 
2391 #ifdef VOLATILE_FH_TEST
2392 /*
2393  * Test for volatile fh's - add file handle to list and set its volatile id
2394  * to time it was renamed. If EX_VOLFH is also on and the fs is reshared,
2395  * the vol_rename queue is purged.
2396  *
2397  * XXX This code is for unit testing purposes only... To correctly use it, it
2398  * needs to tie a rename list to the export struct and (more
2399  * important), protect access to the exi rename list using a write lock.
2400  */
2401 
2402 /*
2403  * get the fh vol record if it's in the volatile on rename list. Don't check
2404  * volatile_id in the file handle - compare only the file handles.
2405  */
2406 static struct ex_vol_rename *
2407 find_volrnm_fh(struct exportinfo *exi, nfs_fh4 *fh4p)
2408 {
2409 	struct ex_vol_rename *p = NULL;
2410 	fhandle_t *fhp;
2411 
2412 	/* XXX shouldn't we assert &exported_lock held? */
2413 	ASSERT(MUTEX_HELD(&exi->exi_vol_rename_lock));
2414 
2415 	if (fh4p->nfs_fh4_len != NFS_FH4_LEN) {
2416 		return (NULL);
2417 	}
2418 	fhp = &((struct nfs_fh4_fmt *)fh4p->nfs_fh4_val)->fh4_i;
2419 	for (p = exi->exi_vol_rename; p != NULL; p = p->vrn_next) {
2420 		if (bcmp(fhp, &p->vrn_fh_fmt.fh4_i, sizeof (fhandle_t)) == 0)
2421 			break;
2422 	}
2423 	return (p);
2424 }
2425 
2426 /*
2427  * get the volatile id for the fh (if there is - else return 0). Ignore the
2428  * volatile_id in the file handle - compare only the file handles.
2429  */
2430 static uint32_t
2431 find_volrnm_fh_id(struct exportinfo *exi, nfs_fh4 *fh4p)
2432 {
2433 	struct ex_vol_rename *p;
2434 	uint32_t volatile_id;
2435 
2436 	mutex_enter(&exi->exi_vol_rename_lock);
2437 	p = find_volrnm_fh(exi, fh4p);
2438 	volatile_id = (p ? p->vrn_fh_fmt.fh4_volatile_id :
2439 				exi->exi_volatile_id);
2440 	mutex_exit(&exi->exi_vol_rename_lock);
2441 	return (volatile_id);
2442 }
2443 
2444 /*
2445  * Free the volatile on rename list - will be called if a filesystem is
2446  * unshared or reshared without EX_VOLRNM
2447  */
2448 static void
2449 free_volrnm_list(struct exportinfo *exi)
2450 {
2451 	struct ex_vol_rename *p, *pnext;
2452 
2453 	/* no need to hold mutex lock - this one is called from exportfree */
2454 	for (p = exi->exi_vol_rename; p != NULL; p = pnext) {
2455 		pnext = p->vrn_next;
2456 		kmem_free(p, sizeof (*p));
2457 	}
2458 	exi->exi_vol_rename = NULL;
2459 }
2460 
2461 /*
2462  * Add a file handle to the volatile on rename list.
2463  */
2464 void
2465 add_volrnm_fh(struct exportinfo *exi, vnode_t *vp)
2466 {
2467 	struct ex_vol_rename *p;
2468 	char fhbuf[NFS4_FHSIZE];
2469 	nfs_fh4 fh4;
2470 	int error;
2471 
2472 	fh4.nfs_fh4_val = fhbuf;
2473 	error = makefh4(&fh4, vp, exi);
2474 	if ((error) || (fh4.nfs_fh4_len != sizeof (p->vrn_fh_fmt))) {
2475 		return;
2476 	}
2477 
2478 	mutex_enter(&exi->exi_vol_rename_lock);
2479 
2480 	p = find_volrnm_fh(exi, &fh4);
2481 
2482 	if (p == NULL) {
2483 		p = kmem_alloc(sizeof (*p), KM_SLEEP);
2484 		bcopy(fh4.nfs_fh4_val, &p->vrn_fh_fmt, sizeof (p->vrn_fh_fmt));
2485 		p->vrn_next = exi->exi_vol_rename;
2486 		exi->exi_vol_rename = p;
2487 	}
2488 
2489 	p->vrn_fh_fmt.fh4_volatile_id = gethrestime_sec();
2490 	mutex_exit(&exi->exi_vol_rename_lock);
2491 }
2492 
2493 #endif /* VOLATILE_FH_TEST */
2494