4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
24 * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Copyright 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T.
29 * All rights reserved.
33 #include <sys/types.h>
34 #include <sys/param.h>
37 #include <sys/vnode.h>
38 #include <sys/socket.h>
39 #include <sys/errno.h>
44 #include <sys/tiuser.h>
46 #include <sys/pathname.h>
47 #include <sys/debug.h>
48 #include <sys/vtrace.h>
49 #include <sys/cmn_err.h>
51 #include <sys/utsname.h>
53 #include <netinet/in.h>
56 #include <rpc/types.h>
61 #include <nfs/export.h>
62 #include <nfs/nfssys.h>
63 #include <nfs/nfs_clnt.h>
64 #include <nfs/nfs_acl.h>
65 #include <nfs/nfs_log.h>
67 #include <sys/sunddi.h>
68 #include <sys/pkp_hash.h>
72 struct exportinfo
*exptable_path_hash
[PKP_HASH_SIZE
];
73 struct exportinfo
*exptable
[EXPTABLESIZE
];
75 static int unexport(exportinfo_t
*);
76 static void exportfree(exportinfo_t
*);
77 static int loadindex(exportdata_t
*);
79 extern void nfsauth_cache_free(exportinfo_t
*);
80 extern int sec_svc_loadrootnames(int, int, caddr_t
**, model_t
);
81 extern void sec_svc_freerootnames(int, int, caddr_t
*);
83 static int build_seclist_nodups(exportdata_t
*, secinfo_t
*, int);
84 static void srv_secinfo_add(secinfo_t
**, int *, secinfo_t
*, int, int);
85 static void srv_secinfo_remove(secinfo_t
**, int *, secinfo_t
*, int);
86 static void srv_secinfo_treeclimb(exportinfo_t
*, secinfo_t
*, int, int);
88 #ifdef VOLATILE_FH_TEST
89 static struct ex_vol_rename
*find_volrnm_fh(exportinfo_t
*, nfs_fh4
*);
90 static uint32_t find_volrnm_fh_id(exportinfo_t
*, nfs_fh4
*);
91 static void free_volrnm_list(exportinfo_t
*);
92 #endif /* VOLATILE_FH_TEST */
95 * exported_lock Read/Write lock that protects the exportinfo list.
96 * This lock must be held when searching or modifiying
97 * the exportinfo list.
99 krwlock_t exported_lock
;
102 * "public" and default (root) location for public filehandle
104 struct exportinfo
*exi_public
, *exi_root
;
106 fid_t exi_rootfid
; /* for checking the default public file handle */
108 fhandle_t nullfh2
; /* for comparing V2 filehandles */
111 * macro for static dtrace probes to trace server namespace ref count mods.
113 #define SECREF_TRACE(seclist, tag, flav, aftcnt) \
114 DTRACE_PROBE4(nfss__i__nmspc__secref, struct secinfo *, (seclist), \
115 char *, (tag), int, (int)(flav), int, (int)(aftcnt))
118 #define exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1))
121 xor_hash(uint8_t *data
, int len
)
132 * File handle hash function, XOR over all bytes in fsid and fid.
135 nfs_fhhash(fsid_t
*fsid
, fid_t
*fid
)
140 h
= xor_hash((uint8_t *)fsid
, sizeof (fsid_t
));
143 * Sanity check the length before using it
144 * blindly in case the client trashed it.
146 len
= fid
->fid_len
> NFS_FH4MAXDATA
? 0 : fid
->fid_len
;
147 h
^= xor_hash((uint8_t *)fid
->fid_data
, len
);
149 return ((unsigned)h
);
153 * Free the memory allocated within a secinfo entry.
156 srv_secinfo_entry_free(struct secinfo
*secp
)
158 if (secp
->s_rootcnt
> 0 && secp
->s_rootnames
!= NULL
) {
159 sec_svc_freerootnames(secp
->s_secinfo
.sc_rpcnum
,
160 secp
->s_rootcnt
, secp
->s_rootnames
);
164 if ((secp
->s_secinfo
.sc_rpcnum
== RPCSEC_GSS
) &&
165 (secp
->s_secinfo
.sc_gss_mech_type
)) {
166 kmem_free(secp
->s_secinfo
.sc_gss_mech_type
->elements
,
167 secp
->s_secinfo
.sc_gss_mech_type
->length
);
168 kmem_free(secp
->s_secinfo
.sc_gss_mech_type
,
169 sizeof (rpc_gss_OID_desc
));
170 secp
->s_secinfo
.sc_gss_mech_type
= NULL
;
175 * Free a list of secinfo allocated in the exportdata structure.
178 srv_secinfo_list_free(struct secinfo
*secinfo
, int cnt
)
185 for (i
= 0; i
< cnt
; i
++)
186 srv_secinfo_entry_free(&secinfo
[i
]);
188 kmem_free(secinfo
, cnt
* sizeof (struct secinfo
));
192 * Allocate and copy a secinfo data from "from" to "to".
194 * This routine is used by srv_secinfo_add() to add a new flavor to an
195 * ancestor's export node. The rootnames are not copied because the
196 * allowable rootname access only applies to the explicit exported node,
197 * not its ancestor's.
199 * "to" should have already been allocated and zeroed before calling
202 * This routine is used under the protection of exported_lock (RW_WRITER).
205 srv_secinfo_copy(struct secinfo
*from
, struct secinfo
*to
)
207 to
->s_secinfo
.sc_nfsnum
= from
->s_secinfo
.sc_nfsnum
;
208 to
->s_secinfo
.sc_rpcnum
= from
->s_secinfo
.sc_rpcnum
;
210 if (from
->s_secinfo
.sc_rpcnum
== RPCSEC_GSS
) {
211 to
->s_secinfo
.sc_service
= from
->s_secinfo
.sc_service
;
212 bcopy(from
->s_secinfo
.sc_name
, to
->s_secinfo
.sc_name
,
213 strlen(from
->s_secinfo
.sc_name
));
214 bcopy(from
->s_secinfo
.sc_gss_mech
, to
->s_secinfo
.sc_gss_mech
,
215 strlen(from
->s_secinfo
.sc_gss_mech
));
217 /* copy mechanism oid */
218 to
->s_secinfo
.sc_gss_mech_type
=
219 kmem_alloc(sizeof (rpc_gss_OID_desc
), KM_SLEEP
);
220 to
->s_secinfo
.sc_gss_mech_type
->length
=
221 from
->s_secinfo
.sc_gss_mech_type
->length
;
222 to
->s_secinfo
.sc_gss_mech_type
->elements
=
223 kmem_alloc(from
->s_secinfo
.sc_gss_mech_type
->length
,
225 bcopy(from
->s_secinfo
.sc_gss_mech_type
->elements
,
226 to
->s_secinfo
.sc_gss_mech_type
->elements
,
227 from
->s_secinfo
.sc_gss_mech_type
->length
);
230 to
->s_refcnt
= from
->s_refcnt
;
231 to
->s_window
= from
->s_window
;
232 /* no need to copy the mode bits - s_flags */
236 * Create a secinfo array without duplicates. The condensed
237 * flavor list is used to propagate flavor ref counts to an
238 * export's ancestor pseudonodes.
241 build_seclist_nodups(exportdata_t
*exd
, secinfo_t
*nodups
, int exponly
)
245 struct secinfo
*cursec
;
248 ccnt
= exd
->ex_seccnt
;
249 cursec
= exd
->ex_secinfo
;
251 for (c
= 0; c
< ccnt
; c
++) {
253 if (exponly
&& ! SEC_REF_EXPORTED(&cursec
[c
]))
256 for (n
= 0; n
< ncnt
; n
++) {
257 if (nodups
[n
].s_secinfo
.sc_nfsnum
==
258 cursec
[c
].s_secinfo
.sc_nfsnum
)
263 * The structure copy below also copys ptrs embedded
264 * within struct secinfo. The ptrs are copied but
265 * they are never freed from the nodups array. If
266 * an ancestor's secinfo array doesn't contain one
267 * of the nodups flavors, then the entry is properly
268 * copied into the ancestor's secinfo array.
269 * (see srv_secinfo_copy)
272 nodups
[n
] = cursec
[c
];
280 * Add the new security flavors from newdata to the current list, pcursec.
281 * Upon return, *pcursec has the newly merged secinfo list.
283 * There should be at least 1 secinfo entry in newsec.
285 * This routine is used under the protection of exported_lock (RW_WRITER).
288 srv_secinfo_add(secinfo_t
**pcursec
, int *pcurcnt
, secinfo_t
*newsec
,
289 int newcnt
, int is_pseudo
)
291 int ccnt
, c
; /* sec count in current data - curdata */
292 int n
; /* index for newsec - newsecinfo */
293 int tcnt
; /* total sec count after merge */
294 int mcnt
; /* total sec count after merge */
295 struct secinfo
*msec
; /* merged secinfo list */
296 struct secinfo
*cursec
;
302 tcnt
= ccnt
+ newcnt
;
304 for (n
= 0; n
< newcnt
; n
++) {
305 for (c
= 0; c
< ccnt
; c
++) {
306 if (newsec
[n
].s_secinfo
.sc_nfsnum
==
307 cursec
[c
].s_secinfo
.sc_nfsnum
) {
308 cursec
[c
].s_refcnt
+= newsec
[n
].s_refcnt
;
309 SECREF_TRACE(cursec
, "add_ref",
310 cursec
[c
].s_secinfo
.sc_nfsnum
,
319 return; /* no change; no new flavors */
321 msec
= kmem_zalloc(tcnt
* sizeof (struct secinfo
), KM_SLEEP
);
323 /* move current secinfo list data to the new list */
324 for (c
= 0; c
< ccnt
; c
++)
327 /* Add the flavor that's not in the current data */
329 for (n
= 0; n
< newcnt
; n
++) {
330 for (c
= 0; c
< ccnt
; c
++) {
331 if (newsec
[n
].s_secinfo
.sc_nfsnum
==
332 cursec
[c
].s_secinfo
.sc_nfsnum
)
336 /* This is the one. Add it. */
338 srv_secinfo_copy(&newsec
[n
], &msec
[mcnt
]);
341 msec
[mcnt
].s_flags
= M_RO
;
343 SECREF_TRACE(msec
, "new_ref",
344 msec
[mcnt
].s_secinfo
.sc_nfsnum
,
345 msec
[mcnt
].s_refcnt
);
350 ASSERT(mcnt
== tcnt
);
353 * Done. Update curdata. Free the old secinfo list in
354 * curdata and return the new sec array info
357 kmem_free(cursec
, ccnt
* sizeof (struct secinfo
));
364 * Remove the security data of the unexported node from its ancestors.
365 * Assume there is at least one flavor entry in the current sec list
368 * This routine is used under the protection of exported_lock (RW_WRITER).
370 * Every element of remsec is an explicitly exported flavor. If
371 * srv_secinfo_remove() is called fom an exportfs error path, then
372 * the flavor list was derived from the user's share cmdline,
373 * and all flavors are explicit. If it was called from the unshare path,
374 * build_seclist_nodups() was called with the exponly flag.
377 srv_secinfo_remove(secinfo_t
**pcursec
, int *pcurcnt
, secinfo_t
*remsec
,
380 int ccnt
, c
; /* sec count in current data - cursec */
381 int r
; /* sec count in removal data - remsec */
382 int tcnt
, mcnt
; /* total sec count after removing */
383 struct secinfo
*msec
; /* final secinfo list after removing */
384 struct secinfo
*cursec
;
390 for (r
= 0; r
< remcnt
; r
++) {
392 * At unshare/reshare time, only explicitly shared flavor ref
393 * counts are decremented and propagated to ancestors.
394 * Implicit flavor refs came from shared descendants, and
397 if (! SEC_REF_EXPORTED(&remsec
[r
]))
400 for (c
= 0; c
< ccnt
; c
++) {
401 if (remsec
[r
].s_secinfo
.sc_nfsnum
==
402 cursec
[c
].s_secinfo
.sc_nfsnum
) {
405 * Decrement secinfo reference count by 1.
406 * If this entry is invalid after decrementing
407 * the count (i.e. count < 1), this entry will
410 cursec
[c
].s_refcnt
--;
412 SECREF_TRACE(cursec
, "del_ref",
413 cursec
[c
].s_secinfo
.sc_nfsnum
,
416 ASSERT(cursec
[c
].s_refcnt
>= 0);
418 if (SEC_REF_INVALID(&cursec
[c
]))
427 return; /* no change; no flavors to remove */
430 srv_secinfo_list_free(cursec
, ccnt
);
436 msec
= kmem_zalloc(tcnt
* sizeof (struct secinfo
), KM_SLEEP
);
438 /* walk thru the given secinfo list to remove the flavors */
440 for (c
= 0; c
< ccnt
; c
++) {
441 if (SEC_REF_INVALID(&cursec
[c
])) {
442 srv_secinfo_entry_free(&cursec
[c
]);
444 msec
[mcnt
] = cursec
[c
];
449 ASSERT(mcnt
== tcnt
);
451 * Done. Update curdata.
452 * Free the existing secinfo list in curdata. All pointers
453 * within the list have either been moved to msec or freed
456 kmem_free(*pcursec
, ccnt
* sizeof (struct secinfo
));
463 * For the reshare case, sec flavor accounting happens in 3 steps:
464 * 1) propagate addition of new flavor refs up the ancestor tree
465 * 2) transfer flavor refs of descendants to new/reshared exportdata
466 * 3) propagate removal of old flavor refs up the ancestor tree
468 * srv_secinfo_exp2exp() implements step 2 of a reshare. At this point,
469 * the new flavor list has already been propagated up through the
470 * ancestor tree via srv_secinfo_treeclimb().
472 * If there is more than 1 export reference to an old flavor (i.e. some
473 * of its children shared with this flavor), this flavor information
474 * needs to be transferred to the new exportdata struct. A flavor in
475 * the old exportdata has descendant refs when its s_refcnt > 1 or it
476 * is implicitly shared (M_SEC4_EXPORTED not set in s_flags).
478 * SEC_REF_EXPORTED() is only true when M_SEC4_EXPORTED is set
479 * SEC_REF_SELF() is only true when both M_SEC4_EXPORTED is set and s_refcnt==1
481 * Transferring descendant flavor refcnts happens in 2 passes:
482 * a) flavors used before (oldsecinfo) and after (curdata->ex_secinfo) reshare
483 * b) flavors used before but not after reshare
485 * This routine is used under the protection of exported_lock (RW_WRITER).
488 srv_secinfo_exp2exp(exportdata_t
*curdata
, secinfo_t
*oldsecinfo
, int ocnt
)
490 int ccnt
, c
; /* sec count in current data - curdata */
491 int o
; /* sec count in old data - oldsecinfo */
492 int tcnt
, mcnt
; /* total sec count after the transfer */
493 struct secinfo
*msec
; /* merged secinfo list */
495 ccnt
= curdata
->ex_seccnt
;
498 ASSERT(!(curdata
->ex_flags
& EX_PSEUDO
));
501 * If the oldsecinfo has flavors with more than 1 reference count
502 * and the flavor is specified in the reshare, transfer the flavor
503 * refs to the new seclist (curdata.ex_secinfo).
507 for (o
= 0; o
< ocnt
; o
++) {
509 if (SEC_REF_SELF(&oldsecinfo
[o
])) {
514 for (c
= 0; c
< ccnt
; c
++) {
515 if (oldsecinfo
[o
].s_secinfo
.sc_nfsnum
==
516 curdata
->ex_secinfo
[c
].s_secinfo
.sc_nfsnum
) {
519 * add old reference to the current
522 curdata
->ex_secinfo
[c
].s_refcnt
+=
523 oldsecinfo
[o
].s_refcnt
;
526 * Delete the old export flavor
527 * reference. The initial reference
528 * was created during srv_secinfo_add,
529 * and the count is decremented below
530 * to account for the initial reference.
532 if (SEC_REF_EXPORTED(&oldsecinfo
[o
]))
533 curdata
->ex_secinfo
[c
].s_refcnt
--;
535 SECREF_TRACE(curdata
->ex_path
,
536 "reshare_xfer_common_child_refs",
537 curdata
->ex_secinfo
[c
].s_secinfo
.sc_nfsnum
,
538 curdata
->ex_secinfo
[c
].s_refcnt
);
540 ASSERT(curdata
->ex_secinfo
[c
].s_refcnt
>= 0);
549 return; /* no more transfer to do */
552 * oldsecinfo has flavors referenced by its children that are not
553 * in the current (new) export flavor list. Add these flavors.
555 msec
= kmem_zalloc(tcnt
* sizeof (struct secinfo
), KM_SLEEP
);
557 /* move current secinfo list data to the new list */
558 for (c
= 0; c
< ccnt
; c
++)
559 msec
[c
] = curdata
->ex_secinfo
[c
];
562 * Add the flavor that's not in the new export, but still
563 * referenced by its children.
566 for (o
= 0; o
< ocnt
; o
++) {
567 if (! SEC_REF_SELF(&oldsecinfo
[o
])) {
568 for (c
= 0; c
< ccnt
; c
++) {
569 if (oldsecinfo
[o
].s_secinfo
.sc_nfsnum
==
570 curdata
->ex_secinfo
[c
].s_secinfo
.sc_nfsnum
)
575 * This is the one. Add it. Decrement the ref count
576 * by 1 if the flavor is an explicitly shared flavor
577 * for the oldsecinfo export node.
580 srv_secinfo_copy(&oldsecinfo
[o
], &msec
[mcnt
]);
581 if (SEC_REF_EXPORTED(&oldsecinfo
[o
]))
582 msec
[mcnt
].s_refcnt
--;
584 SECREF_TRACE(curdata
,
585 "reshare_xfer_implicit_child_refs",
586 msec
[mcnt
].s_secinfo
.sc_nfsnum
,
587 msec
[mcnt
].s_refcnt
);
589 ASSERT(msec
[mcnt
].s_refcnt
>= 0);
595 ASSERT(mcnt
== tcnt
);
597 * Done. Update curdata, free the existing secinfo list in
598 * curdata and set the new value.
601 kmem_free(curdata
->ex_secinfo
, ccnt
* sizeof (struct secinfo
));
602 curdata
->ex_seccnt
= tcnt
;
603 curdata
->ex_secinfo
= msec
;
607 * When unsharing an old export node and the old node becomes a pseudo node,
608 * if there is more than 1 export reference to an old flavor (i.e. some of
609 * its children shared with this flavor), this flavor information needs to
610 * be transferred to the new shared node.
612 * This routine is used under the protection of exported_lock (RW_WRITER).
615 srv_secinfo_exp2pseu(exportdata_t
*curdata
, exportdata_t
*olddata
)
617 int ocnt
, o
; /* sec count in transfer data - trandata */
618 int tcnt
, mcnt
; /* total sec count after transfer */
619 struct secinfo
*msec
; /* merged secinfo list */
621 ASSERT(curdata
->ex_flags
& EX_PSEUDO
);
622 ASSERT(curdata
->ex_seccnt
== 0);
624 ocnt
= olddata
->ex_seccnt
;
627 * If the olddata has flavors with more than 1 reference count,
628 * transfer the information to the curdata.
632 for (o
= 0; o
< ocnt
; o
++) {
633 if (SEC_REF_SELF(&olddata
->ex_secinfo
[o
]))
638 return; /* no transfer to do */
640 msec
= kmem_zalloc(tcnt
* sizeof (struct secinfo
), KM_SLEEP
);
643 for (o
= 0; o
< ocnt
; o
++) {
644 if (! SEC_REF_SELF(&olddata
->ex_secinfo
[o
])) {
647 * Decrement the reference count by 1 if the flavor is
648 * an explicitly shared flavor for the olddata export
651 srv_secinfo_copy(&olddata
->ex_secinfo
[o
], &msec
[mcnt
]);
652 msec
[mcnt
].s_flags
= M_RO
;
653 if (SEC_REF_EXPORTED(&olddata
->ex_secinfo
[o
]))
654 msec
[mcnt
].s_refcnt
--;
656 SECREF_TRACE(curdata
, "unshare_morph_pseudo",
657 msec
[mcnt
].s_secinfo
.sc_nfsnum
,
658 msec
[mcnt
].s_refcnt
);
660 ASSERT(msec
[mcnt
].s_refcnt
>= 0);
665 ASSERT(mcnt
== tcnt
);
667 * Done. Update curdata.
668 * Free up the existing secinfo list in curdata and
671 curdata
->ex_seccnt
= tcnt
;
672 curdata
->ex_secinfo
= msec
;
676 * Find for given treenode the exportinfo which has its
677 * exp_visible linked on its exi_visible list.
679 * Note: We could add new pointer either to treenode or
680 * to exp_visible, which will point there directly.
681 * This would buy some speed for some memory.
684 vis2exi(treenode_t
*tnode
)
686 exportinfo_t
*exi_ret
= NULL
;
689 tnode
= tnode
->tree_parent
;
690 if (TREE_ROOT(tnode
)) {
691 exi_ret
= tnode
->tree_exi
;
696 ASSERT(exi_ret
); /* Every visible should have its home exportinfo */
702 * Add or remove the newly exported or unexported security flavors of the
703 * given exportinfo from its ancestors upto the system root.
706 srv_secinfo_treeclimb(exportinfo_t
*exip
, secinfo_t
*sec
, int seccnt
, int isadd
)
708 treenode_t
*tnode
= exip
->exi_tree
;
710 ASSERT(RW_WRITE_HELD(&exported_lock
));
717 * If flavors are being added and the new export root isn't
718 * also VROOT, its implicitly allowed flavors are inherited from
719 * from its pseudonode.
720 * Note - for VROOT exports the implicitly allowed flavors were
721 * transferred from the PSEUDO export in exportfs()
723 if (isadd
&& !(exip
->exi_vp
->v_flag
& VROOT
) &&
724 tnode
->tree_vis
->vis_seccnt
> 0) {
725 srv_secinfo_add(&exip
->exi_export
.ex_secinfo
,
726 &exip
->exi_export
.ex_seccnt
, tnode
->tree_vis
->vis_secinfo
,
727 tnode
->tree_vis
->vis_seccnt
, FALSE
);
731 * Move to parent node and propagate sec flavor
732 * to exportinfo and to visible structures.
734 tnode
= tnode
->tree_parent
;
738 /* If there is exportinfo, update it */
739 if (tnode
->tree_exi
) {
741 &tnode
->tree_exi
->exi_export
.ex_secinfo
;
742 int *pxcnt
= &tnode
->tree_exi
->exi_export
.ex_seccnt
;
743 int is_pseudo
= PSEUDO(tnode
->tree_exi
);
745 srv_secinfo_add(pxsec
, pxcnt
, sec
, seccnt
,
748 srv_secinfo_remove(pxsec
, pxcnt
, sec
, seccnt
);
751 /* Update every visible - only root node has no visible */
752 if (tnode
->tree_vis
) {
753 secinfo_t
**pxsec
= &tnode
->tree_vis
->vis_secinfo
;
754 int *pxcnt
= &tnode
->tree_vis
->vis_seccnt
;
756 srv_secinfo_add(pxsec
, pxcnt
, sec
, seccnt
,
759 srv_secinfo_remove(pxsec
, pxcnt
, sec
, seccnt
);
761 tnode
= tnode
->tree_parent
;
765 /* hash_name is a text substitution for either fid_hash or path_hash */
766 #define exp_hash_unlink(exi, hash_name) \
767 if (*(exi)->hash_name.bckt == (exi)) \
768 *(exi)->hash_name.bckt = (exi)->hash_name.next; \
769 if ((exi)->hash_name.prev) \
770 (exi)->hash_name.prev->hash_name.next = (exi)->hash_name.next; \
771 if ((exi)->hash_name.next) \
772 (exi)->hash_name.next->hash_name.prev = (exi)->hash_name.prev; \
773 (exi)->hash_name.bckt = NULL;
775 #define exp_hash_link(exi, hash_name, bucket) \
776 (exi)->hash_name.bckt = (bucket); \
777 (exi)->hash_name.prev = NULL; \
778 (exi)->hash_name.next = *(bucket); \
779 if ((exi)->hash_name.next) \
780 (exi)->hash_name.next->hash_name.prev = (exi); \
784 export_link(exportinfo_t
*exi
)
788 bckt
= &exptable
[exptablehash(&exi
->exi_fsid
, &exi
->exi_fid
)];
789 exp_hash_link(exi
, fid_hash
, bckt
);
791 bckt
= &exptable_path_hash
[pkp_tab_hash(exi
->exi_export
.ex_path
,
792 strlen(exi
->exi_export
.ex_path
))];
793 exp_hash_link(exi
, path_hash
, bckt
);
797 * Initialization routine for export routines. Should only be called once.
805 rw_init(&exported_lock
, NULL
, RW_DEFAULT
, NULL
);
808 * Allocate the place holder for the public file handle, which
809 * is all zeroes. It is initially set to the root filesystem.
811 exi_root
= kmem_zalloc(sizeof (*exi_root
), KM_SLEEP
);
812 exi_public
= exi_root
;
814 exi_root
->exi_export
.ex_flags
= EX_PUBLIC
;
815 exi_root
->exi_export
.ex_pathlen
= 1; /* length of "/" */
816 exi_root
->exi_export
.ex_path
=
817 kmem_alloc(exi_root
->exi_export
.ex_pathlen
+ 1, KM_SLEEP
);
818 exi_root
->exi_export
.ex_path
[0] = '/';
819 exi_root
->exi_export
.ex_path
[1] = '\0';
821 exi_root
->exi_count
= 1;
822 mutex_init(&exi_root
->exi_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
824 exi_root
->exi_vp
= rootdir
;
825 exi_rootfid
.fid_len
= MAXFIDSZ
;
826 error
= vop_fid_pseudo(exi_root
->exi_vp
, &exi_rootfid
);
828 mutex_destroy(&exi_root
->exi_lock
);
829 kmem_free(exi_root
, sizeof (*exi_root
));
834 * Initialize auth cache and auth cache lock
836 for (i
= 0; i
< AUTH_TABLESIZE
; i
++) {
837 exi_root
->exi_cache
[i
] = kmem_alloc(sizeof (avl_tree_t
),
839 avl_create(exi_root
->exi_cache
[i
], nfsauth_cache_clnt_compar
,
840 sizeof (struct auth_cache_clnt
),
841 offsetof(struct auth_cache_clnt
, authc_link
));
843 rw_init(&exi_root
->exi_cache_lock
, NULL
, RW_DEFAULT
, NULL
);
845 /* setup the fhandle template */
846 exi_root
->exi_fh
.fh_fsid
= rootdir
->v_vfsp
->vfs_fsid
;
847 exi_root
->exi_fh
.fh_xlen
= exi_rootfid
.fid_len
;
848 bcopy(exi_rootfid
.fid_data
, exi_root
->exi_fh
.fh_xdata
,
849 exi_rootfid
.fid_len
);
850 exi_root
->exi_fh
.fh_len
= sizeof (exi_root
->exi_fh
.fh_data
);
853 * Publish the exportinfo in the hash table
855 export_link(exi_root
);
864 * Finalization routine for export routines. Called to cleanup previously
865 * initialization work when the NFS server module could not be loaded correctly.
873 * Deallocate the place holder for the public file handle.
875 srv_secinfo_list_free(exi_root
->exi_export
.ex_secinfo
,
876 exi_root
->exi_export
.ex_seccnt
);
877 mutex_destroy(&exi_root
->exi_lock
);
878 rw_destroy(&exi_root
->exi_cache_lock
);
879 for (i
= 0; i
< AUTH_TABLESIZE
; i
++) {
880 avl_destroy(exi_root
->exi_cache
[i
]);
881 kmem_free(exi_root
->exi_cache
[i
], sizeof (avl_tree_t
));
883 kmem_free(exi_root
, sizeof (*exi_root
));
885 rw_destroy(&exported_lock
);
889 * Check if 2 gss mechanism identifiers are the same.
891 * return FALSE if not the same.
892 * return TRUE if the same.
895 nfs_mech_equal(rpc_gss_OID mech1
, rpc_gss_OID mech2
)
897 if ((mech1
->length
== 0) && (mech2
->length
== 0))
900 if (mech1
->length
!= mech2
->length
)
903 return (bcmp(mech1
->elements
, mech2
->elements
, mech1
->length
) == 0);
907 * This routine is used by rpc to map rpc security number
908 * to nfs specific security flavor number.
910 * The gss callback prototype is
911 * callback(struct svc_req *, gss_cred_id_t *, gss_ctx_id_t *,
912 * rpc_gss_lock_t *, void **),
913 * since nfs does not use the gss_cred_id_t/gss_ctx_id_t arguments
914 * we cast them to void.
918 rfs_gsscallback(struct svc_req
*req
, gss_cred_id_t deleg
, void *gss_context
,
919 rpc_gss_lock_t
*lock
, void **cookie
)
922 rpc_gss_rawcred_t
*raw_cred
;
923 struct exportinfo
*exi
;
926 * We don't deal with delegated credentials.
928 if (deleg
!= GSS_C_NO_CREDENTIAL
)
931 raw_cred
= lock
->raw_cred
;
934 rw_enter(&exported_lock
, RW_READER
);
935 for (i
= 0; i
< EXPTABLESIZE
; i
++) {
938 if (exi
->exi_export
.ex_seccnt
> 0) {
939 struct secinfo
*secp
;
943 secp
= exi
->exi_export
.ex_secinfo
;
944 seccnt
= exi
->exi_export
.ex_seccnt
;
945 for (j
= 0; j
< seccnt
; j
++) {
947 * If there is a map of the triplet
948 * (mechanism, service, qop) between
949 * raw_cred and the exported flavor,
950 * get the psudo flavor number.
951 * Also qop should not be NULL, it
952 * should be "default" or something
955 se
= &secp
[j
].s_secinfo
;
956 if ((se
->sc_rpcnum
== RPCSEC_GSS
) &&
959 se
->sc_gss_mech_type
,
960 raw_cred
->mechanism
)) &&
963 raw_cred
->service
) &&
964 (raw_cred
->qop
== se
->sc_qop
)) {
966 *cookie
= (void *)(uintptr_t)
972 exi
= exi
->fid_hash
.next
;
976 rw_exit(&exported_lock
);
979 * If no nfs pseudo number mapping can be found in the export
980 * table, assign the nfsflavor to NFS_FLAVOR_NOMAP. In V4, we may
981 * recover the flavor mismatch from NFS layer (NFS4ERR_WRONGSEC).
984 * server first shares with krb5i;
985 * client mounts with krb5i;
986 * server re-shares with krb5p;
987 * client tries with krb5i, but no mapping can be found;
988 * rpcsec_gss module calls this routine to do the mapping,
989 * if this routine fails, request is rejected from
991 * What we need is to let the nfs layer rejects the request.
992 * For V4, we can reject with NFS4ERR_WRONGSEC and the client
993 * may recover from it by getting the new flavor via SECINFO.
995 * nfs pseudo number for RPCSEC_GSS mapping (see nfssec.conf)
996 * is owned by IANA (see RFC 2623).
998 * XXX NFS_FLAVOR_NOMAP is defined in Solaris to work around
999 * the implementation issue. This number should not overlap with
1000 * any new IANA defined pseudo flavor numbers.
1002 if (*cookie
== NULL
)
1003 *cookie
= (void *)NFS_FLAVOR_NOMAP
;
1005 lock
->locked
= TRUE
;
1012 * Exportfs system call; credentials should be checked before
1013 * calling this function.
1016 exportfs(struct exportfs_args
*args
, model_t model
, cred_t
*cr
)
1020 struct exportdata
*kex
;
1021 struct exportinfo
*exi
= NULL
;
1022 struct exportinfo
*ex
, *ex1
, *ex2
;
1028 struct secinfo
*exs
;
1029 rpc_gss_callback_t cb
;
1035 STRUCT_HANDLE(exportfs_args
, uap
);
1036 STRUCT_DECL(exportdata
, uexi
);
1037 struct secinfo newsec
[MAX_FLAVORS
];
1039 struct secinfo oldsec
[MAX_FLAVORS
];
1042 struct pathname lookpn
;
1044 STRUCT_SET_HANDLE(uap
, model
, args
);
1046 /* Read in pathname from userspace */
1047 if (error
= pn_get(STRUCT_FGETP(uap
, dname
), UIO_USERSPACE
, &lookpn
))
1050 /* Walk the export list looking for that pathname */
1051 rw_enter(&exported_lock
, RW_READER
);
1052 DTRACE_PROBE(nfss__i__exported_lock1_start
);
1053 for (ex1
= exptable_path_hash
[pkp_tab_hash(lookpn
.pn_path
,
1054 strlen(lookpn
.pn_path
))]; ex1
; ex1
= ex1
->path_hash
.next
) {
1055 if (ex1
!= exi_root
&& 0 ==
1056 strcmp(ex1
->exi_export
.ex_path
, lookpn
.pn_path
)) {
1061 DTRACE_PROBE(nfss__i__exported_lock1_stop
);
1062 rw_exit(&exported_lock
);
1064 /* Is this an unshare? */
1065 if (STRUCT_FGETP(uap
, uex
) == NULL
) {
1069 error
= unexport(ex1
);
1074 /* It is a share or a re-share */
1075 error
= lookupname(STRUCT_FGETP(uap
, dname
), UIO_USERSPACE
,
1077 if (error
== EINVAL
) {
1079 * if fname resolves to / we get EINVAL error
1080 * since we wanted the parent vnode. Try again
1083 error
= lookupname(STRUCT_FGETP(uap
, dname
), UIO_USERSPACE
,
1087 if (!error
&& vp
== NULL
) {
1088 /* Last component of fname not found */
1101 * 'vp' may be an AUTOFS node, so we perform a
1102 * VOP_ACCESS() to trigger the mount of the
1103 * intended filesystem, so we can share the intended
1104 * filesystem instead of the AUTOFS filesystem.
1106 (void) VOP_ACCESS(vp
, 0, 0, cr
, NULL
);
1109 * We're interested in the top most filesystem.
1110 * This is specially important when uap->dname is a trigger
1111 * AUTOFS node, since we're really interested in sharing the
1112 * filesystem AUTOFS mounted as result of the VOP_ACCESS()
1113 * call not the AUTOFS node itself.
1115 if (vn_mountedvfs(vp
) != NULL
) {
1116 if (error
= traverse(&vp
)) {
1127 /* Do not allow sharing another vnode for already shared path */
1128 if (ex1
&& !PSEUDO(ex1
) && !VN_CMP(ex1
->exi_vp
, vp
)) {
1142 bzero(&fid
, sizeof (fid
));
1143 fid
.fid_len
= MAXFIDSZ
;
1144 error
= VOP_FID(vp
, &fid
, NULL
);
1145 fsid
= vp
->v_vfsp
->vfs_fsid
;
1152 * If VOP_FID returns ENOSPC then the fid supplied
1153 * is too small. For now we simply return EREMOTE.
1155 if (error
== ENOSPC
)
1162 * Do not allow re-sharing a shared vnode under a different path
1163 * PSEUDO export has ex_path fabricated, e.g. "/tmp (pseudo)", skip it.
1165 rw_enter(&exported_lock
, RW_READER
);
1166 DTRACE_PROBE(nfss__i__exported_lock2_start
);
1167 for (ex2
= exptable
[exptablehash(&fsid
, &fid
)]; ex2
;
1168 ex2
= ex2
->fid_hash
.next
) {
1169 if (ex2
!= exi_root
&& !PSEUDO(ex2
) &&
1170 VN_CMP(ex2
->exi_vp
, vp
) &&
1171 strcmp(ex2
->exi_export
.ex_path
, lookpn
.pn_path
) != 0) {
1172 DTRACE_PROBE(nfss__i__exported_lock2_stop
);
1173 rw_exit(&exported_lock
);
1181 DTRACE_PROBE(nfss__i__exported_lock2_stop
);
1182 rw_exit(&exported_lock
);
1185 exi
= kmem_zalloc(sizeof (*exi
), KM_SLEEP
);
1186 exi
->exi_fsid
= fsid
;
1190 exi
->exi_volatile_dev
= (vfssw
[vp
->v_vfsp
->vfs_fstype
].vsw_flag
&
1191 VSW_VOLATILEDEV
) ? 1 : 0;
1192 mutex_init(&exi
->exi_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
1196 * Initialize auth cache and auth cache lock
1198 for (i
= 0; i
< AUTH_TABLESIZE
; i
++) {
1199 exi
->exi_cache
[i
] = kmem_alloc(sizeof (avl_tree_t
), KM_SLEEP
);
1200 avl_create(exi
->exi_cache
[i
], nfsauth_cache_clnt_compar
,
1201 sizeof (struct auth_cache_clnt
),
1202 offsetof(struct auth_cache_clnt
, authc_link
));
1204 rw_init(&exi
->exi_cache_lock
, NULL
, RW_DEFAULT
, NULL
);
1207 * Build up the template fhandle
1209 exi
->exi_fh
.fh_fsid
= fsid
;
1210 if (exi
->exi_fid
.fid_len
> sizeof (exi
->exi_fh
.fh_xdata
)) {
1214 exi
->exi_fh
.fh_xlen
= exi
->exi_fid
.fid_len
;
1215 bcopy(exi
->exi_fid
.fid_data
, exi
->exi_fh
.fh_xdata
,
1216 exi
->exi_fid
.fid_len
);
1218 exi
->exi_fh
.fh_len
= sizeof (exi
->exi_fh
.fh_data
);
1220 kex
= &exi
->exi_export
;
1223 * Load in everything, and do sanity checking
1225 STRUCT_INIT(uexi
, model
);
1226 if (copyin(STRUCT_FGETP(uap
, uex
), STRUCT_BUF(uexi
),
1227 STRUCT_SIZE(uexi
))) {
1232 kex
->ex_version
= STRUCT_FGET(uexi
, ex_version
);
1233 if (kex
->ex_version
!= EX_CURRENT_VERSION
) {
1236 "NFS: exportfs requires export struct version 2 - got %d\n",
1242 * Must have at least one security entry
1244 kex
->ex_seccnt
= STRUCT_FGET(uexi
, ex_seccnt
);
1245 if (kex
->ex_seccnt
< 1) {
1250 kex
->ex_path
= STRUCT_FGETP(uexi
, ex_path
);
1251 kex
->ex_pathlen
= STRUCT_FGET(uexi
, ex_pathlen
);
1252 kex
->ex_flags
= STRUCT_FGET(uexi
, ex_flags
);
1253 kex
->ex_anon
= STRUCT_FGET(uexi
, ex_anon
);
1254 kex
->ex_secinfo
= STRUCT_FGETP(uexi
, ex_secinfo
);
1255 kex
->ex_index
= STRUCT_FGETP(uexi
, ex_index
);
1256 kex
->ex_log_buffer
= STRUCT_FGETP(uexi
, ex_log_buffer
);
1257 kex
->ex_log_bufferlen
= STRUCT_FGET(uexi
, ex_log_bufferlen
);
1258 kex
->ex_tag
= STRUCT_FGETP(uexi
, ex_tag
);
1259 kex
->ex_taglen
= STRUCT_FGET(uexi
, ex_taglen
);
1262 * Copy the exported pathname into
1263 * an appropriately sized buffer.
1265 pathbuf
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
1266 if (copyinstr(kex
->ex_path
, pathbuf
, MAXPATHLEN
, &kex
->ex_pathlen
)) {
1267 kmem_free(pathbuf
, MAXPATHLEN
);
1271 kex
->ex_path
= kmem_alloc(kex
->ex_pathlen
+ 1, KM_SLEEP
);
1272 bcopy(pathbuf
, kex
->ex_path
, kex
->ex_pathlen
);
1273 kex
->ex_path
[kex
->ex_pathlen
] = '\0';
1274 kmem_free(pathbuf
, MAXPATHLEN
);
1277 * Get the path to the logging buffer and the tag
1279 if (kex
->ex_flags
& EX_LOG
) {
1280 log_buffer
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
1281 if (copyinstr(kex
->ex_log_buffer
, log_buffer
, MAXPATHLEN
,
1282 &kex
->ex_log_bufferlen
)) {
1283 kmem_free(log_buffer
, MAXPATHLEN
);
1287 kex
->ex_log_buffer
=
1288 kmem_alloc(kex
->ex_log_bufferlen
+ 1, KM_SLEEP
);
1289 bcopy(log_buffer
, kex
->ex_log_buffer
, kex
->ex_log_bufferlen
);
1290 kex
->ex_log_buffer
[kex
->ex_log_bufferlen
] = '\0';
1291 kmem_free(log_buffer
, MAXPATHLEN
);
1293 tagbuf
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
1294 if (copyinstr(kex
->ex_tag
, tagbuf
, MAXPATHLEN
,
1296 kmem_free(tagbuf
, MAXPATHLEN
);
1300 kex
->ex_tag
= kmem_alloc(kex
->ex_taglen
+ 1, KM_SLEEP
);
1301 bcopy(tagbuf
, kex
->ex_tag
, kex
->ex_taglen
);
1302 kex
->ex_tag
[kex
->ex_taglen
] = '\0';
1303 kmem_free(tagbuf
, MAXPATHLEN
);
1307 * Load the security information for each flavor
1309 allocsize
= kex
->ex_seccnt
* SIZEOF_STRUCT(secinfo
, model
);
1310 sp
= kmem_zalloc(allocsize
, KM_SLEEP
);
1311 if (copyin(kex
->ex_secinfo
, sp
, allocsize
)) {
1312 kmem_free(sp
, allocsize
);
1318 * All of these nested structures need to be converted to
1319 * the kernel native format.
1321 if (model
!= DATAMODEL_NATIVE
) {
1323 struct secinfo
*sp2
;
1325 allocsize2
= kex
->ex_seccnt
* sizeof (struct secinfo
);
1326 sp2
= kmem_zalloc(allocsize2
, KM_SLEEP
);
1328 for (i
= 0; i
< kex
->ex_seccnt
; i
++) {
1329 STRUCT_HANDLE(secinfo
, usi
);
1331 STRUCT_SET_HANDLE(usi
, model
,
1332 (struct secinfo
*)((caddr_t
)sp
+
1333 (i
* SIZEOF_STRUCT(secinfo
, model
))));
1334 bcopy(STRUCT_FGET(usi
, s_secinfo
.sc_name
),
1335 sp2
[i
].s_secinfo
.sc_name
, MAX_NAME_LEN
);
1336 sp2
[i
].s_secinfo
.sc_nfsnum
=
1337 STRUCT_FGET(usi
, s_secinfo
.sc_nfsnum
);
1338 sp2
[i
].s_secinfo
.sc_rpcnum
=
1339 STRUCT_FGET(usi
, s_secinfo
.sc_rpcnum
);
1340 bcopy(STRUCT_FGET(usi
, s_secinfo
.sc_gss_mech
),
1341 sp2
[i
].s_secinfo
.sc_gss_mech
, MAX_NAME_LEN
);
1342 sp2
[i
].s_secinfo
.sc_gss_mech_type
=
1343 STRUCT_FGETP(usi
, s_secinfo
.sc_gss_mech_type
);
1344 sp2
[i
].s_secinfo
.sc_qop
=
1345 STRUCT_FGET(usi
, s_secinfo
.sc_qop
);
1346 sp2
[i
].s_secinfo
.sc_service
=
1347 STRUCT_FGET(usi
, s_secinfo
.sc_service
);
1349 sp2
[i
].s_flags
= STRUCT_FGET(usi
, s_flags
);
1350 sp2
[i
].s_window
= STRUCT_FGET(usi
, s_window
);
1351 sp2
[i
].s_rootid
= STRUCT_FGET(usi
, s_rootid
);
1352 sp2
[i
].s_rootcnt
= STRUCT_FGET(usi
, s_rootcnt
);
1353 sp2
[i
].s_rootnames
= STRUCT_FGETP(usi
, s_rootnames
);
1355 kmem_free(sp
, allocsize
);
1357 allocsize
= allocsize2
;
1360 kex
->ex_secinfo
= sp
;
1363 * And now copy rootnames for each individual secinfo.
1367 while (allocd_seccnt
< kex
->ex_seccnt
) {
1369 exs
= &sp
[allocd_seccnt
];
1370 if (exs
->s_rootcnt
> 0) {
1371 if (!sec_svc_loadrootnames(exs
->s_secinfo
.sc_rpcnum
,
1372 exs
->s_rootcnt
, &exs
->s_rootnames
, model
)) {
1378 if (exs
->s_secinfo
.sc_rpcnum
== RPCSEC_GSS
) {
1379 rpc_gss_OID mech_tmp
;
1380 STRUCT_DECL(rpc_gss_OID_s
, umech_tmp
);
1381 caddr_t elements_tmp
;
1383 /* Copyin mechanism type */
1384 STRUCT_INIT(umech_tmp
, model
);
1385 mech_tmp
= kmem_alloc(sizeof (*mech_tmp
), KM_SLEEP
);
1386 if (copyin(exs
->s_secinfo
.sc_gss_mech_type
,
1387 STRUCT_BUF(umech_tmp
), STRUCT_SIZE(umech_tmp
))) {
1388 kmem_free(mech_tmp
, sizeof (*mech_tmp
));
1392 mech_tmp
->length
= STRUCT_FGET(umech_tmp
, length
);
1393 mech_tmp
->elements
= STRUCT_FGETP(umech_tmp
, elements
);
1395 elements_tmp
= kmem_alloc(mech_tmp
->length
, KM_SLEEP
);
1396 if (copyin(mech_tmp
->elements
, elements_tmp
,
1397 mech_tmp
->length
)) {
1398 kmem_free(elements_tmp
, mech_tmp
->length
);
1399 kmem_free(mech_tmp
, sizeof (*mech_tmp
));
1403 mech_tmp
->elements
= elements_tmp
;
1404 exs
->s_secinfo
.sc_gss_mech_type
= mech_tmp
;
1413 * Init the secinfo reference count and mark these flavors
1414 * explicitly exported flavors.
1416 for (i
= 0; i
< kex
->ex_seccnt
; i
++) {
1417 kex
->ex_secinfo
[i
].s_flags
|= M_4SEC_EXPORTED
;
1418 kex
->ex_secinfo
[i
].s_refcnt
= 1;
1422 * Set up rpcsec_gss callback routine entry if any.
1425 cb
.callback
= rfs_gsscallback
;
1426 cb
.program
= NFS_ACL_PROGRAM
;
1427 for (cb
.version
= NFS_ACL_VERSMIN
;
1428 cb
.version
<= NFS_ACL_VERSMAX
; cb
.version
++) {
1429 (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK
,
1433 cb
.program
= NFS_PROGRAM
;
1434 for (cb
.version
= NFS_VERSMIN
;
1435 cb
.version
<= NFS_VERSMAX
; cb
.version
++) {
1436 (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK
,
1442 * Check the index flag. Do this here to avoid holding the
1443 * lock while dealing with the index option (as we do with
1444 * the public option).
1446 if (kex
->ex_flags
& EX_INDEX
) {
1447 if (!kex
->ex_index
) { /* sanity check */
1451 if (error
= loadindex(kex
))
1455 if (kex
->ex_flags
& EX_LOG
) {
1456 if (error
= nfslog_setup(exi
))
1461 * Insert the new entry at the front of the export list
1463 rw_enter(&exported_lock
, RW_WRITER
);
1464 DTRACE_PROBE(nfss__i__exported_lock3_start
);
1469 * Check the rest of the list for an old entry for the fs.
1470 * If one is found then unlink it, wait until this is the
1471 * only reference and then free it.
1473 for (ex
= exi
->fid_hash
.next
; ex
!= NULL
; ex
= ex
->fid_hash
.next
) {
1474 if (ex
!= exi_root
&& VN_CMP(ex
->exi_vp
, vp
)) {
1481 * If the public filehandle is pointing at the
1482 * old entry, then point it back at the root.
1484 if (ex
!= NULL
&& ex
== exi_public
)
1485 exi_public
= exi_root
;
1488 * If the public flag is on, make the global exi_public
1489 * point to this entry and turn off the public bit so that
1490 * we can distinguish it from the place holder export.
1492 if (kex
->ex_flags
& EX_PUBLIC
) {
1494 kex
->ex_flags
&= ~EX_PUBLIC
;
1497 #ifdef VOLATILE_FH_TEST
1499 * Set up the volatile_id value if volatile on share.
1500 * The list of volatile renamed filehandles is always destroyed,
1501 * if the fs was reshared.
1503 if (kex
->ex_flags
& EX_VOLFH
)
1504 exi
->exi_volatile_id
= gethrestime_sec();
1506 mutex_init(&exi
->exi_vol_rename_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
1507 #endif /* VOLATILE_FH_TEST */
1510 * If this is a new export, then climb up
1511 * the tree and check if any pseudo exports
1512 * need to be created to provide a path for
1516 error
= treeclimb_export(exi
);
1520 /* If it's a re-export update namespace tree */
1521 exi
->exi_tree
= ex
->exi_tree
;
1522 exi
->exi_tree
->tree_exi
= exi
;
1526 * build a unique flavor list from the flavors specified
1527 * in the share cmd. unique means that each flavor only
1528 * appears once in the secinfo list -- no duplicates allowed.
1530 newcnt
= build_seclist_nodups(&exi
->exi_export
, newsec
, FALSE
);
1532 srv_secinfo_treeclimb(exi
, newsec
, newcnt
, TRUE
);
1535 * If re-sharing an old export entry, update the secinfo data
1536 * depending on if the old entry is a pseudo node or not.
1539 oldcnt
= build_seclist_nodups(&ex
->exi_export
, oldsec
, FALSE
);
1542 * The dir being shared is a pseudo export root (which
1543 * will be transformed into a real export root). The
1544 * flavor(s) of the new share were propagated to the
1545 * ancestors by srv_secinfo_treeclimb() above. Now
1546 * transfer the implicit flavor refs from the old
1547 * pseudo exprot root to the new (real) export root.
1549 srv_secinfo_add(&exi
->exi_export
.ex_secinfo
,
1550 &exi
->exi_export
.ex_seccnt
, oldsec
, oldcnt
, TRUE
);
1553 * First transfer implicit flavor refs to new export.
1554 * Remove old flavor refs last.
1556 srv_secinfo_exp2exp(&exi
->exi_export
, oldsec
, oldcnt
);
1557 srv_secinfo_treeclimb(ex
, oldsec
, oldcnt
, FALSE
);
1562 * If it's a re-export and the old entry has a pseudonode list,
1563 * transfer it to the new export.
1565 if (ex
!= NULL
&& (ex
->exi_visible
!= NULL
)) {
1566 exi
->exi_visible
= ex
->exi_visible
;
1567 ex
->exi_visible
= NULL
;
1570 DTRACE_PROBE(nfss__i__exported_lock3_stop
);
1571 rw_exit(&exported_lock
);
1573 if (exi_public
== exi
|| kex
->ex_flags
& EX_LOG
) {
1575 * Log share operation to this buffer only.
1577 nfslog_share_record(exi
, cr
);
1586 /* Unlink the new export in exptable. */
1588 DTRACE_PROBE(nfss__i__exported_lock3_stop
);
1589 rw_exit(&exported_lock
);
1591 if (kex
->ex_flags
& EX_INDEX
)
1592 kmem_free(kex
->ex_index
, strlen(kex
->ex_index
) + 1);
1594 /* free partially completed allocation */
1595 while (--allocd_seccnt
>= 0) {
1596 exs
= &kex
->ex_secinfo
[allocd_seccnt
];
1597 srv_secinfo_entry_free(exs
);
1600 if (kex
->ex_secinfo
) {
1601 kmem_free(kex
->ex_secinfo
,
1602 kex
->ex_seccnt
* sizeof (struct secinfo
));
1606 if ((kex
->ex_flags
& EX_LOG
) && kex
->ex_tag
!= NULL
)
1607 kmem_free(kex
->ex_tag
, kex
->ex_taglen
+ 1);
1609 if ((kex
->ex_flags
& EX_LOG
) && kex
->ex_log_buffer
!= NULL
)
1610 kmem_free(kex
->ex_log_buffer
, kex
->ex_log_bufferlen
+ 1);
1612 kmem_free(kex
->ex_path
, kex
->ex_pathlen
+ 1);
1617 mutex_destroy(&exi
->exi_lock
);
1618 rw_destroy(&exi
->exi_cache_lock
);
1619 for (i
= 0; i
< AUTH_TABLESIZE
; i
++) {
1620 avl_destroy(exi
->exi_cache
[i
]);
1621 kmem_free(exi
->exi_cache
[i
], sizeof (avl_tree_t
));
1624 kmem_free(exi
, sizeof (*exi
));
1630 * Remove the exportinfo from the export list
1633 export_unlink(struct exportinfo
*exi
)
1635 ASSERT(RW_WRITE_HELD(&exported_lock
));
1637 exp_hash_unlink(exi
, fid_hash
);
1638 exp_hash_unlink(exi
, path_hash
);
1642 * Unexport an exported filesystem
1645 unexport(struct exportinfo
*exi
)
1647 struct secinfo cursec
[MAX_FLAVORS
];
1650 rw_enter(&exported_lock
, RW_WRITER
);
1652 /* Check if exi is still linked in the export table */
1653 if (!EXP_LINKED(exi
) || PSEUDO(exi
)) {
1654 rw_exit(&exported_lock
);
1661 * Remove security flavors before treeclimb_unexport() is called
1662 * because srv_secinfo_treeclimb needs the namespace tree
1664 curcnt
= build_seclist_nodups(&exi
->exi_export
, cursec
, TRUE
);
1666 srv_secinfo_treeclimb(exi
, cursec
, curcnt
, FALSE
);
1669 * If there's a visible list, then need to leave
1670 * a pseudo export here to retain the visible list
1671 * for paths to exports below.
1673 if (exi
->exi_visible
) {
1674 struct exportinfo
*newexi
;
1676 newexi
= pseudo_exportfs(exi
->exi_vp
, &exi
->exi_fid
,
1677 exi
->exi_visible
, &exi
->exi_export
);
1678 exi
->exi_visible
= NULL
;
1680 /* interconnect the existing treenode with the new exportinfo */
1681 newexi
->exi_tree
= exi
->exi_tree
;
1682 newexi
->exi_tree
->tree_exi
= newexi
;
1684 treeclimb_unexport(exi
);
1687 rw_exit(&exported_lock
);
1690 * Need to call into the NFSv4 server and release all data
1691 * held on this particular export. This is important since
1692 * the v4 server may be holding file locks or vnodes under
1695 rfs4_clean_state_exi(exi
);
1698 * Notify the lock manager that the filesystem is being
1704 * If this was a public export, restore
1705 * the public filehandle to the root.
1707 if (exi
== exi_public
) {
1708 exi_public
= exi_root
;
1710 nfslog_share_record(exi_public
, CRED());
1713 if (exi
->exi_export
.ex_flags
& EX_LOG
) {
1714 nfslog_unshare_record(exi
, CRED());
1722 * Get file handle system call.
1723 * Takes file name and returns a file handle for it.
1724 * Credentials must be verified before calling.
1727 nfs_getfh(struct nfs_getfh_args
*args
, model_t model
, cred_t
*cr
)
1730 char buf
[NFS3_MAXFHSIZE
];
1731 char *logptr
, logbuf
[NFS3_MAXFHSIZE
];
1732 int l
= NFS3_MAXFHSIZE
;
1735 struct exportinfo
*exi
;
1738 STRUCT_HANDLE(nfs_getfh_args
, uap
);
1741 model
= model
; /* STRUCT macros don't always use it */
1744 STRUCT_SET_HANDLE(uap
, model
, args
);
1746 error
= lookupname(STRUCT_FGETP(uap
, fname
), UIO_USERSPACE
,
1748 if (error
== EINVAL
) {
1750 * if fname resolves to / we get EINVAL error
1751 * since we wanted the parent vnode. Try again
1754 error
= lookupname(STRUCT_FGETP(uap
, fname
), UIO_USERSPACE
,
1758 if (!error
&& vp
== NULL
) {
1760 * Last component of fname not found
1771 * 'vp' may be an AUTOFS node, so we perform a
1772 * VOP_ACCESS() to trigger the mount of the
1773 * intended filesystem, so we can share the intended
1774 * filesystem instead of the AUTOFS filesystem.
1776 (void) VOP_ACCESS(vp
, 0, 0, cr
, NULL
);
1779 * We're interested in the top most filesystem.
1780 * This is specially important when uap->dname is a trigger
1781 * AUTOFS node, since we're really interested in sharing the
1782 * filesystem AUTOFS mounted as result of the VOP_ACCESS()
1783 * call not the AUTOFS node itself.
1785 if (vn_mountedvfs(vp
) != NULL
) {
1786 if (error
= traverse(&vp
)) {
1794 vers
= STRUCT_FGET(uap
, vers
);
1795 exi
= nfs_vptoexi(dvp
, vp
, cr
, NULL
, &error
, FALSE
);
1797 if (vers
== NFS_VERSION
) {
1798 error
= makefh((fhandle_t
*)buf
, vp
, exi
);
1801 } else if (vers
== NFS_V3
) {
1804 error
= makefh3(&fh
, vp
, exi
);
1805 l
= RNDUP(fh
.fh3_length
);
1806 if (!error
&& (l
> sizeof (fhandle3_t
)))
1811 sz
= sizeof (fsid_t
);
1812 bcopy(&fh
.fh3_fsid
, &buf
[i
], sz
);
1816 * For backwards compatibility, the
1817 * fid length may be less than
1818 * NFS_FHMAXDATA, but it was always
1819 * encoded as NFS_FHMAXDATA bytes.
1822 sz
= sizeof (ushort_t
);
1823 bcopy(&fh
.fh3_len
, &buf
[i
], sz
);
1825 bcopy(fh
.fh3_data
, &buf
[i
], fh
.fh3_len
);
1827 pad
= (NFS_FHMAXDATA
- fh
.fh3_len
);
1829 bzero(&buf
[i
], pad
);
1834 sz
= sizeof (ushort_t
);
1835 bcopy(&fh
.fh3_xlen
, &buf
[i
], sz
);
1837 bcopy(fh
.fh3_xdata
, &buf
[i
], fh
.fh3_xlen
);
1839 pad
= (NFS_FHMAXDATA
- fh
.fh3_xlen
);
1841 bzero(&buf
[i
], pad
);
1847 * If we need to do NFS logging, the filehandle
1848 * must be downsized to 32 bytes.
1850 if (!error
&& exi
->exi_export
.ex_flags
& EX_LOG
) {
1852 sz
= sizeof (fsid_t
);
1853 bcopy(&fh
.fh3_fsid
, &logbuf
[i
], sz
);
1855 sz
= sizeof (ushort_t
);
1856 bcopy(&fh
.fh3_len
, &logbuf
[i
], sz
);
1859 bcopy(fh
.fh3_data
, &logbuf
[i
], sz
);
1861 sz
= sizeof (ushort_t
);
1862 bcopy(&fh
.fh3_xlen
, &logbuf
[i
], sz
);
1865 bcopy(fh
.fh3_xdata
, &logbuf
[i
], sz
);
1869 if (!error
&& exi
->exi_export
.ex_flags
& EX_LOG
) {
1870 nfslog_getfh(exi
, (fhandle_t
*)logptr
,
1871 STRUCT_FGETP(uap
, fname
), UIO_USERSPACE
, cr
);
1875 if (copyout(&l
, STRUCT_FGETP(uap
, lenp
), sizeof (int)))
1877 if (copyout(buf
, STRUCT_FGETP(uap
, fhp
), l
))
1889 * Strategy: if vp is in the export list, then
1890 * return the associated file handle. Otherwise, ".."
1891 * once up the vp and try again, until the root of the
1892 * filesystem is reached.
1895 nfs_vptoexi(vnode_t
*dvp
, vnode_t
*vp
, cred_t
*cr
, int *walk
,
1896 int *err
, bool_t v4srv
)
1900 struct exportinfo
*exi
;
1911 bzero(&fid
, sizeof (fid
));
1912 fid
.fid_len
= MAXFIDSZ
;
1913 error
= vop_fid_pseudo(vp
, &fid
);
1916 * If vop_fid_pseudo returns ENOSPC then the fid
1917 * supplied is too small. For now we simply
1920 if (error
== ENOSPC
)
1926 exi
= checkexport4(&vp
->v_vfsp
->vfs_fsid
, &fid
, vp
);
1928 exi
= checkexport(&vp
->v_vfsp
->vfs_fsid
, &fid
);
1932 * Found the export info
1938 * We have just failed finding a matching export.
1939 * If we're at the root of this filesystem, then
1940 * it's time to stop (with failure).
1942 if (vp
->v_flag
& VROOT
) {
1951 * Now, do a ".." up vp. If dvp is supplied, use it,
1952 * otherwise, look it up.
1955 error
= VOP_LOOKUP(vp
, "..", &dvp
, NULL
, 0, NULL
, cr
,
1977 chk_clnt_sec(exportinfo_t
*exi
, struct svc_req
*req
)
1983 * Get the nfs flavor number from xprt.
1985 nfsflavor
= (int)(uintptr_t)req
->rq_xprt
->xp_cookie
;
1987 sp
= exi
->exi_export
.ex_secinfo
;
1988 for (i
= 0; i
< exi
->exi_export
.ex_seccnt
; i
++) {
1989 if ((nfsflavor
== sp
[i
].s_secinfo
.sc_nfsnum
) &&
1990 SEC_REF_EXPORTED(sp
+ i
))
1997 * Make an fhandle from a vnode
2000 makefh(fhandle_t
*fh
, vnode_t
*vp
, exportinfo_t
*exi
)
2004 *fh
= exi
->exi_fh
; /* struct copy */
2006 error
= VOP_FID(vp
, (fid_t
*)&fh
->fh_len
, NULL
);
2009 * Should be something other than EREMOTE
2017 * This routine makes an overloaded V2 fhandle which contains
2020 * Note that the first four octets contain the length octet,
2021 * the status octet, and two padded octets to make them XDR
2022 * four-octet aligned.
2025 * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+
2026 * | l | s | | | sec_1 |...| sec_n |...| |
2027 * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+
2031 * the status octet s indicates whether there are more security
2032 * flavors (1 means yes, 0 means no) that require the client to
2033 * perform another 0x81 LOOKUP to get them,
2035 * the length octet l is the length describing the number of
2036 * valid octets that follow. (l = 4 * n, where n is the number
2037 * of security flavors sent in the current overloaded filehandle.)
2039 * sec_index should always be in the inclusive range: [1 - ex_seccnt],
2040 * and it tells server where to start within the secinfo array.
2041 * Usually it will always be 1; however, if more flavors are used
2042 * for the public export than can be encoded in the overloaded FH
2043 * (7 for NFS2), subsequent SNEGO MCLs will have a larger index
2044 * so the server will pick up where it left off from the previous
2047 * With NFS4 support, implicitly allowed flavors are also in
2048 * the secinfo array; however, they should not be returned in
2049 * SNEGO MCL replies.
2052 makefh_ol(fhandle_t
*fh
, exportinfo_t
*exi
, uint_t sec_index
)
2054 secinfo_t sec
[MAX_FLAVORS
];
2055 int totalcnt
, i
, *ipt
, cnt
, seccnt
, secidx
, fh_max_cnt
;
2058 if (fh
== NULL
|| exi
== NULL
|| sec_index
< 1)
2062 * WebNFS clients need to know the unique set of explicitly
2063 * shared flavors in used for the public export. When
2064 * "TRUE" is passed to build_seclist_nodups(), only explicitly
2065 * shared flavors are included in the list.
2067 seccnt
= build_seclist_nodups(&exi
->exi_export
, sec
, TRUE
);
2068 if (sec_index
> seccnt
)
2071 fh_max_cnt
= (NFS_FHSIZE
/ sizeof (int)) - 1;
2072 totalcnt
= seccnt
- sec_index
+ 1;
2073 cnt
= totalcnt
> fh_max_cnt
? fh_max_cnt
: totalcnt
;
2077 * Encode the length octet representing the number of
2078 * security flavors (in bytes) in this overloaded fh.
2080 *c
= cnt
* sizeof (int);
2083 * Encode the status octet that indicates whether there
2084 * are more security flavors the client needs to get.
2086 *(c
+ 1) = totalcnt
> fh_max_cnt
;
2089 * put security flavors in the overloaded fh
2091 ipt
= (int *)(c
+ sizeof (int32_t));
2092 secidx
= sec_index
- 1;
2093 for (i
= 0; i
< cnt
; i
++) {
2094 ipt
[i
] = htonl(sec
[i
+ secidx
].s_secinfo
.sc_nfsnum
);
2100 * Make an nfs_fh3 from a vnode
2103 makefh3(nfs_fh3
*fh
, vnode_t
*vp
, struct exportinfo
*exi
)
2108 bzero(&fid
, sizeof (fid
));
2109 fid
.fid_len
= sizeof (fh
->fh3_data
);
2110 error
= VOP_FID(vp
, &fid
, NULL
);
2114 bzero(fh
, sizeof (nfs_fh3
));
2115 fh
->fh3_fsid
= exi
->exi_fsid
;
2116 fh
->fh3_len
= fid
.fid_len
;
2117 bcopy(fid
.fid_data
, fh
->fh3_data
, fh
->fh3_len
);
2119 fh
->fh3_xlen
= exi
->exi_fid
.fid_len
;
2120 ASSERT(fh
->fh3_xlen
<= sizeof (fh
->fh3_xdata
));
2121 bcopy(exi
->exi_fid
.fid_data
, fh
->fh3_xdata
, fh
->fh3_xlen
);
2123 fh
->fh3_length
= sizeof (fh
->fh3_fsid
)
2124 + sizeof (fh
->fh3_len
) + fh
->fh3_len
2125 + sizeof (fh
->fh3_xlen
) + fh
->fh3_xlen
;
2132 * This routine makes an overloaded V3 fhandle which contains
2140 * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+
2141 * |s | | | | sec_1 | sec_2 | ... | sec_n |
2142 * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+
2144 * len = 4 * (n+1), where n is the number of security flavors
2145 * sent in the current overloaded filehandle.
2147 * the status octet s indicates whether there are more security
2148 * mechanisms (1 means yes, 0 means no) that require the client
2149 * to perform another 0x81 LOOKUP to get them.
2151 * Three octets are padded after the status octet.
2154 makefh3_ol(nfs_fh3
*fh
, struct exportinfo
*exi
, uint_t sec_index
)
2156 secinfo_t sec
[MAX_FLAVORS
];
2157 int totalcnt
, cnt
, *ipt
, i
, seccnt
, fh_max_cnt
, secidx
;
2160 if (fh
== NULL
|| exi
== NULL
|| sec_index
< 1)
2164 * WebNFS clients need to know the unique set of explicitly
2165 * shared flavors in used for the public export. When
2166 * "TRUE" is passed to build_seclist_nodups(), only explicitly
2167 * shared flavors are included in the list.
2169 seccnt
= build_seclist_nodups(&exi
->exi_export
, sec
, TRUE
);
2171 if (sec_index
> seccnt
)
2174 fh_max_cnt
= (NFS3_FHSIZE
/ sizeof (int)) - 1;
2175 totalcnt
= seccnt
- sec_index
+ 1;
2176 cnt
= totalcnt
> fh_max_cnt
? fh_max_cnt
: totalcnt
;
2179 * Place the length in fh3_length representing the number
2180 * of security flavors (in bytes) in this overloaded fh.
2182 fh
->fh3_flags
= FH_WEBNFS
;
2183 fh
->fh3_length
= (cnt
+1) * sizeof (int32_t);
2185 c
= (char *)&fh
->fh3_u
.nfs_fh3_i
.fh3_i
;
2187 * Encode the status octet that indicates whether there
2188 * are more security flavors the client needs to get.
2190 *c
= totalcnt
> fh_max_cnt
;
2193 * put security flavors in the overloaded fh
2195 secidx
= sec_index
- 1;
2196 ipt
= (int *)(c
+ sizeof (int32_t));
2197 for (i
= 0; i
< cnt
; i
++) {
2198 ipt
[i
] = htonl(sec
[i
+ secidx
].s_secinfo
.sc_nfsnum
);
2204 * Make an nfs_fh4 from a vnode
2207 makefh4(nfs_fh4
*fh
, vnode_t
*vp
, struct exportinfo
*exi
)
2210 nfs_fh4_fmt_t
*fh_fmtp
= (nfs_fh4_fmt_t
*)fh
->nfs_fh4_val
;
2213 bzero(&fid
, sizeof (fid
));
2214 fid
.fid_len
= MAXFIDSZ
;
2216 * vop_fid_pseudo() is used to set up NFSv4 namespace, so
2217 * use vop_fid_pseudo() here to get the fid instead of VOP_FID.
2219 error
= vop_fid_pseudo(vp
, &fid
);
2223 fh
->nfs_fh4_len
= NFS_FH4_LEN
;
2225 fh_fmtp
->fh4_i
.fhx_fsid
= exi
->exi_fh
.fh_fsid
;
2226 fh_fmtp
->fh4_i
.fhx_xlen
= exi
->exi_fh
.fh_xlen
;
2228 bzero(fh_fmtp
->fh4_i
.fhx_data
, sizeof (fh_fmtp
->fh4_i
.fhx_data
));
2229 bzero(fh_fmtp
->fh4_i
.fhx_xdata
, sizeof (fh_fmtp
->fh4_i
.fhx_xdata
));
2230 ASSERT(exi
->exi_fh
.fh_xlen
<= sizeof (fh_fmtp
->fh4_i
.fhx_xdata
));
2231 bcopy(exi
->exi_fh
.fh_xdata
, fh_fmtp
->fh4_i
.fhx_xdata
,
2232 exi
->exi_fh
.fh_xlen
);
2234 fh_fmtp
->fh4_len
= fid
.fid_len
;
2235 ASSERT(fid
.fid_len
<= sizeof (fh_fmtp
->fh4_data
));
2236 bcopy(fid
.fid_data
, fh_fmtp
->fh4_data
, fid
.fid_len
);
2237 fh_fmtp
->fh4_flag
= 0;
2239 #ifdef VOLATILE_FH_TEST
2242 * Use the rnode volatile_id value to add volatility to the fh.
2244 * For testing purposes there are currently two scenarios, based
2245 * on whether the filesystem was shared with "volatile_fh"
2246 * or "expire_on_rename". In the first case, use the value of
2247 * export struct share_time as the volatile_id. In the second
2248 * case use the vnode volatile_id value (which is set to the
2249 * time in which the file was renamed).
2251 * Note that the above are temporary constructs for testing only
2254 if (exi
->exi_export
.ex_flags
& EX_VOLRNM
) {
2255 fh_fmtp
->fh4_volatile_id
= find_volrnm_fh_id(exi
, fh
);
2256 } else if (exi
->exi_export
.ex_flags
& EX_VOLFH
) {
2257 fh_fmtp
->fh4_volatile_id
= exi
->exi_volatile_id
;
2259 fh_fmtp
->fh4_volatile_id
= 0;
2261 #endif /* VOLATILE_FH_TEST */
2267 * Convert an fhandle into a vnode.
2268 * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode.
2269 * WARNING: users of this routine must do a VN_RELE on the vnode when they
2273 nfs_fhtovp(fhandle_t
*fh
, struct exportinfo
*exi
)
2280 TRACE_0(TR_FAC_NFS
, TR_FHTOVP_START
,
2284 TRACE_1(TR_FAC_NFS
, TR_FHTOVP_END
,
2285 "fhtovp_end:(%S)", "exi NULL");
2286 return (NULL
); /* not exported */
2289 ASSERT(exi
->exi_vp
!= NULL
);
2291 if (PUBLIC_FH2(fh
)) {
2292 if (exi
->exi_export
.ex_flags
& EX_PUBLIC
) {
2293 TRACE_1(TR_FAC_NFS
, TR_FHTOVP_END
,
2294 "fhtovp_end:(%S)", "root not exported");
2302 vfsp
= exi
->exi_vp
->v_vfsp
;
2303 ASSERT(vfsp
!= NULL
);
2304 fidp
= (fid_t
*)&fh
->fh_len
;
2306 error
= VFS_VGET(vfsp
, &vp
, fidp
);
2307 if (error
|| vp
== NULL
) {
2308 TRACE_1(TR_FAC_NFS
, TR_FHTOVP_END
,
2309 "fhtovp_end:(%S)", "VFS_GET failed or vp NULL");
2312 TRACE_1(TR_FAC_NFS
, TR_FHTOVP_END
,
2313 "fhtovp_end:(%S)", "end");
2318 * Convert an nfs_fh3 into a vnode.
2319 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2320 * WARNING: users of this routine must do a VN_RELE on the vnode when they
2324 nfs3_fhtovp(nfs_fh3
*fh
, struct exportinfo
*exi
)
2332 return (NULL
); /* not exported */
2334 ASSERT(exi
->exi_vp
!= NULL
);
2336 if (PUBLIC_FH3(fh
)) {
2337 if (exi
->exi_export
.ex_flags
& EX_PUBLIC
)
2344 if (fh
->fh3_length
< NFS3_OLDFHSIZE
||
2345 fh
->fh3_length
> NFS3_MAXFHSIZE
)
2348 vfsp
= exi
->exi_vp
->v_vfsp
;
2349 ASSERT(vfsp
!= NULL
);
2350 fidp
= FH3TOFIDP(fh
);
2352 error
= VFS_VGET(vfsp
, &vp
, fidp
);
2353 if (error
|| vp
== NULL
)
2360 * Convert an nfs_fh4 into a vnode.
2361 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2362 * WARNING: users of this routine must do a VN_RELE on the vnode when they
2366 nfs4_fhtovp(nfs_fh4
*fh
, struct exportinfo
*exi
, nfsstat4
*statp
)
2372 nfs_fh4_fmt_t
*fh_fmtp
;
2373 #ifdef VOLATILE_FH_TEST
2374 uint32_t volatile_id
= 0;
2375 #endif /* VOLATILE_FH_TEST */
2378 *statp
= NFS4ERR_STALE
;
2379 return (NULL
); /* not exported */
2381 ASSERT(exi
->exi_vp
!= NULL
);
2383 /* caller should have checked this */
2384 ASSERT(fh
->nfs_fh4_len
>= NFS_FH4_LEN
);
2386 fh_fmtp
= (nfs_fh4_fmt_t
*)fh
->nfs_fh4_val
;
2387 vfsp
= exi
->exi_vp
->v_vfsp
;
2388 ASSERT(vfsp
!= NULL
);
2389 fidp
= (fid_t
*)&fh_fmtp
->fh4_len
;
2391 #ifdef VOLATILE_FH_TEST
2392 /* XXX check if volatile - should be changed later */
2393 if (exi
->exi_export
.ex_flags
& (EX_VOLRNM
| EX_VOLFH
)) {
2395 * Filesystem is shared with volatile filehandles
2397 if (exi
->exi_export
.ex_flags
& EX_VOLRNM
)
2398 volatile_id
= find_volrnm_fh_id(exi
, fh
);
2400 volatile_id
= exi
->exi_volatile_id
;
2402 if (fh_fmtp
->fh4_volatile_id
!= volatile_id
) {
2403 *statp
= NFS4ERR_FHEXPIRED
;
2408 * XXX even if test_volatile_fh false, the fh may contain a
2409 * volatile id if obtained when the test was set.
2411 fh_fmtp
->fh4_volatile_id
= (uchar_t
)0;
2412 #endif /* VOLATILE_FH_TEST */
2414 error
= VFS_VGET(vfsp
, &vp
, fidp
);
2416 * If we can not get vp from VFS_VGET, perhaps this is
2417 * an nfs v2/v3/v4 node in an nfsv4 pseudo filesystem.
2420 if (error
&& PSEUDO(exi
))
2421 error
= nfs4_vget_pseudo(exi
, &vp
, fidp
);
2423 if (error
|| vp
== NULL
) {
2424 *statp
= NFS4ERR_STALE
;
2427 /* XXX - disgusting hack */
2428 if (vp
->v_type
== VNON
&& vp
->v_flag
& V_XATTRDIR
)
2435 * Find the export structure associated with the given filesystem.
2436 * If found, then increment the ref count (exi_count).
2439 checkexport(fsid_t
*fsid
, fid_t
*fid
)
2441 struct exportinfo
*exi
;
2443 rw_enter(&exported_lock
, RW_READER
);
2444 for (exi
= exptable
[exptablehash(fsid
, fid
)];
2446 exi
= exi
->fid_hash
.next
) {
2447 if (exportmatch(exi
, fsid
, fid
)) {
2449 * If this is the place holder for the
2450 * public file handle, then return the
2451 * real export entry for the public file
2454 if (exi
->exi_export
.ex_flags
& EX_PUBLIC
) {
2459 rw_exit(&exported_lock
);
2463 rw_exit(&exported_lock
);
2469 * "old school" version of checkexport() for NFS4. NFS4
2470 * rfs4_compound holds exported_lock for duration of compound
2471 * processing. This version doesn't manipulate exi_count
2472 * since NFS4 breaks fundamental assumptions in the exi_count
2476 checkexport4(fsid_t
*fsid
, fid_t
*fid
, vnode_t
*vp
)
2478 struct exportinfo
*exi
;
2480 ASSERT(RW_LOCK_HELD(&exported_lock
));
2482 for (exi
= exptable
[exptablehash(fsid
, fid
)];
2484 exi
= exi
->fid_hash
.next
) {
2485 if (exportmatch(exi
, fsid
, fid
)) {
2487 * If this is the place holder for the
2488 * public file handle, then return the
2489 * real export entry for the public file
2492 if (exi
->exi_export
.ex_flags
& EX_PUBLIC
) {
2497 * If vp is given, check if vp is the
2498 * same vnode as the exported node.
2500 * Since VOP_FID of a lofs node returns the
2501 * fid of its real node (ufs), the exported
2502 * node for lofs and (pseudo) ufs may have
2503 * the same fsid and fid.
2505 if (vp
== NULL
|| vp
== exi
->exi_vp
)
2514 * Free an entire export list node
2517 exportfree(struct exportinfo
*exi
)
2519 struct exportdata
*ex
;
2520 struct charset_cache
*cache
;
2523 ex
= &exi
->exi_export
;
2525 ASSERT(exi
->exi_vp
!= NULL
&& !(exi
->exi_export
.ex_flags
& EX_PUBLIC
));
2526 VN_RELE(exi
->exi_vp
);
2527 if (exi
->exi_dvp
!= NULL
)
2528 VN_RELE(exi
->exi_dvp
);
2530 if (ex
->ex_flags
& EX_INDEX
)
2531 kmem_free(ex
->ex_index
, strlen(ex
->ex_index
) + 1);
2533 kmem_free(ex
->ex_path
, ex
->ex_pathlen
+ 1);
2534 nfsauth_cache_free(exi
);
2537 * if there is a character set mapping cached, clean it up.
2539 for (cache
= exi
->exi_charset
; cache
!= NULL
;
2540 cache
= exi
->exi_charset
) {
2541 if (cache
->inbound
!= (kiconv_t
)-1)
2542 (void) kiconv_close(cache
->inbound
);
2543 if (cache
->outbound
!= (kiconv_t
)-1)
2544 (void) kiconv_close(cache
->outbound
);
2545 exi
->exi_charset
= cache
->next
;
2546 kmem_free(cache
, sizeof (struct charset_cache
));
2549 if (exi
->exi_logbuffer
!= NULL
)
2550 nfslog_disable(exi
);
2552 if (ex
->ex_flags
& EX_LOG
) {
2553 kmem_free(ex
->ex_log_buffer
, ex
->ex_log_bufferlen
+ 1);
2554 kmem_free(ex
->ex_tag
, ex
->ex_taglen
+ 1);
2557 if (exi
->exi_visible
)
2558 free_visible(exi
->exi_visible
);
2560 srv_secinfo_list_free(ex
->ex_secinfo
, ex
->ex_seccnt
);
2562 #ifdef VOLATILE_FH_TEST
2563 free_volrnm_list(exi
);
2564 mutex_destroy(&exi
->exi_vol_rename_lock
);
2565 #endif /* VOLATILE_FH_TEST */
2567 mutex_destroy(&exi
->exi_lock
);
2568 rw_destroy(&exi
->exi_cache_lock
);
2570 * All nodes in the exi_cache AVL trees were removed and freed in the
2571 * nfsauth_cache_free() call above. We will just destroy and free the
2572 * empty AVL trees here.
2574 for (i
= 0; i
< AUTH_TABLESIZE
; i
++) {
2575 avl_destroy(exi
->exi_cache
[i
]);
2576 kmem_free(exi
->exi_cache
[i
], sizeof (avl_tree_t
));
2579 kmem_free(exi
, sizeof (*exi
));
2583 * load the index file from user space into kernel space.
2586 loadindex(struct exportdata
*kex
)
2589 char index
[MAXNAMELEN
+1];
2593 * copyinstr copies the complete string including the NULL and
2594 * returns the len with the NULL byte included in the calculation
2595 * as long as the max length is not exceeded.
2597 if (error
= copyinstr(kex
->ex_index
, index
, sizeof (index
), &len
))
2600 kex
->ex_index
= kmem_alloc(len
, KM_SLEEP
);
2601 bcopy(index
, kex
->ex_index
, len
);
2607 exi_hold(struct exportinfo
*exi
)
2609 mutex_enter(&exi
->exi_lock
);
2611 mutex_exit(&exi
->exi_lock
);
2615 * When a thread completes using exi, it should call exi_rele().
2616 * exi_rele() decrements exi_count. It releases exi if exi_count == 0, i.e.
2617 * if this is the last user of exi and exi is not on exportinfo list anymore
2620 exi_rele(struct exportinfo
*exi
)
2622 mutex_enter(&exi
->exi_lock
);
2624 if (exi
->exi_count
== 0) {
2625 mutex_exit(&exi
->exi_lock
);
2628 mutex_exit(&exi
->exi_lock
);
2631 #ifdef VOLATILE_FH_TEST
2633 * Test for volatile fh's - add file handle to list and set its volatile id
2634 * to time it was renamed. If EX_VOLFH is also on and the fs is reshared,
2635 * the vol_rename queue is purged.
2637 * XXX This code is for unit testing purposes only... To correctly use it, it
2638 * needs to tie a rename list to the export struct and (more
2639 * important), protect access to the exi rename list using a write lock.
2643 * get the fh vol record if it's in the volatile on rename list. Don't check
2644 * volatile_id in the file handle - compare only the file handles.
2646 static struct ex_vol_rename
*
2647 find_volrnm_fh(struct exportinfo
*exi
, nfs_fh4
*fh4p
)
2649 struct ex_vol_rename
*p
= NULL
;
2652 /* XXX shouldn't we assert &exported_lock held? */
2653 ASSERT(MUTEX_HELD(&exi
->exi_vol_rename_lock
));
2655 if (fh4p
->nfs_fh4_len
!= NFS_FH4_LEN
) {
2658 fhp
= &((nfs_fh4_fmt_t
*)fh4p
->nfs_fh4_val
)->fh4_i
;
2659 for (p
= exi
->exi_vol_rename
; p
!= NULL
; p
= p
->vrn_next
) {
2660 if (bcmp(fhp
, &p
->vrn_fh_fmt
.fh4_i
,
2661 sizeof (fhandle4_t
)) == 0)
2668 * get the volatile id for the fh (if there is - else return 0). Ignore the
2669 * volatile_id in the file handle - compare only the file handles.
2672 find_volrnm_fh_id(struct exportinfo
*exi
, nfs_fh4
*fh4p
)
2674 struct ex_vol_rename
*p
;
2675 uint32_t volatile_id
;
2677 mutex_enter(&exi
->exi_vol_rename_lock
);
2678 p
= find_volrnm_fh(exi
, fh4p
);
2679 volatile_id
= (p
? p
->vrn_fh_fmt
.fh4_volatile_id
:
2680 exi
->exi_volatile_id
);
2681 mutex_exit(&exi
->exi_vol_rename_lock
);
2682 return (volatile_id
);
2686 * Free the volatile on rename list - will be called if a filesystem is
2687 * unshared or reshared without EX_VOLRNM
2690 free_volrnm_list(struct exportinfo
*exi
)
2692 struct ex_vol_rename
*p
, *pnext
;
2694 /* no need to hold mutex lock - this one is called from exportfree */
2695 for (p
= exi
->exi_vol_rename
; p
!= NULL
; p
= pnext
) {
2696 pnext
= p
->vrn_next
;
2697 kmem_free(p
, sizeof (*p
));
2699 exi
->exi_vol_rename
= NULL
;
2703 * Add a file handle to the volatile on rename list.
2706 add_volrnm_fh(struct exportinfo
*exi
, vnode_t
*vp
)
2708 struct ex_vol_rename
*p
;
2709 char fhbuf
[NFS4_FHSIZE
];
2713 fh4
.nfs_fh4_val
= fhbuf
;
2714 error
= makefh4(&fh4
, vp
, exi
);
2715 if ((error
) || (fh4
.nfs_fh4_len
!= sizeof (p
->vrn_fh_fmt
))) {
2719 mutex_enter(&exi
->exi_vol_rename_lock
);
2721 p
= find_volrnm_fh(exi
, &fh4
);
2724 p
= kmem_alloc(sizeof (*p
), KM_SLEEP
);
2725 bcopy(fh4
.nfs_fh4_val
, &p
->vrn_fh_fmt
, sizeof (p
->vrn_fh_fmt
));
2726 p
->vrn_next
= exi
->exi_vol_rename
;
2727 exi
->exi_vol_rename
= p
;
2730 p
->vrn_fh_fmt
.fh4_volatile_id
= gethrestime_sec();
2731 mutex_exit(&exi
->exi_vol_rename_lock
);
2734 #endif /* VOLATILE_FH_TEST */