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, bool_t
);
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
,
709 treenode_t
*tnode
= exip
->exi_tree
;
711 ASSERT(RW_WRITE_HELD(&exported_lock
));
712 ASSERT(tnode
!= NULL
);
718 * If flavors are being added and the new export root isn't
719 * also VROOT, its implicitly allowed flavors are inherited from
721 * Note - for VROOT exports the implicitly allowed flavors were
722 * transferred from the PSEUDO export in exportfs()
724 if (isadd
&& !(exip
->exi_vp
->v_flag
& VROOT
) &&
725 tnode
->tree_vis
->vis_seccnt
> 0) {
726 srv_secinfo_add(&exip
->exi_export
.ex_secinfo
,
727 &exip
->exi_export
.ex_seccnt
, tnode
->tree_vis
->vis_secinfo
,
728 tnode
->tree_vis
->vis_seccnt
, FALSE
);
732 * Move to parent node and propagate sec flavor
733 * to exportinfo and to visible structures.
735 tnode
= tnode
->tree_parent
;
737 while (tnode
!= NULL
) {
739 /* If there is exportinfo, update it */
740 if (tnode
->tree_exi
!= NULL
) {
742 &tnode
->tree_exi
->exi_export
.ex_secinfo
;
743 int *pxcnt
= &tnode
->tree_exi
->exi_export
.ex_seccnt
;
744 int is_pseudo
= PSEUDO(tnode
->tree_exi
);
746 srv_secinfo_add(pxsec
, pxcnt
, sec
, seccnt
,
749 srv_secinfo_remove(pxsec
, pxcnt
, sec
, seccnt
);
752 /* Update every visible - only root node has no visible */
753 if (tnode
->tree_vis
!= NULL
) {
754 secinfo_t
**pxsec
= &tnode
->tree_vis
->vis_secinfo
;
755 int *pxcnt
= &tnode
->tree_vis
->vis_seccnt
;
757 srv_secinfo_add(pxsec
, pxcnt
, sec
, seccnt
,
760 srv_secinfo_remove(pxsec
, pxcnt
, sec
, seccnt
);
762 tnode
= tnode
->tree_parent
;
766 /* hash_name is a text substitution for either fid_hash or path_hash */
767 #define exp_hash_unlink(exi, hash_name) \
768 if (*(exi)->hash_name.bckt == (exi)) \
769 *(exi)->hash_name.bckt = (exi)->hash_name.next; \
770 if ((exi)->hash_name.prev) \
771 (exi)->hash_name.prev->hash_name.next = (exi)->hash_name.next; \
772 if ((exi)->hash_name.next) \
773 (exi)->hash_name.next->hash_name.prev = (exi)->hash_name.prev; \
774 (exi)->hash_name.bckt = NULL;
776 #define exp_hash_link(exi, hash_name, bucket) \
777 (exi)->hash_name.bckt = (bucket); \
778 (exi)->hash_name.prev = NULL; \
779 (exi)->hash_name.next = *(bucket); \
780 if ((exi)->hash_name.next) \
781 (exi)->hash_name.next->hash_name.prev = (exi); \
785 export_link(exportinfo_t
*exi
)
789 bckt
= &exptable
[exptablehash(&exi
->exi_fsid
, &exi
->exi_fid
)];
790 exp_hash_link(exi
, fid_hash
, bckt
);
792 bckt
= &exptable_path_hash
[pkp_tab_hash(exi
->exi_export
.ex_path
,
793 strlen(exi
->exi_export
.ex_path
))];
794 exp_hash_link(exi
, path_hash
, bckt
);
798 * Initialization routine for export routines. Should only be called once.
806 rw_init(&exported_lock
, NULL
, RW_DEFAULT
, NULL
);
809 * Allocate the place holder for the public file handle, which
810 * is all zeroes. It is initially set to the root filesystem.
812 exi_root
= kmem_zalloc(sizeof (*exi_root
), KM_SLEEP
);
813 exi_public
= exi_root
;
815 exi_root
->exi_export
.ex_flags
= EX_PUBLIC
;
816 exi_root
->exi_export
.ex_pathlen
= 1; /* length of "/" */
817 exi_root
->exi_export
.ex_path
=
818 kmem_alloc(exi_root
->exi_export
.ex_pathlen
+ 1, KM_SLEEP
);
819 exi_root
->exi_export
.ex_path
[0] = '/';
820 exi_root
->exi_export
.ex_path
[1] = '\0';
822 exi_root
->exi_count
= 1;
823 mutex_init(&exi_root
->exi_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
825 exi_root
->exi_vp
= rootdir
;
826 exi_rootfid
.fid_len
= MAXFIDSZ
;
827 error
= vop_fid_pseudo(exi_root
->exi_vp
, &exi_rootfid
);
829 mutex_destroy(&exi_root
->exi_lock
);
830 kmem_free(exi_root
, sizeof (*exi_root
));
835 * Initialize auth cache and auth cache lock
837 for (i
= 0; i
< AUTH_TABLESIZE
; i
++) {
838 exi_root
->exi_cache
[i
] = kmem_alloc(sizeof (avl_tree_t
),
840 avl_create(exi_root
->exi_cache
[i
], nfsauth_cache_clnt_compar
,
841 sizeof (struct auth_cache_clnt
),
842 offsetof(struct auth_cache_clnt
, authc_link
));
844 rw_init(&exi_root
->exi_cache_lock
, NULL
, RW_DEFAULT
, NULL
);
846 /* setup the fhandle template */
847 exi_root
->exi_fh
.fh_fsid
= rootdir
->v_vfsp
->vfs_fsid
;
848 exi_root
->exi_fh
.fh_xlen
= exi_rootfid
.fid_len
;
849 bcopy(exi_rootfid
.fid_data
, exi_root
->exi_fh
.fh_xdata
,
850 exi_rootfid
.fid_len
);
851 exi_root
->exi_fh
.fh_len
= sizeof (exi_root
->exi_fh
.fh_data
);
854 * Publish the exportinfo in the hash table
856 export_link(exi_root
);
865 * Finalization routine for export routines. Called to cleanup previously
866 * initialization work when the NFS server module could not be loaded correctly.
874 * Deallocate the place holder for the public file handle.
876 srv_secinfo_list_free(exi_root
->exi_export
.ex_secinfo
,
877 exi_root
->exi_export
.ex_seccnt
);
878 mutex_destroy(&exi_root
->exi_lock
);
879 rw_destroy(&exi_root
->exi_cache_lock
);
880 for (i
= 0; i
< AUTH_TABLESIZE
; i
++) {
881 avl_destroy(exi_root
->exi_cache
[i
]);
882 kmem_free(exi_root
->exi_cache
[i
], sizeof (avl_tree_t
));
884 kmem_free(exi_root
, sizeof (*exi_root
));
886 rw_destroy(&exported_lock
);
890 * Check if 2 gss mechanism identifiers are the same.
892 * return FALSE if not the same.
893 * return TRUE if the same.
896 nfs_mech_equal(rpc_gss_OID mech1
, rpc_gss_OID mech2
)
898 if ((mech1
->length
== 0) && (mech2
->length
== 0))
901 if (mech1
->length
!= mech2
->length
)
904 return (bcmp(mech1
->elements
, mech2
->elements
, mech1
->length
) == 0);
908 * This routine is used by rpc to map rpc security number
909 * to nfs specific security flavor number.
911 * The gss callback prototype is
912 * callback(struct svc_req *, gss_cred_id_t *, gss_ctx_id_t *,
913 * rpc_gss_lock_t *, void **),
914 * since nfs does not use the gss_cred_id_t/gss_ctx_id_t arguments
915 * we cast them to void.
919 rfs_gsscallback(struct svc_req
*req
, gss_cred_id_t deleg
, void *gss_context
,
920 rpc_gss_lock_t
*lock
, void **cookie
)
923 rpc_gss_rawcred_t
*raw_cred
;
924 struct exportinfo
*exi
;
927 * We don't deal with delegated credentials.
929 if (deleg
!= GSS_C_NO_CREDENTIAL
)
932 raw_cred
= lock
->raw_cred
;
935 rw_enter(&exported_lock
, RW_READER
);
936 for (i
= 0; i
< EXPTABLESIZE
; i
++) {
939 if (exi
->exi_export
.ex_seccnt
> 0) {
940 struct secinfo
*secp
;
944 secp
= exi
->exi_export
.ex_secinfo
;
945 seccnt
= exi
->exi_export
.ex_seccnt
;
946 for (j
= 0; j
< seccnt
; j
++) {
948 * If there is a map of the triplet
949 * (mechanism, service, qop) between
950 * raw_cred and the exported flavor,
951 * get the psudo flavor number.
952 * Also qop should not be NULL, it
953 * should be "default" or something
956 se
= &secp
[j
].s_secinfo
;
957 if ((se
->sc_rpcnum
== RPCSEC_GSS
) &&
960 se
->sc_gss_mech_type
,
961 raw_cred
->mechanism
)) &&
964 raw_cred
->service
) &&
965 (raw_cred
->qop
== se
->sc_qop
)) {
967 *cookie
= (void *)(uintptr_t)
973 exi
= exi
->fid_hash
.next
;
977 rw_exit(&exported_lock
);
980 * If no nfs pseudo number mapping can be found in the export
981 * table, assign the nfsflavor to NFS_FLAVOR_NOMAP. In V4, we may
982 * recover the flavor mismatch from NFS layer (NFS4ERR_WRONGSEC).
985 * server first shares with krb5i;
986 * client mounts with krb5i;
987 * server re-shares with krb5p;
988 * client tries with krb5i, but no mapping can be found;
989 * rpcsec_gss module calls this routine to do the mapping,
990 * if this routine fails, request is rejected from
992 * What we need is to let the nfs layer rejects the request.
993 * For V4, we can reject with NFS4ERR_WRONGSEC and the client
994 * may recover from it by getting the new flavor via SECINFO.
996 * nfs pseudo number for RPCSEC_GSS mapping (see nfssec.conf)
997 * is owned by IANA (see RFC 2623).
999 * XXX NFS_FLAVOR_NOMAP is defined in Solaris to work around
1000 * the implementation issue. This number should not overlap with
1001 * any new IANA defined pseudo flavor numbers.
1003 if (*cookie
== NULL
)
1004 *cookie
= (void *)NFS_FLAVOR_NOMAP
;
1006 lock
->locked
= TRUE
;
1013 * Exportfs system call; credentials should be checked before
1014 * calling this function.
1017 exportfs(struct exportfs_args
*args
, model_t model
, cred_t
*cr
)
1021 struct exportdata
*kex
;
1022 struct exportinfo
*exi
= NULL
;
1023 struct exportinfo
*ex
, *ex1
, *ex2
;
1029 struct secinfo
*exs
;
1030 rpc_gss_callback_t cb
;
1036 STRUCT_HANDLE(exportfs_args
, uap
);
1037 STRUCT_DECL(exportdata
, uexi
);
1038 struct secinfo newsec
[MAX_FLAVORS
];
1040 struct secinfo oldsec
[MAX_FLAVORS
];
1043 struct pathname lookpn
;
1045 STRUCT_SET_HANDLE(uap
, model
, args
);
1047 /* Read in pathname from userspace */
1048 if (error
= pn_get(STRUCT_FGETP(uap
, dname
), UIO_USERSPACE
, &lookpn
))
1051 /* Walk the export list looking for that pathname */
1052 rw_enter(&exported_lock
, RW_READER
);
1053 DTRACE_PROBE(nfss__i__exported_lock1_start
);
1054 for (ex1
= exptable_path_hash
[pkp_tab_hash(lookpn
.pn_path
,
1055 strlen(lookpn
.pn_path
))]; ex1
; ex1
= ex1
->path_hash
.next
) {
1056 if (ex1
!= exi_root
&& 0 ==
1057 strcmp(ex1
->exi_export
.ex_path
, lookpn
.pn_path
)) {
1062 DTRACE_PROBE(nfss__i__exported_lock1_stop
);
1063 rw_exit(&exported_lock
);
1065 /* Is this an unshare? */
1066 if (STRUCT_FGETP(uap
, uex
) == NULL
) {
1070 error
= unexport(ex1
);
1075 /* It is a share or a re-share */
1076 error
= lookupname(STRUCT_FGETP(uap
, dname
), UIO_USERSPACE
,
1078 if (error
== EINVAL
) {
1080 * if fname resolves to / we get EINVAL error
1081 * since we wanted the parent vnode. Try again
1084 error
= lookupname(STRUCT_FGETP(uap
, dname
), UIO_USERSPACE
,
1088 if (!error
&& vp
== NULL
) {
1089 /* Last component of fname not found */
1102 * 'vp' may be an AUTOFS node, so we perform a
1103 * fop_access() to trigger the mount of the
1104 * intended filesystem, so we can share the intended
1105 * filesystem instead of the AUTOFS filesystem.
1107 (void) fop_access(vp
, 0, 0, cr
, NULL
);
1110 * We're interested in the top most filesystem.
1111 * This is specially important when uap->dname is a trigger
1112 * AUTOFS node, since we're really interested in sharing the
1113 * filesystem AUTOFS mounted as result of the fop_access()
1114 * call not the AUTOFS node itself.
1116 if (vn_mountedvfs(vp
) != NULL
) {
1117 if (error
= traverse(&vp
)) {
1128 /* Do not allow sharing another vnode for already shared path */
1129 if (ex1
&& !PSEUDO(ex1
) && !VN_CMP(ex1
->exi_vp
, vp
)) {
1143 bzero(&fid
, sizeof (fid
));
1144 fid
.fid_len
= MAXFIDSZ
;
1145 error
= fop_fid(vp
, &fid
, NULL
);
1146 fsid
= vp
->v_vfsp
->vfs_fsid
;
1153 * If fop_fid returns ENOSPC then the fid supplied
1154 * is too small. For now we simply return EREMOTE.
1156 if (error
== ENOSPC
)
1163 * Do not allow re-sharing a shared vnode under a different path
1164 * PSEUDO export has ex_path fabricated, e.g. "/tmp (pseudo)", skip it.
1166 rw_enter(&exported_lock
, RW_READER
);
1167 DTRACE_PROBE(nfss__i__exported_lock2_start
);
1168 for (ex2
= exptable
[exptablehash(&fsid
, &fid
)]; ex2
;
1169 ex2
= ex2
->fid_hash
.next
) {
1170 if (ex2
!= exi_root
&& !PSEUDO(ex2
) &&
1171 VN_CMP(ex2
->exi_vp
, vp
) &&
1172 strcmp(ex2
->exi_export
.ex_path
, lookpn
.pn_path
) != 0) {
1173 DTRACE_PROBE(nfss__i__exported_lock2_stop
);
1174 rw_exit(&exported_lock
);
1182 DTRACE_PROBE(nfss__i__exported_lock2_stop
);
1183 rw_exit(&exported_lock
);
1186 exi
= kmem_zalloc(sizeof (*exi
), KM_SLEEP
);
1187 exi
->exi_fsid
= fsid
;
1191 exi
->exi_volatile_dev
= (vfssw
[vp
->v_vfsp
->vfs_fstype
].vsw_flag
&
1192 VSW_VOLATILEDEV
) ? 1 : 0;
1193 mutex_init(&exi
->exi_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
1197 * Initialize auth cache and auth cache lock
1199 for (i
= 0; i
< AUTH_TABLESIZE
; i
++) {
1200 exi
->exi_cache
[i
] = kmem_alloc(sizeof (avl_tree_t
), KM_SLEEP
);
1201 avl_create(exi
->exi_cache
[i
], nfsauth_cache_clnt_compar
,
1202 sizeof (struct auth_cache_clnt
),
1203 offsetof(struct auth_cache_clnt
, authc_link
));
1205 rw_init(&exi
->exi_cache_lock
, NULL
, RW_DEFAULT
, NULL
);
1208 * Build up the template fhandle
1210 exi
->exi_fh
.fh_fsid
= fsid
;
1211 if (exi
->exi_fid
.fid_len
> sizeof (exi
->exi_fh
.fh_xdata
)) {
1215 exi
->exi_fh
.fh_xlen
= exi
->exi_fid
.fid_len
;
1216 bcopy(exi
->exi_fid
.fid_data
, exi
->exi_fh
.fh_xdata
,
1217 exi
->exi_fid
.fid_len
);
1219 exi
->exi_fh
.fh_len
= sizeof (exi
->exi_fh
.fh_data
);
1221 kex
= &exi
->exi_export
;
1224 * Load in everything, and do sanity checking
1226 STRUCT_INIT(uexi
, model
);
1227 if (copyin(STRUCT_FGETP(uap
, uex
), STRUCT_BUF(uexi
),
1228 STRUCT_SIZE(uexi
))) {
1233 kex
->ex_version
= STRUCT_FGET(uexi
, ex_version
);
1234 if (kex
->ex_version
!= EX_CURRENT_VERSION
) {
1237 "NFS: exportfs requires export struct version 2 - got %d\n",
1243 * Must have at least one security entry
1245 kex
->ex_seccnt
= STRUCT_FGET(uexi
, ex_seccnt
);
1246 if (kex
->ex_seccnt
< 1) {
1251 kex
->ex_path
= STRUCT_FGETP(uexi
, ex_path
);
1252 kex
->ex_pathlen
= STRUCT_FGET(uexi
, ex_pathlen
);
1253 kex
->ex_flags
= STRUCT_FGET(uexi
, ex_flags
);
1254 kex
->ex_anon
= STRUCT_FGET(uexi
, ex_anon
);
1255 kex
->ex_secinfo
= STRUCT_FGETP(uexi
, ex_secinfo
);
1256 kex
->ex_index
= STRUCT_FGETP(uexi
, ex_index
);
1257 kex
->ex_log_buffer
= STRUCT_FGETP(uexi
, ex_log_buffer
);
1258 kex
->ex_log_bufferlen
= STRUCT_FGET(uexi
, ex_log_bufferlen
);
1259 kex
->ex_tag
= STRUCT_FGETP(uexi
, ex_tag
);
1260 kex
->ex_taglen
= STRUCT_FGET(uexi
, ex_taglen
);
1263 * Copy the exported pathname into
1264 * an appropriately sized buffer.
1266 pathbuf
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
1267 if (copyinstr(kex
->ex_path
, pathbuf
, MAXPATHLEN
, &kex
->ex_pathlen
)) {
1268 kmem_free(pathbuf
, MAXPATHLEN
);
1272 kex
->ex_path
= kmem_alloc(kex
->ex_pathlen
+ 1, KM_SLEEP
);
1273 bcopy(pathbuf
, kex
->ex_path
, kex
->ex_pathlen
);
1274 kex
->ex_path
[kex
->ex_pathlen
] = '\0';
1275 kmem_free(pathbuf
, MAXPATHLEN
);
1278 * Get the path to the logging buffer and the tag
1280 if (kex
->ex_flags
& EX_LOG
) {
1281 log_buffer
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
1282 if (copyinstr(kex
->ex_log_buffer
, log_buffer
, MAXPATHLEN
,
1283 &kex
->ex_log_bufferlen
)) {
1284 kmem_free(log_buffer
, MAXPATHLEN
);
1288 kex
->ex_log_buffer
=
1289 kmem_alloc(kex
->ex_log_bufferlen
+ 1, KM_SLEEP
);
1290 bcopy(log_buffer
, kex
->ex_log_buffer
, kex
->ex_log_bufferlen
);
1291 kex
->ex_log_buffer
[kex
->ex_log_bufferlen
] = '\0';
1292 kmem_free(log_buffer
, MAXPATHLEN
);
1294 tagbuf
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
1295 if (copyinstr(kex
->ex_tag
, tagbuf
, MAXPATHLEN
,
1297 kmem_free(tagbuf
, MAXPATHLEN
);
1301 kex
->ex_tag
= kmem_alloc(kex
->ex_taglen
+ 1, KM_SLEEP
);
1302 bcopy(tagbuf
, kex
->ex_tag
, kex
->ex_taglen
);
1303 kex
->ex_tag
[kex
->ex_taglen
] = '\0';
1304 kmem_free(tagbuf
, MAXPATHLEN
);
1308 * Load the security information for each flavor
1310 allocsize
= kex
->ex_seccnt
* SIZEOF_STRUCT(secinfo
, model
);
1311 sp
= kmem_zalloc(allocsize
, KM_SLEEP
);
1312 if (copyin(kex
->ex_secinfo
, sp
, allocsize
)) {
1313 kmem_free(sp
, allocsize
);
1319 * All of these nested structures need to be converted to
1320 * the kernel native format.
1322 if (model
!= DATAMODEL_NATIVE
) {
1324 struct secinfo
*sp2
;
1326 allocsize2
= kex
->ex_seccnt
* sizeof (struct secinfo
);
1327 sp2
= kmem_zalloc(allocsize2
, KM_SLEEP
);
1329 for (i
= 0; i
< kex
->ex_seccnt
; i
++) {
1330 STRUCT_HANDLE(secinfo
, usi
);
1332 STRUCT_SET_HANDLE(usi
, model
,
1333 (struct secinfo
*)((caddr_t
)sp
+
1334 (i
* SIZEOF_STRUCT(secinfo
, model
))));
1335 bcopy(STRUCT_FGET(usi
, s_secinfo
.sc_name
),
1336 sp2
[i
].s_secinfo
.sc_name
, MAX_NAME_LEN
);
1337 sp2
[i
].s_secinfo
.sc_nfsnum
=
1338 STRUCT_FGET(usi
, s_secinfo
.sc_nfsnum
);
1339 sp2
[i
].s_secinfo
.sc_rpcnum
=
1340 STRUCT_FGET(usi
, s_secinfo
.sc_rpcnum
);
1341 bcopy(STRUCT_FGET(usi
, s_secinfo
.sc_gss_mech
),
1342 sp2
[i
].s_secinfo
.sc_gss_mech
, MAX_NAME_LEN
);
1343 sp2
[i
].s_secinfo
.sc_gss_mech_type
=
1344 STRUCT_FGETP(usi
, s_secinfo
.sc_gss_mech_type
);
1345 sp2
[i
].s_secinfo
.sc_qop
=
1346 STRUCT_FGET(usi
, s_secinfo
.sc_qop
);
1347 sp2
[i
].s_secinfo
.sc_service
=
1348 STRUCT_FGET(usi
, s_secinfo
.sc_service
);
1350 sp2
[i
].s_flags
= STRUCT_FGET(usi
, s_flags
);
1351 sp2
[i
].s_window
= STRUCT_FGET(usi
, s_window
);
1352 sp2
[i
].s_rootid
= STRUCT_FGET(usi
, s_rootid
);
1353 sp2
[i
].s_rootcnt
= STRUCT_FGET(usi
, s_rootcnt
);
1354 sp2
[i
].s_rootnames
= STRUCT_FGETP(usi
, s_rootnames
);
1356 kmem_free(sp
, allocsize
);
1358 allocsize
= allocsize2
;
1361 kex
->ex_secinfo
= sp
;
1364 * And now copy rootnames for each individual secinfo.
1368 while (allocd_seccnt
< kex
->ex_seccnt
) {
1370 exs
= &sp
[allocd_seccnt
];
1371 if (exs
->s_rootcnt
> 0) {
1372 if (!sec_svc_loadrootnames(exs
->s_secinfo
.sc_rpcnum
,
1373 exs
->s_rootcnt
, &exs
->s_rootnames
, model
)) {
1379 if (exs
->s_secinfo
.sc_rpcnum
== RPCSEC_GSS
) {
1380 rpc_gss_OID mech_tmp
;
1381 STRUCT_DECL(rpc_gss_OID_s
, umech_tmp
);
1382 caddr_t elements_tmp
;
1384 /* Copyin mechanism type */
1385 STRUCT_INIT(umech_tmp
, model
);
1386 mech_tmp
= kmem_alloc(sizeof (*mech_tmp
), KM_SLEEP
);
1387 if (copyin(exs
->s_secinfo
.sc_gss_mech_type
,
1388 STRUCT_BUF(umech_tmp
), STRUCT_SIZE(umech_tmp
))) {
1389 kmem_free(mech_tmp
, sizeof (*mech_tmp
));
1393 mech_tmp
->length
= STRUCT_FGET(umech_tmp
, length
);
1394 mech_tmp
->elements
= STRUCT_FGETP(umech_tmp
, elements
);
1396 elements_tmp
= kmem_alloc(mech_tmp
->length
, KM_SLEEP
);
1397 if (copyin(mech_tmp
->elements
, elements_tmp
,
1398 mech_tmp
->length
)) {
1399 kmem_free(elements_tmp
, mech_tmp
->length
);
1400 kmem_free(mech_tmp
, sizeof (*mech_tmp
));
1404 mech_tmp
->elements
= elements_tmp
;
1405 exs
->s_secinfo
.sc_gss_mech_type
= mech_tmp
;
1414 * Init the secinfo reference count and mark these flavors
1415 * explicitly exported flavors.
1417 for (i
= 0; i
< kex
->ex_seccnt
; i
++) {
1418 kex
->ex_secinfo
[i
].s_flags
|= M_4SEC_EXPORTED
;
1419 kex
->ex_secinfo
[i
].s_refcnt
= 1;
1423 * Set up rpcsec_gss callback routine entry if any.
1426 cb
.callback
= rfs_gsscallback
;
1427 cb
.program
= NFS_ACL_PROGRAM
;
1428 for (cb
.version
= NFS_ACL_VERSMIN
;
1429 cb
.version
<= NFS_ACL_VERSMAX
; cb
.version
++) {
1430 (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK
,
1434 cb
.program
= NFS_PROGRAM
;
1435 for (cb
.version
= NFS_VERSMIN
;
1436 cb
.version
<= NFS_VERSMAX
; cb
.version
++) {
1437 (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK
,
1443 * Check the index flag. Do this here to avoid holding the
1444 * lock while dealing with the index option (as we do with
1445 * the public option).
1447 if (kex
->ex_flags
& EX_INDEX
) {
1448 if (!kex
->ex_index
) { /* sanity check */
1452 if (error
= loadindex(kex
))
1456 if (kex
->ex_flags
& EX_LOG
) {
1457 if (error
= nfslog_setup(exi
))
1462 * Insert the new entry at the front of the export list
1464 rw_enter(&exported_lock
, RW_WRITER
);
1465 DTRACE_PROBE(nfss__i__exported_lock3_start
);
1470 * Check the rest of the list for an old entry for the fs.
1471 * If one is found then unlink it, wait until this is the
1472 * only reference and then free it.
1474 for (ex
= exi
->fid_hash
.next
; ex
!= NULL
; ex
= ex
->fid_hash
.next
) {
1475 if (ex
!= exi_root
&& VN_CMP(ex
->exi_vp
, vp
)) {
1482 * If the public filehandle is pointing at the
1483 * old entry, then point it back at the root.
1485 if (ex
!= NULL
&& ex
== exi_public
)
1486 exi_public
= exi_root
;
1489 * If the public flag is on, make the global exi_public
1490 * point to this entry and turn off the public bit so that
1491 * we can distinguish it from the place holder export.
1493 if (kex
->ex_flags
& EX_PUBLIC
) {
1495 kex
->ex_flags
&= ~EX_PUBLIC
;
1498 #ifdef VOLATILE_FH_TEST
1500 * Set up the volatile_id value if volatile on share.
1501 * The list of volatile renamed filehandles is always destroyed,
1502 * if the fs was reshared.
1504 if (kex
->ex_flags
& EX_VOLFH
)
1505 exi
->exi_volatile_id
= gethrestime_sec();
1507 mutex_init(&exi
->exi_vol_rename_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
1508 #endif /* VOLATILE_FH_TEST */
1511 * If this is a new export, then climb up
1512 * the tree and check if any pseudo exports
1513 * need to be created to provide a path for
1517 error
= treeclimb_export(exi
);
1521 /* If it's a re-export update namespace tree */
1522 exi
->exi_tree
= ex
->exi_tree
;
1523 exi
->exi_tree
->tree_exi
= exi
;
1525 /* Update the change timestamp */
1526 tree_update_change(exi
->exi_tree
, NULL
);
1530 * build a unique flavor list from the flavors specified
1531 * in the share cmd. unique means that each flavor only
1532 * appears once in the secinfo list -- no duplicates allowed.
1534 newcnt
= build_seclist_nodups(&exi
->exi_export
, newsec
, FALSE
);
1536 srv_secinfo_treeclimb(exi
, newsec
, newcnt
, TRUE
);
1539 * If re-sharing an old export entry, update the secinfo data
1540 * depending on if the old entry is a pseudo node or not.
1543 oldcnt
= build_seclist_nodups(&ex
->exi_export
, oldsec
, FALSE
);
1546 * The dir being shared is a pseudo export root (which
1547 * will be transformed into a real export root). The
1548 * flavor(s) of the new share were propagated to the
1549 * ancestors by srv_secinfo_treeclimb() above. Now
1550 * transfer the implicit flavor refs from the old
1551 * pseudo exprot root to the new (real) export root.
1553 srv_secinfo_add(&exi
->exi_export
.ex_secinfo
,
1554 &exi
->exi_export
.ex_seccnt
, oldsec
, oldcnt
, TRUE
);
1557 * First transfer implicit flavor refs to new export.
1558 * Remove old flavor refs last.
1560 srv_secinfo_exp2exp(&exi
->exi_export
, oldsec
, oldcnt
);
1561 srv_secinfo_treeclimb(ex
, oldsec
, oldcnt
, FALSE
);
1566 * If it's a re-export and the old entry has a pseudonode list,
1567 * transfer it to the new export.
1569 if (ex
!= NULL
&& (ex
->exi_visible
!= NULL
)) {
1570 exi
->exi_visible
= ex
->exi_visible
;
1571 ex
->exi_visible
= NULL
;
1574 DTRACE_PROBE(nfss__i__exported_lock3_stop
);
1575 rw_exit(&exported_lock
);
1577 if (exi_public
== exi
|| kex
->ex_flags
& EX_LOG
) {
1579 * Log share operation to this buffer only.
1581 nfslog_share_record(exi
, cr
);
1590 /* Unlink the new export in exptable. */
1592 DTRACE_PROBE(nfss__i__exported_lock3_stop
);
1593 rw_exit(&exported_lock
);
1595 if (kex
->ex_flags
& EX_INDEX
)
1596 kmem_free(kex
->ex_index
, strlen(kex
->ex_index
) + 1);
1598 /* free partially completed allocation */
1599 while (--allocd_seccnt
>= 0) {
1600 exs
= &kex
->ex_secinfo
[allocd_seccnt
];
1601 srv_secinfo_entry_free(exs
);
1604 if (kex
->ex_secinfo
) {
1605 kmem_free(kex
->ex_secinfo
,
1606 kex
->ex_seccnt
* sizeof (struct secinfo
));
1610 if ((kex
->ex_flags
& EX_LOG
) && kex
->ex_tag
!= NULL
)
1611 kmem_free(kex
->ex_tag
, kex
->ex_taglen
+ 1);
1613 if ((kex
->ex_flags
& EX_LOG
) && kex
->ex_log_buffer
!= NULL
)
1614 kmem_free(kex
->ex_log_buffer
, kex
->ex_log_bufferlen
+ 1);
1616 kmem_free(kex
->ex_path
, kex
->ex_pathlen
+ 1);
1621 mutex_destroy(&exi
->exi_lock
);
1622 rw_destroy(&exi
->exi_cache_lock
);
1623 for (i
= 0; i
< AUTH_TABLESIZE
; i
++) {
1624 avl_destroy(exi
->exi_cache
[i
]);
1625 kmem_free(exi
->exi_cache
[i
], sizeof (avl_tree_t
));
1628 kmem_free(exi
, sizeof (*exi
));
1634 * Remove the exportinfo from the export list
1637 export_unlink(struct exportinfo
*exi
)
1639 ASSERT(RW_WRITE_HELD(&exported_lock
));
1641 exp_hash_unlink(exi
, fid_hash
);
1642 exp_hash_unlink(exi
, path_hash
);
1646 * Unexport an exported filesystem
1649 unexport(struct exportinfo
*exi
)
1651 struct secinfo cursec
[MAX_FLAVORS
];
1654 rw_enter(&exported_lock
, RW_WRITER
);
1656 /* Check if exi is still linked in the export table */
1657 if (!EXP_LINKED(exi
) || PSEUDO(exi
)) {
1658 rw_exit(&exported_lock
);
1665 * Remove security flavors before treeclimb_unexport() is called
1666 * because srv_secinfo_treeclimb needs the namespace tree
1668 curcnt
= build_seclist_nodups(&exi
->exi_export
, cursec
, TRUE
);
1670 srv_secinfo_treeclimb(exi
, cursec
, curcnt
, FALSE
);
1673 * If there's a visible list, then need to leave
1674 * a pseudo export here to retain the visible list
1675 * for paths to exports below.
1677 if (exi
->exi_visible
!= NULL
) {
1678 struct exportinfo
*newexi
;
1680 newexi
= pseudo_exportfs(exi
->exi_vp
, &exi
->exi_fid
,
1681 exi
->exi_visible
, &exi
->exi_export
);
1682 exi
->exi_visible
= NULL
;
1684 /* interconnect the existing treenode with the new exportinfo */
1685 newexi
->exi_tree
= exi
->exi_tree
;
1686 newexi
->exi_tree
->tree_exi
= newexi
;
1688 /* Update the change timestamp */
1689 tree_update_change(exi
->exi_tree
, NULL
);
1691 treeclimb_unexport(exi
);
1694 rw_exit(&exported_lock
);
1697 * Need to call into the NFSv4 server and release all data
1698 * held on this particular export. This is important since
1699 * the v4 server may be holding file locks or vnodes under
1702 rfs4_clean_state_exi(exi
);
1705 * Notify the lock manager that the filesystem is being
1711 * If this was a public export, restore
1712 * the public filehandle to the root.
1714 if (exi
== exi_public
) {
1715 exi_public
= exi_root
;
1717 nfslog_share_record(exi_public
, CRED());
1720 if (exi
->exi_export
.ex_flags
& EX_LOG
) {
1721 nfslog_unshare_record(exi
, CRED());
1729 * Get file handle system call.
1730 * Takes file name and returns a file handle for it.
1731 * Credentials must be verified before calling.
1734 nfs_getfh(struct nfs_getfh_args
*args
, model_t model
, cred_t
*cr
)
1737 char buf
[NFS3_MAXFHSIZE
];
1738 char *logptr
, logbuf
[NFS3_MAXFHSIZE
];
1739 int l
= NFS3_MAXFHSIZE
;
1742 struct exportinfo
*exi
;
1745 STRUCT_HANDLE(nfs_getfh_args
, uap
);
1748 STRUCT_SET_HANDLE(uap
, model
, args
);
1750 error
= lookupname(STRUCT_FGETP(uap
, fname
), UIO_USERSPACE
,
1752 if (error
== EINVAL
) {
1754 * if fname resolves to / we get EINVAL error
1755 * since we wanted the parent vnode. Try again
1758 error
= lookupname(STRUCT_FGETP(uap
, fname
), UIO_USERSPACE
,
1762 if (!error
&& vp
== NULL
) {
1764 * Last component of fname not found
1775 * 'vp' may be an AUTOFS node, so we perform a
1776 * fop_access() to trigger the mount of the
1777 * intended filesystem, so we can share the intended
1778 * filesystem instead of the AUTOFS filesystem.
1780 (void) fop_access(vp
, 0, 0, cr
, NULL
);
1783 * We're interested in the top most filesystem.
1784 * This is specially important when uap->dname is a trigger
1785 * AUTOFS node, since we're really interested in sharing the
1786 * filesystem AUTOFS mounted as result of the fop_access()
1787 * call not the AUTOFS node itself.
1789 if (vn_mountedvfs(vp
) != NULL
) {
1790 if (error
= traverse(&vp
)) {
1798 vers
= STRUCT_FGET(uap
, vers
);
1799 exi
= nfs_vptoexi(dvp
, vp
, cr
, NULL
, &error
, FALSE
);
1801 if (vers
== NFS_VERSION
) {
1802 error
= makefh((fhandle_t
*)buf
, vp
, exi
);
1805 } else if (vers
== NFS_V3
) {
1808 error
= makefh3(&fh
, vp
, exi
);
1809 l
= RNDUP(fh
.fh3_length
);
1810 if (!error
&& (l
> sizeof (fhandle3_t
)))
1815 sz
= sizeof (fsid_t
);
1816 bcopy(&fh
.fh3_fsid
, &buf
[i
], sz
);
1820 * For backwards compatibility, the
1821 * fid length may be less than
1822 * NFS_FHMAXDATA, but it was always
1823 * encoded as NFS_FHMAXDATA bytes.
1826 sz
= sizeof (ushort_t
);
1827 bcopy(&fh
.fh3_len
, &buf
[i
], sz
);
1829 bcopy(fh
.fh3_data
, &buf
[i
], fh
.fh3_len
);
1831 pad
= (NFS_FHMAXDATA
- fh
.fh3_len
);
1833 bzero(&buf
[i
], pad
);
1838 sz
= sizeof (ushort_t
);
1839 bcopy(&fh
.fh3_xlen
, &buf
[i
], sz
);
1841 bcopy(fh
.fh3_xdata
, &buf
[i
], fh
.fh3_xlen
);
1843 pad
= (NFS_FHMAXDATA
- fh
.fh3_xlen
);
1845 bzero(&buf
[i
], pad
);
1851 * If we need to do NFS logging, the filehandle
1852 * must be downsized to 32 bytes.
1854 if (!error
&& exi
->exi_export
.ex_flags
& EX_LOG
) {
1856 sz
= sizeof (fsid_t
);
1857 bcopy(&fh
.fh3_fsid
, &logbuf
[i
], sz
);
1859 sz
= sizeof (ushort_t
);
1860 bcopy(&fh
.fh3_len
, &logbuf
[i
], sz
);
1863 bcopy(fh
.fh3_data
, &logbuf
[i
], sz
);
1865 sz
= sizeof (ushort_t
);
1866 bcopy(&fh
.fh3_xlen
, &logbuf
[i
], sz
);
1869 bcopy(fh
.fh3_xdata
, &logbuf
[i
], sz
);
1873 if (!error
&& exi
->exi_export
.ex_flags
& EX_LOG
) {
1874 nfslog_getfh(exi
, (fhandle_t
*)logptr
,
1875 STRUCT_FGETP(uap
, fname
), UIO_USERSPACE
, cr
);
1879 if (copyout(&l
, STRUCT_FGETP(uap
, lenp
), sizeof (int)))
1881 if (copyout(buf
, STRUCT_FGETP(uap
, fhp
), l
))
1893 * Strategy: if vp is in the export list, then
1894 * return the associated file handle. Otherwise, ".."
1895 * once up the vp and try again, until the root of the
1896 * filesystem is reached.
1899 nfs_vptoexi(vnode_t
*dvp
, vnode_t
*vp
, cred_t
*cr
, int *walk
,
1900 int *err
, bool_t v4srv
)
1904 struct exportinfo
*exi
;
1915 bzero(&fid
, sizeof (fid
));
1916 fid
.fid_len
= MAXFIDSZ
;
1917 error
= vop_fid_pseudo(vp
, &fid
);
1920 * If vop_fid_pseudo returns ENOSPC then the fid
1921 * supplied is too small. For now we simply
1924 if (error
== ENOSPC
)
1930 exi
= checkexport4(&vp
->v_vfsp
->vfs_fsid
, &fid
, vp
);
1932 exi
= checkexport(&vp
->v_vfsp
->vfs_fsid
, &fid
);
1936 * Found the export info
1942 * We have just failed finding a matching export.
1943 * If we're at the root of this filesystem, then
1944 * it's time to stop (with failure).
1946 if (vp
->v_flag
& VROOT
) {
1955 * Now, do a ".." up vp. If dvp is supplied, use it,
1956 * otherwise, look it up.
1959 error
= fop_lookup(vp
, "..", &dvp
, NULL
, 0, NULL
, cr
,
1981 chk_clnt_sec(exportinfo_t
*exi
, struct svc_req
*req
)
1987 * Get the nfs flavor number from xprt.
1989 nfsflavor
= (int)(uintptr_t)req
->rq_xprt
->xp_cookie
;
1991 sp
= exi
->exi_export
.ex_secinfo
;
1992 for (i
= 0; i
< exi
->exi_export
.ex_seccnt
; i
++) {
1993 if ((nfsflavor
== sp
[i
].s_secinfo
.sc_nfsnum
) &&
1994 SEC_REF_EXPORTED(sp
+ i
))
2001 * Make an fhandle from a vnode
2004 makefh(fhandle_t
*fh
, vnode_t
*vp
, exportinfo_t
*exi
)
2008 *fh
= exi
->exi_fh
; /* struct copy */
2010 error
= fop_fid(vp
, (fid_t
*)&fh
->fh_len
, NULL
);
2013 * Should be something other than EREMOTE
2021 * This routine makes an overloaded V2 fhandle which contains
2024 * Note that the first four octets contain the length octet,
2025 * the status octet, and two padded octets to make them XDR
2026 * four-octet aligned.
2029 * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+
2030 * | l | s | | | sec_1 |...| sec_n |...| |
2031 * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+
2035 * the status octet s indicates whether there are more security
2036 * flavors (1 means yes, 0 means no) that require the client to
2037 * perform another 0x81 LOOKUP to get them,
2039 * the length octet l is the length describing the number of
2040 * valid octets that follow. (l = 4 * n, where n is the number
2041 * of security flavors sent in the current overloaded filehandle.)
2043 * sec_index should always be in the inclusive range: [1 - ex_seccnt],
2044 * and it tells server where to start within the secinfo array.
2045 * Usually it will always be 1; however, if more flavors are used
2046 * for the public export than can be encoded in the overloaded FH
2047 * (7 for NFS2), subsequent SNEGO MCLs will have a larger index
2048 * so the server will pick up where it left off from the previous
2051 * With NFS4 support, implicitly allowed flavors are also in
2052 * the secinfo array; however, they should not be returned in
2053 * SNEGO MCL replies.
2056 makefh_ol(fhandle_t
*fh
, exportinfo_t
*exi
, uint_t sec_index
)
2058 secinfo_t sec
[MAX_FLAVORS
];
2059 int totalcnt
, i
, *ipt
, cnt
, seccnt
, secidx
, fh_max_cnt
;
2062 if (fh
== NULL
|| exi
== NULL
|| sec_index
< 1)
2066 * WebNFS clients need to know the unique set of explicitly
2067 * shared flavors in used for the public export. When
2068 * "TRUE" is passed to build_seclist_nodups(), only explicitly
2069 * shared flavors are included in the list.
2071 seccnt
= build_seclist_nodups(&exi
->exi_export
, sec
, TRUE
);
2072 if (sec_index
> seccnt
)
2075 fh_max_cnt
= (NFS_FHSIZE
/ sizeof (int)) - 1;
2076 totalcnt
= seccnt
- sec_index
+ 1;
2077 cnt
= totalcnt
> fh_max_cnt
? fh_max_cnt
: totalcnt
;
2081 * Encode the length octet representing the number of
2082 * security flavors (in bytes) in this overloaded fh.
2084 *c
= cnt
* sizeof (int);
2087 * Encode the status octet that indicates whether there
2088 * are more security flavors the client needs to get.
2090 *(c
+ 1) = totalcnt
> fh_max_cnt
;
2093 * put security flavors in the overloaded fh
2095 ipt
= (int *)(c
+ sizeof (int32_t));
2096 secidx
= sec_index
- 1;
2097 for (i
= 0; i
< cnt
; i
++) {
2098 ipt
[i
] = htonl(sec
[i
+ secidx
].s_secinfo
.sc_nfsnum
);
2104 * Make an nfs_fh3 from a vnode
2107 makefh3(nfs_fh3
*fh
, vnode_t
*vp
, struct exportinfo
*exi
)
2112 bzero(&fid
, sizeof (fid
));
2113 fid
.fid_len
= sizeof (fh
->fh3_data
);
2114 error
= fop_fid(vp
, &fid
, NULL
);
2118 bzero(fh
, sizeof (nfs_fh3
));
2119 fh
->fh3_fsid
= exi
->exi_fsid
;
2120 fh
->fh3_len
= fid
.fid_len
;
2121 bcopy(fid
.fid_data
, fh
->fh3_data
, fh
->fh3_len
);
2123 fh
->fh3_xlen
= exi
->exi_fid
.fid_len
;
2124 ASSERT(fh
->fh3_xlen
<= sizeof (fh
->fh3_xdata
));
2125 bcopy(exi
->exi_fid
.fid_data
, fh
->fh3_xdata
, fh
->fh3_xlen
);
2127 fh
->fh3_length
= sizeof (fh
->fh3_fsid
)
2128 + sizeof (fh
->fh3_len
) + fh
->fh3_len
2129 + sizeof (fh
->fh3_xlen
) + fh
->fh3_xlen
;
2136 * This routine makes an overloaded V3 fhandle which contains
2144 * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+
2145 * |s | | | | sec_1 | sec_2 | ... | sec_n |
2146 * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+
2148 * len = 4 * (n+1), where n is the number of security flavors
2149 * sent in the current overloaded filehandle.
2151 * the status octet s indicates whether there are more security
2152 * mechanisms (1 means yes, 0 means no) that require the client
2153 * to perform another 0x81 LOOKUP to get them.
2155 * Three octets are padded after the status octet.
2158 makefh3_ol(nfs_fh3
*fh
, struct exportinfo
*exi
, uint_t sec_index
)
2160 secinfo_t sec
[MAX_FLAVORS
];
2161 int totalcnt
, cnt
, *ipt
, i
, seccnt
, fh_max_cnt
, secidx
;
2164 if (fh
== NULL
|| exi
== NULL
|| sec_index
< 1)
2168 * WebNFS clients need to know the unique set of explicitly
2169 * shared flavors in used for the public export. When
2170 * "TRUE" is passed to build_seclist_nodups(), only explicitly
2171 * shared flavors are included in the list.
2173 seccnt
= build_seclist_nodups(&exi
->exi_export
, sec
, TRUE
);
2175 if (sec_index
> seccnt
)
2178 fh_max_cnt
= (NFS3_FHSIZE
/ sizeof (int)) - 1;
2179 totalcnt
= seccnt
- sec_index
+ 1;
2180 cnt
= totalcnt
> fh_max_cnt
? fh_max_cnt
: totalcnt
;
2183 * Place the length in fh3_length representing the number
2184 * of security flavors (in bytes) in this overloaded fh.
2186 fh
->fh3_flags
= FH_WEBNFS
;
2187 fh
->fh3_length
= (cnt
+1) * sizeof (int32_t);
2189 c
= (char *)&fh
->fh3_u
.nfs_fh3_i
.fh3_i
;
2191 * Encode the status octet that indicates whether there
2192 * are more security flavors the client needs to get.
2194 *c
= totalcnt
> fh_max_cnt
;
2197 * put security flavors in the overloaded fh
2199 secidx
= sec_index
- 1;
2200 ipt
= (int *)(c
+ sizeof (int32_t));
2201 for (i
= 0; i
< cnt
; i
++) {
2202 ipt
[i
] = htonl(sec
[i
+ secidx
].s_secinfo
.sc_nfsnum
);
2208 * Make an nfs_fh4 from a vnode
2211 makefh4(nfs_fh4
*fh
, vnode_t
*vp
, struct exportinfo
*exi
)
2214 nfs_fh4_fmt_t
*fh_fmtp
= (nfs_fh4_fmt_t
*)fh
->nfs_fh4_val
;
2217 bzero(&fid
, sizeof (fid
));
2218 fid
.fid_len
= MAXFIDSZ
;
2220 * vop_fid_pseudo() is used to set up NFSv4 namespace, so
2221 * use vop_fid_pseudo() here to get the fid instead of fop_fid.
2223 error
= vop_fid_pseudo(vp
, &fid
);
2227 fh
->nfs_fh4_len
= NFS_FH4_LEN
;
2229 fh_fmtp
->fh4_i
.fhx_fsid
= exi
->exi_fh
.fh_fsid
;
2230 fh_fmtp
->fh4_i
.fhx_xlen
= exi
->exi_fh
.fh_xlen
;
2232 bzero(fh_fmtp
->fh4_i
.fhx_data
, sizeof (fh_fmtp
->fh4_i
.fhx_data
));
2233 bzero(fh_fmtp
->fh4_i
.fhx_xdata
, sizeof (fh_fmtp
->fh4_i
.fhx_xdata
));
2234 ASSERT(exi
->exi_fh
.fh_xlen
<= sizeof (fh_fmtp
->fh4_i
.fhx_xdata
));
2235 bcopy(exi
->exi_fh
.fh_xdata
, fh_fmtp
->fh4_i
.fhx_xdata
,
2236 exi
->exi_fh
.fh_xlen
);
2238 fh_fmtp
->fh4_len
= fid
.fid_len
;
2239 ASSERT(fid
.fid_len
<= sizeof (fh_fmtp
->fh4_data
));
2240 bcopy(fid
.fid_data
, fh_fmtp
->fh4_data
, fid
.fid_len
);
2241 fh_fmtp
->fh4_flag
= 0;
2243 #ifdef VOLATILE_FH_TEST
2246 * Use the rnode volatile_id value to add volatility to the fh.
2248 * For testing purposes there are currently two scenarios, based
2249 * on whether the filesystem was shared with "volatile_fh"
2250 * or "expire_on_rename". In the first case, use the value of
2251 * export struct share_time as the volatile_id. In the second
2252 * case use the vnode volatile_id value (which is set to the
2253 * time in which the file was renamed).
2255 * Note that the above are temporary constructs for testing only
2258 if (exi
->exi_export
.ex_flags
& EX_VOLRNM
) {
2259 fh_fmtp
->fh4_volatile_id
= find_volrnm_fh_id(exi
, fh
);
2260 } else if (exi
->exi_export
.ex_flags
& EX_VOLFH
) {
2261 fh_fmtp
->fh4_volatile_id
= exi
->exi_volatile_id
;
2263 fh_fmtp
->fh4_volatile_id
= 0;
2265 #endif /* VOLATILE_FH_TEST */
2271 * Convert an fhandle into a vnode.
2272 * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode.
2273 * WARNING: users of this routine must do a VN_RELE on the vnode when they
2277 nfs_fhtovp(fhandle_t
*fh
, struct exportinfo
*exi
)
2284 TRACE_0(TR_FAC_NFS
, TR_FHTOVP_START
,
2288 TRACE_1(TR_FAC_NFS
, TR_FHTOVP_END
,
2289 "fhtovp_end:(%S)", "exi NULL");
2290 return (NULL
); /* not exported */
2293 ASSERT(exi
->exi_vp
!= NULL
);
2295 if (PUBLIC_FH2(fh
)) {
2296 if (exi
->exi_export
.ex_flags
& EX_PUBLIC
) {
2297 TRACE_1(TR_FAC_NFS
, TR_FHTOVP_END
,
2298 "fhtovp_end:(%S)", "root not exported");
2306 vfsp
= exi
->exi_vp
->v_vfsp
;
2307 ASSERT(vfsp
!= NULL
);
2308 fidp
= (fid_t
*)&fh
->fh_len
;
2310 error
= VFS_VGET(vfsp
, &vp
, fidp
);
2311 if (error
|| vp
== NULL
) {
2312 TRACE_1(TR_FAC_NFS
, TR_FHTOVP_END
,
2313 "fhtovp_end:(%S)", "VFS_GET failed or vp NULL");
2316 TRACE_1(TR_FAC_NFS
, TR_FHTOVP_END
,
2317 "fhtovp_end:(%S)", "end");
2322 * Convert an nfs_fh3 into a vnode.
2323 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2324 * WARNING: users of this routine must do a VN_RELE on the vnode when they
2328 nfs3_fhtovp(nfs_fh3
*fh
, struct exportinfo
*exi
)
2336 return (NULL
); /* not exported */
2338 ASSERT(exi
->exi_vp
!= NULL
);
2340 if (PUBLIC_FH3(fh
)) {
2341 if (exi
->exi_export
.ex_flags
& EX_PUBLIC
)
2348 if (fh
->fh3_length
< NFS3_OLDFHSIZE
||
2349 fh
->fh3_length
> NFS3_MAXFHSIZE
)
2352 vfsp
= exi
->exi_vp
->v_vfsp
;
2353 ASSERT(vfsp
!= NULL
);
2354 fidp
= FH3TOFIDP(fh
);
2356 error
= VFS_VGET(vfsp
, &vp
, fidp
);
2357 if (error
|| vp
== NULL
)
2364 * Convert an nfs_fh4 into a vnode.
2365 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2366 * WARNING: users of this routine must do a VN_RELE on the vnode when they
2370 nfs4_fhtovp(nfs_fh4
*fh
, struct exportinfo
*exi
, nfsstat4
*statp
)
2376 nfs_fh4_fmt_t
*fh_fmtp
;
2377 #ifdef VOLATILE_FH_TEST
2378 uint32_t volatile_id
= 0;
2379 #endif /* VOLATILE_FH_TEST */
2382 *statp
= NFS4ERR_STALE
;
2383 return (NULL
); /* not exported */
2385 ASSERT(exi
->exi_vp
!= NULL
);
2387 /* caller should have checked this */
2388 ASSERT(fh
->nfs_fh4_len
>= NFS_FH4_LEN
);
2390 fh_fmtp
= (nfs_fh4_fmt_t
*)fh
->nfs_fh4_val
;
2391 vfsp
= exi
->exi_vp
->v_vfsp
;
2392 ASSERT(vfsp
!= NULL
);
2393 fidp
= (fid_t
*)&fh_fmtp
->fh4_len
;
2395 #ifdef VOLATILE_FH_TEST
2396 /* XXX check if volatile - should be changed later */
2397 if (exi
->exi_export
.ex_flags
& (EX_VOLRNM
| EX_VOLFH
)) {
2399 * Filesystem is shared with volatile filehandles
2401 if (exi
->exi_export
.ex_flags
& EX_VOLRNM
)
2402 volatile_id
= find_volrnm_fh_id(exi
, fh
);
2404 volatile_id
= exi
->exi_volatile_id
;
2406 if (fh_fmtp
->fh4_volatile_id
!= volatile_id
) {
2407 *statp
= NFS4ERR_FHEXPIRED
;
2412 * XXX even if test_volatile_fh false, the fh may contain a
2413 * volatile id if obtained when the test was set.
2415 fh_fmtp
->fh4_volatile_id
= (uchar_t
)0;
2416 #endif /* VOLATILE_FH_TEST */
2418 error
= VFS_VGET(vfsp
, &vp
, fidp
);
2420 * If we can not get vp from VFS_VGET, perhaps this is
2421 * an nfs v2/v3/v4 node in an nfsv4 pseudo filesystem.
2424 if (error
&& PSEUDO(exi
))
2425 error
= nfs4_vget_pseudo(exi
, &vp
, fidp
);
2427 if (error
|| vp
== NULL
) {
2428 *statp
= NFS4ERR_STALE
;
2431 /* XXX - disgusting hack */
2432 if (vp
->v_type
== VNON
&& vp
->v_flag
& V_XATTRDIR
)
2439 * Find the export structure associated with the given filesystem.
2440 * If found, then increment the ref count (exi_count).
2443 checkexport(fsid_t
*fsid
, fid_t
*fid
)
2445 struct exportinfo
*exi
;
2447 rw_enter(&exported_lock
, RW_READER
);
2448 for (exi
= exptable
[exptablehash(fsid
, fid
)];
2450 exi
= exi
->fid_hash
.next
) {
2451 if (exportmatch(exi
, fsid
, fid
)) {
2453 * If this is the place holder for the
2454 * public file handle, then return the
2455 * real export entry for the public file
2458 if (exi
->exi_export
.ex_flags
& EX_PUBLIC
) {
2463 rw_exit(&exported_lock
);
2467 rw_exit(&exported_lock
);
2473 * "old school" version of checkexport() for NFS4. NFS4
2474 * rfs4_compound holds exported_lock for duration of compound
2475 * processing. This version doesn't manipulate exi_count
2476 * since NFS4 breaks fundamental assumptions in the exi_count
2480 checkexport4(fsid_t
*fsid
, fid_t
*fid
, vnode_t
*vp
)
2482 struct exportinfo
*exi
;
2484 ASSERT(RW_LOCK_HELD(&exported_lock
));
2486 for (exi
= exptable
[exptablehash(fsid
, fid
)];
2488 exi
= exi
->fid_hash
.next
) {
2489 if (exportmatch(exi
, fsid
, fid
)) {
2491 * If this is the place holder for the
2492 * public file handle, then return the
2493 * real export entry for the public file
2496 if (exi
->exi_export
.ex_flags
& EX_PUBLIC
) {
2501 * If vp is given, check if vp is the
2502 * same vnode as the exported node.
2504 * Since fop_fid of a lofs node returns the
2505 * fid of its real node (ufs), the exported
2506 * node for lofs and (pseudo) ufs may have
2507 * the same fsid and fid.
2509 if (vp
== NULL
|| vp
== exi
->exi_vp
)
2518 * Free an entire export list node
2521 exportfree(struct exportinfo
*exi
)
2523 struct exportdata
*ex
;
2524 struct charset_cache
*cache
;
2527 ex
= &exi
->exi_export
;
2529 ASSERT(exi
->exi_vp
!= NULL
&& !(exi
->exi_export
.ex_flags
& EX_PUBLIC
));
2530 VN_RELE(exi
->exi_vp
);
2531 if (exi
->exi_dvp
!= NULL
)
2532 VN_RELE(exi
->exi_dvp
);
2534 if (ex
->ex_flags
& EX_INDEX
)
2535 kmem_free(ex
->ex_index
, strlen(ex
->ex_index
) + 1);
2537 kmem_free(ex
->ex_path
, ex
->ex_pathlen
+ 1);
2538 nfsauth_cache_free(exi
);
2541 * if there is a character set mapping cached, clean it up.
2543 for (cache
= exi
->exi_charset
; cache
!= NULL
;
2544 cache
= exi
->exi_charset
) {
2545 if (cache
->inbound
!= (kiconv_t
)-1)
2546 (void) kiconv_close(cache
->inbound
);
2547 if (cache
->outbound
!= (kiconv_t
)-1)
2548 (void) kiconv_close(cache
->outbound
);
2549 exi
->exi_charset
= cache
->next
;
2550 kmem_free(cache
, sizeof (struct charset_cache
));
2553 if (exi
->exi_logbuffer
!= NULL
)
2554 nfslog_disable(exi
);
2556 if (ex
->ex_flags
& EX_LOG
) {
2557 kmem_free(ex
->ex_log_buffer
, ex
->ex_log_bufferlen
+ 1);
2558 kmem_free(ex
->ex_tag
, ex
->ex_taglen
+ 1);
2561 if (exi
->exi_visible
)
2562 free_visible(exi
->exi_visible
);
2564 srv_secinfo_list_free(ex
->ex_secinfo
, ex
->ex_seccnt
);
2566 #ifdef VOLATILE_FH_TEST
2567 free_volrnm_list(exi
);
2568 mutex_destroy(&exi
->exi_vol_rename_lock
);
2569 #endif /* VOLATILE_FH_TEST */
2571 mutex_destroy(&exi
->exi_lock
);
2572 rw_destroy(&exi
->exi_cache_lock
);
2574 * All nodes in the exi_cache AVL trees were removed and freed in the
2575 * nfsauth_cache_free() call above. We will just destroy and free the
2576 * empty AVL trees here.
2578 for (i
= 0; i
< AUTH_TABLESIZE
; i
++) {
2579 avl_destroy(exi
->exi_cache
[i
]);
2580 kmem_free(exi
->exi_cache
[i
], sizeof (avl_tree_t
));
2583 kmem_free(exi
, sizeof (*exi
));
2587 * load the index file from user space into kernel space.
2590 loadindex(struct exportdata
*kex
)
2593 char index
[MAXNAMELEN
+1];
2597 * copyinstr copies the complete string including the NULL and
2598 * returns the len with the NULL byte included in the calculation
2599 * as long as the max length is not exceeded.
2601 if (error
= copyinstr(kex
->ex_index
, index
, sizeof (index
), &len
))
2604 kex
->ex_index
= kmem_alloc(len
, KM_SLEEP
);
2605 bcopy(index
, kex
->ex_index
, len
);
2611 exi_hold(struct exportinfo
*exi
)
2613 mutex_enter(&exi
->exi_lock
);
2615 mutex_exit(&exi
->exi_lock
);
2619 * When a thread completes using exi, it should call exi_rele().
2620 * exi_rele() decrements exi_count. It releases exi if exi_count == 0, i.e.
2621 * if this is the last user of exi and exi is not on exportinfo list anymore
2624 exi_rele(struct exportinfo
*exi
)
2626 mutex_enter(&exi
->exi_lock
);
2628 if (exi
->exi_count
== 0) {
2629 mutex_exit(&exi
->exi_lock
);
2632 mutex_exit(&exi
->exi_lock
);
2635 #ifdef VOLATILE_FH_TEST
2637 * Test for volatile fh's - add file handle to list and set its volatile id
2638 * to time it was renamed. If EX_VOLFH is also on and the fs is reshared,
2639 * the vol_rename queue is purged.
2641 * XXX This code is for unit testing purposes only... To correctly use it, it
2642 * needs to tie a rename list to the export struct and (more
2643 * important), protect access to the exi rename list using a write lock.
2647 * get the fh vol record if it's in the volatile on rename list. Don't check
2648 * volatile_id in the file handle - compare only the file handles.
2650 static struct ex_vol_rename
*
2651 find_volrnm_fh(struct exportinfo
*exi
, nfs_fh4
*fh4p
)
2653 struct ex_vol_rename
*p
= NULL
;
2656 /* XXX shouldn't we assert &exported_lock held? */
2657 ASSERT(MUTEX_HELD(&exi
->exi_vol_rename_lock
));
2659 if (fh4p
->nfs_fh4_len
!= NFS_FH4_LEN
) {
2662 fhp
= &((nfs_fh4_fmt_t
*)fh4p
->nfs_fh4_val
)->fh4_i
;
2663 for (p
= exi
->exi_vol_rename
; p
!= NULL
; p
= p
->vrn_next
) {
2664 if (bcmp(fhp
, &p
->vrn_fh_fmt
.fh4_i
,
2665 sizeof (fhandle4_t
)) == 0)
2672 * get the volatile id for the fh (if there is - else return 0). Ignore the
2673 * volatile_id in the file handle - compare only the file handles.
2676 find_volrnm_fh_id(struct exportinfo
*exi
, nfs_fh4
*fh4p
)
2678 struct ex_vol_rename
*p
;
2679 uint32_t volatile_id
;
2681 mutex_enter(&exi
->exi_vol_rename_lock
);
2682 p
= find_volrnm_fh(exi
, fh4p
);
2683 volatile_id
= (p
? p
->vrn_fh_fmt
.fh4_volatile_id
:
2684 exi
->exi_volatile_id
);
2685 mutex_exit(&exi
->exi_vol_rename_lock
);
2686 return (volatile_id
);
2690 * Free the volatile on rename list - will be called if a filesystem is
2691 * unshared or reshared without EX_VOLRNM
2694 free_volrnm_list(struct exportinfo
*exi
)
2696 struct ex_vol_rename
*p
, *pnext
;
2698 /* no need to hold mutex lock - this one is called from exportfree */
2699 for (p
= exi
->exi_vol_rename
; p
!= NULL
; p
= pnext
) {
2700 pnext
= p
->vrn_next
;
2701 kmem_free(p
, sizeof (*p
));
2703 exi
->exi_vol_rename
= NULL
;
2707 * Add a file handle to the volatile on rename list.
2710 add_volrnm_fh(struct exportinfo
*exi
, vnode_t
*vp
)
2712 struct ex_vol_rename
*p
;
2713 char fhbuf
[NFS4_FHSIZE
];
2717 fh4
.nfs_fh4_val
= fhbuf
;
2718 error
= makefh4(&fh4
, vp
, exi
);
2719 if ((error
) || (fh4
.nfs_fh4_len
!= sizeof (p
->vrn_fh_fmt
))) {
2723 mutex_enter(&exi
->exi_vol_rename_lock
);
2725 p
= find_volrnm_fh(exi
, &fh4
);
2728 p
= kmem_alloc(sizeof (*p
), KM_SLEEP
);
2729 bcopy(fh4
.nfs_fh4_val
, &p
->vrn_fh_fmt
, sizeof (p
->vrn_fh_fmt
));
2730 p
->vrn_next
= exi
->exi_vol_rename
;
2731 exi
->exi_vol_rename
= p
;
2734 p
->vrn_fh_fmt
.fh4_volatile_id
= gethrestime_sec();
2735 mutex_exit(&exi
->exi_vol_rename_lock
);
2738 #endif /* VOLATILE_FH_TEST */