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