xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs_export.c (revision bd3561fb)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
527242a7cSthurlow  * Common Development and Distribution License (the "License").
627242a7cSthurlow  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2171da0c32SMarcel Telka 
227c478bd9Sstevel@tonic-gate /*
233ccecb66SThomas Haynes  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
270dfe541eSEvan Layton  *	Copyright 1983, 1984, 1985, 1986, 1987, 1988, 1989  AT&T.
287c478bd9Sstevel@tonic-gate  *		All rights reserved.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
310dfe541eSEvan Layton /*
320dfe541eSEvan Layton  * Copyright 2018 Nexenta Systems, Inc.
330dfe541eSEvan Layton  */
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include <sys/types.h>
367c478bd9Sstevel@tonic-gate #include <sys/param.h>
377c478bd9Sstevel@tonic-gate #include <sys/time.h>
387c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
397c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
407c478bd9Sstevel@tonic-gate #include <sys/socket.h>
417c478bd9Sstevel@tonic-gate #include <sys/errno.h>
427c478bd9Sstevel@tonic-gate #include <sys/uio.h>
437c478bd9Sstevel@tonic-gate #include <sys/proc.h>
447c478bd9Sstevel@tonic-gate #include <sys/user.h>
457c478bd9Sstevel@tonic-gate #include <sys/file.h>
467c478bd9Sstevel@tonic-gate #include <sys/tiuser.h>
477c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
487c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
497c478bd9Sstevel@tonic-gate #include <sys/debug.h>
507c478bd9Sstevel@tonic-gate #include <sys/vtrace.h>
517c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
527c478bd9Sstevel@tonic-gate #include <sys/acl.h>
537c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
54af9f9769Sjasmith #include <sys/sdt.h>
557c478bd9Sstevel@tonic-gate #include <netinet/in.h>
5671da0c32SMarcel Telka #include <sys/avl.h>
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #include <rpc/types.h>
597c478bd9Sstevel@tonic-gate #include <rpc/auth.h>
607c478bd9Sstevel@tonic-gate #include <rpc/svc.h>
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
637c478bd9Sstevel@tonic-gate #include <nfs/export.h>
647c478bd9Sstevel@tonic-gate #include <nfs/nfssys.h>
657c478bd9Sstevel@tonic-gate #include <nfs/nfs_clnt.h>
667c478bd9Sstevel@tonic-gate #include <nfs/nfs_acl.h>
677c478bd9Sstevel@tonic-gate #include <nfs/nfs_log.h>
687c478bd9Sstevel@tonic-gate #include <nfs/lm.h>
69b89a8333Snatalie li - Sun Microsystems - Irvine United States #include <sys/sunddi.h>
707c478bd9Sstevel@tonic-gate 
710dfe541eSEvan Layton /*
720dfe541eSEvan Layton  * exi_id support
730dfe541eSEvan Layton  *
740dfe541eSEvan Layton  * exi_id_next		The next exi_id available.
750dfe541eSEvan Layton  * exi_id_overflow	The exi_id_next already overflowed, so we should
760dfe541eSEvan Layton  *			thoroughly check for duplicates.
770dfe541eSEvan Layton  * exi_id_tree		AVL tree indexed by exi_id.
780dfe541eSEvan Layton  * nfs_exi_id_lock	Lock to protect the export ID list
790dfe541eSEvan Layton  *
800dfe541eSEvan Layton  * All exi_id_next, exi_id_overflow, and exi_id_tree are protected by
810dfe541eSEvan Layton  * nfs_exi_id_lock.
820dfe541eSEvan Layton  */
830dfe541eSEvan Layton static int exi_id_next;
840dfe541eSEvan Layton static bool_t exi_id_overflow;
850dfe541eSEvan Layton avl_tree_t exi_id_tree;
860dfe541eSEvan Layton kmutex_t nfs_exi_id_lock;
877c478bd9Sstevel@tonic-gate 
8806260e34SDan McDonald static int	unexport(nfs_export_t *, exportinfo_t *, cred_t *);
89af9f9769Sjasmith static void	exportfree(exportinfo_t *);
90af9f9769Sjasmith static int	loadindex(exportdata_t *);
917c478bd9Sstevel@tonic-gate 
92af9f9769Sjasmith extern void	nfsauth_cache_free(exportinfo_t *);
937c478bd9Sstevel@tonic-gate extern int	sec_svc_loadrootnames(int, int, caddr_t **, model_t);
947c478bd9Sstevel@tonic-gate extern void	sec_svc_freerootnames(int, int, caddr_t *);
957c478bd9Sstevel@tonic-gate 
960dfe541eSEvan Layton static int	build_seclist_nodups(exportdata_t *, secinfo_t *, int);
970dfe541eSEvan Layton static void	srv_secinfo_add(secinfo_t **, int *, secinfo_t *, int, int);
980dfe541eSEvan Layton static void	srv_secinfo_remove(secinfo_t **, int *, secinfo_t *, int);
990dfe541eSEvan Layton static void	srv_secinfo_treeclimb(nfs_export_t *, exportinfo_t *,
1000dfe541eSEvan Layton 		    secinfo_t *, int, bool_t);
101af9f9769Sjasmith 
1027c478bd9Sstevel@tonic-gate #ifdef VOLATILE_FH_TEST
103af9f9769Sjasmith static struct ex_vol_rename *find_volrnm_fh(exportinfo_t *, nfs_fh4 *);
104af9f9769Sjasmith static uint32_t find_volrnm_fh_id(exportinfo_t *, nfs_fh4 *);
1050dfe541eSEvan Layton static void	free_volrnm_list(exportinfo_t *);
1067c478bd9Sstevel@tonic-gate #endif /* VOLATILE_FH_TEST */
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate fhandle_t nullfh2;	/* for comparing V2 filehandles */
1097c478bd9Sstevel@tonic-gate 
110af9f9769Sjasmith /*
111af9f9769Sjasmith  * macro for static dtrace probes to trace server namespace ref count mods.
112af9f9769Sjasmith  */
113af9f9769Sjasmith #define	SECREF_TRACE(seclist, tag, flav, aftcnt) \
114992d2facSpf 	DTRACE_PROBE4(nfss__i__nmspc__secref, struct secinfo *, (seclist), \
115af9f9769Sjasmith 		char *, (tag), int, (int)(flav), int, (int)(aftcnt))
116af9f9769Sjasmith 
117af9f9769Sjasmith 
1187c478bd9Sstevel@tonic-gate #define	exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1))
1197c478bd9Sstevel@tonic-gate 
1200dfe541eSEvan Layton extern nfs_export_t *
nfs_get_export(void)1210dfe541eSEvan Layton nfs_get_export(void)
1220dfe541eSEvan Layton {
1230dfe541eSEvan Layton 	nfs_globals_t *ng = nfs_srv_getzg();
1240dfe541eSEvan Layton 	nfs_export_t *ne = ng->nfs_export;
1250dfe541eSEvan Layton 	ASSERT(ne != NULL);
1260dfe541eSEvan Layton 	return (ne);
1270dfe541eSEvan Layton }
1280dfe541eSEvan Layton 
1290616fd7fSPavel Filipensky static uint8_t
xor_hash(uint8_t * data,int len)1300616fd7fSPavel Filipensky xor_hash(uint8_t *data, int len)
131f932e4e7SPavel Filipensky {
1320616fd7fSPavel Filipensky 	uint8_t h = 0;
133bfbb13c9Sjmcp 
1340616fd7fSPavel Filipensky 	while (len--)
1350616fd7fSPavel Filipensky 		h ^= *data++;
1367c478bd9Sstevel@tonic-gate 
1370616fd7fSPavel Filipensky 	return (h);
1380616fd7fSPavel Filipensky }
139bfbb13c9Sjmcp 
1400616fd7fSPavel Filipensky /*
1410616fd7fSPavel Filipensky  * File handle hash function, XOR over all bytes in fsid and fid.
1420616fd7fSPavel Filipensky  */
1430616fd7fSPavel Filipensky static unsigned
nfs_fhhash(fsid_t * fsid,fid_t * fid)1440616fd7fSPavel Filipensky nfs_fhhash(fsid_t *fsid, fid_t *fid)
1450616fd7fSPavel Filipensky {
1460616fd7fSPavel Filipensky 	int len;
1470616fd7fSPavel Filipensky 	uint8_t h;
148bfbb13c9Sjmcp 
1490616fd7fSPavel Filipensky 	h = xor_hash((uint8_t *)fsid, sizeof (fsid_t));
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	/*
1527c478bd9Sstevel@tonic-gate 	 * Sanity check the length before using it
1537c478bd9Sstevel@tonic-gate 	 * blindly in case the client trashed it.
1547c478bd9Sstevel@tonic-gate 	 */
1550616fd7fSPavel Filipensky 	len = fid->fid_len > NFS_FH4MAXDATA ? 0 : fid->fid_len;
1560616fd7fSPavel Filipensky 	h ^= xor_hash((uint8_t *)fid->fid_data, len);
1577c478bd9Sstevel@tonic-gate 
1580616fd7fSPavel Filipensky 	return ((unsigned)h);
1597c478bd9Sstevel@tonic-gate }
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate /*
1627c478bd9Sstevel@tonic-gate  * Free the memory allocated within a secinfo entry.
1637c478bd9Sstevel@tonic-gate  */
1647c478bd9Sstevel@tonic-gate void
srv_secinfo_entry_free(struct secinfo * secp)1657c478bd9Sstevel@tonic-gate srv_secinfo_entry_free(struct secinfo *secp)
1667c478bd9Sstevel@tonic-gate {
1677c478bd9Sstevel@tonic-gate 	if (secp->s_rootcnt > 0 && secp->s_rootnames != NULL) {
1687c478bd9Sstevel@tonic-gate 		sec_svc_freerootnames(secp->s_secinfo.sc_rpcnum,
169af9f9769Sjasmith 		    secp->s_rootcnt, secp->s_rootnames);
1707c478bd9Sstevel@tonic-gate 		secp->s_rootcnt = 0;
1717c478bd9Sstevel@tonic-gate 	}
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	if ((secp->s_secinfo.sc_rpcnum == RPCSEC_GSS) &&
1747c478bd9Sstevel@tonic-gate 	    (secp->s_secinfo.sc_gss_mech_type)) {
1757c478bd9Sstevel@tonic-gate 		kmem_free(secp->s_secinfo.sc_gss_mech_type->elements,
176af9f9769Sjasmith 		    secp->s_secinfo.sc_gss_mech_type->length);
1777c478bd9Sstevel@tonic-gate 		kmem_free(secp->s_secinfo.sc_gss_mech_type,
178af9f9769Sjasmith 		    sizeof (rpc_gss_OID_desc));
1797c478bd9Sstevel@tonic-gate 		secp->s_secinfo.sc_gss_mech_type = NULL;
1807c478bd9Sstevel@tonic-gate 	}
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate /*
1847c478bd9Sstevel@tonic-gate  * Free a list of secinfo allocated in the exportdata structure.
1857c478bd9Sstevel@tonic-gate  */
1867c478bd9Sstevel@tonic-gate void
srv_secinfo_list_free(struct secinfo * secinfo,int cnt)1877c478bd9Sstevel@tonic-gate srv_secinfo_list_free(struct secinfo *secinfo, int cnt)
1887c478bd9Sstevel@tonic-gate {
1897c478bd9Sstevel@tonic-gate 	int i;
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	if (cnt == 0)
1927c478bd9Sstevel@tonic-gate 		return;
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	for (i = 0; i < cnt; i++)
1957c478bd9Sstevel@tonic-gate 		srv_secinfo_entry_free(&secinfo[i]);
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	kmem_free(secinfo, cnt * sizeof (struct secinfo));
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate /*
2017c478bd9Sstevel@tonic-gate  * Allocate and copy a secinfo data from "from" to "to".
2027c478bd9Sstevel@tonic-gate  *
2037c478bd9Sstevel@tonic-gate  * This routine is used by srv_secinfo_add() to add a new flavor to an
2047c478bd9Sstevel@tonic-gate  * ancestor's export node. The rootnames are not copied because the
2057c478bd9Sstevel@tonic-gate  * allowable rootname access only applies to the explicit exported node,
2067c478bd9Sstevel@tonic-gate  * not its ancestor's.
2077c478bd9Sstevel@tonic-gate  *
2087c478bd9Sstevel@tonic-gate  * "to" should have already been allocated and zeroed before calling
2097c478bd9Sstevel@tonic-gate  * this routine.
2107c478bd9Sstevel@tonic-gate  *
2117c478bd9Sstevel@tonic-gate  * This routine is used under the protection of exported_lock (RW_WRITER).
2127c478bd9Sstevel@tonic-gate  */
2137c478bd9Sstevel@tonic-gate void
srv_secinfo_copy(struct secinfo * from,struct secinfo * to)2147c478bd9Sstevel@tonic-gate srv_secinfo_copy(struct secinfo *from, struct secinfo *to)
2157c478bd9Sstevel@tonic-gate {
2167c478bd9Sstevel@tonic-gate 	to->s_secinfo.sc_nfsnum = from->s_secinfo.sc_nfsnum;
2177c478bd9Sstevel@tonic-gate 	to->s_secinfo.sc_rpcnum = from->s_secinfo.sc_rpcnum;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	if (from->s_secinfo.sc_rpcnum == RPCSEC_GSS) {
2207c478bd9Sstevel@tonic-gate 		to->s_secinfo.sc_service = from->s_secinfo.sc_service;
2217c478bd9Sstevel@tonic-gate 		bcopy(from->s_secinfo.sc_name, to->s_secinfo.sc_name,
222af9f9769Sjasmith 		    strlen(from->s_secinfo.sc_name));
2237c478bd9Sstevel@tonic-gate 		bcopy(from->s_secinfo.sc_gss_mech, to->s_secinfo.sc_gss_mech,
224af9f9769Sjasmith 		    strlen(from->s_secinfo.sc_gss_mech));
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 		/* copy mechanism oid */
2277c478bd9Sstevel@tonic-gate 		to->s_secinfo.sc_gss_mech_type =
228af9f9769Sjasmith 		    kmem_alloc(sizeof (rpc_gss_OID_desc), KM_SLEEP);
2297c478bd9Sstevel@tonic-gate 		to->s_secinfo.sc_gss_mech_type->length =
230af9f9769Sjasmith 		    from->s_secinfo.sc_gss_mech_type->length;
2317c478bd9Sstevel@tonic-gate 		to->s_secinfo.sc_gss_mech_type->elements =
232af9f9769Sjasmith 		    kmem_alloc(from->s_secinfo.sc_gss_mech_type->length,
233af9f9769Sjasmith 		    KM_SLEEP);
2347c478bd9Sstevel@tonic-gate 		bcopy(from->s_secinfo.sc_gss_mech_type->elements,
235af9f9769Sjasmith 		    to->s_secinfo.sc_gss_mech_type->elements,
236af9f9769Sjasmith 		    from->s_secinfo.sc_gss_mech_type->length);
2377c478bd9Sstevel@tonic-gate 	}
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	to->s_refcnt = from->s_refcnt;
2407c478bd9Sstevel@tonic-gate 	to->s_window = from->s_window;
2417c478bd9Sstevel@tonic-gate 	/* no need to copy the mode bits - s_flags */
2427c478bd9Sstevel@tonic-gate }
2437c478bd9Sstevel@tonic-gate 
2448a429e7eSms /*
245af9f9769Sjasmith  * Create a secinfo array without duplicates.  The condensed
246af9f9769Sjasmith  * flavor list is used to propagate flavor ref counts  to an
247af9f9769Sjasmith  * export's ancestor pseudonodes.
2488a429e7eSms  */
249af9f9769Sjasmith static int
build_seclist_nodups(exportdata_t * exd,secinfo_t * nodups,int exponly)250af9f9769Sjasmith build_seclist_nodups(exportdata_t *exd, secinfo_t *nodups, int exponly)
2518a429e7eSms {
252af9f9769Sjasmith 	int ccnt, c;
253af9f9769Sjasmith 	int ncnt, n;
254af9f9769Sjasmith 	struct secinfo *cursec;
255af9f9769Sjasmith 
256af9f9769Sjasmith 	ncnt = 0;
257af9f9769Sjasmith 	ccnt = exd->ex_seccnt;
258af9f9769Sjasmith 	cursec = exd->ex_secinfo;
259af9f9769Sjasmith 
260af9f9769Sjasmith 	for (c = 0; c < ccnt; c++) {
261af9f9769Sjasmith 
262af9f9769Sjasmith 		if (exponly && ! SEC_REF_EXPORTED(&cursec[c]))
263af9f9769Sjasmith 			continue;
264af9f9769Sjasmith 
265af9f9769Sjasmith 		for (n = 0; n < ncnt; n++) {
266af9f9769Sjasmith 			if (nodups[n].s_secinfo.sc_nfsnum ==
267af9f9769Sjasmith 			    cursec[c].s_secinfo.sc_nfsnum)
2688a429e7eSms 				break;
2698a429e7eSms 		}
270af9f9769Sjasmith 
271af9f9769Sjasmith 		/*
272af9f9769Sjasmith 		 * The structure copy below also copys ptrs embedded
273af9f9769Sjasmith 		 * within struct secinfo.  The ptrs are copied but
274af9f9769Sjasmith 		 * they are never freed from the nodups array.  If
275af9f9769Sjasmith 		 * an ancestor's secinfo array doesn't contain one
276af9f9769Sjasmith 		 * of the nodups flavors, then the entry is properly
277af9f9769Sjasmith 		 * copied into the ancestor's secinfo array.
278af9f9769Sjasmith 		 * (see srv_secinfo_copy)
279af9f9769Sjasmith 		 */
280af9f9769Sjasmith 		if (n == ncnt) {
281af9f9769Sjasmith 			nodups[n] = cursec[c];
2828a429e7eSms 			ncnt++;
2838a429e7eSms 		}
2848a429e7eSms 	}
2858a429e7eSms 	return (ncnt);
2868a429e7eSms }
2878a429e7eSms 
2887c478bd9Sstevel@tonic-gate /*
289af9f9769Sjasmith  * Add the new security flavors from newdata to the current list, pcursec.
290af9f9769Sjasmith  * Upon return, *pcursec has the newly merged secinfo list.
2917c478bd9Sstevel@tonic-gate  *
292af9f9769Sjasmith  * There should be at least 1 secinfo entry in newsec.
2937c478bd9Sstevel@tonic-gate  *
2947c478bd9Sstevel@tonic-gate  * This routine is used under the protection of exported_lock (RW_WRITER).
2957c478bd9Sstevel@tonic-gate  */
296af9f9769Sjasmith static void
srv_secinfo_add(secinfo_t ** pcursec,int * pcurcnt,secinfo_t * newsec,int newcnt,int is_pseudo)297af9f9769Sjasmith srv_secinfo_add(secinfo_t **pcursec, int *pcurcnt, secinfo_t *newsec,
298af9f9769Sjasmith     int newcnt, int is_pseudo)
2997c478bd9Sstevel@tonic-gate {
3007c478bd9Sstevel@tonic-gate 	int ccnt, c;		/* sec count in current data - curdata */
301af9f9769Sjasmith 	int n;			/* index for newsec  - newsecinfo */
302af9f9769Sjasmith 	int tcnt;		/* total sec count after merge */
303af9f9769Sjasmith 	int mcnt;		/* total sec count after merge */
3047c478bd9Sstevel@tonic-gate 	struct secinfo *msec;	/* merged secinfo list */
305af9f9769Sjasmith 	struct secinfo *cursec;
3067c478bd9Sstevel@tonic-gate 
307af9f9769Sjasmith 	cursec = *pcursec;
308af9f9769Sjasmith 	ccnt = *pcurcnt;
3097c478bd9Sstevel@tonic-gate 
310af9f9769Sjasmith 	ASSERT(newcnt > 0);
311af9f9769Sjasmith 	tcnt = ccnt + newcnt;
3127c478bd9Sstevel@tonic-gate 
313af9f9769Sjasmith 	for (n = 0; n < newcnt; n++) {
3147c478bd9Sstevel@tonic-gate 		for (c = 0; c < ccnt; c++) {
315af9f9769Sjasmith 			if (newsec[n].s_secinfo.sc_nfsnum ==
316af9f9769Sjasmith 			    cursec[c].s_secinfo.sc_nfsnum) {
3176ca33dd1Sjasmith 				cursec[c].s_refcnt += newsec[n].s_refcnt;
318af9f9769Sjasmith 				SECREF_TRACE(cursec, "add_ref",
319af9f9769Sjasmith 				    cursec[c].s_secinfo.sc_nfsnum,
320af9f9769Sjasmith 				    cursec[c].s_refcnt);
321af9f9769Sjasmith 				tcnt--;
322af9f9769Sjasmith 				break;
323af9f9769Sjasmith 			}
3247c478bd9Sstevel@tonic-gate 		}
3257c478bd9Sstevel@tonic-gate 	}
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	if (tcnt == ccnt)
3287c478bd9Sstevel@tonic-gate 		return; /* no change; no new flavors */
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	/* move current secinfo list data to the new list */
333af9f9769Sjasmith 	for (c = 0; c < ccnt; c++)
334af9f9769Sjasmith 		msec[c] = cursec[c];
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	/* Add the flavor that's not in the current data */
3377c478bd9Sstevel@tonic-gate 	mcnt = ccnt;
338af9f9769Sjasmith 	for (n = 0; n < newcnt; n++) {
3397c478bd9Sstevel@tonic-gate 		for (c = 0; c < ccnt; c++) {
340af9f9769Sjasmith 			if (newsec[n].s_secinfo.sc_nfsnum ==
341af9f9769Sjasmith 			    cursec[c].s_secinfo.sc_nfsnum)
3427c478bd9Sstevel@tonic-gate 				break;
3437c478bd9Sstevel@tonic-gate 		}
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 		/* This is the one. Add it. */
3467c478bd9Sstevel@tonic-gate 		if (c == ccnt) {
347af9f9769Sjasmith 			srv_secinfo_copy(&newsec[n], &msec[mcnt]);
348af9f9769Sjasmith 
349af9f9769Sjasmith 			if (is_pseudo)
350af9f9769Sjasmith 				msec[mcnt].s_flags = M_RO;
351af9f9769Sjasmith 
352af9f9769Sjasmith 			SECREF_TRACE(msec, "new_ref",
353af9f9769Sjasmith 			    msec[mcnt].s_secinfo.sc_nfsnum,
354af9f9769Sjasmith 			    msec[mcnt].s_refcnt);
355af9f9769Sjasmith 			mcnt++;
3567c478bd9Sstevel@tonic-gate 		}
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	ASSERT(mcnt == tcnt);
360af9f9769Sjasmith 
3617c478bd9Sstevel@tonic-gate 	/*
362af9f9769Sjasmith 	 * Done. Update curdata. Free the old secinfo list in
363af9f9769Sjasmith 	 * curdata and return the new sec array info
3647c478bd9Sstevel@tonic-gate 	 */
3657c478bd9Sstevel@tonic-gate 	if (ccnt > 0)
366af9f9769Sjasmith 		kmem_free(cursec, ccnt * sizeof (struct secinfo));
367af9f9769Sjasmith 	*pcurcnt = tcnt;
368af9f9769Sjasmith 	*pcursec = msec;
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate /*
3727c478bd9Sstevel@tonic-gate  * For NFS V4.
3737c478bd9Sstevel@tonic-gate  * Remove the security data of the unexported node from its ancestors.
374af9f9769Sjasmith  * Assume there is at least one flavor entry in the current sec list
375af9f9769Sjasmith  * (pcursec).
3767c478bd9Sstevel@tonic-gate  *
3777c478bd9Sstevel@tonic-gate  * This routine is used under the protection of exported_lock (RW_WRITER).
378af9f9769Sjasmith  *
379af9f9769Sjasmith  * Every element of remsec is an explicitly exported flavor.  If
380af9f9769Sjasmith  * srv_secinfo_remove() is called fom an exportfs error path, then
381af9f9769Sjasmith  * the flavor list was derived from the user's share cmdline,
382af9f9769Sjasmith  * and all flavors are explicit.  If it was called from the unshare path,
383af9f9769Sjasmith  * build_seclist_nodups() was called with the exponly flag.
3847c478bd9Sstevel@tonic-gate  */
385af9f9769Sjasmith static void
srv_secinfo_remove(secinfo_t ** pcursec,int * pcurcnt,secinfo_t * remsec,int remcnt)386af9f9769Sjasmith srv_secinfo_remove(secinfo_t **pcursec, int *pcurcnt, secinfo_t *remsec,
387af9f9769Sjasmith     int remcnt)
3887c478bd9Sstevel@tonic-gate {
389f9bfc9a7Sjasmith 	int ccnt, c;		/* sec count in current data - cursec */
390f9bfc9a7Sjasmith 	int r;			/* sec count in removal data - remsec */
3917c478bd9Sstevel@tonic-gate 	int tcnt, mcnt;		/* total sec count after removing */
3927c478bd9Sstevel@tonic-gate 	struct secinfo *msec;	/* final secinfo list after removing */
393af9f9769Sjasmith 	struct secinfo *cursec;
3947c478bd9Sstevel@tonic-gate 
395af9f9769Sjasmith 	cursec = *pcursec;
396af9f9769Sjasmith 	ccnt = *pcurcnt;
3977c478bd9Sstevel@tonic-gate 	tcnt = ccnt;
3987c478bd9Sstevel@tonic-gate 
399af9f9769Sjasmith 	for (r = 0; r < remcnt; r++) {
4007c478bd9Sstevel@tonic-gate 		/*
401f9bfc9a7Sjasmith 		 * At unshare/reshare time, only explicitly shared flavor ref
402f9bfc9a7Sjasmith 		 * counts are decremented and propagated to ancestors.
403f9bfc9a7Sjasmith 		 * Implicit flavor refs came from shared descendants, and
404f9bfc9a7Sjasmith 		 * they must be kept.
4057c478bd9Sstevel@tonic-gate 		 */
406f9bfc9a7Sjasmith 		if (! SEC_REF_EXPORTED(&remsec[r]))
407f9bfc9a7Sjasmith 			continue;
408f9bfc9a7Sjasmith 
4097c478bd9Sstevel@tonic-gate 		for (c = 0; c < ccnt; c++) {
410af9f9769Sjasmith 			if (remsec[r].s_secinfo.sc_nfsnum ==
411af9f9769Sjasmith 			    cursec[c].s_secinfo.sc_nfsnum) {
4127c478bd9Sstevel@tonic-gate 
413af9f9769Sjasmith 				/*
414af9f9769Sjasmith 				 * Decrement secinfo reference count by 1.
415af9f9769Sjasmith 				 * If this entry is invalid after decrementing
416af9f9769Sjasmith 				 * the count (i.e. count < 1), this entry will
417af9f9769Sjasmith 				 * be removed.
418af9f9769Sjasmith 				 */
419af9f9769Sjasmith 				cursec[c].s_refcnt--;
4208a429e7eSms 
421af9f9769Sjasmith 				SECREF_TRACE(cursec, "del_ref",
422af9f9769Sjasmith 				    cursec[c].s_secinfo.sc_nfsnum,
423af9f9769Sjasmith 				    cursec[c].s_refcnt);
4247c478bd9Sstevel@tonic-gate 
425af9f9769Sjasmith 				ASSERT(cursec[c].s_refcnt >= 0);
426af9f9769Sjasmith 
427af9f9769Sjasmith 				if (SEC_REF_INVALID(&cursec[c]))
428af9f9769Sjasmith 					tcnt--;
429af9f9769Sjasmith 				break;
430af9f9769Sjasmith 			}
4317c478bd9Sstevel@tonic-gate 		}
4327c478bd9Sstevel@tonic-gate 	}
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	ASSERT(tcnt >= 0);
4357c478bd9Sstevel@tonic-gate 	if (tcnt == ccnt)
4367c478bd9Sstevel@tonic-gate 		return; /* no change; no flavors to remove */
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	if (tcnt == 0) {
439af9f9769Sjasmith 		srv_secinfo_list_free(cursec, ccnt);
440af9f9769Sjasmith 		*pcurcnt = 0;
441af9f9769Sjasmith 		*pcursec = NULL;
4427c478bd9Sstevel@tonic-gate 		return;
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	/* walk thru the given secinfo list to remove the flavors */
4487c478bd9Sstevel@tonic-gate 	mcnt = 0;
4497c478bd9Sstevel@tonic-gate 	for (c = 0; c < ccnt; c++) {
450af9f9769Sjasmith 		if (SEC_REF_INVALID(&cursec[c])) {
451af9f9769Sjasmith 			srv_secinfo_entry_free(&cursec[c]);
4527c478bd9Sstevel@tonic-gate 		} else {
453af9f9769Sjasmith 			msec[mcnt] = cursec[c];
4547c478bd9Sstevel@tonic-gate 			mcnt++;
4557c478bd9Sstevel@tonic-gate 		}
4567c478bd9Sstevel@tonic-gate 	}
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	ASSERT(mcnt == tcnt);
4597c478bd9Sstevel@tonic-gate 	/*
4607c478bd9Sstevel@tonic-gate 	 * Done. Update curdata.
4617c478bd9Sstevel@tonic-gate 	 * Free the existing secinfo list in curdata. All pointers
4627c478bd9Sstevel@tonic-gate 	 * within the list have either been moved to msec or freed
4637c478bd9Sstevel@tonic-gate 	 * if it's invalid.
4647c478bd9Sstevel@tonic-gate 	 */
465af9f9769Sjasmith 	kmem_free(*pcursec, ccnt * sizeof (struct secinfo));
466af9f9769Sjasmith 	*pcursec = msec;
467af9f9769Sjasmith 	*pcurcnt = tcnt;
468af9f9769Sjasmith }
469af9f9769Sjasmith 
470af9f9769Sjasmith 
4717c478bd9Sstevel@tonic-gate /*
472af9f9769Sjasmith  * For the reshare case, sec flavor accounting happens in 3 steps:
473af9f9769Sjasmith  * 1) propagate addition of new flavor refs up the ancestor tree
474af9f9769Sjasmith  * 2) transfer flavor refs of descendants to new/reshared exportdata
475af9f9769Sjasmith  * 3) propagate removal of old flavor refs up the ancestor tree
476af9f9769Sjasmith  *
477af9f9769Sjasmith  * srv_secinfo_exp2exp() implements step 2 of a reshare.  At this point,
478af9f9769Sjasmith  * the new flavor list has already been propagated up through the
479af9f9769Sjasmith  * ancestor tree via srv_secinfo_treeclimb().
4807c478bd9Sstevel@tonic-gate  *
481af9f9769Sjasmith  * If there is more than 1 export reference to an old flavor (i.e. some
482af9f9769Sjasmith  * of its children shared with this flavor), this flavor information
483da6c28aaSamw  * needs to be transferred to the new exportdata struct.  A flavor in
484992d2facSpf  * the old exportdata has descendant refs when its s_refcnt > 1 or it
485992d2facSpf  * is implicitly shared (M_SEC4_EXPORTED not set in s_flags).
486992d2facSpf  *
487992d2facSpf  * SEC_REF_EXPORTED() is only true when  M_SEC4_EXPORTED is set
488992d2facSpf  * SEC_REF_SELF() is only true when both M_SEC4_EXPORTED is set and s_refcnt==1
489af9f9769Sjasmith  *
490af9f9769Sjasmith  * Transferring descendant flavor refcnts happens in 2 passes:
491af9f9769Sjasmith  * a) flavors used before (oldsecinfo) and after (curdata->ex_secinfo) reshare
492af9f9769Sjasmith  * b) flavors used before but not after reshare
4937c478bd9Sstevel@tonic-gate  *
4947c478bd9Sstevel@tonic-gate  * This routine is used under the protection of exported_lock (RW_WRITER).
4957c478bd9Sstevel@tonic-gate  */
4967c478bd9Sstevel@tonic-gate void
srv_secinfo_exp2exp(exportdata_t * curdata,secinfo_t * oldsecinfo,int ocnt)497af9f9769Sjasmith srv_secinfo_exp2exp(exportdata_t *curdata, secinfo_t *oldsecinfo, int ocnt)
4987c478bd9Sstevel@tonic-gate {
4997c478bd9Sstevel@tonic-gate 	int ccnt, c;		/* sec count in current data - curdata */
5008a429e7eSms 	int o;			/* sec count in old data - oldsecinfo */
5017c478bd9Sstevel@tonic-gate 	int tcnt, mcnt;		/* total sec count after the transfer */
5027c478bd9Sstevel@tonic-gate 	struct secinfo *msec;	/* merged secinfo list */
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	ccnt = curdata->ex_seccnt;
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 	ASSERT(ocnt > 0);
5077c478bd9Sstevel@tonic-gate 	ASSERT(!(curdata->ex_flags & EX_PSEUDO));
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	/*
510af9f9769Sjasmith 	 * If the oldsecinfo has flavors with more than 1 reference count
511af9f9769Sjasmith 	 * and the flavor is specified in the reshare, transfer the flavor
512af9f9769Sjasmith 	 * refs to the new seclist (curdata.ex_secinfo).
5137c478bd9Sstevel@tonic-gate 	 */
5147c478bd9Sstevel@tonic-gate 	tcnt = ccnt + ocnt;
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	for (o = 0; o < ocnt; o++) {
5177c478bd9Sstevel@tonic-gate 
518af9f9769Sjasmith 		if (SEC_REF_SELF(&oldsecinfo[o])) {
519af9f9769Sjasmith 			tcnt--;
520af9f9769Sjasmith 			continue;
521af9f9769Sjasmith 		}
522af9f9769Sjasmith 
5237c478bd9Sstevel@tonic-gate 		for (c = 0; c < ccnt; c++) {
524af9f9769Sjasmith 			if (oldsecinfo[o].s_secinfo.sc_nfsnum ==
525af9f9769Sjasmith 			    curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) {
526af9f9769Sjasmith 
527af9f9769Sjasmith 				/*
528af9f9769Sjasmith 				 * add old reference to the current
529af9f9769Sjasmith 				 * secinfo count
530af9f9769Sjasmith 				 */
531af9f9769Sjasmith 				curdata->ex_secinfo[c].s_refcnt +=
532af9f9769Sjasmith 				    oldsecinfo[o].s_refcnt;
5337c478bd9Sstevel@tonic-gate 
534af9f9769Sjasmith 				/*
535af9f9769Sjasmith 				 * Delete the old export flavor
536af9f9769Sjasmith 				 * reference.  The initial reference
537af9f9769Sjasmith 				 * was created during srv_secinfo_add,
538af9f9769Sjasmith 				 * and the count is decremented below
539af9f9769Sjasmith 				 * to account for the initial reference.
540af9f9769Sjasmith 				 */
541af9f9769Sjasmith 				if (SEC_REF_EXPORTED(&oldsecinfo[o]))
542af9f9769Sjasmith 					curdata->ex_secinfo[c].s_refcnt--;
5437c478bd9Sstevel@tonic-gate 
544af9f9769Sjasmith 				SECREF_TRACE(curdata->ex_path,
545af9f9769Sjasmith 				    "reshare_xfer_common_child_refs",
546af9f9769Sjasmith 				    curdata->ex_secinfo[c].s_secinfo.sc_nfsnum,
547af9f9769Sjasmith 				    curdata->ex_secinfo[c].s_refcnt);
5488a429e7eSms 
549af9f9769Sjasmith 				ASSERT(curdata->ex_secinfo[c].s_refcnt >= 0);
5508a429e7eSms 
551af9f9769Sjasmith 				tcnt--;
552af9f9769Sjasmith 				break;
553af9f9769Sjasmith 			}
5547c478bd9Sstevel@tonic-gate 		}
5557c478bd9Sstevel@tonic-gate 	}
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	if (tcnt == ccnt)
5587c478bd9Sstevel@tonic-gate 		return; /* no more transfer to do */
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	/*
561af9f9769Sjasmith 	 * oldsecinfo has flavors referenced by its children that are not
562af9f9769Sjasmith 	 * in the current (new) export flavor list.  Add these flavors.
5637c478bd9Sstevel@tonic-gate 	 */
5647c478bd9Sstevel@tonic-gate 	msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	/* move current secinfo list data to the new list */
567af9f9769Sjasmith 	for (c = 0; c < ccnt; c++)
568af9f9769Sjasmith 		msec[c] = curdata->ex_secinfo[c];
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	/*
5717c478bd9Sstevel@tonic-gate 	 * Add the flavor that's not in the new export, but still
572af9f9769Sjasmith 	 * referenced by its children.
5737c478bd9Sstevel@tonic-gate 	 */
5747c478bd9Sstevel@tonic-gate 	mcnt = ccnt;
5757c478bd9Sstevel@tonic-gate 	for (o = 0; o < ocnt; o++) {
576af9f9769Sjasmith 		if (! SEC_REF_SELF(&oldsecinfo[o])) {
577af9f9769Sjasmith 			for (c = 0; c < ccnt; c++) {
578af9f9769Sjasmith 				if (oldsecinfo[o].s_secinfo.sc_nfsnum ==
579af9f9769Sjasmith 				    curdata->ex_secinfo[c].s_secinfo.sc_nfsnum)
580af9f9769Sjasmith 					break;
581af9f9769Sjasmith 			}
5827c478bd9Sstevel@tonic-gate 
583af9f9769Sjasmith 			/*
584af9f9769Sjasmith 			 * This is the one. Add it. Decrement the ref count
585af9f9769Sjasmith 			 * by 1 if the flavor is an explicitly shared flavor
586af9f9769Sjasmith 			 * for the oldsecinfo export node.
587af9f9769Sjasmith 			 */
588af9f9769Sjasmith 			if (c == ccnt) {
589af9f9769Sjasmith 				srv_secinfo_copy(&oldsecinfo[o], &msec[mcnt]);
590af9f9769Sjasmith 				if (SEC_REF_EXPORTED(&oldsecinfo[o]))
591af9f9769Sjasmith 					msec[mcnt].s_refcnt--;
592af9f9769Sjasmith 
593af9f9769Sjasmith 				SECREF_TRACE(curdata,
594af9f9769Sjasmith 				    "reshare_xfer_implicit_child_refs",
595af9f9769Sjasmith 				    msec[mcnt].s_secinfo.sc_nfsnum,
596af9f9769Sjasmith 				    msec[mcnt].s_refcnt);
597af9f9769Sjasmith 
598af9f9769Sjasmith 				ASSERT(msec[mcnt].s_refcnt >= 0);
599af9f9769Sjasmith 				mcnt++;
600af9f9769Sjasmith 			}
6017c478bd9Sstevel@tonic-gate 		}
6027c478bd9Sstevel@tonic-gate 	}
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	ASSERT(mcnt == tcnt);
6057c478bd9Sstevel@tonic-gate 	/*
606af9f9769Sjasmith 	 * Done. Update curdata, free the existing secinfo list in
607af9f9769Sjasmith 	 * curdata and set the new value.
6087c478bd9Sstevel@tonic-gate 	 */
6097c478bd9Sstevel@tonic-gate 	if (ccnt > 0)
6107c478bd9Sstevel@tonic-gate 		kmem_free(curdata->ex_secinfo, ccnt * sizeof (struct secinfo));
6117c478bd9Sstevel@tonic-gate 	curdata->ex_seccnt = tcnt;
6127c478bd9Sstevel@tonic-gate 	curdata->ex_secinfo = msec;
6137c478bd9Sstevel@tonic-gate }
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate /*
6167c478bd9Sstevel@tonic-gate  * When unsharing an old export node and the old node becomes a pseudo node,
6177c478bd9Sstevel@tonic-gate  * if there is more than 1 export reference to an old flavor (i.e. some of
6187c478bd9Sstevel@tonic-gate  * its children shared with this flavor), this flavor information needs to
619da6c28aaSamw  * be transferred to the new shared node.
6207c478bd9Sstevel@tonic-gate  *
6217c478bd9Sstevel@tonic-gate  * This routine is used under the protection of exported_lock (RW_WRITER).
6227c478bd9Sstevel@tonic-gate  */
6237c478bd9Sstevel@tonic-gate void
srv_secinfo_exp2pseu(exportdata_t * curdata,exportdata_t * olddata)624af9f9769Sjasmith srv_secinfo_exp2pseu(exportdata_t *curdata, exportdata_t *olddata)
6257c478bd9Sstevel@tonic-gate {
6267c478bd9Sstevel@tonic-gate 	int ocnt, o;		/* sec count in transfer data - trandata */
6277c478bd9Sstevel@tonic-gate 	int tcnt, mcnt;		/* total sec count after transfer */
6287c478bd9Sstevel@tonic-gate 	struct secinfo *msec;	/* merged secinfo list */
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	ASSERT(curdata->ex_flags & EX_PSEUDO);
6317c478bd9Sstevel@tonic-gate 	ASSERT(curdata->ex_seccnt == 0);
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 	ocnt = olddata->ex_seccnt;
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	/*
6367c478bd9Sstevel@tonic-gate 	 * If the olddata has flavors with more than 1 reference count,
6377c478bd9Sstevel@tonic-gate 	 * transfer the information to the curdata.
6387c478bd9Sstevel@tonic-gate 	 */
6397c478bd9Sstevel@tonic-gate 	tcnt = ocnt;
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	for (o = 0; o < ocnt; o++) {
642af9f9769Sjasmith 		if (SEC_REF_SELF(&olddata->ex_secinfo[o]))
643af9f9769Sjasmith 			tcnt--;
6447c478bd9Sstevel@tonic-gate 	}
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	if (tcnt == 0)
6477c478bd9Sstevel@tonic-gate 		return; /* no transfer to do */
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 	msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	mcnt = 0;
6527c478bd9Sstevel@tonic-gate 	for (o = 0; o < ocnt; o++) {
653af9f9769Sjasmith 		if (! SEC_REF_SELF(&olddata->ex_secinfo[o])) {
6547c478bd9Sstevel@tonic-gate 
655af9f9769Sjasmith 			/*
656af9f9769Sjasmith 			 * Decrement the reference count by 1 if the flavor is
657af9f9769Sjasmith 			 * an explicitly shared flavor for the olddata export
658af9f9769Sjasmith 			 * node.
659af9f9769Sjasmith 			 */
660af9f9769Sjasmith 			srv_secinfo_copy(&olddata->ex_secinfo[o], &msec[mcnt]);
661af9f9769Sjasmith 			msec[mcnt].s_flags = M_RO;
662af9f9769Sjasmith 			if (SEC_REF_EXPORTED(&olddata->ex_secinfo[o]))
663af9f9769Sjasmith 				msec[mcnt].s_refcnt--;
664af9f9769Sjasmith 
665af9f9769Sjasmith 			SECREF_TRACE(curdata, "unshare_morph_pseudo",
666af9f9769Sjasmith 			    msec[mcnt].s_secinfo.sc_nfsnum,
667af9f9769Sjasmith 			    msec[mcnt].s_refcnt);
668af9f9769Sjasmith 
669af9f9769Sjasmith 			ASSERT(msec[mcnt].s_refcnt >= 0);
670af9f9769Sjasmith 			mcnt++;
671af9f9769Sjasmith 		}
6727c478bd9Sstevel@tonic-gate 	}
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 	ASSERT(mcnt == tcnt);
6757c478bd9Sstevel@tonic-gate 	/*
6767c478bd9Sstevel@tonic-gate 	 * Done. Update curdata.
6777c478bd9Sstevel@tonic-gate 	 * Free up the existing secinfo list in curdata and
6787c478bd9Sstevel@tonic-gate 	 * set the new value.
6797c478bd9Sstevel@tonic-gate 	 */
6807c478bd9Sstevel@tonic-gate 	curdata->ex_seccnt = tcnt;
6817c478bd9Sstevel@tonic-gate 	curdata->ex_secinfo = msec;
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate 
684992d2facSpf /*
6853f238301SPavel Filipensky  * Find for given treenode the exportinfo which has its
6863f238301SPavel Filipensky  * exp_visible linked on its exi_visible list.
687992d2facSpf  *
688992d2facSpf  * Note: We could add new pointer either to treenode or
689992d2facSpf  * to exp_visible, which will point there directly.
690992d2facSpf  * This would buy some speed for some memory.
691992d2facSpf  */
692992d2facSpf exportinfo_t *
vis2exi(treenode_t * tnode)6933f238301SPavel Filipensky vis2exi(treenode_t *tnode)
694992d2facSpf {
695992d2facSpf 	exportinfo_t *exi_ret = NULL;
696992d2facSpf 
697992d2facSpf 	for (;;) {
698992d2facSpf 		tnode = tnode->tree_parent;
699992d2facSpf 		if (TREE_ROOT(tnode)) {
700992d2facSpf 			exi_ret = tnode->tree_exi;
701992d2facSpf 			break;
702992d2facSpf 		}
703992d2facSpf 	}
704992d2facSpf 
7050dfe541eSEvan Layton 	/* Every visible should have its home exportinfo */
7060dfe541eSEvan Layton 	ASSERT(exi_ret != NULL);
707992d2facSpf 	return (exi_ret);
708992d2facSpf }
709af9f9769Sjasmith 
7107c478bd9Sstevel@tonic-gate /*
7117c478bd9Sstevel@tonic-gate  * For NFS V4.
7127c478bd9Sstevel@tonic-gate  * Add or remove the newly exported or unexported security flavors of the
7137c478bd9Sstevel@tonic-gate  * given exportinfo from its ancestors upto the system root.
7147c478bd9Sstevel@tonic-gate  */
7150dfe541eSEvan Layton static void
srv_secinfo_treeclimb(nfs_export_t * ne,exportinfo_t * exip,secinfo_t * sec,int seccnt,bool_t isadd)7160dfe541eSEvan Layton srv_secinfo_treeclimb(nfs_export_t *ne, exportinfo_t *exip, secinfo_t *sec,
7170dfe541eSEvan Layton     int seccnt, bool_t isadd)
7187c478bd9Sstevel@tonic-gate {
7190dfe541eSEvan Layton 	treenode_t *tnode;
7207c478bd9Sstevel@tonic-gate 
7210dfe541eSEvan Layton 	ASSERT(RW_WRITE_HELD(&ne->exported_lock));
7220dfe541eSEvan Layton 
7230dfe541eSEvan Layton 	/*
7240dfe541eSEvan Layton 	 * exi_tree can be null for the zone root
7250dfe541eSEvan Layton 	 * which means we're already at the "top"
7260dfe541eSEvan Layton 	 * and there's nothing more to "climb".
7270dfe541eSEvan Layton 	 */
7280dfe541eSEvan Layton 	tnode = exip->exi_tree;
7290dfe541eSEvan Layton 	if (tnode == NULL) {
7300dfe541eSEvan Layton 		/* Should only happen for... */
7310dfe541eSEvan Layton 		ASSERT(exip == ne->exi_root);
7320dfe541eSEvan Layton 		return;
7330dfe541eSEvan Layton 	}
7347c478bd9Sstevel@tonic-gate 
735af9f9769Sjasmith 	if (seccnt == 0)
736992d2facSpf 		return;
7377c478bd9Sstevel@tonic-gate 
738af9f9769Sjasmith 	/*
739af9f9769Sjasmith 	 * If flavors are being added and the new export root isn't
740af9f9769Sjasmith 	 * also VROOT, its implicitly allowed flavors are inherited from
7414a695956SMarcel Telka 	 * its pseudonode.
742992d2facSpf 	 * Note - for VROOT exports the implicitly allowed flavors were
743992d2facSpf 	 * transferred from the PSEUDO export in exportfs()
744af9f9769Sjasmith 	 */
745992d2facSpf 	if (isadd && !(exip->exi_vp->v_flag & VROOT) &&
7460dfe541eSEvan Layton 	    !VN_CMP(exip->exi_vp, EXI_TO_ZONEROOTVP(exip)) &&
747992d2facSpf 	    tnode->tree_vis->vis_seccnt > 0) {
748992d2facSpf 		srv_secinfo_add(&exip->exi_export.ex_secinfo,
749992d2facSpf 		    &exip->exi_export.ex_seccnt, tnode->tree_vis->vis_secinfo,
750992d2facSpf 		    tnode->tree_vis->vis_seccnt, FALSE);
751992d2facSpf 	}
7527c478bd9Sstevel@tonic-gate 
753992d2facSpf 	/*
754992d2facSpf 	 * Move to parent node and propagate sec flavor
755992d2facSpf 	 * to exportinfo and to visible structures.
756992d2facSpf 	 */
757992d2facSpf 	tnode = tnode->tree_parent;
758992d2facSpf 
7594a695956SMarcel Telka 	while (tnode != NULL) {
760992d2facSpf 
761992d2facSpf 		/* If there is exportinfo, update it */
7624a695956SMarcel Telka 		if (tnode->tree_exi != NULL) {
763992d2facSpf 			secinfo_t **pxsec =
764992d2facSpf 			    &tnode->tree_exi->exi_export.ex_secinfo;
765992d2facSpf 			int *pxcnt = &tnode->tree_exi->exi_export.ex_seccnt;
766992d2facSpf 			int is_pseudo = PSEUDO(tnode->tree_exi);
767992d2facSpf 			if (isadd)
768992d2facSpf 				srv_secinfo_add(pxsec, pxcnt, sec, seccnt,
769992d2facSpf 				    is_pseudo);
770992d2facSpf 			else
771992d2facSpf 				srv_secinfo_remove(pxsec, pxcnt, sec, seccnt);
7727c478bd9Sstevel@tonic-gate 		}
7737c478bd9Sstevel@tonic-gate 
774992d2facSpf 		/* Update every visible - only root node has no visible */
7754a695956SMarcel Telka 		if (tnode->tree_vis != NULL) {
776992d2facSpf 			secinfo_t **pxsec = &tnode->tree_vis->vis_secinfo;
777992d2facSpf 			int *pxcnt = &tnode->tree_vis->vis_seccnt;
778992d2facSpf 			if (isadd)
779992d2facSpf 				srv_secinfo_add(pxsec, pxcnt, sec, seccnt,
780992d2facSpf 				    FALSE);
781992d2facSpf 			else
782992d2facSpf 				srv_secinfo_remove(pxsec, pxcnt, sec, seccnt);
7837c478bd9Sstevel@tonic-gate 		}
784992d2facSpf 		tnode = tnode->tree_parent;
785af9f9769Sjasmith 	}
786af9f9769Sjasmith }
787af9f9769Sjasmith 
7880616fd7fSPavel Filipensky /* hash_name is a text substitution for either fid_hash or path_hash */
7890616fd7fSPavel Filipensky #define	exp_hash_unlink(exi, hash_name) \
7900616fd7fSPavel Filipensky 	if (*(exi)->hash_name.bckt == (exi)) \
7910616fd7fSPavel Filipensky 		*(exi)->hash_name.bckt = (exi)->hash_name.next; \
7920616fd7fSPavel Filipensky 	if ((exi)->hash_name.prev) \
7930616fd7fSPavel Filipensky 		(exi)->hash_name.prev->hash_name.next = (exi)->hash_name.next; \
7940616fd7fSPavel Filipensky 	if ((exi)->hash_name.next) \
7950616fd7fSPavel Filipensky 		(exi)->hash_name.next->hash_name.prev = (exi)->hash_name.prev; \
7960616fd7fSPavel Filipensky 	(exi)->hash_name.bckt = NULL;
7970616fd7fSPavel Filipensky 
7980616fd7fSPavel Filipensky #define	exp_hash_link(exi, hash_name, bucket) \
7990616fd7fSPavel Filipensky 	(exi)->hash_name.bckt = (bucket); \
8000616fd7fSPavel Filipensky 	(exi)->hash_name.prev = NULL; \
8010616fd7fSPavel Filipensky 	(exi)->hash_name.next = *(bucket); \
8020616fd7fSPavel Filipensky 	if ((exi)->hash_name.next) \
8030616fd7fSPavel Filipensky 		(exi)->hash_name.next->hash_name.prev = (exi); \
8040616fd7fSPavel Filipensky 	*(bucket) = (exi);
8050616fd7fSPavel Filipensky 
8067c478bd9Sstevel@tonic-gate void
export_link(nfs_export_t * ne,exportinfo_t * exi)8070dfe541eSEvan Layton export_link(nfs_export_t *ne, exportinfo_t *exi)
8080616fd7fSPavel Filipensky {
8090616fd7fSPavel Filipensky 	exportinfo_t **bckt;
8100616fd7fSPavel Filipensky 
8110dfe541eSEvan Layton 	ASSERT(RW_WRITE_HELD(&ne->exported_lock));
8120dfe541eSEvan Layton 
8130dfe541eSEvan Layton 	bckt = &ne->exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)];
8140616fd7fSPavel Filipensky 	exp_hash_link(exi, fid_hash, bckt);
8157c478bd9Sstevel@tonic-gate 
8160dfe541eSEvan Layton 	bckt = &ne->exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
8170616fd7fSPavel Filipensky 	    strlen(exi->exi_export.ex_path))];
8180616fd7fSPavel Filipensky 	exp_hash_link(exi, path_hash, bckt);
8190dfe541eSEvan Layton 	exi->exi_ne = ne;
8207c478bd9Sstevel@tonic-gate }
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate /*
8230dfe541eSEvan Layton  * Helper functions for exi_id handling
8247c478bd9Sstevel@tonic-gate  */
8250dfe541eSEvan Layton static int
exi_id_compar(const void * v1,const void * v2)8260dfe541eSEvan Layton exi_id_compar(const void *v1, const void *v2)
8270dfe541eSEvan Layton {
8280dfe541eSEvan Layton 	const struct exportinfo *e1 = v1;
8290dfe541eSEvan Layton 	const struct exportinfo *e2 = v2;
8300dfe541eSEvan Layton 
8310dfe541eSEvan Layton 	if (e1->exi_id < e2->exi_id)
8320dfe541eSEvan Layton 		return (-1);
8330dfe541eSEvan Layton 	if (e1->exi_id > e2->exi_id)
8340dfe541eSEvan Layton 		return (1);
8350dfe541eSEvan Layton 
8360dfe541eSEvan Layton 	return (0);
8370dfe541eSEvan Layton }
8380dfe541eSEvan Layton 
8397c478bd9Sstevel@tonic-gate int
exi_id_get_next()8400dfe541eSEvan Layton exi_id_get_next()
8410dfe541eSEvan Layton {
8420dfe541eSEvan Layton 	struct exportinfo e;
8430dfe541eSEvan Layton 	int ret = exi_id_next;
8440dfe541eSEvan Layton 
8450dfe541eSEvan Layton 	ASSERT(MUTEX_HELD(&nfs_exi_id_lock));
8460dfe541eSEvan Layton 
8470dfe541eSEvan Layton 	do {
8480dfe541eSEvan Layton 		exi_id_next++;
8490dfe541eSEvan Layton 		if (exi_id_next == 0)
8500dfe541eSEvan Layton 			exi_id_overflow = TRUE;
8510dfe541eSEvan Layton 
8520dfe541eSEvan Layton 		if (!exi_id_overflow)
8530dfe541eSEvan Layton 			break;
8540dfe541eSEvan Layton 
8550dfe541eSEvan Layton 		if (exi_id_next == ret)
8560dfe541eSEvan Layton 			cmn_err(CE_PANIC, "exi_id exhausted");
8570dfe541eSEvan Layton 
8580dfe541eSEvan Layton 		e.exi_id = exi_id_next;
8590dfe541eSEvan Layton 	} while (avl_find(&exi_id_tree, &e, NULL) != NULL);
8600dfe541eSEvan Layton 
8610dfe541eSEvan Layton 	return (ret);
8620dfe541eSEvan Layton }
8630dfe541eSEvan Layton 
8640dfe541eSEvan Layton /*
8650dfe541eSEvan Layton  * Get the root file handle for this zone.
8660dfe541eSEvan Layton  * Called when nfs_svc() starts
8670dfe541eSEvan Layton  */
8680dfe541eSEvan Layton int
nfs_export_get_rootfh(nfs_globals_t * g)8690dfe541eSEvan Layton nfs_export_get_rootfh(nfs_globals_t *g)
8700dfe541eSEvan Layton {
8710dfe541eSEvan Layton 	nfs_export_t *ne = g->nfs_export;
8720dfe541eSEvan Layton 	int err;
8730dfe541eSEvan Layton 
8740dfe541eSEvan Layton 	ne->exi_rootfid.fid_len = MAXFIDSZ;
8750dfe541eSEvan Layton 	err = vop_fid_pseudo(ne->exi_root->exi_vp, &ne->exi_rootfid);
8760dfe541eSEvan Layton 	if (err != 0) {
8770dfe541eSEvan Layton 		ne->exi_rootfid.fid_len = 0;
8780dfe541eSEvan Layton 		return (err);
8790dfe541eSEvan Layton 	}
8800dfe541eSEvan Layton 
8810dfe541eSEvan Layton 	/* Setup the fhandle template exi_fh */
8820dfe541eSEvan Layton 	ne->exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid;
8830dfe541eSEvan Layton 	ne->exi_root->exi_fh.fh_xlen = ne->exi_rootfid.fid_len;
8840dfe541eSEvan Layton 	bcopy(ne->exi_rootfid.fid_data, ne->exi_root->exi_fh.fh_xdata,
8850dfe541eSEvan Layton 	    ne->exi_rootfid.fid_len);
8860dfe541eSEvan Layton 	ne->exi_root->exi_fh.fh_len = sizeof (ne->exi_root->exi_fh.fh_data);
8870dfe541eSEvan Layton 
8880dfe541eSEvan Layton 	return (0);
8890dfe541eSEvan Layton }
8900dfe541eSEvan Layton 
8910dfe541eSEvan Layton void
nfs_export_zone_init(nfs_globals_t * ng)8920dfe541eSEvan Layton nfs_export_zone_init(nfs_globals_t *ng)
8937c478bd9Sstevel@tonic-gate {
89471da0c32SMarcel Telka 	int i;
8950dfe541eSEvan Layton 	nfs_export_t *ne;
8960dfe541eSEvan Layton 	zone_t *zone;
8970dfe541eSEvan Layton 
8980dfe541eSEvan Layton 	ne = kmem_zalloc(sizeof (*ne), KM_SLEEP);
8997c478bd9Sstevel@tonic-gate 
9000dfe541eSEvan Layton 	rw_init(&ne->exported_lock, NULL, RW_DEFAULT, NULL);
9010dfe541eSEvan Layton 
9020dfe541eSEvan Layton 	ne->ne_globals = ng; /* "up" pointer */
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 	/*
9057c478bd9Sstevel@tonic-gate 	 * Allocate the place holder for the public file handle, which
9067c478bd9Sstevel@tonic-gate 	 * is all zeroes. It is initially set to the root filesystem.
9077c478bd9Sstevel@tonic-gate 	 */
9080dfe541eSEvan Layton 	ne->exi_root = kmem_zalloc(sizeof (*ne->exi_root), KM_SLEEP);
9090dfe541eSEvan Layton 	ne->exi_public = ne->exi_root;
9107c478bd9Sstevel@tonic-gate 
9110dfe541eSEvan Layton 	ne->exi_root->exi_export.ex_flags = EX_PUBLIC;
9120dfe541eSEvan Layton 	ne->exi_root->exi_export.ex_pathlen = 1;	/* length of "/" */
9130dfe541eSEvan Layton 	ne->exi_root->exi_export.ex_path =
9140dfe541eSEvan Layton 	    kmem_alloc(ne->exi_root->exi_export.ex_pathlen + 1, KM_SLEEP);
9150dfe541eSEvan Layton 	ne->exi_root->exi_export.ex_path[0] = '/';
9160dfe541eSEvan Layton 	ne->exi_root->exi_export.ex_path[1] = '\0';
9177c478bd9Sstevel@tonic-gate 
9180dfe541eSEvan Layton 	ne->exi_root->exi_count = 1;
9190dfe541eSEvan Layton 	mutex_init(&ne->exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
9207c478bd9Sstevel@tonic-gate 
9210dfe541eSEvan Layton 	/*
9220dfe541eSEvan Layton 	 * Because we cannot:
9230dfe541eSEvan Layton 	 *	ASSERT(curzone->zone_id == ng->nfs_zoneid);
9240dfe541eSEvan Layton 	 * We grab the zone pointer explicitly (like netstacks do) and
9250dfe541eSEvan Layton 	 * set the rootvp here.
9260dfe541eSEvan Layton 	 *
9270dfe541eSEvan Layton 	 * Subsequent exportinfo_t's that get export_link()ed to "ne" also
9280dfe541eSEvan Layton 	 * will backpoint to "ne" such that exi->exi_ne->exi_root->exi_vp
9290dfe541eSEvan Layton 	 * will get the zone's rootvp for a given exportinfo_t.
9300dfe541eSEvan Layton 	 */
9310dfe541eSEvan Layton 	zone = zone_find_by_id_nolock(ng->nfs_zoneid);
9320dfe541eSEvan Layton 	ne->exi_root->exi_vp = zone->zone_rootvp;
9330dfe541eSEvan Layton 	ne->exi_root->exi_zoneid = ng->nfs_zoneid;
9347c478bd9Sstevel@tonic-gate 
93571da0c32SMarcel Telka 	/*
9360dfe541eSEvan Layton 	 * Fill in ne->exi_rootfid later, in nfs_export_get_rootfid
9370dfe541eSEvan Layton 	 * because we can't correctly return errors here.
93871da0c32SMarcel Telka 	 */
9390dfe541eSEvan Layton 
9400dfe541eSEvan Layton 	/* Initialize auth cache and auth cache lock */
94171da0c32SMarcel Telka 	for (i = 0; i < AUTH_TABLESIZE; i++) {
9420dfe541eSEvan Layton 		ne->exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t),
94371da0c32SMarcel Telka 		    KM_SLEEP);
9440dfe541eSEvan Layton 		avl_create(ne->exi_root->exi_cache[i],
9450dfe541eSEvan Layton 		    nfsauth_cache_clnt_compar, sizeof (struct auth_cache_clnt),
94671da0c32SMarcel Telka 		    offsetof(struct auth_cache_clnt, authc_link));
94771da0c32SMarcel Telka 	}
9480dfe541eSEvan Layton 	rw_init(&ne->exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL);
94971da0c32SMarcel Telka 
9500dfe541eSEvan Layton 	/* setup exi_fh later, in nfs_export_get_rootfid */
9517c478bd9Sstevel@tonic-gate 
9520dfe541eSEvan Layton 	rw_enter(&ne->exported_lock, RW_WRITER);
9537c478bd9Sstevel@tonic-gate 
9540dfe541eSEvan Layton 	/* Publish the exportinfo in the hash table */
9550dfe541eSEvan Layton 	export_link(ne, ne->exi_root);
9567c478bd9Sstevel@tonic-gate 
9570dfe541eSEvan Layton 	/* Initialize exi_id and exi_kstats */
9580dfe541eSEvan Layton 	mutex_enter(&nfs_exi_id_lock);
9590dfe541eSEvan Layton 	ne->exi_root->exi_id = exi_id_get_next();
9600dfe541eSEvan Layton 	avl_add(&exi_id_tree, ne->exi_root);
9610dfe541eSEvan Layton 	mutex_exit(&nfs_exi_id_lock);
9620dfe541eSEvan Layton 
9630dfe541eSEvan Layton 	rw_exit(&ne->exported_lock);
9640dfe541eSEvan Layton 	ne->ns_root = NULL;
9650dfe541eSEvan Layton 
9660dfe541eSEvan Layton 	ng->nfs_export = ne;
9677c478bd9Sstevel@tonic-gate }
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate /*
9700dfe541eSEvan Layton  * During zone shutdown, remove exports
9717c478bd9Sstevel@tonic-gate  */
9727c478bd9Sstevel@tonic-gate void
nfs_export_zone_shutdown(nfs_globals_t * ng)9730dfe541eSEvan Layton nfs_export_zone_shutdown(nfs_globals_t *ng)
9740dfe541eSEvan Layton {
9750dfe541eSEvan Layton 	nfs_export_t *ne = ng->nfs_export;
9760dfe541eSEvan Layton 	struct exportinfo *exi, *nexi;
9770dfe541eSEvan Layton 	int i, errors;
97806260e34SDan McDonald 	zoneid_t zoneid = ng->nfs_zoneid;
97906260e34SDan McDonald 	cred_t *cr;
9800dfe541eSEvan Layton 
98106260e34SDan McDonald 	/*
98206260e34SDan McDonald 	 * Use the zone's credential.  Since this is a zone shutdown method,
98306260e34SDan McDonald 	 * the zone_t should still be around for a zone_get_kcred() call.
98406260e34SDan McDonald 	 */
98506260e34SDan McDonald 	cr = zone_get_kcred(zoneid);
98606260e34SDan McDonald 	VERIFY(cr != NULL);
9870dfe541eSEvan Layton 	rw_enter(&ne->exported_lock, RW_READER);
9880dfe541eSEvan Layton 
9890dfe541eSEvan Layton 	errors = 0;
9900dfe541eSEvan Layton 	for (i = 0; i < EXPTABLESIZE; i++) {
9910dfe541eSEvan Layton 
9920dfe541eSEvan Layton 		exi = ne->exptable[i];
9930dfe541eSEvan Layton 		if (exi != NULL)
9940dfe541eSEvan Layton 			exi_hold(exi);
9950dfe541eSEvan Layton 
9960dfe541eSEvan Layton 		while (exi != NULL) {
99706260e34SDan McDonald 			ASSERT3U(zoneid, ==, exi->exi_zoneid);
9980dfe541eSEvan Layton 			/*
9990dfe541eSEvan Layton 			 * Get and hold next export before
10000dfe541eSEvan Layton 			 * dropping the rwlock and unexport
10010dfe541eSEvan Layton 			 */
10020dfe541eSEvan Layton 			nexi = exi->fid_hash.next;
10030dfe541eSEvan Layton 			if (nexi != NULL)
10040dfe541eSEvan Layton 				exi_hold(nexi);
10050dfe541eSEvan Layton 
10060dfe541eSEvan Layton 			rw_exit(&ne->exported_lock);
10070dfe541eSEvan Layton 
10080dfe541eSEvan Layton 			/*
10090dfe541eSEvan Layton 			 * Skip ne->exi_root which gets special
10100dfe541eSEvan Layton 			 * create/destroy handling.
10110dfe541eSEvan Layton 			 */
10120dfe541eSEvan Layton 			if (exi != ne->exi_root &&
101306260e34SDan McDonald 			    unexport(ne, exi, cr) != 0)
10140dfe541eSEvan Layton 				errors++;
10150dfe541eSEvan Layton 			exi_rele(exi);
10160dfe541eSEvan Layton 
10170dfe541eSEvan Layton 			rw_enter(&ne->exported_lock, RW_READER);
10180dfe541eSEvan Layton 			exi = nexi;
10190dfe541eSEvan Layton 		}
10200dfe541eSEvan Layton 	}
10210dfe541eSEvan Layton 	if (errors > 0) {
10220dfe541eSEvan Layton 		cmn_err(CE_NOTE, "NFS: failed un-exports in zone %d",
10230dfe541eSEvan Layton 		    (int)ng->nfs_zoneid);
10240dfe541eSEvan Layton 	}
10250dfe541eSEvan Layton 
10260dfe541eSEvan Layton 	rw_exit(&ne->exported_lock);
102706260e34SDan McDonald 	crfree(cr);
10280dfe541eSEvan Layton }
10290dfe541eSEvan Layton 
10300dfe541eSEvan Layton void
nfs_export_zone_fini(nfs_globals_t * ng)10310dfe541eSEvan Layton nfs_export_zone_fini(nfs_globals_t *ng)
10327c478bd9Sstevel@tonic-gate {
103371da0c32SMarcel Telka 	int i;
10340dfe541eSEvan Layton 	nfs_export_t *ne = ng->nfs_export;
10350dfe541eSEvan Layton 	struct exportinfo *exi;
103671da0c32SMarcel Telka 
10370dfe541eSEvan Layton 	ng->nfs_export = NULL;
10380dfe541eSEvan Layton 
10390dfe541eSEvan Layton 	rw_enter(&ne->exported_lock, RW_WRITER);
10400dfe541eSEvan Layton 
10410dfe541eSEvan Layton 	mutex_enter(&nfs_exi_id_lock);
10420dfe541eSEvan Layton 	avl_remove(&exi_id_tree, ne->exi_root);
10430dfe541eSEvan Layton 	mutex_exit(&nfs_exi_id_lock);
10440dfe541eSEvan Layton 
10450dfe541eSEvan Layton 	export_unlink(ne, ne->exi_root);
10460dfe541eSEvan Layton 
10470dfe541eSEvan Layton 	rw_exit(&ne->exported_lock);
10480dfe541eSEvan Layton 
10490dfe541eSEvan Layton 	/* Deallocate the place holder for the public file handle */
10500dfe541eSEvan Layton 	srv_secinfo_list_free(ne->exi_root->exi_export.ex_secinfo,
10510dfe541eSEvan Layton 	    ne->exi_root->exi_export.ex_seccnt);
10520dfe541eSEvan Layton 	mutex_destroy(&ne->exi_root->exi_lock);
10530dfe541eSEvan Layton 
10540dfe541eSEvan Layton 	rw_destroy(&ne->exi_root->exi_cache_lock);
105571da0c32SMarcel Telka 	for (i = 0; i < AUTH_TABLESIZE; i++) {
10560dfe541eSEvan Layton 		avl_destroy(ne->exi_root->exi_cache[i]);
10570dfe541eSEvan Layton 		kmem_free(ne->exi_root->exi_cache[i], sizeof (avl_tree_t));
105871da0c32SMarcel Telka 	}
10597c478bd9Sstevel@tonic-gate 
10600dfe541eSEvan Layton 	kmem_free(ne->exi_root->exi_export.ex_path,
10610dfe541eSEvan Layton 	    ne->exi_root->exi_export.ex_pathlen + 1);
10620dfe541eSEvan Layton 	kmem_free(ne->exi_root, sizeof (*ne->exi_root));
10630dfe541eSEvan Layton 
10640dfe541eSEvan Layton 	/*
10650dfe541eSEvan Layton 	 * The shutdown hook should have left the exi_id_tree
10660dfe541eSEvan Layton 	 * with nothing belonging to this zone.
10670dfe541eSEvan Layton 	 */
10680dfe541eSEvan Layton 	mutex_enter(&nfs_exi_id_lock);
10690dfe541eSEvan Layton 	i = 0;
10700dfe541eSEvan Layton 	exi = avl_first(&exi_id_tree);
10710dfe541eSEvan Layton 	while (exi != NULL) {
10720dfe541eSEvan Layton 		if (exi->exi_zoneid == ng->nfs_zoneid)
10730dfe541eSEvan Layton 			i++;
10740dfe541eSEvan Layton 		exi = AVL_NEXT(&exi_id_tree, exi);
10750dfe541eSEvan Layton 	}
10760dfe541eSEvan Layton 	mutex_exit(&nfs_exi_id_lock);
10770dfe541eSEvan Layton 	if (i > 0) {
10780dfe541eSEvan Layton 		cmn_err(CE_NOTE,
10790dfe541eSEvan Layton 		    "NFS: zone %d has %d export IDs left after shutdown",
10800dfe541eSEvan Layton 		    (int)ng->nfs_zoneid, i);
10810dfe541eSEvan Layton 	}
10820dfe541eSEvan Layton 	rw_destroy(&ne->exported_lock);
10830dfe541eSEvan Layton 	kmem_free(ne, sizeof (*ne));
10840dfe541eSEvan Layton }
10850dfe541eSEvan Layton 
10860dfe541eSEvan Layton /*
10870dfe541eSEvan Layton  * Initialization routine for export routines.
10880dfe541eSEvan Layton  * Should only be called once.
10890dfe541eSEvan Layton  */
10900dfe541eSEvan Layton void
nfs_exportinit(void)10910dfe541eSEvan Layton nfs_exportinit(void)
10920dfe541eSEvan Layton {
10930dfe541eSEvan Layton 	mutex_init(&nfs_exi_id_lock, NULL, MUTEX_DEFAULT, NULL);
10940dfe541eSEvan Layton 
10950dfe541eSEvan Layton 	/* exi_id handling initialization */
10960dfe541eSEvan Layton 	exi_id_next = 0;
10970dfe541eSEvan Layton 	exi_id_overflow = FALSE;
10980dfe541eSEvan Layton 	avl_create(&exi_id_tree, exi_id_compar, sizeof (struct exportinfo),
10990dfe541eSEvan Layton 	    offsetof(struct exportinfo, exi_id_link));
11000dfe541eSEvan Layton 
11010dfe541eSEvan Layton 	nfslog_init();
11020dfe541eSEvan Layton }
11030dfe541eSEvan Layton 
11040dfe541eSEvan Layton /*
11050dfe541eSEvan Layton  * Finalization routine for export routines.
11060dfe541eSEvan Layton  */
11070dfe541eSEvan Layton void
nfs_exportfini(void)11080dfe541eSEvan Layton nfs_exportfini(void)
11090dfe541eSEvan Layton {
11100dfe541eSEvan Layton 	avl_destroy(&exi_id_tree);
11110dfe541eSEvan Layton 	mutex_destroy(&nfs_exi_id_lock);
11127c478bd9Sstevel@tonic-gate }
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate /*
11157c478bd9Sstevel@tonic-gate  *  Check if 2 gss mechanism identifiers are the same.
11167c478bd9Sstevel@tonic-gate  *
11177c478bd9Sstevel@tonic-gate  *  return FALSE if not the same.
11187c478bd9Sstevel@tonic-gate  *  return TRUE if the same.
11197c478bd9Sstevel@tonic-gate  */
11207c478bd9Sstevel@tonic-gate static bool_t
nfs_mech_equal(rpc_gss_OID mech1,rpc_gss_OID mech2)11217c478bd9Sstevel@tonic-gate nfs_mech_equal(rpc_gss_OID mech1, rpc_gss_OID mech2)
11227c478bd9Sstevel@tonic-gate {
11237c478bd9Sstevel@tonic-gate 	if ((mech1->length == 0) && (mech2->length == 0))
11247c478bd9Sstevel@tonic-gate 		return (TRUE);
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 	if (mech1->length != mech2->length)
11277c478bd9Sstevel@tonic-gate 		return (FALSE);
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	return (bcmp(mech1->elements, mech2->elements, mech1->length) == 0);
11307c478bd9Sstevel@tonic-gate }
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate /*
11337c478bd9Sstevel@tonic-gate  *  This routine is used by rpc to map rpc security number
11347c478bd9Sstevel@tonic-gate  *  to nfs specific security flavor number.
11357c478bd9Sstevel@tonic-gate  *
11367c478bd9Sstevel@tonic-gate  *  The gss callback prototype is
11377c478bd9Sstevel@tonic-gate  *  callback(struct svc_req *, gss_cred_id_t *, gss_ctx_id_t *,
11387c478bd9Sstevel@tonic-gate  *				rpc_gss_lock_t *, void **),
11397c478bd9Sstevel@tonic-gate  *  since nfs does not use the gss_cred_id_t/gss_ctx_id_t arguments
11407c478bd9Sstevel@tonic-gate  *  we cast them to void.
11417c478bd9Sstevel@tonic-gate  */
11427c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11437c478bd9Sstevel@tonic-gate bool_t
rfs_gsscallback(struct svc_req * req,gss_cred_id_t deleg,void * gss_context,rpc_gss_lock_t * lock,void ** cookie)11447c478bd9Sstevel@tonic-gate rfs_gsscallback(struct svc_req *req, gss_cred_id_t deleg, void *gss_context,
11457c478bd9Sstevel@tonic-gate     rpc_gss_lock_t *lock, void **cookie)
11467c478bd9Sstevel@tonic-gate {
11477c478bd9Sstevel@tonic-gate 	int i, j;
11487c478bd9Sstevel@tonic-gate 	rpc_gss_rawcred_t *raw_cred;
11497c478bd9Sstevel@tonic-gate 	struct exportinfo *exi;
11500dfe541eSEvan Layton 	nfs_export_t *ne = nfs_get_export();
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate 	/*
11537c478bd9Sstevel@tonic-gate 	 * We don't deal with delegated credentials.
11547c478bd9Sstevel@tonic-gate 	 */
11557c478bd9Sstevel@tonic-gate 	if (deleg != GSS_C_NO_CREDENTIAL)
11567c478bd9Sstevel@tonic-gate 		return (FALSE);
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate 	raw_cred = lock->raw_cred;
11597c478bd9Sstevel@tonic-gate 	*cookie = NULL;
11607c478bd9Sstevel@tonic-gate 
11610dfe541eSEvan Layton 	rw_enter(&ne->exported_lock, RW_READER);
11620dfe541eSEvan Layton 
11637c478bd9Sstevel@tonic-gate 	for (i = 0; i < EXPTABLESIZE; i++) {
11640dfe541eSEvan Layton 		exi = ne->exptable[i];
1165af9f9769Sjasmith 		while (exi) {
1166af9f9769Sjasmith 			if (exi->exi_export.ex_seccnt > 0) {
1167af9f9769Sjasmith 				struct secinfo *secp;
1168af9f9769Sjasmith 				seconfig_t *se;
1169af9f9769Sjasmith 				int seccnt;
1170af9f9769Sjasmith 
1171af9f9769Sjasmith 				secp = exi->exi_export.ex_secinfo;
1172af9f9769Sjasmith 				seccnt = exi->exi_export.ex_seccnt;
1173af9f9769Sjasmith 				for (j = 0; j < seccnt; j++) {
1174af9f9769Sjasmith 					/*
1175af9f9769Sjasmith 					 *  If there is a map of the triplet
1176af9f9769Sjasmith 					 *  (mechanism, service, qop) between
1177af9f9769Sjasmith 					 *  raw_cred and the exported flavor,
1178af9f9769Sjasmith 					 *  get the psudo flavor number.
1179af9f9769Sjasmith 					 *  Also qop should not be NULL, it
1180af9f9769Sjasmith 					 *  should be "default" or something
1181af9f9769Sjasmith 					 *  else.
1182af9f9769Sjasmith 					 */
1183af9f9769Sjasmith 					se = &secp[j].s_secinfo;
1184af9f9769Sjasmith 					if ((se->sc_rpcnum == RPCSEC_GSS) &&
1185af9f9769Sjasmith 
1186af9f9769Sjasmith 					    (nfs_mech_equal(
1187af9f9769Sjasmith 					    se->sc_gss_mech_type,
1188af9f9769Sjasmith 					    raw_cred->mechanism)) &&
1189af9f9769Sjasmith 
1190af9f9769Sjasmith 					    (se->sc_service ==
1191af9f9769Sjasmith 					    raw_cred->service) &&
1192af9f9769Sjasmith 					    (raw_cred->qop == se->sc_qop)) {
1193af9f9769Sjasmith 
1194af9f9769Sjasmith 						*cookie = (void *)(uintptr_t)
1195af9f9769Sjasmith 						    se->sc_nfsnum;
1196af9f9769Sjasmith 						goto done;
1197af9f9769Sjasmith 					}
1198af9f9769Sjasmith 				}
11997c478bd9Sstevel@tonic-gate 			}
12000616fd7fSPavel Filipensky 			exi = exi->fid_hash.next;
12017c478bd9Sstevel@tonic-gate 		}
12027c478bd9Sstevel@tonic-gate 	}
12037c478bd9Sstevel@tonic-gate done:
12040dfe541eSEvan Layton 	rw_exit(&ne->exported_lock);
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate 	/*
12077c478bd9Sstevel@tonic-gate 	 * If no nfs pseudo number mapping can be found in the export
12087c478bd9Sstevel@tonic-gate 	 * table, assign the nfsflavor to NFS_FLAVOR_NOMAP. In V4, we may
12097c478bd9Sstevel@tonic-gate 	 * recover the flavor mismatch from NFS layer (NFS4ERR_WRONGSEC).
12107c478bd9Sstevel@tonic-gate 	 *
12117c478bd9Sstevel@tonic-gate 	 * For example:
12127c478bd9Sstevel@tonic-gate 	 *	server first shares with krb5i;
12137c478bd9Sstevel@tonic-gate 	 *	client mounts with krb5i;
12147c478bd9Sstevel@tonic-gate 	 *	server re-shares with krb5p;
12157c478bd9Sstevel@tonic-gate 	 *	client tries with krb5i, but no mapping can be found;
12167c478bd9Sstevel@tonic-gate 	 *	rpcsec_gss module calls this routine to do the mapping,
12177c478bd9Sstevel@tonic-gate 	 *		if this routine fails, request is rejected from
12187c478bd9Sstevel@tonic-gate 	 *		the rpc layer.
12197c478bd9Sstevel@tonic-gate 	 *	What we need is to let the nfs layer rejects the request.
12207c478bd9Sstevel@tonic-gate 	 *	For V4, we can reject with NFS4ERR_WRONGSEC and the client
12217c478bd9Sstevel@tonic-gate 	 *	may recover from it by getting the new flavor via SECINFO.
12227c478bd9Sstevel@tonic-gate 	 *
12237c478bd9Sstevel@tonic-gate 	 * nfs pseudo number for RPCSEC_GSS mapping (see nfssec.conf)
12247c478bd9Sstevel@tonic-gate 	 * is owned by IANA (see RFC 2623).
12257c478bd9Sstevel@tonic-gate 	 *
12267c478bd9Sstevel@tonic-gate 	 * XXX NFS_FLAVOR_NOMAP is defined in Solaris to work around
12277c478bd9Sstevel@tonic-gate 	 * the implementation issue. This number should not overlap with
12287c478bd9Sstevel@tonic-gate 	 * any new IANA defined pseudo flavor numbers.
12297c478bd9Sstevel@tonic-gate 	 */
12307c478bd9Sstevel@tonic-gate 	if (*cookie == NULL)
12317c478bd9Sstevel@tonic-gate 		*cookie = (void *)NFS_FLAVOR_NOMAP;
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	lock->locked = TRUE;
12347c478bd9Sstevel@tonic-gate 
12357c478bd9Sstevel@tonic-gate 	return (TRUE);
12367c478bd9Sstevel@tonic-gate }
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 
12397c478bd9Sstevel@tonic-gate /*
12407c478bd9Sstevel@tonic-gate  * Exportfs system call; credentials should be checked before
12417c478bd9Sstevel@tonic-gate  * calling this function.
12427c478bd9Sstevel@tonic-gate  */
12437c478bd9Sstevel@tonic-gate int
exportfs(struct exportfs_args * args,model_t model,cred_t * cr)12447c478bd9Sstevel@tonic-gate exportfs(struct exportfs_args *args, model_t model, cred_t *cr)
12457c478bd9Sstevel@tonic-gate {
12467c478bd9Sstevel@tonic-gate 	vnode_t *vp;
12477c478bd9Sstevel@tonic-gate 	vnode_t *dvp;
1248af9f9769Sjasmith 	struct exportdata *kex;
1249936d128cSVallish Vaidyeshwara 	struct exportinfo *exi = NULL;
12500616fd7fSPavel Filipensky 	struct exportinfo *ex, *ex1, *ex2;
12517c478bd9Sstevel@tonic-gate 	fid_t fid;
12527c478bd9Sstevel@tonic-gate 	fsid_t fsid;
12537c478bd9Sstevel@tonic-gate 	int error;
12547c478bd9Sstevel@tonic-gate 	size_t allocsize;
12557c478bd9Sstevel@tonic-gate 	struct secinfo *sp;
12567c478bd9Sstevel@tonic-gate 	struct secinfo *exs;
12577c478bd9Sstevel@tonic-gate 	rpc_gss_callback_t cb;
12587c478bd9Sstevel@tonic-gate 	char *pathbuf;
12597c478bd9Sstevel@tonic-gate 	char *log_buffer;
12607c478bd9Sstevel@tonic-gate 	char *tagbuf;
12617c478bd9Sstevel@tonic-gate 	int callback;
12627c478bd9Sstevel@tonic-gate 	int allocd_seccnt;
12637c478bd9Sstevel@tonic-gate 	STRUCT_HANDLE(exportfs_args, uap);
12647c478bd9Sstevel@tonic-gate 	STRUCT_DECL(exportdata, uexi);
1265af9f9769Sjasmith 	struct secinfo newsec[MAX_FLAVORS];
1266af9f9769Sjasmith 	int newcnt;
1267af9f9769Sjasmith 	struct secinfo oldsec[MAX_FLAVORS];
1268af9f9769Sjasmith 	int oldcnt;
12697c478bd9Sstevel@tonic-gate 	int i;
12700616fd7fSPavel Filipensky 	struct pathname lookpn;
12710dfe541eSEvan Layton 	nfs_export_t *ne = nfs_get_export();
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 	STRUCT_SET_HANDLE(uap, model, args);
12747c478bd9Sstevel@tonic-gate 
12750616fd7fSPavel Filipensky 	/* Read in pathname from userspace */
1276*bd3561fbSToomas Soome 	error = pn_get(STRUCT_FGETP(uap, dname), UIO_USERSPACE, &lookpn);
1277*bd3561fbSToomas Soome 	if (error != 0)
12780616fd7fSPavel Filipensky 		return (error);
12790616fd7fSPavel Filipensky 
12800616fd7fSPavel Filipensky 	/* Walk the export list looking for that pathname */
12810dfe541eSEvan Layton 	rw_enter(&ne->exported_lock, RW_READER);
12820616fd7fSPavel Filipensky 	DTRACE_PROBE(nfss__i__exported_lock1_start);
12830dfe541eSEvan Layton 	for (ex1 = ne->exptable_path_hash[pkp_tab_hash(lookpn.pn_path,
12840616fd7fSPavel Filipensky 	    strlen(lookpn.pn_path))]; ex1; ex1 = ex1->path_hash.next) {
12850dfe541eSEvan Layton 		if (ex1 != ne->exi_root && 0 ==
12860616fd7fSPavel Filipensky 		    strcmp(ex1->exi_export.ex_path, lookpn.pn_path)) {
12870616fd7fSPavel Filipensky 			exi_hold(ex1);
12880616fd7fSPavel Filipensky 			break;
12890616fd7fSPavel Filipensky 		}
12900616fd7fSPavel Filipensky 	}
12910616fd7fSPavel Filipensky 	DTRACE_PROBE(nfss__i__exported_lock1_stop);
12920dfe541eSEvan Layton 	rw_exit(&ne->exported_lock);
12930616fd7fSPavel Filipensky 
12940616fd7fSPavel Filipensky 	/* Is this an unshare? */
12950616fd7fSPavel Filipensky 	if (STRUCT_FGETP(uap, uex) == NULL) {
12960616fd7fSPavel Filipensky 		pn_free(&lookpn);
12970616fd7fSPavel Filipensky 		if (ex1 == NULL)
12980616fd7fSPavel Filipensky 			return (EINVAL);
129906260e34SDan McDonald 		error = unexport(ne, ex1, cr);
13000616fd7fSPavel Filipensky 		exi_rele(ex1);
13010616fd7fSPavel Filipensky 		return (error);
13020616fd7fSPavel Filipensky 	}
13030616fd7fSPavel Filipensky 
13040616fd7fSPavel Filipensky 	/* It is a share or a re-share */
13057c478bd9Sstevel@tonic-gate 	error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
13067c478bd9Sstevel@tonic-gate 	    FOLLOW, &dvp, &vp);
13077c478bd9Sstevel@tonic-gate 	if (error == EINVAL) {
13087c478bd9Sstevel@tonic-gate 		/*
13097c478bd9Sstevel@tonic-gate 		 * if fname resolves to / we get EINVAL error
13107c478bd9Sstevel@tonic-gate 		 * since we wanted the parent vnode. Try again
13117c478bd9Sstevel@tonic-gate 		 * with NULL dvp.
13127c478bd9Sstevel@tonic-gate 		 */
13137c478bd9Sstevel@tonic-gate 		error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
13147c478bd9Sstevel@tonic-gate 		    FOLLOW, NULL, &vp);
13157c478bd9Sstevel@tonic-gate 		dvp = NULL;
13167c478bd9Sstevel@tonic-gate 	}
13177c478bd9Sstevel@tonic-gate 	if (!error && vp == NULL) {
13180616fd7fSPavel Filipensky 		/* Last component of fname not found */
13190616fd7fSPavel Filipensky 		if (dvp != NULL)
13207c478bd9Sstevel@tonic-gate 			VN_RELE(dvp);
13217c478bd9Sstevel@tonic-gate 		error = ENOENT;
13227c478bd9Sstevel@tonic-gate 	}
1323992d2facSpf 	if (error) {
13240616fd7fSPavel Filipensky 		pn_free(&lookpn);
13250616fd7fSPavel Filipensky 		if (ex1)
13260616fd7fSPavel Filipensky 			exi_rele(ex1);
1327bfbb13c9Sjmcp 		return (error);
13280616fd7fSPavel Filipensky 	}
1329bfbb13c9Sjmcp 
13307c478bd9Sstevel@tonic-gate 	/*
13317c478bd9Sstevel@tonic-gate 	 * 'vp' may be an AUTOFS node, so we perform a
13327c478bd9Sstevel@tonic-gate 	 * VOP_ACCESS() to trigger the mount of the
13337c478bd9Sstevel@tonic-gate 	 * intended filesystem, so we can share the intended
13347c478bd9Sstevel@tonic-gate 	 * filesystem instead of the AUTOFS filesystem.
13357c478bd9Sstevel@tonic-gate 	 */
1336da6c28aaSamw 	(void) VOP_ACCESS(vp, 0, 0, cr, NULL);
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate 	/*
13397c478bd9Sstevel@tonic-gate 	 * We're interested in the top most filesystem.
13407c478bd9Sstevel@tonic-gate 	 * This is specially important when uap->dname is a trigger
13417c478bd9Sstevel@tonic-gate 	 * AUTOFS node, since we're really interested in sharing the
13427c478bd9Sstevel@tonic-gate 	 * filesystem AUTOFS mounted as result of the VOP_ACCESS()
13437c478bd9Sstevel@tonic-gate 	 * call not the AUTOFS node itself.
13447c478bd9Sstevel@tonic-gate 	 */
13457c478bd9Sstevel@tonic-gate 	if (vn_mountedvfs(vp) != NULL) {
1346*bd3561fbSToomas Soome 		error = traverse(&vp);
1347*bd3561fbSToomas Soome 		if (error != 0) {
13487c478bd9Sstevel@tonic-gate 			VN_RELE(vp);
13497c478bd9Sstevel@tonic-gate 			if (dvp != NULL)
13507c478bd9Sstevel@tonic-gate 				VN_RELE(dvp);
13510616fd7fSPavel Filipensky 			pn_free(&lookpn);
13520616fd7fSPavel Filipensky 			if (ex1)
13530616fd7fSPavel Filipensky 				exi_rele(ex1);
13547c478bd9Sstevel@tonic-gate 			return (error);
13557c478bd9Sstevel@tonic-gate 		}
13567c478bd9Sstevel@tonic-gate 	}
13577c478bd9Sstevel@tonic-gate 
13580616fd7fSPavel Filipensky 	/* Do not allow sharing another vnode for already shared path */
13590616fd7fSPavel Filipensky 	if (ex1 && !PSEUDO(ex1) && !VN_CMP(ex1->exi_vp, vp)) {
1360a3745ee9SPavel Filipensky 		VN_RELE(vp);
1361a3745ee9SPavel Filipensky 		if (dvp != NULL)
1362a3745ee9SPavel Filipensky 			VN_RELE(dvp);
13630616fd7fSPavel Filipensky 		pn_free(&lookpn);
13640616fd7fSPavel Filipensky 		exi_rele(ex1);
13650616fd7fSPavel Filipensky 		return (EEXIST);
13660616fd7fSPavel Filipensky 	}
13670616fd7fSPavel Filipensky 	if (ex1)
13680616fd7fSPavel Filipensky 		exi_rele(ex1);
13690616fd7fSPavel Filipensky 
13707c478bd9Sstevel@tonic-gate 	/*
13717c478bd9Sstevel@tonic-gate 	 * Get the vfs id
13727c478bd9Sstevel@tonic-gate 	 */
13737c478bd9Sstevel@tonic-gate 	bzero(&fid, sizeof (fid));
13747c478bd9Sstevel@tonic-gate 	fid.fid_len = MAXFIDSZ;
1375da6c28aaSamw 	error = VOP_FID(vp, &fid, NULL);
13767c478bd9Sstevel@tonic-gate 	fsid = vp->v_vfsp->vfs_fsid;
1377936d128cSVallish Vaidyeshwara 
13780616fd7fSPavel Filipensky 	if (error) {
13797c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
13807c478bd9Sstevel@tonic-gate 		if (dvp != NULL)
13817c478bd9Sstevel@tonic-gate 			VN_RELE(dvp);
13827c478bd9Sstevel@tonic-gate 		/*
13837c478bd9Sstevel@tonic-gate 		 * If VOP_FID returns ENOSPC then the fid supplied
13847c478bd9Sstevel@tonic-gate 		 * is too small.  For now we simply return EREMOTE.
13857c478bd9Sstevel@tonic-gate 		 */
13867c478bd9Sstevel@tonic-gate 		if (error == ENOSPC)
13877c478bd9Sstevel@tonic-gate 			error = EREMOTE;
13880616fd7fSPavel Filipensky 		pn_free(&lookpn);
13897c478bd9Sstevel@tonic-gate 		return (error);
13907c478bd9Sstevel@tonic-gate 	}
13917c478bd9Sstevel@tonic-gate 
13920616fd7fSPavel Filipensky 	/*
13930616fd7fSPavel Filipensky 	 * Do not allow re-sharing a shared vnode under a different path
13940616fd7fSPavel Filipensky 	 * PSEUDO export has ex_path fabricated, e.g. "/tmp (pseudo)", skip it.
13950616fd7fSPavel Filipensky 	 */
13960dfe541eSEvan Layton 	rw_enter(&ne->exported_lock, RW_READER);
13970616fd7fSPavel Filipensky 	DTRACE_PROBE(nfss__i__exported_lock2_start);
13980dfe541eSEvan Layton 	for (ex2 = ne->exptable[exptablehash(&fsid, &fid)]; ex2;
13990616fd7fSPavel Filipensky 	    ex2 = ex2->fid_hash.next) {
14000dfe541eSEvan Layton 		if (ex2 != ne->exi_root && !PSEUDO(ex2) &&
14010616fd7fSPavel Filipensky 		    VN_CMP(ex2->exi_vp, vp) &&
14020616fd7fSPavel Filipensky 		    strcmp(ex2->exi_export.ex_path, lookpn.pn_path) != 0) {
14030616fd7fSPavel Filipensky 			DTRACE_PROBE(nfss__i__exported_lock2_stop);
14040dfe541eSEvan Layton 			rw_exit(&ne->exported_lock);
1405a3745ee9SPavel Filipensky 			VN_RELE(vp);
1406a3745ee9SPavel Filipensky 			if (dvp != NULL)
1407a3745ee9SPavel Filipensky 				VN_RELE(dvp);
14080616fd7fSPavel Filipensky 			pn_free(&lookpn);
14090616fd7fSPavel Filipensky 			return (EEXIST);
14100616fd7fSPavel Filipensky 		}
14117c478bd9Sstevel@tonic-gate 	}
14120616fd7fSPavel Filipensky 	DTRACE_PROBE(nfss__i__exported_lock2_stop);
14130dfe541eSEvan Layton 	rw_exit(&ne->exported_lock);
14140616fd7fSPavel Filipensky 	pn_free(&lookpn);
14158a429e7eSms 
14167c478bd9Sstevel@tonic-gate 	exi = kmem_zalloc(sizeof (*exi), KM_SLEEP);
14177c478bd9Sstevel@tonic-gate 	exi->exi_fsid = fsid;
14187c478bd9Sstevel@tonic-gate 	exi->exi_fid = fid;
14197c478bd9Sstevel@tonic-gate 	exi->exi_vp = vp;
14207c478bd9Sstevel@tonic-gate 	exi->exi_count = 1;
14210dfe541eSEvan Layton 	exi->exi_zoneid = crgetzoneid(cr);
14220dfe541eSEvan Layton 	ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
14237c478bd9Sstevel@tonic-gate 	exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
1424af9f9769Sjasmith 	    VSW_VOLATILEDEV) ? 1 : 0;
14257c478bd9Sstevel@tonic-gate 	mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
14267c478bd9Sstevel@tonic-gate 	exi->exi_dvp = dvp;
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 	/*
142971da0c32SMarcel Telka 	 * Initialize auth cache and auth cache lock
14307c478bd9Sstevel@tonic-gate 	 */
143171da0c32SMarcel Telka 	for (i = 0; i < AUTH_TABLESIZE; i++) {
143271da0c32SMarcel Telka 		exi->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
143371da0c32SMarcel Telka 		avl_create(exi->exi_cache[i], nfsauth_cache_clnt_compar,
143471da0c32SMarcel Telka 		    sizeof (struct auth_cache_clnt),
143571da0c32SMarcel Telka 		    offsetof(struct auth_cache_clnt, authc_link));
143671da0c32SMarcel Telka 	}
14377c478bd9Sstevel@tonic-gate 	rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL);
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate 	/*
14407c478bd9Sstevel@tonic-gate 	 * Build up the template fhandle
14417c478bd9Sstevel@tonic-gate 	 */
14427c478bd9Sstevel@tonic-gate 	exi->exi_fh.fh_fsid = fsid;
14437c478bd9Sstevel@tonic-gate 	if (exi->exi_fid.fid_len > sizeof (exi->exi_fh.fh_xdata)) {
14447c478bd9Sstevel@tonic-gate 		error = EREMOTE;
14457c478bd9Sstevel@tonic-gate 		goto out1;
14467c478bd9Sstevel@tonic-gate 	}
14477c478bd9Sstevel@tonic-gate 	exi->exi_fh.fh_xlen = exi->exi_fid.fid_len;
14487c478bd9Sstevel@tonic-gate 	bcopy(exi->exi_fid.fid_data, exi->exi_fh.fh_xdata,
14497c478bd9Sstevel@tonic-gate 	    exi->exi_fid.fid_len);
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 	exi->exi_fh.fh_len = sizeof (exi->exi_fh.fh_data);
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate 	kex = &exi->exi_export;
14547c478bd9Sstevel@tonic-gate 
14557c478bd9Sstevel@tonic-gate 	/*
14567c478bd9Sstevel@tonic-gate 	 * Load in everything, and do sanity checking
14577c478bd9Sstevel@tonic-gate 	 */
14587c478bd9Sstevel@tonic-gate 	STRUCT_INIT(uexi, model);
14597c478bd9Sstevel@tonic-gate 	if (copyin(STRUCT_FGETP(uap, uex), STRUCT_BUF(uexi),
14607c478bd9Sstevel@tonic-gate 	    STRUCT_SIZE(uexi))) {
14617c478bd9Sstevel@tonic-gate 		error = EFAULT;
14627c478bd9Sstevel@tonic-gate 		goto out1;
14637c478bd9Sstevel@tonic-gate 	}
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate 	kex->ex_version = STRUCT_FGET(uexi, ex_version);
14667c478bd9Sstevel@tonic-gate 	if (kex->ex_version != EX_CURRENT_VERSION) {
14677c478bd9Sstevel@tonic-gate 		error = EINVAL;
14687c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
1469af9f9769Sjasmith 		    "NFS: exportfs requires export struct version 2 - got %d\n",
1470af9f9769Sjasmith 		    kex->ex_version);
14717c478bd9Sstevel@tonic-gate 		goto out1;
14727c478bd9Sstevel@tonic-gate 	}
14737c478bd9Sstevel@tonic-gate 
14747c478bd9Sstevel@tonic-gate 	/*
14757c478bd9Sstevel@tonic-gate 	 * Must have at least one security entry
14767c478bd9Sstevel@tonic-gate 	 */
14777c478bd9Sstevel@tonic-gate 	kex->ex_seccnt = STRUCT_FGET(uexi, ex_seccnt);
14787c478bd9Sstevel@tonic-gate 	if (kex->ex_seccnt < 1) {
14797c478bd9Sstevel@tonic-gate 		error = EINVAL;
14807c478bd9Sstevel@tonic-gate 		goto out1;
14817c478bd9Sstevel@tonic-gate 	}
14827c478bd9Sstevel@tonic-gate 
14837c478bd9Sstevel@tonic-gate 	kex->ex_path = STRUCT_FGETP(uexi, ex_path);
14847c478bd9Sstevel@tonic-gate 	kex->ex_pathlen = STRUCT_FGET(uexi, ex_pathlen);
14857c478bd9Sstevel@tonic-gate 	kex->ex_flags = STRUCT_FGET(uexi, ex_flags);
14867c478bd9Sstevel@tonic-gate 	kex->ex_anon = STRUCT_FGET(uexi, ex_anon);
14877c478bd9Sstevel@tonic-gate 	kex->ex_secinfo = STRUCT_FGETP(uexi, ex_secinfo);
14887c478bd9Sstevel@tonic-gate 	kex->ex_index = STRUCT_FGETP(uexi, ex_index);
14897c478bd9Sstevel@tonic-gate 	kex->ex_log_buffer = STRUCT_FGETP(uexi, ex_log_buffer);
14907c478bd9Sstevel@tonic-gate 	kex->ex_log_bufferlen = STRUCT_FGET(uexi, ex_log_bufferlen);
14917c478bd9Sstevel@tonic-gate 	kex->ex_tag = STRUCT_FGETP(uexi, ex_tag);
14927c478bd9Sstevel@tonic-gate 	kex->ex_taglen = STRUCT_FGET(uexi, ex_taglen);
14937c478bd9Sstevel@tonic-gate 
14947c478bd9Sstevel@tonic-gate 	/*
14957c478bd9Sstevel@tonic-gate 	 * Copy the exported pathname into
14967c478bd9Sstevel@tonic-gate 	 * an appropriately sized buffer.
14977c478bd9Sstevel@tonic-gate 	 */
14987c478bd9Sstevel@tonic-gate 	pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
14997c478bd9Sstevel@tonic-gate 	if (copyinstr(kex->ex_path, pathbuf, MAXPATHLEN, &kex->ex_pathlen)) {
15007c478bd9Sstevel@tonic-gate 		kmem_free(pathbuf, MAXPATHLEN);
15017c478bd9Sstevel@tonic-gate 		error = EFAULT;
15027c478bd9Sstevel@tonic-gate 		goto out1;
15037c478bd9Sstevel@tonic-gate 	}
15047c478bd9Sstevel@tonic-gate 	kex->ex_path = kmem_alloc(kex->ex_pathlen + 1, KM_SLEEP);
15057c478bd9Sstevel@tonic-gate 	bcopy(pathbuf, kex->ex_path, kex->ex_pathlen);
15067c478bd9Sstevel@tonic-gate 	kex->ex_path[kex->ex_pathlen] = '\0';
15077c478bd9Sstevel@tonic-gate 	kmem_free(pathbuf, MAXPATHLEN);
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate 	/*
15107c478bd9Sstevel@tonic-gate 	 * Get the path to the logging buffer and the tag
15117c478bd9Sstevel@tonic-gate 	 */
15127c478bd9Sstevel@tonic-gate 	if (kex->ex_flags & EX_LOG) {
15137c478bd9Sstevel@tonic-gate 		log_buffer = kmem_alloc(MAXPATHLEN, KM_SLEEP);
15147c478bd9Sstevel@tonic-gate 		if (copyinstr(kex->ex_log_buffer, log_buffer, MAXPATHLEN,
15157c478bd9Sstevel@tonic-gate 		    &kex->ex_log_bufferlen)) {
15167c478bd9Sstevel@tonic-gate 			kmem_free(log_buffer, MAXPATHLEN);
15177c478bd9Sstevel@tonic-gate 			error = EFAULT;
15187c478bd9Sstevel@tonic-gate 			goto out2;
15197c478bd9Sstevel@tonic-gate 		}
15207c478bd9Sstevel@tonic-gate 		kex->ex_log_buffer =
1521af9f9769Sjasmith 		    kmem_alloc(kex->ex_log_bufferlen + 1, KM_SLEEP);
15227c478bd9Sstevel@tonic-gate 		bcopy(log_buffer, kex->ex_log_buffer, kex->ex_log_bufferlen);
15237c478bd9Sstevel@tonic-gate 		kex->ex_log_buffer[kex->ex_log_bufferlen] = '\0';
15247c478bd9Sstevel@tonic-gate 		kmem_free(log_buffer, MAXPATHLEN);
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate 		tagbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
15277c478bd9Sstevel@tonic-gate 		if (copyinstr(kex->ex_tag, tagbuf, MAXPATHLEN,
15287c478bd9Sstevel@tonic-gate 		    &kex->ex_taglen)) {
15297c478bd9Sstevel@tonic-gate 			kmem_free(tagbuf, MAXPATHLEN);
15307c478bd9Sstevel@tonic-gate 			error = EFAULT;
15317c478bd9Sstevel@tonic-gate 			goto out3;
15327c478bd9Sstevel@tonic-gate 		}
15337c478bd9Sstevel@tonic-gate 		kex->ex_tag = kmem_alloc(kex->ex_taglen + 1, KM_SLEEP);
15347c478bd9Sstevel@tonic-gate 		bcopy(tagbuf, kex->ex_tag, kex->ex_taglen);
15357c478bd9Sstevel@tonic-gate 		kex->ex_tag[kex->ex_taglen] = '\0';
15367c478bd9Sstevel@tonic-gate 		kmem_free(tagbuf, MAXPATHLEN);
15377c478bd9Sstevel@tonic-gate 	}
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate 	/*
15407c478bd9Sstevel@tonic-gate 	 * Load the security information for each flavor
15417c478bd9Sstevel@tonic-gate 	 */
15427c478bd9Sstevel@tonic-gate 	allocsize = kex->ex_seccnt * SIZEOF_STRUCT(secinfo, model);
15437c478bd9Sstevel@tonic-gate 	sp = kmem_zalloc(allocsize, KM_SLEEP);
15447c478bd9Sstevel@tonic-gate 	if (copyin(kex->ex_secinfo, sp, allocsize)) {
15457c478bd9Sstevel@tonic-gate 		kmem_free(sp, allocsize);
15467c478bd9Sstevel@tonic-gate 		error = EFAULT;
15477c478bd9Sstevel@tonic-gate 		goto out4;
15487c478bd9Sstevel@tonic-gate 	}
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate 	/*
15517c478bd9Sstevel@tonic-gate 	 * All of these nested structures need to be converted to
15527c478bd9Sstevel@tonic-gate 	 * the kernel native format.
15537c478bd9Sstevel@tonic-gate 	 */
15547c478bd9Sstevel@tonic-gate 	if (model != DATAMODEL_NATIVE) {
15557c478bd9Sstevel@tonic-gate 		size_t allocsize2;
15567c478bd9Sstevel@tonic-gate 		struct secinfo *sp2;
15577c478bd9Sstevel@tonic-gate 
15587c478bd9Sstevel@tonic-gate 		allocsize2 = kex->ex_seccnt * sizeof (struct secinfo);
15597c478bd9Sstevel@tonic-gate 		sp2 = kmem_zalloc(allocsize2, KM_SLEEP);
15607c478bd9Sstevel@tonic-gate 
15617c478bd9Sstevel@tonic-gate 		for (i = 0; i < kex->ex_seccnt; i++) {
15627c478bd9Sstevel@tonic-gate 			STRUCT_HANDLE(secinfo, usi);
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate 			STRUCT_SET_HANDLE(usi, model,
15657c478bd9Sstevel@tonic-gate 			    (struct secinfo *)((caddr_t)sp +
15667c478bd9Sstevel@tonic-gate 			    (i * SIZEOF_STRUCT(secinfo, model))));
15677c478bd9Sstevel@tonic-gate 			bcopy(STRUCT_FGET(usi, s_secinfo.sc_name),
15687c478bd9Sstevel@tonic-gate 			    sp2[i].s_secinfo.sc_name, MAX_NAME_LEN);
15697c478bd9Sstevel@tonic-gate 			sp2[i].s_secinfo.sc_nfsnum =
15707c478bd9Sstevel@tonic-gate 			    STRUCT_FGET(usi, s_secinfo.sc_nfsnum);
15717c478bd9Sstevel@tonic-gate 			sp2[i].s_secinfo.sc_rpcnum =
15727c478bd9Sstevel@tonic-gate 			    STRUCT_FGET(usi, s_secinfo.sc_rpcnum);
15737c478bd9Sstevel@tonic-gate 			bcopy(STRUCT_FGET(usi, s_secinfo.sc_gss_mech),
15747c478bd9Sstevel@tonic-gate 			    sp2[i].s_secinfo.sc_gss_mech, MAX_NAME_LEN);
15757c478bd9Sstevel@tonic-gate 			sp2[i].s_secinfo.sc_gss_mech_type =
15767c478bd9Sstevel@tonic-gate 			    STRUCT_FGETP(usi, s_secinfo.sc_gss_mech_type);
15777c478bd9Sstevel@tonic-gate 			sp2[i].s_secinfo.sc_qop =
15787c478bd9Sstevel@tonic-gate 			    STRUCT_FGET(usi, s_secinfo.sc_qop);
15797c478bd9Sstevel@tonic-gate 			sp2[i].s_secinfo.sc_service =
15807c478bd9Sstevel@tonic-gate 			    STRUCT_FGET(usi, s_secinfo.sc_service);
15817c478bd9Sstevel@tonic-gate 
15827c478bd9Sstevel@tonic-gate 			sp2[i].s_flags = STRUCT_FGET(usi, s_flags);
15837c478bd9Sstevel@tonic-gate 			sp2[i].s_window = STRUCT_FGET(usi, s_window);
1584b89a8333Snatalie li - Sun Microsystems - Irvine United States 			sp2[i].s_rootid = STRUCT_FGET(usi, s_rootid);
15857c478bd9Sstevel@tonic-gate 			sp2[i].s_rootcnt = STRUCT_FGET(usi, s_rootcnt);
15867c478bd9Sstevel@tonic-gate 			sp2[i].s_rootnames = STRUCT_FGETP(usi, s_rootnames);
15877c478bd9Sstevel@tonic-gate 		}
15887c478bd9Sstevel@tonic-gate 		kmem_free(sp, allocsize);
15897c478bd9Sstevel@tonic-gate 		sp = sp2;
15907c478bd9Sstevel@tonic-gate 		allocsize = allocsize2;
15917c478bd9Sstevel@tonic-gate 	}
15927c478bd9Sstevel@tonic-gate 
15937c478bd9Sstevel@tonic-gate 	kex->ex_secinfo = sp;
15947c478bd9Sstevel@tonic-gate 
15957c478bd9Sstevel@tonic-gate 	/*
15967c478bd9Sstevel@tonic-gate 	 * And now copy rootnames for each individual secinfo.
15977c478bd9Sstevel@tonic-gate 	 */
15987c478bd9Sstevel@tonic-gate 	callback = 0;
15997c478bd9Sstevel@tonic-gate 	allocd_seccnt = 0;
16007c478bd9Sstevel@tonic-gate 	while (allocd_seccnt < kex->ex_seccnt) {
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 		exs = &sp[allocd_seccnt];
16037c478bd9Sstevel@tonic-gate 		if (exs->s_rootcnt > 0) {
16047c478bd9Sstevel@tonic-gate 			if (!sec_svc_loadrootnames(exs->s_secinfo.sc_rpcnum,
16057c478bd9Sstevel@tonic-gate 			    exs->s_rootcnt, &exs->s_rootnames, model)) {
16067c478bd9Sstevel@tonic-gate 				error = EFAULT;
16077c478bd9Sstevel@tonic-gate 				goto out5;
16087c478bd9Sstevel@tonic-gate 			}
16097c478bd9Sstevel@tonic-gate 		}
16107c478bd9Sstevel@tonic-gate 
16117c478bd9Sstevel@tonic-gate 		if (exs->s_secinfo.sc_rpcnum == RPCSEC_GSS) {
16127c478bd9Sstevel@tonic-gate 			rpc_gss_OID mech_tmp;
16137c478bd9Sstevel@tonic-gate 			STRUCT_DECL(rpc_gss_OID_s, umech_tmp);
16147c478bd9Sstevel@tonic-gate 			caddr_t elements_tmp;
16157c478bd9Sstevel@tonic-gate 
16167c478bd9Sstevel@tonic-gate 			/* Copyin mechanism type */
16177c478bd9Sstevel@tonic-gate 			STRUCT_INIT(umech_tmp, model);
16187c478bd9Sstevel@tonic-gate 			mech_tmp = kmem_alloc(sizeof (*mech_tmp), KM_SLEEP);
16197c478bd9Sstevel@tonic-gate 			if (copyin(exs->s_secinfo.sc_gss_mech_type,
16207c478bd9Sstevel@tonic-gate 			    STRUCT_BUF(umech_tmp), STRUCT_SIZE(umech_tmp))) {
16217c478bd9Sstevel@tonic-gate 				kmem_free(mech_tmp, sizeof (*mech_tmp));
16227c478bd9Sstevel@tonic-gate 				error = EFAULT;
16237c478bd9Sstevel@tonic-gate 				goto out5;
16247c478bd9Sstevel@tonic-gate 			}
16257c478bd9Sstevel@tonic-gate 			mech_tmp->length = STRUCT_FGET(umech_tmp, length);
16267c478bd9Sstevel@tonic-gate 			mech_tmp->elements = STRUCT_FGETP(umech_tmp, elements);
16277c478bd9Sstevel@tonic-gate 
16287c478bd9Sstevel@tonic-gate 			elements_tmp = kmem_alloc(mech_tmp->length, KM_SLEEP);
16297c478bd9Sstevel@tonic-gate 			if (copyin(mech_tmp->elements, elements_tmp,
16307c478bd9Sstevel@tonic-gate 			    mech_tmp->length)) {
16317c478bd9Sstevel@tonic-gate 				kmem_free(elements_tmp, mech_tmp->length);
16327c478bd9Sstevel@tonic-gate 				kmem_free(mech_tmp, sizeof (*mech_tmp));
16337c478bd9Sstevel@tonic-gate 				error = EFAULT;
16347c478bd9Sstevel@tonic-gate 				goto out5;
16357c478bd9Sstevel@tonic-gate 			}
16367c478bd9Sstevel@tonic-gate 			mech_tmp->elements = elements_tmp;
16377c478bd9Sstevel@tonic-gate 			exs->s_secinfo.sc_gss_mech_type = mech_tmp;
16387c478bd9Sstevel@tonic-gate 			allocd_seccnt++;
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate 			callback = 1;
16417c478bd9Sstevel@tonic-gate 		} else
16427c478bd9Sstevel@tonic-gate 			allocd_seccnt++;
16437c478bd9Sstevel@tonic-gate 	}
16447c478bd9Sstevel@tonic-gate 
16457c478bd9Sstevel@tonic-gate 	/*
16467c478bd9Sstevel@tonic-gate 	 * Init the secinfo reference count and mark these flavors
16477c478bd9Sstevel@tonic-gate 	 * explicitly exported flavors.
16487c478bd9Sstevel@tonic-gate 	 */
16497c478bd9Sstevel@tonic-gate 	for (i = 0; i < kex->ex_seccnt; i++) {
16507c478bd9Sstevel@tonic-gate 		kex->ex_secinfo[i].s_flags |= M_4SEC_EXPORTED;
16511a220b56Sjasmith 		kex->ex_secinfo[i].s_refcnt = 1;
16527c478bd9Sstevel@tonic-gate 	}
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 	/*
16557c478bd9Sstevel@tonic-gate 	 *  Set up rpcsec_gss callback routine entry if any.
16567c478bd9Sstevel@tonic-gate 	 */
16577c478bd9Sstevel@tonic-gate 	if (callback) {
16587c478bd9Sstevel@tonic-gate 		cb.callback = rfs_gsscallback;
16597c478bd9Sstevel@tonic-gate 		cb.program = NFS_ACL_PROGRAM;
16607c478bd9Sstevel@tonic-gate 		for (cb.version = NFS_ACL_VERSMIN;
16617c478bd9Sstevel@tonic-gate 		    cb.version <= NFS_ACL_VERSMAX; cb.version++) {
16627c478bd9Sstevel@tonic-gate 			(void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK,
16637c478bd9Sstevel@tonic-gate 			    (void *)&cb);
16647c478bd9Sstevel@tonic-gate 		}
16657c478bd9Sstevel@tonic-gate 
16667c478bd9Sstevel@tonic-gate 		cb.program = NFS_PROGRAM;
16677c478bd9Sstevel@tonic-gate 		for (cb.version = NFS_VERSMIN;
16687c478bd9Sstevel@tonic-gate 		    cb.version <= NFS_VERSMAX; cb.version++) {
16697c478bd9Sstevel@tonic-gate 			(void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK,
16707c478bd9Sstevel@tonic-gate 			    (void *)&cb);
16717c478bd9Sstevel@tonic-gate 		}
16727c478bd9Sstevel@tonic-gate 	}
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 	/*
16757c478bd9Sstevel@tonic-gate 	 * Check the index flag. Do this here to avoid holding the
16767c478bd9Sstevel@tonic-gate 	 * lock while dealing with the index option (as we do with
16777c478bd9Sstevel@tonic-gate 	 * the public option).
16787c478bd9Sstevel@tonic-gate 	 */
16797c478bd9Sstevel@tonic-gate 	if (kex->ex_flags & EX_INDEX) {
16807c478bd9Sstevel@tonic-gate 		if (!kex->ex_index) {	/* sanity check */
16817c478bd9Sstevel@tonic-gate 			error = EINVAL;
16827c478bd9Sstevel@tonic-gate 			goto out5;
16837c478bd9Sstevel@tonic-gate 		}
1684*bd3561fbSToomas Soome 		error = loadindex(kex);
1685*bd3561fbSToomas Soome 		if (error != 0)
16867c478bd9Sstevel@tonic-gate 			goto out5;
16877c478bd9Sstevel@tonic-gate 	}
16887c478bd9Sstevel@tonic-gate 
16897c478bd9Sstevel@tonic-gate 	if (kex->ex_flags & EX_LOG) {
1690*bd3561fbSToomas Soome 		error = nfslog_setup(exi);
1691*bd3561fbSToomas Soome 		if (error != 0)
16927c478bd9Sstevel@tonic-gate 			goto out6;
16937c478bd9Sstevel@tonic-gate 	}
16947c478bd9Sstevel@tonic-gate 
16957c478bd9Sstevel@tonic-gate 	/*
16967c478bd9Sstevel@tonic-gate 	 * Insert the new entry at the front of the export list
16977c478bd9Sstevel@tonic-gate 	 */
16980dfe541eSEvan Layton 	rw_enter(&ne->exported_lock, RW_WRITER);
16990616fd7fSPavel Filipensky 	DTRACE_PROBE(nfss__i__exported_lock3_start);
17007c478bd9Sstevel@tonic-gate 
17010dfe541eSEvan Layton 	export_link(ne, exi);
17027c478bd9Sstevel@tonic-gate 
17037c478bd9Sstevel@tonic-gate 	/*
17047c478bd9Sstevel@tonic-gate 	 * Check the rest of the list for an old entry for the fs.
17057c478bd9Sstevel@tonic-gate 	 * If one is found then unlink it, wait until this is the
17067c478bd9Sstevel@tonic-gate 	 * only reference and then free it.
17077c478bd9Sstevel@tonic-gate 	 */
17080616fd7fSPavel Filipensky 	for (ex = exi->fid_hash.next; ex != NULL; ex = ex->fid_hash.next) {
17090dfe541eSEvan Layton 		if (ex != ne->exi_root && VN_CMP(ex->exi_vp, vp)) {
17100dfe541eSEvan Layton 			mutex_enter(&nfs_exi_id_lock);
17110dfe541eSEvan Layton 			avl_remove(&exi_id_tree, ex);
17120dfe541eSEvan Layton 			mutex_exit(&nfs_exi_id_lock);
17130dfe541eSEvan Layton 			export_unlink(ne, ex);
17147c478bd9Sstevel@tonic-gate 			break;
17157c478bd9Sstevel@tonic-gate 		}
17167c478bd9Sstevel@tonic-gate 	}
17177c478bd9Sstevel@tonic-gate 
17187c478bd9Sstevel@tonic-gate 	/*
17197c478bd9Sstevel@tonic-gate 	 * If the public filehandle is pointing at the
17207c478bd9Sstevel@tonic-gate 	 * old entry, then point it back at the root.
17217c478bd9Sstevel@tonic-gate 	 */
17220dfe541eSEvan Layton 	if (ex != NULL && ex == ne->exi_public)
17230dfe541eSEvan Layton 		ne->exi_public = ne->exi_root;
17247c478bd9Sstevel@tonic-gate 
17257c478bd9Sstevel@tonic-gate 	/*
17267c478bd9Sstevel@tonic-gate 	 * If the public flag is on, make the global exi_public
17277c478bd9Sstevel@tonic-gate 	 * point to this entry and turn off the public bit so that
17287c478bd9Sstevel@tonic-gate 	 * we can distinguish it from the place holder export.
17297c478bd9Sstevel@tonic-gate 	 */
17307c478bd9Sstevel@tonic-gate 	if (kex->ex_flags & EX_PUBLIC) {
17310dfe541eSEvan Layton 		ne->exi_public = exi;
17327c478bd9Sstevel@tonic-gate 		kex->ex_flags &= ~EX_PUBLIC;
17337c478bd9Sstevel@tonic-gate 	}
17347c478bd9Sstevel@tonic-gate 
17357c478bd9Sstevel@tonic-gate #ifdef VOLATILE_FH_TEST
17367c478bd9Sstevel@tonic-gate 	/*
17377c478bd9Sstevel@tonic-gate 	 * Set up the volatile_id value if volatile on share.
17387c478bd9Sstevel@tonic-gate 	 * The list of volatile renamed filehandles is always destroyed,
17397c478bd9Sstevel@tonic-gate 	 * if the fs was reshared.
17407c478bd9Sstevel@tonic-gate 	 */
17417c478bd9Sstevel@tonic-gate 	if (kex->ex_flags & EX_VOLFH)
17427c478bd9Sstevel@tonic-gate 		exi->exi_volatile_id = gethrestime_sec();
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 	mutex_init(&exi->exi_vol_rename_lock, NULL, MUTEX_DEFAULT, NULL);
17457c478bd9Sstevel@tonic-gate #endif /* VOLATILE_FH_TEST */
17467c478bd9Sstevel@tonic-gate 
17477c478bd9Sstevel@tonic-gate 	/*
17487c478bd9Sstevel@tonic-gate 	 * If this is a new export, then climb up
17497c478bd9Sstevel@tonic-gate 	 * the tree and check if any pseudo exports
17507c478bd9Sstevel@tonic-gate 	 * need to be created to provide a path for
17517c478bd9Sstevel@tonic-gate 	 * NFS v4 clients.
17527c478bd9Sstevel@tonic-gate 	 */
1753992d2facSpf 	if (ex == NULL) {
17547c478bd9Sstevel@tonic-gate 		error = treeclimb_export(exi);
1755992d2facSpf 		if (error)
1756992d2facSpf 			goto out7;
1757992d2facSpf 	} else {
17584a695956SMarcel Telka 		/* If it's a re-export update namespace tree */
1759992d2facSpf 		exi->exi_tree = ex->exi_tree;
1760992d2facSpf 		exi->exi_tree->tree_exi = exi;
17614a695956SMarcel Telka 
17624a695956SMarcel Telka 		/* Update the change timestamp */
17630dfe541eSEvan Layton 		tree_update_change(ne, exi->exi_tree, NULL);
1764992d2facSpf 	}
17657c478bd9Sstevel@tonic-gate 
17668a429e7eSms 	/*
1767af9f9769Sjasmith 	 * build a unique flavor list from the flavors specified
1768af9f9769Sjasmith 	 * in the share cmd.  unique means that each flavor only
1769af9f9769Sjasmith 	 * appears once in the secinfo list -- no duplicates allowed.
17708a429e7eSms 	 */
1771af9f9769Sjasmith 	newcnt = build_seclist_nodups(&exi->exi_export, newsec, FALSE);
17728a429e7eSms 
17730dfe541eSEvan Layton 	srv_secinfo_treeclimb(ne, exi, newsec, newcnt, TRUE);
17747c478bd9Sstevel@tonic-gate 
17757c478bd9Sstevel@tonic-gate 	/*
17767c478bd9Sstevel@tonic-gate 	 * If re-sharing an old export entry, update the secinfo data
17777c478bd9Sstevel@tonic-gate 	 * depending on if the old entry is a pseudo node or not.
17787c478bd9Sstevel@tonic-gate 	 */
1779992d2facSpf 	if (ex != NULL) {
1780af9f9769Sjasmith 		oldcnt = build_seclist_nodups(&ex->exi_export, oldsec, FALSE);
17817c478bd9Sstevel@tonic-gate 		if (PSEUDO(ex)) {
1782af9f9769Sjasmith 			/*
1783af9f9769Sjasmith 			 * The dir being shared is a pseudo export root (which
1784af9f9769Sjasmith 			 * will be transformed into a real export root).  The
1785af9f9769Sjasmith 			 * flavor(s) of the new share were propagated to the
1786af9f9769Sjasmith 			 * ancestors by srv_secinfo_treeclimb() above.  Now
1787af9f9769Sjasmith 			 * transfer the implicit flavor refs from the old
1788af9f9769Sjasmith 			 * pseudo exprot root to the new (real) export root.
1789af9f9769Sjasmith 			 */
1790af9f9769Sjasmith 			srv_secinfo_add(&exi->exi_export.ex_secinfo,
1791af9f9769Sjasmith 			    &exi->exi_export.ex_seccnt, oldsec, oldcnt, TRUE);
17927c478bd9Sstevel@tonic-gate 		} else {
1793af9f9769Sjasmith 			/*
1794af9f9769Sjasmith 			 * First transfer implicit flavor refs to new export.
1795af9f9769Sjasmith 			 * Remove old flavor refs last.
1796af9f9769Sjasmith 			 */
1797af9f9769Sjasmith 			srv_secinfo_exp2exp(&exi->exi_export, oldsec, oldcnt);
17980dfe541eSEvan Layton 			srv_secinfo_treeclimb(ne, ex, oldsec, oldcnt, FALSE);
17997c478bd9Sstevel@tonic-gate 		}
18007c478bd9Sstevel@tonic-gate 	}
18017c478bd9Sstevel@tonic-gate 
18027c478bd9Sstevel@tonic-gate 	/*
1803992d2facSpf 	 * If it's a re-export and the old entry has a pseudonode list,
1804af9f9769Sjasmith 	 * transfer it to the new export.
18057c478bd9Sstevel@tonic-gate 	 */
18067c478bd9Sstevel@tonic-gate 	if (ex != NULL && (ex->exi_visible != NULL)) {
18077c478bd9Sstevel@tonic-gate 		exi->exi_visible = ex->exi_visible;
18087c478bd9Sstevel@tonic-gate 		ex->exi_visible = NULL;
18097c478bd9Sstevel@tonic-gate 	}
18107c478bd9Sstevel@tonic-gate 
18110dfe541eSEvan Layton 	/*
18120dfe541eSEvan Layton 	 * Initialize exi_id and exi_kstats
18130dfe541eSEvan Layton 	 */
18140dfe541eSEvan Layton 	if (ex != NULL) {
18150dfe541eSEvan Layton 		exi->exi_id = ex->exi_id;
18160dfe541eSEvan Layton 	} else {
18170dfe541eSEvan Layton 		mutex_enter(&nfs_exi_id_lock);
18180dfe541eSEvan Layton 		exi->exi_id = exi_id_get_next();
18190dfe541eSEvan Layton 		mutex_exit(&nfs_exi_id_lock);
18200dfe541eSEvan Layton 	}
18210dfe541eSEvan Layton 	mutex_enter(&nfs_exi_id_lock);
18220dfe541eSEvan Layton 	avl_add(&exi_id_tree, exi);
18230dfe541eSEvan Layton 	mutex_exit(&nfs_exi_id_lock);
18240dfe541eSEvan Layton 
18250616fd7fSPavel Filipensky 	DTRACE_PROBE(nfss__i__exported_lock3_stop);
18260dfe541eSEvan Layton 	rw_exit(&ne->exported_lock);
18277c478bd9Sstevel@tonic-gate 
18280dfe541eSEvan Layton 	if (ne->exi_public == exi || kex->ex_flags & EX_LOG) {
18297c478bd9Sstevel@tonic-gate 		/*
18307c478bd9Sstevel@tonic-gate 		 * Log share operation to this buffer only.
18317c478bd9Sstevel@tonic-gate 		 */
18327c478bd9Sstevel@tonic-gate 		nfslog_share_record(exi, cr);
18337c478bd9Sstevel@tonic-gate 	}
18347c478bd9Sstevel@tonic-gate 
18357c478bd9Sstevel@tonic-gate 	if (ex != NULL)
18367c478bd9Sstevel@tonic-gate 		exi_rele(ex);
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate 	return (0);
18397c478bd9Sstevel@tonic-gate 
18407c478bd9Sstevel@tonic-gate out7:
18413f238301SPavel Filipensky 	/* Unlink the new export in exptable. */
18420dfe541eSEvan Layton 	export_unlink(ne, exi);
18430616fd7fSPavel Filipensky 	DTRACE_PROBE(nfss__i__exported_lock3_stop);
18440dfe541eSEvan Layton 	rw_exit(&ne->exported_lock);
18457c478bd9Sstevel@tonic-gate out6:
18467c478bd9Sstevel@tonic-gate 	if (kex->ex_flags & EX_INDEX)
18477c478bd9Sstevel@tonic-gate 		kmem_free(kex->ex_index, strlen(kex->ex_index) + 1);
18487c478bd9Sstevel@tonic-gate out5:
18497c478bd9Sstevel@tonic-gate 	/* free partially completed allocation */
18507c478bd9Sstevel@tonic-gate 	while (--allocd_seccnt >= 0) {
18517c478bd9Sstevel@tonic-gate 		exs = &kex->ex_secinfo[allocd_seccnt];
18527c478bd9Sstevel@tonic-gate 		srv_secinfo_entry_free(exs);
18537c478bd9Sstevel@tonic-gate 	}
18547c478bd9Sstevel@tonic-gate 
18557c478bd9Sstevel@tonic-gate 	if (kex->ex_secinfo) {
18567c478bd9Sstevel@tonic-gate 		kmem_free(kex->ex_secinfo,
1857af9f9769Sjasmith 		    kex->ex_seccnt * sizeof (struct secinfo));
18587c478bd9Sstevel@tonic-gate 	}
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate out4:
18617c478bd9Sstevel@tonic-gate 	if ((kex->ex_flags & EX_LOG) && kex->ex_tag != NULL)
18627c478bd9Sstevel@tonic-gate 		kmem_free(kex->ex_tag, kex->ex_taglen + 1);
18637c478bd9Sstevel@tonic-gate out3:
18647c478bd9Sstevel@tonic-gate 	if ((kex->ex_flags & EX_LOG) && kex->ex_log_buffer != NULL)
18657c478bd9Sstevel@tonic-gate 		kmem_free(kex->ex_log_buffer, kex->ex_log_bufferlen + 1);
18667c478bd9Sstevel@tonic-gate out2:
18677c478bd9Sstevel@tonic-gate 	kmem_free(kex->ex_path, kex->ex_pathlen + 1);
18687c478bd9Sstevel@tonic-gate out1:
18697c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
18707c478bd9Sstevel@tonic-gate 	if (dvp != NULL)
18717c478bd9Sstevel@tonic-gate 		VN_RELE(dvp);
18727c478bd9Sstevel@tonic-gate 	mutex_destroy(&exi->exi_lock);
18737c478bd9Sstevel@tonic-gate 	rw_destroy(&exi->exi_cache_lock);
187471da0c32SMarcel Telka 	for (i = 0; i < AUTH_TABLESIZE; i++) {
187571da0c32SMarcel Telka 		avl_destroy(exi->exi_cache[i]);
187671da0c32SMarcel Telka 		kmem_free(exi->exi_cache[i], sizeof (avl_tree_t));
187771da0c32SMarcel Telka 	}
187871da0c32SMarcel Telka 
18797c478bd9Sstevel@tonic-gate 	kmem_free(exi, sizeof (*exi));
188071da0c32SMarcel Telka 
18817c478bd9Sstevel@tonic-gate 	return (error);
18827c478bd9Sstevel@tonic-gate }
18837c478bd9Sstevel@tonic-gate 
18847c478bd9Sstevel@tonic-gate /*
18857c478bd9Sstevel@tonic-gate  * Remove the exportinfo from the export list
18867c478bd9Sstevel@tonic-gate  */
18870616fd7fSPavel Filipensky void
export_unlink(nfs_export_t * ne,struct exportinfo * exi)18880dfe541eSEvan Layton export_unlink(nfs_export_t *ne, struct exportinfo *exi)
18897c478bd9Sstevel@tonic-gate {
18900dfe541eSEvan Layton 	ASSERT(RW_WRITE_HELD(&ne->exported_lock));
18917c478bd9Sstevel@tonic-gate 
18920616fd7fSPavel Filipensky 	exp_hash_unlink(exi, fid_hash);
18930616fd7fSPavel Filipensky 	exp_hash_unlink(exi, path_hash);
18940dfe541eSEvan Layton 	ASSERT3P(exi->exi_ne, ==, ne);
18950dfe541eSEvan Layton 	exi->exi_ne = NULL;
18967c478bd9Sstevel@tonic-gate }
18977c478bd9Sstevel@tonic-gate 
18987c478bd9Sstevel@tonic-gate /*
18997c478bd9Sstevel@tonic-gate  * Unexport an exported filesystem
19007c478bd9Sstevel@tonic-gate  */
19010616fd7fSPavel Filipensky static int
unexport(nfs_export_t * ne,struct exportinfo * exi,cred_t * cr)190206260e34SDan McDonald unexport(nfs_export_t *ne, struct exportinfo *exi, cred_t *cr)
19037c478bd9Sstevel@tonic-gate {
1904af9f9769Sjasmith 	struct secinfo cursec[MAX_FLAVORS];
1905af9f9769Sjasmith 	int curcnt;
19067c478bd9Sstevel@tonic-gate 
19070dfe541eSEvan Layton 	rw_enter(&ne->exported_lock, RW_WRITER);
19087c478bd9Sstevel@tonic-gate 
19090616fd7fSPavel Filipensky 	/* Check if exi is still linked in the export table */
19100616fd7fSPavel Filipensky 	if (!EXP_LINKED(exi) || PSEUDO(exi)) {
19110dfe541eSEvan Layton 		rw_exit(&ne->exported_lock);
1912bfbb13c9Sjmcp 		return (EINVAL);
1913bfbb13c9Sjmcp 	}
19147c478bd9Sstevel@tonic-gate 
19150dfe541eSEvan Layton 	mutex_enter(&nfs_exi_id_lock);
19160dfe541eSEvan Layton 	avl_remove(&exi_id_tree, exi);
19170dfe541eSEvan Layton 	mutex_exit(&nfs_exi_id_lock);
19180dfe541eSEvan Layton 	export_unlink(ne, exi);
19190616fd7fSPavel Filipensky 
1920992d2facSpf 	/*
1921992d2facSpf 	 * Remove security flavors before treeclimb_unexport() is called
1922992d2facSpf 	 * because srv_secinfo_treeclimb needs the namespace tree
1923992d2facSpf 	 */
1924992d2facSpf 	curcnt = build_seclist_nodups(&exi->exi_export, cursec, TRUE);
19250dfe541eSEvan Layton 	srv_secinfo_treeclimb(ne, exi, cursec, curcnt, FALSE);
1926992d2facSpf 
19277c478bd9Sstevel@tonic-gate 	/*
19287c478bd9Sstevel@tonic-gate 	 * If there's a visible list, then need to leave
19297c478bd9Sstevel@tonic-gate 	 * a pseudo export here to retain the visible list
19307c478bd9Sstevel@tonic-gate 	 * for paths to exports below.
19317c478bd9Sstevel@tonic-gate 	 */
19324a695956SMarcel Telka 	if (exi->exi_visible != NULL) {
1933992d2facSpf 		struct exportinfo *newexi;
1934992d2facSpf 
19350dfe541eSEvan Layton 		newexi = pseudo_exportfs(ne, exi->exi_vp, &exi->exi_fid,
19360616fd7fSPavel Filipensky 		    exi->exi_visible, &exi->exi_export);
1937bfbb13c9Sjmcp 		exi->exi_visible = NULL;
19380616fd7fSPavel Filipensky 
19390616fd7fSPavel Filipensky 		/* interconnect the existing treenode with the new exportinfo */
1940992d2facSpf 		newexi->exi_tree = exi->exi_tree;
1941992d2facSpf 		newexi->exi_tree->tree_exi = newexi;
19424a695956SMarcel Telka 
19434a695956SMarcel Telka 		/* Update the change timestamp */
19440dfe541eSEvan Layton 		tree_update_change(ne, exi->exi_tree, NULL);
19457c478bd9Sstevel@tonic-gate 	} else {
19460dfe541eSEvan Layton 		treeclimb_unexport(ne, exi);
19477c478bd9Sstevel@tonic-gate 	}
19487c478bd9Sstevel@tonic-gate 
19490dfe541eSEvan Layton 	rw_exit(&ne->exported_lock);
1950bfbb13c9Sjmcp 
19517c478bd9Sstevel@tonic-gate 	/*
19527c478bd9Sstevel@tonic-gate 	 * Need to call into the NFSv4 server and release all data
19537c478bd9Sstevel@tonic-gate 	 * held on this particular export.  This is important since
19547c478bd9Sstevel@tonic-gate 	 * the v4 server may be holding file locks or vnodes under
19557c478bd9Sstevel@tonic-gate 	 * this export.
19567c478bd9Sstevel@tonic-gate 	 */
19570dfe541eSEvan Layton 	rfs4_clean_state_exi(ne, exi);
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate 	/*
19607c478bd9Sstevel@tonic-gate 	 * Notify the lock manager that the filesystem is being
19617c478bd9Sstevel@tonic-gate 	 * unexported.
19627c478bd9Sstevel@tonic-gate 	 */
19637c478bd9Sstevel@tonic-gate 	lm_unexport(exi);
19647c478bd9Sstevel@tonic-gate 
19657c478bd9Sstevel@tonic-gate 	/*
19667c478bd9Sstevel@tonic-gate 	 * If this was a public export, restore
19677c478bd9Sstevel@tonic-gate 	 * the public filehandle to the root.
19687c478bd9Sstevel@tonic-gate 	 */
19697c478bd9Sstevel@tonic-gate 
19700dfe541eSEvan Layton 	if (exi == ne->exi_public) {
19710dfe541eSEvan Layton 		ne->exi_public = ne->exi_root;
19720dfe541eSEvan Layton 
197306260e34SDan McDonald 		nfslog_share_record(ne->exi_public, cr);
19747c478bd9Sstevel@tonic-gate 	}
19757c478bd9Sstevel@tonic-gate 
19760dfe541eSEvan Layton 	if (exi->exi_export.ex_flags & EX_LOG)
197706260e34SDan McDonald 		nfslog_unshare_record(exi, cr);
19787c478bd9Sstevel@tonic-gate 
19797c478bd9Sstevel@tonic-gate 	exi_rele(exi);
19800616fd7fSPavel Filipensky 	return (0);
19817c478bd9Sstevel@tonic-gate }
19827c478bd9Sstevel@tonic-gate 
19837c478bd9Sstevel@tonic-gate /*
19847c478bd9Sstevel@tonic-gate  * Get file handle system call.
19857c478bd9Sstevel@tonic-gate  * Takes file name and returns a file handle for it.
19867c478bd9Sstevel@tonic-gate  * Credentials must be verified before calling.
19877c478bd9Sstevel@tonic-gate  */
19887c478bd9Sstevel@tonic-gate int
nfs_getfh(struct nfs_getfh_args * args,model_t model,cred_t * cr)19897c478bd9Sstevel@tonic-gate nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr)
19907c478bd9Sstevel@tonic-gate {
199127242a7cSthurlow 	nfs_fh3 fh;
199227242a7cSthurlow 	char buf[NFS3_MAXFHSIZE];
199327242a7cSthurlow 	char *logptr, logbuf[NFS3_MAXFHSIZE];
199427242a7cSthurlow 	int l = NFS3_MAXFHSIZE;
19957c478bd9Sstevel@tonic-gate 	vnode_t *vp;
19967c478bd9Sstevel@tonic-gate 	vnode_t *dvp;
19977c478bd9Sstevel@tonic-gate 	struct exportinfo *exi;
19987c478bd9Sstevel@tonic-gate 	int error;
199927242a7cSthurlow 	int vers;
20007c478bd9Sstevel@tonic-gate 	STRUCT_HANDLE(nfs_getfh_args, uap);
20017c478bd9Sstevel@tonic-gate 
20027c478bd9Sstevel@tonic-gate #ifdef lint
20037c478bd9Sstevel@tonic-gate 	model = model;		/* STRUCT macros don't always use it */
20047c478bd9Sstevel@tonic-gate #endif
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate 	STRUCT_SET_HANDLE(uap, model, args);
20077c478bd9Sstevel@tonic-gate 
20087c478bd9Sstevel@tonic-gate 	error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE,
20097c478bd9Sstevel@tonic-gate 	    FOLLOW, &dvp, &vp);
20107c478bd9Sstevel@tonic-gate 	if (error == EINVAL) {
20117c478bd9Sstevel@tonic-gate 		/*
20127c478bd9Sstevel@tonic-gate 		 * if fname resolves to / we get EINVAL error
20137c478bd9Sstevel@tonic-gate 		 * since we wanted the parent vnode. Try again
20147c478bd9Sstevel@tonic-gate 		 * with NULL dvp.
20157c478bd9Sstevel@tonic-gate 		 */
20167c478bd9Sstevel@tonic-gate 		error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE,
20177c478bd9Sstevel@tonic-gate 		    FOLLOW, NULL, &vp);
20187c478bd9Sstevel@tonic-gate 		dvp = NULL;
20197c478bd9Sstevel@tonic-gate 	}
20207c478bd9Sstevel@tonic-gate 	if (!error && vp == NULL) {
20217c478bd9Sstevel@tonic-gate 		/*
20227c478bd9Sstevel@tonic-gate 		 * Last component of fname not found
20237c478bd9Sstevel@tonic-gate 		 */
20247c478bd9Sstevel@tonic-gate 		if (dvp != NULL) {
20257c478bd9Sstevel@tonic-gate 			VN_RELE(dvp);
20267c478bd9Sstevel@tonic-gate 		}
20277c478bd9Sstevel@tonic-gate 		error = ENOENT;
20287c478bd9Sstevel@tonic-gate 	}
20297c478bd9Sstevel@tonic-gate 	if (error)
20307c478bd9Sstevel@tonic-gate 		return (error);
20317c478bd9Sstevel@tonic-gate 
20327c478bd9Sstevel@tonic-gate 	/*
20337c478bd9Sstevel@tonic-gate 	 * 'vp' may be an AUTOFS node, so we perform a
20347c478bd9Sstevel@tonic-gate 	 * VOP_ACCESS() to trigger the mount of the
20357c478bd9Sstevel@tonic-gate 	 * intended filesystem, so we can share the intended
20367c478bd9Sstevel@tonic-gate 	 * filesystem instead of the AUTOFS filesystem.
20377c478bd9Sstevel@tonic-gate 	 */
2038da6c28aaSamw 	(void) VOP_ACCESS(vp, 0, 0, cr, NULL);
20397c478bd9Sstevel@tonic-gate 
20407c478bd9Sstevel@tonic-gate 	/*
20417c478bd9Sstevel@tonic-gate 	 * We're interested in the top most filesystem.
20427c478bd9Sstevel@tonic-gate 	 * This is specially important when uap->dname is a trigger
20437c478bd9Sstevel@tonic-gate 	 * AUTOFS node, since we're really interested in sharing the
20447c478bd9Sstevel@tonic-gate 	 * filesystem AUTOFS mounted as result of the VOP_ACCESS()
20457c478bd9Sstevel@tonic-gate 	 * call not the AUTOFS node itself.
20467c478bd9Sstevel@tonic-gate 	 */
20477c478bd9Sstevel@tonic-gate 	if (vn_mountedvfs(vp) != NULL) {
2048*bd3561fbSToomas Soome 		error = traverse(&vp);
2049*bd3561fbSToomas Soome 		if (error != 0) {
20507c478bd9Sstevel@tonic-gate 			VN_RELE(vp);
20517c478bd9Sstevel@tonic-gate 			if (dvp != NULL)
20527c478bd9Sstevel@tonic-gate 				VN_RELE(dvp);
20537c478bd9Sstevel@tonic-gate 			return (error);
20547c478bd9Sstevel@tonic-gate 		}
20557c478bd9Sstevel@tonic-gate 	}
20567c478bd9Sstevel@tonic-gate 
205727242a7cSthurlow 	vers = STRUCT_FGET(uap, vers);
20587c478bd9Sstevel@tonic-gate 	exi = nfs_vptoexi(dvp, vp, cr, NULL, &error, FALSE);
20597c478bd9Sstevel@tonic-gate 	if (!error) {
206027242a7cSthurlow 		if (vers == NFS_VERSION) {
206127242a7cSthurlow 			error = makefh((fhandle_t *)buf, vp, exi);
206227242a7cSthurlow 			l = NFS_FHSIZE;
206327242a7cSthurlow 			logptr = buf;
206427242a7cSthurlow 		} else if (vers == NFS_V3) {
206558053c85Speteh 			int i, sz, pad;
206627242a7cSthurlow 
206727242a7cSthurlow 			error = makefh3(&fh, vp, exi);
20686b086bafSSam Falkner 			l = RNDUP(fh.fh3_length);
20696b086bafSSam Falkner 			if (!error && (l > sizeof (fhandle3_t)))
20706b086bafSSam Falkner 				error = EREMOTE;
207127242a7cSthurlow 			logptr = logbuf;
207227242a7cSthurlow 			if (!error) {
207327242a7cSthurlow 				i = 0;
207427242a7cSthurlow 				sz = sizeof (fsid_t);
207527242a7cSthurlow 				bcopy(&fh.fh3_fsid, &buf[i], sz);
207627242a7cSthurlow 				i += sz;
207758053c85Speteh 
207858053c85Speteh 				/*
2079da6c28aaSamw 				 * For backwards compatibility, the
208058053c85Speteh 				 * fid length may be less than
208158053c85Speteh 				 * NFS_FHMAXDATA, but it was always
208258053c85Speteh 				 * encoded as NFS_FHMAXDATA bytes.
208358053c85Speteh 				 */
208458053c85Speteh 
208527242a7cSthurlow 				sz = sizeof (ushort_t);
208627242a7cSthurlow 				bcopy(&fh.fh3_len, &buf[i], sz);
208727242a7cSthurlow 				i += sz;
208858053c85Speteh 				bcopy(fh.fh3_data, &buf[i], fh.fh3_len);
208958053c85Speteh 				i += fh.fh3_len;
209058053c85Speteh 				pad = (NFS_FHMAXDATA - fh.fh3_len);
209158053c85Speteh 				if (pad > 0) {
209258053c85Speteh 					bzero(&buf[i], pad);
209358053c85Speteh 					i += pad;
209458053c85Speteh 					l += pad;
209558053c85Speteh 				}
209658053c85Speteh 
209727242a7cSthurlow 				sz = sizeof (ushort_t);
209827242a7cSthurlow 				bcopy(&fh.fh3_xlen, &buf[i], sz);
209927242a7cSthurlow 				i += sz;
210058053c85Speteh 				bcopy(fh.fh3_xdata, &buf[i], fh.fh3_xlen);
210158053c85Speteh 				i += fh.fh3_xlen;
210258053c85Speteh 				pad = (NFS_FHMAXDATA - fh.fh3_xlen);
210358053c85Speteh 				if (pad > 0) {
210458053c85Speteh 					bzero(&buf[i], pad);
210558053c85Speteh 					i += pad;
210658053c85Speteh 					l += pad;
210758053c85Speteh 				}
210827242a7cSthurlow 			}
210927242a7cSthurlow 			/*
211027242a7cSthurlow 			 * If we need to do NFS logging, the filehandle
211127242a7cSthurlow 			 * must be downsized to 32 bytes.
211227242a7cSthurlow 			 */
211327242a7cSthurlow 			if (!error && exi->exi_export.ex_flags & EX_LOG) {
211427242a7cSthurlow 				i = 0;
211527242a7cSthurlow 				sz = sizeof (fsid_t);
211627242a7cSthurlow 				bcopy(&fh.fh3_fsid, &logbuf[i], sz);
211727242a7cSthurlow 				i += sz;
211827242a7cSthurlow 				sz = sizeof (ushort_t);
211927242a7cSthurlow 				bcopy(&fh.fh3_len, &logbuf[i], sz);
212027242a7cSthurlow 				i += sz;
212127242a7cSthurlow 				sz = NFS_FHMAXDATA;
212227242a7cSthurlow 				bcopy(fh.fh3_data, &logbuf[i], sz);
212327242a7cSthurlow 				i += sz;
212427242a7cSthurlow 				sz = sizeof (ushort_t);
212527242a7cSthurlow 				bcopy(&fh.fh3_xlen, &logbuf[i], sz);
212627242a7cSthurlow 				i += sz;
212727242a7cSthurlow 				sz = NFS_FHMAXDATA;
212827242a7cSthurlow 				bcopy(fh.fh3_xdata, &logbuf[i], sz);
212927242a7cSthurlow 				i += sz;
213027242a7cSthurlow 			}
213127242a7cSthurlow 		}
21327c478bd9Sstevel@tonic-gate 		if (!error && exi->exi_export.ex_flags & EX_LOG) {
213327242a7cSthurlow 			nfslog_getfh(exi, (fhandle_t *)logptr,
213427242a7cSthurlow 			    STRUCT_FGETP(uap, fname), UIO_USERSPACE, cr);
21357c478bd9Sstevel@tonic-gate 		}
21367c478bd9Sstevel@tonic-gate 		exi_rele(exi);
21377c478bd9Sstevel@tonic-gate 		if (!error) {
213827242a7cSthurlow 			if (copyout(&l, STRUCT_FGETP(uap, lenp), sizeof (int)))
213927242a7cSthurlow 				error = EFAULT;
214027242a7cSthurlow 			if (copyout(buf, STRUCT_FGETP(uap, fhp), l))
21417c478bd9Sstevel@tonic-gate 				error = EFAULT;
21427c478bd9Sstevel@tonic-gate 		}
21437c478bd9Sstevel@tonic-gate 	}
21447c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
21457c478bd9Sstevel@tonic-gate 	if (dvp != NULL) {
21467c478bd9Sstevel@tonic-gate 		VN_RELE(dvp);
21477c478bd9Sstevel@tonic-gate 	}
21487c478bd9Sstevel@tonic-gate 	return (error);
21497c478bd9Sstevel@tonic-gate }
21507c478bd9Sstevel@tonic-gate 
21517c478bd9Sstevel@tonic-gate /*
21527c478bd9Sstevel@tonic-gate  * Strategy: if vp is in the export list, then
21537c478bd9Sstevel@tonic-gate  * return the associated file handle. Otherwise, ".."
21547c478bd9Sstevel@tonic-gate  * once up the vp and try again, until the root of the
21557c478bd9Sstevel@tonic-gate  * filesystem is reached.
21567c478bd9Sstevel@tonic-gate  */
21577c478bd9Sstevel@tonic-gate struct   exportinfo *
nfs_vptoexi(vnode_t * dvp,vnode_t * vp,cred_t * cr,int * walk,int * err,bool_t v4srv)21587c478bd9Sstevel@tonic-gate nfs_vptoexi(vnode_t *dvp, vnode_t *vp, cred_t *cr, int *walk,
21594a695956SMarcel Telka     int *err, bool_t v4srv)
21607c478bd9Sstevel@tonic-gate {
21617c478bd9Sstevel@tonic-gate 	fid_t fid;
21627c478bd9Sstevel@tonic-gate 	int error;
21637c478bd9Sstevel@tonic-gate 	struct exportinfo *exi;
21647c478bd9Sstevel@tonic-gate 
21657c478bd9Sstevel@tonic-gate 	ASSERT(vp);
21667c478bd9Sstevel@tonic-gate 	VN_HOLD(vp);
21677c478bd9Sstevel@tonic-gate 	if (dvp != NULL) {
21687c478bd9Sstevel@tonic-gate 		VN_HOLD(dvp);
21697c478bd9Sstevel@tonic-gate 	}
21707c478bd9Sstevel@tonic-gate 	if (walk != NULL)
21717c478bd9Sstevel@tonic-gate 		*walk = 0;
21727c478bd9Sstevel@tonic-gate 
21737c478bd9Sstevel@tonic-gate 	for (;;) {
21747c478bd9Sstevel@tonic-gate 		bzero(&fid, sizeof (fid));
21757c478bd9Sstevel@tonic-gate 		fid.fid_len = MAXFIDSZ;
21767c478bd9Sstevel@tonic-gate 		error = vop_fid_pseudo(vp, &fid);
21777c478bd9Sstevel@tonic-gate 		if (error) {
21787c478bd9Sstevel@tonic-gate 			/*
21797c478bd9Sstevel@tonic-gate 			 * If vop_fid_pseudo returns ENOSPC then the fid
21807c478bd9Sstevel@tonic-gate 			 * supplied is too small. For now we simply
21817c478bd9Sstevel@tonic-gate 			 * return EREMOTE.
21827c478bd9Sstevel@tonic-gate 			 */
21837c478bd9Sstevel@tonic-gate 			if (error == ENOSPC)
21847c478bd9Sstevel@tonic-gate 				error = EREMOTE;
21857c478bd9Sstevel@tonic-gate 			break;
21867c478bd9Sstevel@tonic-gate 		}
21877c478bd9Sstevel@tonic-gate 
21887c478bd9Sstevel@tonic-gate 		if (v4srv)
21897c478bd9Sstevel@tonic-gate 			exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
21907c478bd9Sstevel@tonic-gate 		else
21917c478bd9Sstevel@tonic-gate 			exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid);
21927c478bd9Sstevel@tonic-gate 
21937c478bd9Sstevel@tonic-gate 		if (exi != NULL) {
21947c478bd9Sstevel@tonic-gate 			/*
21957c478bd9Sstevel@tonic-gate 			 * Found the export info
21967c478bd9Sstevel@tonic-gate 			 */
21977c478bd9Sstevel@tonic-gate 			break;
21987c478bd9Sstevel@tonic-gate 		}
21997c478bd9Sstevel@tonic-gate 
22007c478bd9Sstevel@tonic-gate 		/*
22017c478bd9Sstevel@tonic-gate 		 * We have just failed finding a matching export.
22027c478bd9Sstevel@tonic-gate 		 * If we're at the root of this filesystem, then
22037c478bd9Sstevel@tonic-gate 		 * it's time to stop (with failure).
22047c478bd9Sstevel@tonic-gate 		 */
22050dfe541eSEvan Layton 		ASSERT3P(vp->v_vfsp->vfs_zone, ==, curzone);
22060dfe541eSEvan Layton 		if ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp)) {
22077c478bd9Sstevel@tonic-gate 			error = EINVAL;
22087c478bd9Sstevel@tonic-gate 			break;
22097c478bd9Sstevel@tonic-gate 		}
22107c478bd9Sstevel@tonic-gate 
22117c478bd9Sstevel@tonic-gate 		if (walk != NULL)
22127c478bd9Sstevel@tonic-gate 			(*walk)++;
22137c478bd9Sstevel@tonic-gate 
22147c478bd9Sstevel@tonic-gate 		/*
22157c478bd9Sstevel@tonic-gate 		 * Now, do a ".." up vp. If dvp is supplied, use it,
22167c478bd9Sstevel@tonic-gate 		 * otherwise, look it up.
22177c478bd9Sstevel@tonic-gate 		 */
22187c478bd9Sstevel@tonic-gate 		if (dvp == NULL) {
2219da6c28aaSamw 			error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr,
2220da6c28aaSamw 			    NULL, NULL, NULL);
22217c478bd9Sstevel@tonic-gate 			if (error)
22227c478bd9Sstevel@tonic-gate 				break;
22237c478bd9Sstevel@tonic-gate 		}
22247c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
22257c478bd9Sstevel@tonic-gate 		vp = dvp;
22267c478bd9Sstevel@tonic-gate 		dvp = NULL;
22277c478bd9Sstevel@tonic-gate 	}
22287c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
22297c478bd9Sstevel@tonic-gate 	if (dvp != NULL) {
22307c478bd9Sstevel@tonic-gate 		VN_RELE(dvp);
22317c478bd9Sstevel@tonic-gate 	}
22327c478bd9Sstevel@tonic-gate 	if (error != 0) {
22337c478bd9Sstevel@tonic-gate 		if (err != NULL)
22347c478bd9Sstevel@tonic-gate 			*err = error;
22357c478bd9Sstevel@tonic-gate 		return (NULL);
22367c478bd9Sstevel@tonic-gate 	}
22377c478bd9Sstevel@tonic-gate 	return (exi);
22387c478bd9Sstevel@tonic-gate }
22397c478bd9Sstevel@tonic-gate 
2240d7c6abe8Sjasmith int
chk_clnt_sec(exportinfo_t * exi,struct svc_req * req)2241af9f9769Sjasmith chk_clnt_sec(exportinfo_t *exi, struct svc_req *req)
22427c478bd9Sstevel@tonic-gate {
22437c478bd9Sstevel@tonic-gate 	int i, nfsflavor;
22447c478bd9Sstevel@tonic-gate 	struct secinfo *sp;
22457c478bd9Sstevel@tonic-gate 
22467c478bd9Sstevel@tonic-gate 	/*
22477c478bd9Sstevel@tonic-gate 	 *  Get the nfs flavor number from xprt.
22487c478bd9Sstevel@tonic-gate 	 */
22497c478bd9Sstevel@tonic-gate 	nfsflavor = (int)(uintptr_t)req->rq_xprt->xp_cookie;
22507c478bd9Sstevel@tonic-gate 
22517c478bd9Sstevel@tonic-gate 	sp = exi->exi_export.ex_secinfo;
22527c478bd9Sstevel@tonic-gate 	for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
2253d7c6abe8Sjasmith 		if ((nfsflavor == sp[i].s_secinfo.sc_nfsnum) &&
2254d7c6abe8Sjasmith 		    SEC_REF_EXPORTED(sp + i))
2255d7c6abe8Sjasmith 			return (TRUE);
22567c478bd9Sstevel@tonic-gate 	}
2257d7c6abe8Sjasmith 	return (FALSE);
22587c478bd9Sstevel@tonic-gate }
22597c478bd9Sstevel@tonic-gate 
22607c478bd9Sstevel@tonic-gate /*
22617c478bd9Sstevel@tonic-gate  * Make an fhandle from a vnode
22627c478bd9Sstevel@tonic-gate  */
22637c478bd9Sstevel@tonic-gate int
makefh(fhandle_t * fh,vnode_t * vp,exportinfo_t * exi)2264af9f9769Sjasmith makefh(fhandle_t *fh, vnode_t *vp, exportinfo_t *exi)
22657c478bd9Sstevel@tonic-gate {
22667c478bd9Sstevel@tonic-gate 	int error;
22677c478bd9Sstevel@tonic-gate 
22687c478bd9Sstevel@tonic-gate 	*fh = exi->exi_fh;	/* struct copy */
22697c478bd9Sstevel@tonic-gate 
2270da6c28aaSamw 	error = VOP_FID(vp, (fid_t *)&fh->fh_len, NULL);
22717c478bd9Sstevel@tonic-gate 	if (error) {
22727c478bd9Sstevel@tonic-gate 		/*
22737c478bd9Sstevel@tonic-gate 		 * Should be something other than EREMOTE
22747c478bd9Sstevel@tonic-gate 		 */
22757c478bd9Sstevel@tonic-gate 		return (EREMOTE);
22767c478bd9Sstevel@tonic-gate 	}
22777c478bd9Sstevel@tonic-gate 	return (0);
22787c478bd9Sstevel@tonic-gate }
22797c478bd9Sstevel@tonic-gate 
22807c478bd9Sstevel@tonic-gate /*
22817c478bd9Sstevel@tonic-gate  * This routine makes an overloaded V2 fhandle which contains
22827c478bd9Sstevel@tonic-gate  * sec modes.
22837c478bd9Sstevel@tonic-gate  *
22847c478bd9Sstevel@tonic-gate  * Note that the first four octets contain the length octet,
22857c478bd9Sstevel@tonic-gate  * the status octet, and two padded octets to make them XDR
22867c478bd9Sstevel@tonic-gate  * four-octet aligned.
22877c478bd9Sstevel@tonic-gate  *
22887c478bd9Sstevel@tonic-gate  *   1   2   3   4                                          32
22897c478bd9Sstevel@tonic-gate  * +---+---+---+---+---+---+---+---+   +---+---+---+---+   +---+
22907c478bd9Sstevel@tonic-gate  * | l | s |   |   |     sec_1     |...|     sec_n     |...|   |
22917c478bd9Sstevel@tonic-gate  * +---+---+---+---+---+---+---+---+   +---+---+---+---+   +---+
22927c478bd9Sstevel@tonic-gate  *
22937c478bd9Sstevel@tonic-gate  * where
22947c478bd9Sstevel@tonic-gate  *
22957c478bd9Sstevel@tonic-gate  *   the status octet s indicates whether there are more security
22967c478bd9Sstevel@tonic-gate  *   flavors (1 means yes, 0 means no) that require the client to
22977c478bd9Sstevel@tonic-gate  *   perform another 0x81 LOOKUP to get them,
22987c478bd9Sstevel@tonic-gate  *
22997c478bd9Sstevel@tonic-gate  *   the length octet l is the length describing the number of
23007c478bd9Sstevel@tonic-gate  *   valid octets that follow.  (l = 4 * n, where n is the number
23017c478bd9Sstevel@tonic-gate  *   of security flavors sent in the current overloaded filehandle.)
2302d7c6abe8Sjasmith  *
2303d7c6abe8Sjasmith  *   sec_index should always be in the inclusive range: [1 - ex_seccnt],
2304d7c6abe8Sjasmith  *   and it tells server where to start within the secinfo array.
2305d7c6abe8Sjasmith  *   Usually it will always be 1; however, if more flavors are used
2306d7c6abe8Sjasmith  *   for the public export than can be encoded in the overloaded FH
2307d7c6abe8Sjasmith  *   (7 for NFS2), subsequent SNEGO MCLs will have a larger index
2308d7c6abe8Sjasmith  *   so the server will pick up where it left off from the previous
2309d7c6abe8Sjasmith  *   MCL reply.
2310d7c6abe8Sjasmith  *
2311d7c6abe8Sjasmith  *   With NFS4 support, implicitly allowed flavors are also in
2312d7c6abe8Sjasmith  *   the secinfo array; however, they should not be returned in
2313d7c6abe8Sjasmith  *   SNEGO MCL replies.
23147c478bd9Sstevel@tonic-gate  */
23157c478bd9Sstevel@tonic-gate int
makefh_ol(fhandle_t * fh,exportinfo_t * exi,uint_t sec_index)2316af9f9769Sjasmith makefh_ol(fhandle_t *fh, exportinfo_t *exi, uint_t sec_index)
23177c478bd9Sstevel@tonic-gate {
2318d7c6abe8Sjasmith 	secinfo_t sec[MAX_FLAVORS];
2319d7c6abe8Sjasmith 	int totalcnt, i, *ipt, cnt, seccnt, secidx, fh_max_cnt;
23207c478bd9Sstevel@tonic-gate 	char *c;
23217c478bd9Sstevel@tonic-gate 
2322d7c6abe8Sjasmith 	if (fh == NULL || exi == NULL || sec_index < 1)
2323d7c6abe8Sjasmith 		return (EREMOTE);
2324d7c6abe8Sjasmith 
2325d7c6abe8Sjasmith 	/*
2326d7c6abe8Sjasmith 	 * WebNFS clients need to know the unique set of explicitly
2327d7c6abe8Sjasmith 	 * shared flavors in used for the public export. When
2328d7c6abe8Sjasmith 	 * "TRUE" is passed to build_seclist_nodups(), only explicitly
2329d7c6abe8Sjasmith 	 * shared flavors are included in the list.
2330d7c6abe8Sjasmith 	 */
2331d7c6abe8Sjasmith 	seccnt = build_seclist_nodups(&exi->exi_export, sec, TRUE);
2332d7c6abe8Sjasmith 	if (sec_index > seccnt)
23337c478bd9Sstevel@tonic-gate 		return (EREMOTE);
23347c478bd9Sstevel@tonic-gate 
2335d7c6abe8Sjasmith 	fh_max_cnt = (NFS_FHSIZE / sizeof (int)) - 1;
2336d7c6abe8Sjasmith 	totalcnt = seccnt - sec_index + 1;
2337d7c6abe8Sjasmith 	cnt = totalcnt > fh_max_cnt ? fh_max_cnt : totalcnt;
23387c478bd9Sstevel@tonic-gate 
23397c478bd9Sstevel@tonic-gate 	c = (char *)fh;
23407c478bd9Sstevel@tonic-gate 	/*
23417c478bd9Sstevel@tonic-gate 	 * Encode the length octet representing the number of
23427c478bd9Sstevel@tonic-gate 	 * security flavors (in bytes) in this overloaded fh.
23437c478bd9Sstevel@tonic-gate 	 */
23447c478bd9Sstevel@tonic-gate 	*c = cnt * sizeof (int);
23457c478bd9Sstevel@tonic-gate 
23467c478bd9Sstevel@tonic-gate 	/*
23477c478bd9Sstevel@tonic-gate 	 * Encode the status octet that indicates whether there
23487c478bd9Sstevel@tonic-gate 	 * are more security flavors the client needs to get.
23497c478bd9Sstevel@tonic-gate 	 */
2350d7c6abe8Sjasmith 	*(c + 1) = totalcnt > fh_max_cnt;
23517c478bd9Sstevel@tonic-gate 
23527c478bd9Sstevel@tonic-gate 	/*
23537c478bd9Sstevel@tonic-gate 	 * put security flavors in the overloaded fh
23547c478bd9Sstevel@tonic-gate 	 */
23557c478bd9Sstevel@tonic-gate 	ipt = (int *)(c + sizeof (int32_t));
2356d7c6abe8Sjasmith 	secidx = sec_index - 1;
23577c478bd9Sstevel@tonic-gate 	for (i = 0; i < cnt; i++) {
2358d7c6abe8Sjasmith 		ipt[i] = htonl(sec[i + secidx].s_secinfo.sc_nfsnum);
23597c478bd9Sstevel@tonic-gate 	}
23607c478bd9Sstevel@tonic-gate 	return (0);
23617c478bd9Sstevel@tonic-gate }
23627c478bd9Sstevel@tonic-gate 
23637c478bd9Sstevel@tonic-gate /*
23647c478bd9Sstevel@tonic-gate  * Make an nfs_fh3 from a vnode
23657c478bd9Sstevel@tonic-gate  */
23667c478bd9Sstevel@tonic-gate int
makefh3(nfs_fh3 * fh,vnode_t * vp,struct exportinfo * exi)23677c478bd9Sstevel@tonic-gate makefh3(nfs_fh3 *fh, vnode_t *vp, struct exportinfo *exi)
23687c478bd9Sstevel@tonic-gate {
23697c478bd9Sstevel@tonic-gate 	int error;
237027242a7cSthurlow 	fid_t fid;
23717c478bd9Sstevel@tonic-gate 
237227242a7cSthurlow 	bzero(&fid, sizeof (fid));
2373fec13dd9SMarcel Telka 	fid.fid_len = sizeof (fh->fh3_data);
2374da6c28aaSamw 	error = VOP_FID(vp, &fid, NULL);
237527242a7cSthurlow 	if (error)
23767c478bd9Sstevel@tonic-gate 		return (EREMOTE);
237727242a7cSthurlow 
237827242a7cSthurlow 	bzero(fh, sizeof (nfs_fh3));
237927242a7cSthurlow 	fh->fh3_fsid = exi->exi_fsid;
238027242a7cSthurlow 	fh->fh3_len = fid.fid_len;
238127242a7cSthurlow 	bcopy(fid.fid_data, fh->fh3_data, fh->fh3_len);
2382fec13dd9SMarcel Telka 
238327242a7cSthurlow 	fh->fh3_xlen = exi->exi_fid.fid_len;
2384fec13dd9SMarcel Telka 	ASSERT(fh->fh3_xlen <= sizeof (fh->fh3_xdata));
238527242a7cSthurlow 	bcopy(exi->exi_fid.fid_data, fh->fh3_xdata, fh->fh3_xlen);
2386fec13dd9SMarcel Telka 
2387fec13dd9SMarcel Telka 	fh->fh3_length = sizeof (fh->fh3_fsid)
2388fec13dd9SMarcel Telka 	    + sizeof (fh->fh3_len) + fh->fh3_len
2389fec13dd9SMarcel Telka 	    + sizeof (fh->fh3_xlen) + fh->fh3_xlen;
23906a8ebdc3Sthurlow 	fh->fh3_flags = 0;
2391fec13dd9SMarcel Telka 
23927c478bd9Sstevel@tonic-gate 	return (0);
23937c478bd9Sstevel@tonic-gate }
23947c478bd9Sstevel@tonic-gate 
23957c478bd9Sstevel@tonic-gate /*
23967c478bd9Sstevel@tonic-gate  * This routine makes an overloaded V3 fhandle which contains
23977c478bd9Sstevel@tonic-gate  * sec modes.
23987c478bd9Sstevel@tonic-gate  *
23997c478bd9Sstevel@tonic-gate  *  1        4
24007c478bd9Sstevel@tonic-gate  * +--+--+--+--+
24017c478bd9Sstevel@tonic-gate  * |    len    |
24027c478bd9Sstevel@tonic-gate  * +--+--+--+--+
24037c478bd9Sstevel@tonic-gate  *                                               up to 64
24047c478bd9Sstevel@tonic-gate  * +--+--+--+--+--+--+--+--+--+--+--+--+     +--+--+--+--+
24057c478bd9Sstevel@tonic-gate  * |s |  |  |  |   sec_1   |   sec_2   | ... |   sec_n   |
24067c478bd9Sstevel@tonic-gate  * +--+--+--+--+--+--+--+--+--+--+--+--+     +--+--+--+--+
24077c478bd9Sstevel@tonic-gate  *
24087c478bd9Sstevel@tonic-gate  * len = 4 * (n+1), where n is the number of security flavors
24097c478bd9Sstevel@tonic-gate  * sent in the current overloaded filehandle.
24107c478bd9Sstevel@tonic-gate  *
24117c478bd9Sstevel@tonic-gate  * the status octet s indicates whether there are more security
24127c478bd9Sstevel@tonic-gate  * mechanisms (1 means yes, 0 means no) that require the client
24137c478bd9Sstevel@tonic-gate  * to perform another 0x81 LOOKUP to get them.
24147c478bd9Sstevel@tonic-gate  *
24157c478bd9Sstevel@tonic-gate  * Three octets are padded after the status octet.
24167c478bd9Sstevel@tonic-gate  */
24177c478bd9Sstevel@tonic-gate int
makefh3_ol(nfs_fh3 * fh,struct exportinfo * exi,uint_t sec_index)24187c478bd9Sstevel@tonic-gate makefh3_ol(nfs_fh3 *fh, struct exportinfo *exi, uint_t sec_index)
24197c478bd9Sstevel@tonic-gate {
2420d7c6abe8Sjasmith 	secinfo_t sec[MAX_FLAVORS];
2421d7c6abe8Sjasmith 	int totalcnt, cnt, *ipt, i, seccnt, fh_max_cnt, secidx;
24227c478bd9Sstevel@tonic-gate 	char *c;
24237c478bd9Sstevel@tonic-gate 
2424d7c6abe8Sjasmith 	if (fh == NULL || exi == NULL || sec_index < 1)
2425d7c6abe8Sjasmith 		return (EREMOTE);
2426d7c6abe8Sjasmith 
2427d7c6abe8Sjasmith 	/*
2428d7c6abe8Sjasmith 	 * WebNFS clients need to know the unique set of explicitly
2429d7c6abe8Sjasmith 	 * shared flavors in used for the public export. When
2430d7c6abe8Sjasmith 	 * "TRUE" is passed to build_seclist_nodups(), only explicitly
2431d7c6abe8Sjasmith 	 * shared flavors are included in the list.
2432d7c6abe8Sjasmith 	 */
2433d7c6abe8Sjasmith 	seccnt = build_seclist_nodups(&exi->exi_export, sec, TRUE);
2434d7c6abe8Sjasmith 
2435d7c6abe8Sjasmith 	if (sec_index > seccnt)
24367c478bd9Sstevel@tonic-gate 		return (EREMOTE);
24377c478bd9Sstevel@tonic-gate 
2438d7c6abe8Sjasmith 	fh_max_cnt = (NFS3_FHSIZE / sizeof (int)) - 1;
2439d7c6abe8Sjasmith 	totalcnt = seccnt - sec_index + 1;
2440d7c6abe8Sjasmith 	cnt = totalcnt > fh_max_cnt ? fh_max_cnt : totalcnt;
24417c478bd9Sstevel@tonic-gate 
24427c478bd9Sstevel@tonic-gate 	/*
24437c478bd9Sstevel@tonic-gate 	 * Place the length in fh3_length representing the number
24447c478bd9Sstevel@tonic-gate 	 * of security flavors (in bytes) in this overloaded fh.
24457c478bd9Sstevel@tonic-gate 	 */
24466a8ebdc3Sthurlow 	fh->fh3_flags = FH_WEBNFS;
24477c478bd9Sstevel@tonic-gate 	fh->fh3_length = (cnt+1) * sizeof (int32_t);
24487c478bd9Sstevel@tonic-gate 
24497c478bd9Sstevel@tonic-gate 	c = (char *)&fh->fh3_u.nfs_fh3_i.fh3_i;
24507c478bd9Sstevel@tonic-gate 	/*
24517c478bd9Sstevel@tonic-gate 	 * Encode the status octet that indicates whether there
24527c478bd9Sstevel@tonic-gate 	 * are more security flavors the client needs to get.
24537c478bd9Sstevel@tonic-gate 	 */
2454d7c6abe8Sjasmith 	*c = totalcnt > fh_max_cnt;
24557c478bd9Sstevel@tonic-gate 
24567c478bd9Sstevel@tonic-gate 	/*
24577c478bd9Sstevel@tonic-gate 	 * put security flavors in the overloaded fh
24587c478bd9Sstevel@tonic-gate 	 */
2459d7c6abe8Sjasmith 	secidx = sec_index - 1;
24607c478bd9Sstevel@tonic-gate 	ipt = (int *)(c + sizeof (int32_t));
24617c478bd9Sstevel@tonic-gate 	for (i = 0; i < cnt; i++) {
2462d7c6abe8Sjasmith 		ipt[i] = htonl(sec[i + secidx].s_secinfo.sc_nfsnum);
24637c478bd9Sstevel@tonic-gate 	}
24647c478bd9Sstevel@tonic-gate 	return (0);
24657c478bd9Sstevel@tonic-gate }
24667c478bd9Sstevel@tonic-gate 
24677c478bd9Sstevel@tonic-gate /*
24687c478bd9Sstevel@tonic-gate  * Make an nfs_fh4 from a vnode
24697c478bd9Sstevel@tonic-gate  */
24707c478bd9Sstevel@tonic-gate int
makefh4(nfs_fh4 * fh,vnode_t * vp,struct exportinfo * exi)24717c478bd9Sstevel@tonic-gate makefh4(nfs_fh4 *fh, vnode_t *vp, struct exportinfo *exi)
24727c478bd9Sstevel@tonic-gate {
24737c478bd9Sstevel@tonic-gate 	int error;
24747c478bd9Sstevel@tonic-gate 	nfs_fh4_fmt_t *fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val;
24757c478bd9Sstevel@tonic-gate 	fid_t fid;
24767c478bd9Sstevel@tonic-gate 
24777c478bd9Sstevel@tonic-gate 	bzero(&fid, sizeof (fid));
24787c478bd9Sstevel@tonic-gate 	fid.fid_len = MAXFIDSZ;
24797c478bd9Sstevel@tonic-gate 	/*
24807c478bd9Sstevel@tonic-gate 	 * vop_fid_pseudo() is used to set up NFSv4 namespace, so
24817c478bd9Sstevel@tonic-gate 	 * use vop_fid_pseudo() here to get the fid instead of VOP_FID.
24827c478bd9Sstevel@tonic-gate 	 */
24837c478bd9Sstevel@tonic-gate 	error = vop_fid_pseudo(vp, &fid);
24847c478bd9Sstevel@tonic-gate 	if (error)
24857c478bd9Sstevel@tonic-gate 		return (error);
24867c478bd9Sstevel@tonic-gate 
24877c478bd9Sstevel@tonic-gate 	fh->nfs_fh4_len = NFS_FH4_LEN;
24887c478bd9Sstevel@tonic-gate 
24897c46fb7fSek 	fh_fmtp->fh4_i.fhx_fsid = exi->exi_fh.fh_fsid;
24907c46fb7fSek 	fh_fmtp->fh4_i.fhx_xlen = exi->exi_fh.fh_xlen;
24917c46fb7fSek 
24927c46fb7fSek 	bzero(fh_fmtp->fh4_i.fhx_data, sizeof (fh_fmtp->fh4_i.fhx_data));
24937c46fb7fSek 	bzero(fh_fmtp->fh4_i.fhx_xdata, sizeof (fh_fmtp->fh4_i.fhx_xdata));
2494fec13dd9SMarcel Telka 	ASSERT(exi->exi_fh.fh_xlen <= sizeof (fh_fmtp->fh4_i.fhx_xdata));
24957c46fb7fSek 	bcopy(exi->exi_fh.fh_xdata, fh_fmtp->fh4_i.fhx_xdata,
2496af9f9769Sjasmith 	    exi->exi_fh.fh_xlen);
24977c46fb7fSek 
24987c478bd9Sstevel@tonic-gate 	fh_fmtp->fh4_len = fid.fid_len;
24997c478bd9Sstevel@tonic-gate 	ASSERT(fid.fid_len <= sizeof (fh_fmtp->fh4_data));
25007c478bd9Sstevel@tonic-gate 	bcopy(fid.fid_data, fh_fmtp->fh4_data, fid.fid_len);
25017c478bd9Sstevel@tonic-gate 	fh_fmtp->fh4_flag = 0;
25027c478bd9Sstevel@tonic-gate 
25037c478bd9Sstevel@tonic-gate #ifdef VOLATILE_FH_TEST
25047c478bd9Sstevel@tonic-gate 	/*
25057c478bd9Sstevel@tonic-gate 	 * XXX (temporary?)
25067c478bd9Sstevel@tonic-gate 	 * Use the rnode volatile_id value to add volatility to the fh.
25077c478bd9Sstevel@tonic-gate 	 *
25087c478bd9Sstevel@tonic-gate 	 * For testing purposes there are currently two scenarios, based
25097c478bd9Sstevel@tonic-gate 	 * on whether the filesystem was shared with "volatile_fh"
25107c478bd9Sstevel@tonic-gate 	 * or "expire_on_rename". In the first case, use the value of
25117c478bd9Sstevel@tonic-gate 	 * export struct share_time as the volatile_id. In the second
25127c478bd9Sstevel@tonic-gate 	 * case use the vnode volatile_id value (which is set to the
25137c478bd9Sstevel@tonic-gate 	 * time in which the file was renamed).
25147c478bd9Sstevel@tonic-gate 	 *
25157c478bd9Sstevel@tonic-gate 	 * Note that the above are temporary constructs for testing only
25167c478bd9Sstevel@tonic-gate 	 * XXX
25177c478bd9Sstevel@tonic-gate 	 */
25187c478bd9Sstevel@tonic-gate 	if (exi->exi_export.ex_flags & EX_VOLRNM) {
25197c478bd9Sstevel@tonic-gate 		fh_fmtp->fh4_volatile_id = find_volrnm_fh_id(exi, fh);
25207c478bd9Sstevel@tonic-gate 	} else if (exi->exi_export.ex_flags & EX_VOLFH) {
25217c478bd9Sstevel@tonic-gate 		fh_fmtp->fh4_volatile_id = exi->exi_volatile_id;
25227c478bd9Sstevel@tonic-gate 	} else {
25237c478bd9Sstevel@tonic-gate 		fh_fmtp->fh4_volatile_id = 0;
25247c478bd9Sstevel@tonic-gate 	}
25257c478bd9Sstevel@tonic-gate #endif /* VOLATILE_FH_TEST */
25267c478bd9Sstevel@tonic-gate 
25277c478bd9Sstevel@tonic-gate 	return (0);
25287c478bd9Sstevel@tonic-gate }
25297c478bd9Sstevel@tonic-gate 
25307c478bd9Sstevel@tonic-gate /*
25317c478bd9Sstevel@tonic-gate  * Convert an fhandle into a vnode.
25327c478bd9Sstevel@tonic-gate  * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode.
25337c478bd9Sstevel@tonic-gate  * WARNING: users of this routine must do a VN_RELE on the vnode when they
25347c478bd9Sstevel@tonic-gate  * are done with it.
25357c478bd9Sstevel@tonic-gate  */
25367c478bd9Sstevel@tonic-gate vnode_t *
nfs_fhtovp(fhandle_t * fh,struct exportinfo * exi)25377c478bd9Sstevel@tonic-gate nfs_fhtovp(fhandle_t *fh, struct exportinfo *exi)
25387c478bd9Sstevel@tonic-gate {
25397c478bd9Sstevel@tonic-gate 	vfs_t *vfsp;
25407c478bd9Sstevel@tonic-gate 	vnode_t *vp;
25417c478bd9Sstevel@tonic-gate 	int error;
25427c478bd9Sstevel@tonic-gate 	fid_t *fidp;
25437c478bd9Sstevel@tonic-gate 
25447c478bd9Sstevel@tonic-gate 	TRACE_0(TR_FAC_NFS, TR_FHTOVP_START,
2545af9f9769Sjasmith 	    "fhtovp_start");
25467c478bd9Sstevel@tonic-gate 
25477c478bd9Sstevel@tonic-gate 	if (exi == NULL) {
25487c478bd9Sstevel@tonic-gate 		TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2549af9f9769Sjasmith 		    "fhtovp_end:(%S)", "exi NULL");
25507c478bd9Sstevel@tonic-gate 		return (NULL);	/* not exported */
25517c478bd9Sstevel@tonic-gate 	}
25527c478bd9Sstevel@tonic-gate 
25537c478bd9Sstevel@tonic-gate 	ASSERT(exi->exi_vp != NULL);
25547c478bd9Sstevel@tonic-gate 
25557c478bd9Sstevel@tonic-gate 	if (PUBLIC_FH2(fh)) {
25567c478bd9Sstevel@tonic-gate 		if (exi->exi_export.ex_flags & EX_PUBLIC) {
25577c478bd9Sstevel@tonic-gate 			TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2558af9f9769Sjasmith 			    "fhtovp_end:(%S)", "root not exported");
25597c478bd9Sstevel@tonic-gate 			return (NULL);
25607c478bd9Sstevel@tonic-gate 		}
25617c478bd9Sstevel@tonic-gate 		vp = exi->exi_vp;
25627c478bd9Sstevel@tonic-gate 		VN_HOLD(vp);
25637c478bd9Sstevel@tonic-gate 		return (vp);
25647c478bd9Sstevel@tonic-gate 	}
25657c478bd9Sstevel@tonic-gate 
25667c478bd9Sstevel@tonic-gate 	vfsp = exi->exi_vp->v_vfsp;
25677c478bd9Sstevel@tonic-gate 	ASSERT(vfsp != NULL);
25687c478bd9Sstevel@tonic-gate 	fidp = (fid_t *)&fh->fh_len;
25697c478bd9Sstevel@tonic-gate 
25707c478bd9Sstevel@tonic-gate 	error = VFS_VGET(vfsp, &vp, fidp);
25717c478bd9Sstevel@tonic-gate 	if (error || vp == NULL) {
25727c478bd9Sstevel@tonic-gate 		TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2573af9f9769Sjasmith 		    "fhtovp_end:(%S)", "VFS_GET failed or vp NULL");
25747c478bd9Sstevel@tonic-gate 		return (NULL);
25757c478bd9Sstevel@tonic-gate 	}
25767c478bd9Sstevel@tonic-gate 	TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2577af9f9769Sjasmith 	    "fhtovp_end:(%S)", "end");
25787c478bd9Sstevel@tonic-gate 	return (vp);
25797c478bd9Sstevel@tonic-gate }
25807c478bd9Sstevel@tonic-gate 
25817c478bd9Sstevel@tonic-gate /*
25827c478bd9Sstevel@tonic-gate  * Convert an nfs_fh3 into a vnode.
25837c478bd9Sstevel@tonic-gate  * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
25847c478bd9Sstevel@tonic-gate  * WARNING: users of this routine must do a VN_RELE on the vnode when they
25857c478bd9Sstevel@tonic-gate  * are done with it.
25867c478bd9Sstevel@tonic-gate  */
25877c478bd9Sstevel@tonic-gate vnode_t *
nfs3_fhtovp(nfs_fh3 * fh,struct exportinfo * exi)25887c478bd9Sstevel@tonic-gate nfs3_fhtovp(nfs_fh3 *fh, struct exportinfo *exi)
25897c478bd9Sstevel@tonic-gate {
25907c478bd9Sstevel@tonic-gate 	vfs_t *vfsp;
25917c478bd9Sstevel@tonic-gate 	vnode_t *vp;
25927c478bd9Sstevel@tonic-gate 	int error;
25937c478bd9Sstevel@tonic-gate 	fid_t *fidp;
25947c478bd9Sstevel@tonic-gate 
25957c478bd9Sstevel@tonic-gate 	if (exi == NULL)
25967c478bd9Sstevel@tonic-gate 		return (NULL);	/* not exported */
25977c478bd9Sstevel@tonic-gate 
25987c478bd9Sstevel@tonic-gate 	ASSERT(exi->exi_vp != NULL);
25997c478bd9Sstevel@tonic-gate 
26007c478bd9Sstevel@tonic-gate 	if (PUBLIC_FH3(fh)) {
26017c478bd9Sstevel@tonic-gate 		if (exi->exi_export.ex_flags & EX_PUBLIC)
26027c478bd9Sstevel@tonic-gate 			return (NULL);
26037c478bd9Sstevel@tonic-gate 		vp = exi->exi_vp;
26047c478bd9Sstevel@tonic-gate 		VN_HOLD(vp);
26057c478bd9Sstevel@tonic-gate 		return (vp);
26067c478bd9Sstevel@tonic-gate 	}
26077c478bd9Sstevel@tonic-gate 
260827242a7cSthurlow 	if (fh->fh3_length < NFS3_OLDFHSIZE ||
260927242a7cSthurlow 	    fh->fh3_length > NFS3_MAXFHSIZE)
26107c478bd9Sstevel@tonic-gate 		return (NULL);
26117c478bd9Sstevel@tonic-gate 
26127c478bd9Sstevel@tonic-gate 	vfsp = exi->exi_vp->v_vfsp;
26137c478bd9Sstevel@tonic-gate 	ASSERT(vfsp != NULL);
261427242a7cSthurlow 	fidp = FH3TOFIDP(fh);
26157c478bd9Sstevel@tonic-gate 
26167c478bd9Sstevel@tonic-gate 	error = VFS_VGET(vfsp, &vp, fidp);
26177c478bd9Sstevel@tonic-gate 	if (error || vp == NULL)
26187c478bd9Sstevel@tonic-gate 		return (NULL);
26197c478bd9Sstevel@tonic-gate 
26207c478bd9Sstevel@tonic-gate 	return (vp);
26217c478bd9Sstevel@tonic-gate }
26227c478bd9Sstevel@tonic-gate 
26237c478bd9Sstevel@tonic-gate /*
26247c478bd9Sstevel@tonic-gate  * Convert an nfs_fh4 into a vnode.
26257c478bd9Sstevel@tonic-gate  * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
26267c478bd9Sstevel@tonic-gate  * WARNING: users of this routine must do a VN_RELE on the vnode when they
26277c478bd9Sstevel@tonic-gate  * are done with it.
26287c478bd9Sstevel@tonic-gate  */
26297c478bd9Sstevel@tonic-gate vnode_t *
nfs4_fhtovp(nfs_fh4 * fh,struct exportinfo * exi,nfsstat4 * statp)26307c478bd9Sstevel@tonic-gate nfs4_fhtovp(nfs_fh4 *fh, struct exportinfo *exi, nfsstat4 *statp)
26317c478bd9Sstevel@tonic-gate {
26327c478bd9Sstevel@tonic-gate 	vfs_t *vfsp;
26337c478bd9Sstevel@tonic-gate 	vnode_t *vp = NULL;
26347c478bd9Sstevel@tonic-gate 	int error;
26357c478bd9Sstevel@tonic-gate 	fid_t *fidp;
26367c478bd9Sstevel@tonic-gate 	nfs_fh4_fmt_t *fh_fmtp;
26377c478bd9Sstevel@tonic-gate #ifdef VOLATILE_FH_TEST
26387c478bd9Sstevel@tonic-gate 	uint32_t volatile_id = 0;
26397c478bd9Sstevel@tonic-gate #endif /* VOLATILE_FH_TEST */
26407c478bd9Sstevel@tonic-gate 
26417c478bd9Sstevel@tonic-gate 	if (exi == NULL) {
26427c478bd9Sstevel@tonic-gate 		*statp = NFS4ERR_STALE;
26437c478bd9Sstevel@tonic-gate 		return (NULL);	/* not exported */
26447c478bd9Sstevel@tonic-gate 	}
26457c478bd9Sstevel@tonic-gate 	ASSERT(exi->exi_vp != NULL);
26467c478bd9Sstevel@tonic-gate 
26477c478bd9Sstevel@tonic-gate 	/* caller should have checked this */
26487c478bd9Sstevel@tonic-gate 	ASSERT(fh->nfs_fh4_len >= NFS_FH4_LEN);
26497c478bd9Sstevel@tonic-gate 
26507c478bd9Sstevel@tonic-gate 	fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val;
26517c478bd9Sstevel@tonic-gate 	vfsp = exi->exi_vp->v_vfsp;
26527c478bd9Sstevel@tonic-gate 	ASSERT(vfsp != NULL);
26537c478bd9Sstevel@tonic-gate 	fidp = (fid_t *)&fh_fmtp->fh4_len;
26547c478bd9Sstevel@tonic-gate 
26557c478bd9Sstevel@tonic-gate #ifdef VOLATILE_FH_TEST
26567c478bd9Sstevel@tonic-gate 	/* XXX check if volatile - should be changed later */
26577c478bd9Sstevel@tonic-gate 	if (exi->exi_export.ex_flags & (EX_VOLRNM | EX_VOLFH)) {
26587c478bd9Sstevel@tonic-gate 		/*
26597c478bd9Sstevel@tonic-gate 		 * Filesystem is shared with volatile filehandles
26607c478bd9Sstevel@tonic-gate 		 */
26617c478bd9Sstevel@tonic-gate 		if (exi->exi_export.ex_flags & EX_VOLRNM)
26627c478bd9Sstevel@tonic-gate 			volatile_id = find_volrnm_fh_id(exi, fh);
26637c478bd9Sstevel@tonic-gate 		else
26647c478bd9Sstevel@tonic-gate 			volatile_id = exi->exi_volatile_id;
26657c478bd9Sstevel@tonic-gate 
26667c478bd9Sstevel@tonic-gate 		if (fh_fmtp->fh4_volatile_id != volatile_id) {
26677c478bd9Sstevel@tonic-gate 			*statp = NFS4ERR_FHEXPIRED;
26687c478bd9Sstevel@tonic-gate 			return (NULL);
26697c478bd9Sstevel@tonic-gate 		}
26707c478bd9Sstevel@tonic-gate 	}
26717c478bd9Sstevel@tonic-gate 	/*
26727c478bd9Sstevel@tonic-gate 	 * XXX even if test_volatile_fh false, the fh may contain a
26737c478bd9Sstevel@tonic-gate 	 * volatile id if obtained when the test was set.
26747c478bd9Sstevel@tonic-gate 	 */
26757c478bd9Sstevel@tonic-gate 	fh_fmtp->fh4_volatile_id = (uchar_t)0;
26767c478bd9Sstevel@tonic-gate #endif /* VOLATILE_FH_TEST */
26777c478bd9Sstevel@tonic-gate 
26787c478bd9Sstevel@tonic-gate 	error = VFS_VGET(vfsp, &vp, fidp);
26797c478bd9Sstevel@tonic-gate 	/*
26807c478bd9Sstevel@tonic-gate 	 * If we can not get vp from VFS_VGET, perhaps this is
26817c478bd9Sstevel@tonic-gate 	 * an nfs v2/v3/v4 node in an nfsv4 pseudo filesystem.
26827c478bd9Sstevel@tonic-gate 	 * Check it out.
26837c478bd9Sstevel@tonic-gate 	 */
26847c478bd9Sstevel@tonic-gate 	if (error && PSEUDO(exi))
26857c478bd9Sstevel@tonic-gate 		error = nfs4_vget_pseudo(exi, &vp, fidp);
26867c478bd9Sstevel@tonic-gate 
26877c478bd9Sstevel@tonic-gate 	if (error || vp == NULL) {
26887c478bd9Sstevel@tonic-gate 		*statp = NFS4ERR_STALE;
26897c478bd9Sstevel@tonic-gate 		return (NULL);
26907c478bd9Sstevel@tonic-gate 	}
26917c478bd9Sstevel@tonic-gate 	/* XXX - disgusting hack */
26927c478bd9Sstevel@tonic-gate 	if (vp->v_type == VNON && vp->v_flag & V_XATTRDIR)
26937c478bd9Sstevel@tonic-gate 		vp->v_type = VDIR;
26947c478bd9Sstevel@tonic-gate 	*statp = NFS4_OK;
26957c478bd9Sstevel@tonic-gate 	return (vp);
26967c478bd9Sstevel@tonic-gate }
26977c478bd9Sstevel@tonic-gate 
26987c478bd9Sstevel@tonic-gate /*
26997c478bd9Sstevel@tonic-gate  * Find the export structure associated with the given filesystem.
27007c478bd9Sstevel@tonic-gate  * If found, then increment the ref count (exi_count).
27017c478bd9Sstevel@tonic-gate  */
27027c478bd9Sstevel@tonic-gate struct exportinfo *
checkexport(fsid_t * fsid,fid_t * fid)27037c478bd9Sstevel@tonic-gate checkexport(fsid_t *fsid, fid_t *fid)
27047c478bd9Sstevel@tonic-gate {
27057c478bd9Sstevel@tonic-gate 	struct exportinfo *exi;
27060dfe541eSEvan Layton 	nfs_export_t *ne = nfs_get_export();
27077c478bd9Sstevel@tonic-gate 
27080dfe541eSEvan Layton 	rw_enter(&ne->exported_lock, RW_READER);
27090dfe541eSEvan Layton 	for (exi = ne->exptable[exptablehash(fsid, fid)];
27107c478bd9Sstevel@tonic-gate 	    exi != NULL;
27110616fd7fSPavel Filipensky 	    exi = exi->fid_hash.next) {
27127c478bd9Sstevel@tonic-gate 		if (exportmatch(exi, fsid, fid)) {
27137c478bd9Sstevel@tonic-gate 			/*
27147c478bd9Sstevel@tonic-gate 			 * If this is the place holder for the
27157c478bd9Sstevel@tonic-gate 			 * public file handle, then return the
27167c478bd9Sstevel@tonic-gate 			 * real export entry for the public file
27177c478bd9Sstevel@tonic-gate 			 * handle.
27187c478bd9Sstevel@tonic-gate 			 */
27197c478bd9Sstevel@tonic-gate 			if (exi->exi_export.ex_flags & EX_PUBLIC) {
27200dfe541eSEvan Layton 				exi = ne->exi_public;
27217c478bd9Sstevel@tonic-gate 			}
27223ccecb66SThomas Haynes 
27233ccecb66SThomas Haynes 			exi_hold(exi);
27240dfe541eSEvan Layton 			rw_exit(&ne->exported_lock);
27257c478bd9Sstevel@tonic-gate 			return (exi);
27267c478bd9Sstevel@tonic-gate 		}
27277c478bd9Sstevel@tonic-gate 	}
27280dfe541eSEvan Layton 	rw_exit(&ne->exported_lock);
27297c478bd9Sstevel@tonic-gate 	return (NULL);
27307c478bd9Sstevel@tonic-gate }
27317c478bd9Sstevel@tonic-gate 
27327c478bd9Sstevel@tonic-gate 
27337c478bd9Sstevel@tonic-gate /*
27347c478bd9Sstevel@tonic-gate  * "old school" version of checkexport() for NFS4.  NFS4
27357c478bd9Sstevel@tonic-gate  * rfs4_compound holds exported_lock for duration of compound
27367c478bd9Sstevel@tonic-gate  * processing.  This version doesn't manipulate exi_count
27377c478bd9Sstevel@tonic-gate  * since NFS4 breaks fundamental assumptions in the exi_count
27387c478bd9Sstevel@tonic-gate  * design.
27397c478bd9Sstevel@tonic-gate  */
27407c478bd9Sstevel@tonic-gate struct exportinfo *
checkexport4(fsid_t * fsid,fid_t * fid,vnode_t * vp)27417c478bd9Sstevel@tonic-gate checkexport4(fsid_t *fsid, fid_t *fid, vnode_t *vp)
27427c478bd9Sstevel@tonic-gate {
27437c478bd9Sstevel@tonic-gate 	struct exportinfo *exi;
27440dfe541eSEvan Layton 	nfs_export_t *ne = nfs_get_export();
27457c478bd9Sstevel@tonic-gate 
27460dfe541eSEvan Layton 	ASSERT(RW_LOCK_HELD(&ne->exported_lock));
27477c478bd9Sstevel@tonic-gate 
27480dfe541eSEvan Layton 	for (exi = ne->exptable[exptablehash(fsid, fid)];
27497c478bd9Sstevel@tonic-gate 	    exi != NULL;
27500616fd7fSPavel Filipensky 	    exi = exi->fid_hash.next) {
27517c478bd9Sstevel@tonic-gate 		if (exportmatch(exi, fsid, fid)) {
27527c478bd9Sstevel@tonic-gate 			/*
27537c478bd9Sstevel@tonic-gate 			 * If this is the place holder for the
27547c478bd9Sstevel@tonic-gate 			 * public file handle, then return the
27557c478bd9Sstevel@tonic-gate 			 * real export entry for the public file
27567c478bd9Sstevel@tonic-gate 			 * handle.
27577c478bd9Sstevel@tonic-gate 			 */
27587c478bd9Sstevel@tonic-gate 			if (exi->exi_export.ex_flags & EX_PUBLIC) {
27590dfe541eSEvan Layton 				exi = ne->exi_public;
27607c478bd9Sstevel@tonic-gate 			}
27617c478bd9Sstevel@tonic-gate 
27627c478bd9Sstevel@tonic-gate 			/*
27637c478bd9Sstevel@tonic-gate 			 * If vp is given, check if vp is the
27647c478bd9Sstevel@tonic-gate 			 * same vnode as the exported node.
27657c478bd9Sstevel@tonic-gate 			 *
27667c478bd9Sstevel@tonic-gate 			 * Since VOP_FID of a lofs node returns the
27677c478bd9Sstevel@tonic-gate 			 * fid of its real node (ufs), the exported
27687c478bd9Sstevel@tonic-gate 			 * node for lofs and (pseudo) ufs may have
27697c478bd9Sstevel@tonic-gate 			 * the same fsid and fid.
27707c478bd9Sstevel@tonic-gate 			 */
27717c478bd9Sstevel@tonic-gate 			if (vp == NULL || vp == exi->exi_vp)
27727c478bd9Sstevel@tonic-gate 				return (exi);
27737c478bd9Sstevel@tonic-gate 		}
27747c478bd9Sstevel@tonic-gate 	}
27757c478bd9Sstevel@tonic-gate 
27767c478bd9Sstevel@tonic-gate 	return (NULL);
27777c478bd9Sstevel@tonic-gate }
27787c478bd9Sstevel@tonic-gate 
27797c478bd9Sstevel@tonic-gate /*
27807c478bd9Sstevel@tonic-gate  * Free an entire export list node
27817c478bd9Sstevel@tonic-gate  */
27827c478bd9Sstevel@tonic-gate void
exportfree(struct exportinfo * exi)27837c478bd9Sstevel@tonic-gate exportfree(struct exportinfo *exi)
27847c478bd9Sstevel@tonic-gate {
27857c478bd9Sstevel@tonic-gate 	struct exportdata *ex;
2786b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct charset_cache *cache;
278771da0c32SMarcel Telka 	int i;
27887c478bd9Sstevel@tonic-gate 
27897c478bd9Sstevel@tonic-gate 	ex = &exi->exi_export;
27907c478bd9Sstevel@tonic-gate 
27917c478bd9Sstevel@tonic-gate 	ASSERT(exi->exi_vp != NULL && !(exi->exi_export.ex_flags & EX_PUBLIC));
27927c478bd9Sstevel@tonic-gate 	VN_RELE(exi->exi_vp);
27937c478bd9Sstevel@tonic-gate 	if (exi->exi_dvp != NULL)
27947c478bd9Sstevel@tonic-gate 		VN_RELE(exi->exi_dvp);
27957c478bd9Sstevel@tonic-gate 
27967c478bd9Sstevel@tonic-gate 	if (ex->ex_flags & EX_INDEX)
27977c478bd9Sstevel@tonic-gate 		kmem_free(ex->ex_index, strlen(ex->ex_index) + 1);
27987c478bd9Sstevel@tonic-gate 
27997c478bd9Sstevel@tonic-gate 	kmem_free(ex->ex_path, ex->ex_pathlen + 1);
28007c478bd9Sstevel@tonic-gate 	nfsauth_cache_free(exi);
28017c478bd9Sstevel@tonic-gate 
2802b89a8333Snatalie li - Sun Microsystems - Irvine United States 	/*
2803b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * if there is a character set mapping cached, clean it up.
2804b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 */
2805b89a8333Snatalie li - Sun Microsystems - Irvine United States 	for (cache = exi->exi_charset; cache != NULL;
2806b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    cache = exi->exi_charset) {
2807b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (cache->inbound != (kiconv_t)-1)
2808b89a8333Snatalie li - Sun Microsystems - Irvine United States 			(void) kiconv_close(cache->inbound);
2809b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (cache->outbound != (kiconv_t)-1)
2810b89a8333Snatalie li - Sun Microsystems - Irvine United States 			(void) kiconv_close(cache->outbound);
2811b89a8333Snatalie li - Sun Microsystems - Irvine United States 		exi->exi_charset = cache->next;
2812b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kmem_free(cache, sizeof (struct charset_cache));
2813b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
2814b89a8333Snatalie li - Sun Microsystems - Irvine United States 
28157c478bd9Sstevel@tonic-gate 	if (exi->exi_logbuffer != NULL)
28167c478bd9Sstevel@tonic-gate 		nfslog_disable(exi);
28177c478bd9Sstevel@tonic-gate 
28187c478bd9Sstevel@tonic-gate 	if (ex->ex_flags & EX_LOG) {
28197c478bd9Sstevel@tonic-gate 		kmem_free(ex->ex_log_buffer, ex->ex_log_bufferlen + 1);
28207c478bd9Sstevel@tonic-gate 		kmem_free(ex->ex_tag, ex->ex_taglen + 1);
28217c478bd9Sstevel@tonic-gate 	}
28227c478bd9Sstevel@tonic-gate 
28237c478bd9Sstevel@tonic-gate 	if (exi->exi_visible)
28247c478bd9Sstevel@tonic-gate 		free_visible(exi->exi_visible);
28257c478bd9Sstevel@tonic-gate 
28267c478bd9Sstevel@tonic-gate 	srv_secinfo_list_free(ex->ex_secinfo, ex->ex_seccnt);
28277c478bd9Sstevel@tonic-gate 
28287c478bd9Sstevel@tonic-gate #ifdef VOLATILE_FH_TEST
28297c478bd9Sstevel@tonic-gate 	free_volrnm_list(exi);
28307c478bd9Sstevel@tonic-gate 	mutex_destroy(&exi->exi_vol_rename_lock);
28317c478bd9Sstevel@tonic-gate #endif /* VOLATILE_FH_TEST */
28327c478bd9Sstevel@tonic-gate 
28337c478bd9Sstevel@tonic-gate 	mutex_destroy(&exi->exi_lock);
28347c478bd9Sstevel@tonic-gate 	rw_destroy(&exi->exi_cache_lock);
283571da0c32SMarcel Telka 	/*
283671da0c32SMarcel Telka 	 * All nodes in the exi_cache AVL trees were removed and freed in the
283771da0c32SMarcel Telka 	 * nfsauth_cache_free() call above.  We will just destroy and free the
283871da0c32SMarcel Telka 	 * empty AVL trees here.
283971da0c32SMarcel Telka 	 */
284071da0c32SMarcel Telka 	for (i = 0; i < AUTH_TABLESIZE; i++) {
284171da0c32SMarcel Telka 		avl_destroy(exi->exi_cache[i]);
284271da0c32SMarcel Telka 		kmem_free(exi->exi_cache[i], sizeof (avl_tree_t));
284371da0c32SMarcel Telka 	}
28447c478bd9Sstevel@tonic-gate 
28457c478bd9Sstevel@tonic-gate 	kmem_free(exi, sizeof (*exi));
28467c478bd9Sstevel@tonic-gate }
28477c478bd9Sstevel@tonic-gate 
28487c478bd9Sstevel@tonic-gate /*
28497c478bd9Sstevel@tonic-gate  * load the index file from user space into kernel space.
28507c478bd9Sstevel@tonic-gate  */
28517c478bd9Sstevel@tonic-gate static int
loadindex(struct exportdata * kex)28527c478bd9Sstevel@tonic-gate loadindex(struct exportdata *kex)
28537c478bd9Sstevel@tonic-gate {
28547c478bd9Sstevel@tonic-gate 	int error;
28557c478bd9Sstevel@tonic-gate 	char index[MAXNAMELEN+1];
28567c478bd9Sstevel@tonic-gate 	size_t len;
28577c478bd9Sstevel@tonic-gate 
28587c478bd9Sstevel@tonic-gate 	/*
28597c478bd9Sstevel@tonic-gate 	 * copyinstr copies the complete string including the NULL and
28607c478bd9Sstevel@tonic-gate 	 * returns the len with the NULL byte included in the calculation
28617c478bd9Sstevel@tonic-gate 	 * as long as the max length is not exceeded.
28627c478bd9Sstevel@tonic-gate 	 */
2863*bd3561fbSToomas Soome 	error = copyinstr(kex->ex_index, index, sizeof (index), &len);
2864*bd3561fbSToomas Soome 	if (error != 0)
28657c478bd9Sstevel@tonic-gate 		return (error);
28667c478bd9Sstevel@tonic-gate 
28677c478bd9Sstevel@tonic-gate 	kex->ex_index = kmem_alloc(len, KM_SLEEP);
28687c478bd9Sstevel@tonic-gate 	bcopy(index, kex->ex_index, len);
28697c478bd9Sstevel@tonic-gate 
28707c478bd9Sstevel@tonic-gate 	return (0);
28717c478bd9Sstevel@tonic-gate }
28727c478bd9Sstevel@tonic-gate 
28733ccecb66SThomas Haynes void
exi_hold(struct exportinfo * exi)28743ccecb66SThomas Haynes exi_hold(struct exportinfo *exi)
28753ccecb66SThomas Haynes {
28763ccecb66SThomas Haynes 	mutex_enter(&exi->exi_lock);
28773ccecb66SThomas Haynes 	exi->exi_count++;
28783ccecb66SThomas Haynes 	mutex_exit(&exi->exi_lock);
28793ccecb66SThomas Haynes }
28803ccecb66SThomas Haynes 
28817c478bd9Sstevel@tonic-gate /*
28827c478bd9Sstevel@tonic-gate  * When a thread completes using exi, it should call exi_rele().
28837c478bd9Sstevel@tonic-gate  * exi_rele() decrements exi_count. It releases exi if exi_count == 0, i.e.
28847c478bd9Sstevel@tonic-gate  * if this is the last user of exi and exi is not on exportinfo list anymore
28857c478bd9Sstevel@tonic-gate  */
28867c478bd9Sstevel@tonic-gate void
exi_rele(struct exportinfo * exi)28877c478bd9Sstevel@tonic-gate exi_rele(struct exportinfo *exi)
28887c478bd9Sstevel@tonic-gate {
28897c478bd9Sstevel@tonic-gate 	mutex_enter(&exi->exi_lock);
28907c478bd9Sstevel@tonic-gate 	exi->exi_count--;
28917c478bd9Sstevel@tonic-gate 	if (exi->exi_count == 0) {
28927c478bd9Sstevel@tonic-gate 		mutex_exit(&exi->exi_lock);
28937c478bd9Sstevel@tonic-gate 		exportfree(exi);
28947c478bd9Sstevel@tonic-gate 	} else
28957c478bd9Sstevel@tonic-gate 		mutex_exit(&exi->exi_lock);
28967c478bd9Sstevel@tonic-gate }
28977c478bd9Sstevel@tonic-gate 
28987c478bd9Sstevel@tonic-gate #ifdef VOLATILE_FH_TEST
28997c478bd9Sstevel@tonic-gate /*
29007c478bd9Sstevel@tonic-gate  * Test for volatile fh's - add file handle to list and set its volatile id
29017c478bd9Sstevel@tonic-gate  * to time it was renamed. If EX_VOLFH is also on and the fs is reshared,
29027c478bd9Sstevel@tonic-gate  * the vol_rename queue is purged.
29037c478bd9Sstevel@tonic-gate  *
29047c478bd9Sstevel@tonic-gate  * XXX This code is for unit testing purposes only... To correctly use it, it
29057c478bd9Sstevel@tonic-gate  * needs to tie a rename list to the export struct and (more
29067c478bd9Sstevel@tonic-gate  * important), protect access to the exi rename list using a write lock.
29077c478bd9Sstevel@tonic-gate  */
29087c478bd9Sstevel@tonic-gate 
29097c478bd9Sstevel@tonic-gate /*
29107c478bd9Sstevel@tonic-gate  * get the fh vol record if it's in the volatile on rename list. Don't check
29117c478bd9Sstevel@tonic-gate  * volatile_id in the file handle - compare only the file handles.
29127c478bd9Sstevel@tonic-gate  */
29137c478bd9Sstevel@tonic-gate static struct ex_vol_rename *
find_volrnm_fh(struct exportinfo * exi,nfs_fh4 * fh4p)29147c478bd9Sstevel@tonic-gate find_volrnm_fh(struct exportinfo *exi, nfs_fh4 *fh4p)
29157c478bd9Sstevel@tonic-gate {
29167c478bd9Sstevel@tonic-gate 	struct ex_vol_rename *p = NULL;
291727242a7cSthurlow 	fhandle4_t *fhp;
29187c478bd9Sstevel@tonic-gate 
29197c478bd9Sstevel@tonic-gate 	/* XXX shouldn't we assert &exported_lock held? */
29207c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&exi->exi_vol_rename_lock));
29217c478bd9Sstevel@tonic-gate 
29227c478bd9Sstevel@tonic-gate 	if (fh4p->nfs_fh4_len != NFS_FH4_LEN) {
29237c478bd9Sstevel@tonic-gate 		return (NULL);
29247c478bd9Sstevel@tonic-gate 	}
29257c46fb7fSek 	fhp = &((nfs_fh4_fmt_t *)fh4p->nfs_fh4_val)->fh4_i;
29267c478bd9Sstevel@tonic-gate 	for (p = exi->exi_vol_rename; p != NULL; p = p->vrn_next) {
29277c46fb7fSek 		if (bcmp(fhp, &p->vrn_fh_fmt.fh4_i,
292827242a7cSthurlow 		    sizeof (fhandle4_t)) == 0)
29297c478bd9Sstevel@tonic-gate 			break;
29307c478bd9Sstevel@tonic-gate 	}
29317c478bd9Sstevel@tonic-gate 	return (p);
29327c478bd9Sstevel@tonic-gate }
29337c478bd9Sstevel@tonic-gate 
29347c478bd9Sstevel@tonic-gate /*
29357c478bd9Sstevel@tonic-gate  * get the volatile id for the fh (if there is - else return 0). Ignore the
29367c478bd9Sstevel@tonic-gate  * volatile_id in the file handle - compare only the file handles.
29377c478bd9Sstevel@tonic-gate  */
29387c478bd9Sstevel@tonic-gate static uint32_t
find_volrnm_fh_id(struct exportinfo * exi,nfs_fh4 * fh4p)29397c478bd9Sstevel@tonic-gate find_volrnm_fh_id(struct exportinfo *exi, nfs_fh4 *fh4p)
29407c478bd9Sstevel@tonic-gate {
29417c478bd9Sstevel@tonic-gate 	struct ex_vol_rename *p;
29427c478bd9Sstevel@tonic-gate 	uint32_t volatile_id;
29437c478bd9Sstevel@tonic-gate 
29447c478bd9Sstevel@tonic-gate 	mutex_enter(&exi->exi_vol_rename_lock);
29457c478bd9Sstevel@tonic-gate 	p = find_volrnm_fh(exi, fh4p);
29467c478bd9Sstevel@tonic-gate 	volatile_id = (p ? p->vrn_fh_fmt.fh4_volatile_id :
2947af9f9769Sjasmith 	    exi->exi_volatile_id);
29487c478bd9Sstevel@tonic-gate 	mutex_exit(&exi->exi_vol_rename_lock);
29497c478bd9Sstevel@tonic-gate 	return (volatile_id);
29507c478bd9Sstevel@tonic-gate }
29517c478bd9Sstevel@tonic-gate 
29527c478bd9Sstevel@tonic-gate /*
29537c478bd9Sstevel@tonic-gate  * Free the volatile on rename list - will be called if a filesystem is
29547c478bd9Sstevel@tonic-gate  * unshared or reshared without EX_VOLRNM
29557c478bd9Sstevel@tonic-gate  */
29567c478bd9Sstevel@tonic-gate static void
free_volrnm_list(struct exportinfo * exi)29577c478bd9Sstevel@tonic-gate free_volrnm_list(struct exportinfo *exi)
29587c478bd9Sstevel@tonic-gate {
29597c478bd9Sstevel@tonic-gate 	struct ex_vol_rename *p, *pnext;
29607c478bd9Sstevel@tonic-gate 
29617c478bd9Sstevel@tonic-gate 	/* no need to hold mutex lock - this one is called from exportfree */
29627c478bd9Sstevel@tonic-gate 	for (p = exi->exi_vol_rename; p != NULL; p = pnext) {
29637c478bd9Sstevel@tonic-gate 		pnext = p->vrn_next;
29647c478bd9Sstevel@tonic-gate 		kmem_free(p, sizeof (*p));
29657c478bd9Sstevel@tonic-gate 	}
29667c478bd9Sstevel@tonic-gate 	exi->exi_vol_rename = NULL;
29677c478bd9Sstevel@tonic-gate }
29687c478bd9Sstevel@tonic-gate 
29697c478bd9Sstevel@tonic-gate /*
29707c478bd9Sstevel@tonic-gate  * Add a file handle to the volatile on rename list.
29717c478bd9Sstevel@tonic-gate  */
29727c478bd9Sstevel@tonic-gate void
add_volrnm_fh(struct exportinfo * exi,vnode_t * vp)29737c478bd9Sstevel@tonic-gate add_volrnm_fh(struct exportinfo *exi, vnode_t *vp)
29747c478bd9Sstevel@tonic-gate {
29757c478bd9Sstevel@tonic-gate 	struct ex_vol_rename *p;
29767c478bd9Sstevel@tonic-gate 	char fhbuf[NFS4_FHSIZE];
29777c478bd9Sstevel@tonic-gate 	nfs_fh4 fh4;
29787c478bd9Sstevel@tonic-gate 	int error;
29797c478bd9Sstevel@tonic-gate 
29807c478bd9Sstevel@tonic-gate 	fh4.nfs_fh4_val = fhbuf;
29817c478bd9Sstevel@tonic-gate 	error = makefh4(&fh4, vp, exi);
29827c478bd9Sstevel@tonic-gate 	if ((error) || (fh4.nfs_fh4_len != sizeof (p->vrn_fh_fmt))) {
29837c478bd9Sstevel@tonic-gate 		return;
29847c478bd9Sstevel@tonic-gate 	}
29857c478bd9Sstevel@tonic-gate 
29867c478bd9Sstevel@tonic-gate 	mutex_enter(&exi->exi_vol_rename_lock);
29877c478bd9Sstevel@tonic-gate 
29887c478bd9Sstevel@tonic-gate 	p = find_volrnm_fh(exi, &fh4);
29897c478bd9Sstevel@tonic-gate 
29907c478bd9Sstevel@tonic-gate 	if (p == NULL) {
29917c478bd9Sstevel@tonic-gate 		p = kmem_alloc(sizeof (*p), KM_SLEEP);
29927c478bd9Sstevel@tonic-gate 		bcopy(fh4.nfs_fh4_val, &p->vrn_fh_fmt, sizeof (p->vrn_fh_fmt));
29937c478bd9Sstevel@tonic-gate 		p->vrn_next = exi->exi_vol_rename;
29947c478bd9Sstevel@tonic-gate 		exi->exi_vol_rename = p;
29957c478bd9Sstevel@tonic-gate 	}
29967c478bd9Sstevel@tonic-gate 
29977c478bd9Sstevel@tonic-gate 	p->vrn_fh_fmt.fh4_volatile_id = gethrestime_sec();
29987c478bd9Sstevel@tonic-gate 	mutex_exit(&exi->exi_vol_rename_lock);
29997c478bd9Sstevel@tonic-gate }
30007c478bd9Sstevel@tonic-gate 
30017c478bd9Sstevel@tonic-gate #endif /* VOLATILE_FH_TEST */
3002