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]
22 * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
27 * Copyright 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T.
28 * All rights reserved.
32 #include <sys/types.h>
33 #include <sys/param.h>
36 #include <sys/vnode.h>
37 #include <sys/socket.h>
38 #include <sys/errno.h>
43 #include <sys/tiuser.h>
45 #include <sys/pathname.h>
46 #include <sys/debug.h>
47 #include <sys/vtrace.h>
48 #include <sys/cmn_err.h>
50 #include <sys/utsname.h>
52 #include <netinet/in.h>
54 #include <rpc/types.h>
59 #include <nfs/export.h>
60 #include <nfs/nfssys.h>
61 #include <nfs/nfs_clnt.h>
62 #include <nfs/nfs_acl.h>
63 #include <nfs/nfs_log.h>
65 #include <sys/sunddi.h>
66 #include <sys/pkp_hash.h>
70 struct exportinfo
*exptable_path_hash
[PKP_HASH_SIZE
];
71 struct exportinfo
*exptable
[EXPTABLESIZE
];
73 static int unexport(exportinfo_t
*);
74 static void exportfree(exportinfo_t
*);
75 static int loadindex(exportdata_t
*);
77 extern void nfsauth_cache_free(exportinfo_t
*);
78 extern int sec_svc_loadrootnames(int, int, caddr_t
**, model_t
);
79 extern void sec_svc_freerootnames(int, int, caddr_t
*);
81 static int build_seclist_nodups(exportdata_t
*, secinfo_t
*, int);
82 static void srv_secinfo_add(secinfo_t
**, int *, secinfo_t
*, int, int);
83 static void srv_secinfo_remove(secinfo_t
**, int *, secinfo_t
*, int);
84 static void srv_secinfo_treeclimb(exportinfo_t
*, secinfo_t
*, int, int);
86 #ifdef VOLATILE_FH_TEST
87 static struct ex_vol_rename
*find_volrnm_fh(exportinfo_t
*, nfs_fh4
*);
88 static uint32_t find_volrnm_fh_id(exportinfo_t
*, nfs_fh4
*);
89 static void free_volrnm_list(exportinfo_t
*);
90 #endif /* VOLATILE_FH_TEST */
93 * exported_lock Read/Write lock that protects the exportinfo list.
94 * This lock must be held when searching or modifiying
95 * the exportinfo list.
97 krwlock_t exported_lock
;
100 * "public" and default (root) location for public filehandle
102 struct exportinfo
*exi_public
, *exi_root
;
104 fid_t exi_rootfid
; /* for checking the default public file handle */
106 fhandle_t nullfh2
; /* for comparing V2 filehandles */
109 * macro for static dtrace probes to trace server namespace ref count mods.
111 #define SECREF_TRACE(seclist, tag, flav, aftcnt) \
112 DTRACE_PROBE4(nfss__i__nmspc__secref, struct secinfo *, (seclist), \
113 char *, (tag), int, (int)(flav), int, (int)(aftcnt))
116 #define exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1))
119 xor_hash(uint8_t *data
, int len
)
130 * File handle hash function, XOR over all bytes in fsid and fid.
133 nfs_fhhash(fsid_t
*fsid
, fid_t
*fid
)
138 h
= xor_hash((uint8_t *)fsid
, sizeof (fsid_t
));
141 * Sanity check the length before using it
142 * blindly in case the client trashed it.
144 len
= fid
->fid_len
> NFS_FH4MAXDATA
? 0 : fid
->fid_len
;
145 h
^= xor_hash((uint8_t *)fid
->fid_data
, len
);
147 return ((unsigned)h
);
151 * Free the memory allocated within a secinfo entry.
154 srv_secinfo_entry_free(struct secinfo
*secp
)
156 if (secp
->s_rootcnt
> 0 && secp
->s_rootnames
!= NULL
) {
157 sec_svc_freerootnames(secp
->s_secinfo
.sc_rpcnum
,
158 secp
->s_rootcnt
, secp
->s_rootnames
);
162 if ((secp
->s_secinfo
.sc_rpcnum
== RPCSEC_GSS
) &&
163 (secp
->s_secinfo
.sc_gss_mech_type
)) {
164 kmem_free(secp
->s_secinfo
.sc_gss_mech_type
->elements
,
165 secp
->s_secinfo
.sc_gss_mech_type
->length
);
166 kmem_free(secp
->s_secinfo
.sc_gss_mech_type
,
167 sizeof (rpc_gss_OID_desc
));
168 secp
->s_secinfo
.sc_gss_mech_type
= NULL
;
173 * Free a list of secinfo allocated in the exportdata structure.
176 srv_secinfo_list_free(struct secinfo
*secinfo
, int cnt
)
183 for (i
= 0; i
< cnt
; i
++)
184 srv_secinfo_entry_free(&secinfo
[i
]);
186 kmem_free(secinfo
, cnt
* sizeof (struct secinfo
));
190 * Allocate and copy a secinfo data from "from" to "to".
192 * This routine is used by srv_secinfo_add() to add a new flavor to an
193 * ancestor's export node. The rootnames are not copied because the
194 * allowable rootname access only applies to the explicit exported node,
195 * not its ancestor's.
197 * "to" should have already been allocated and zeroed before calling
200 * This routine is used under the protection of exported_lock (RW_WRITER).
203 srv_secinfo_copy(struct secinfo
*from
, struct secinfo
*to
)
205 to
->s_secinfo
.sc_nfsnum
= from
->s_secinfo
.sc_nfsnum
;
206 to
->s_secinfo
.sc_rpcnum
= from
->s_secinfo
.sc_rpcnum
;
208 if (from
->s_secinfo
.sc_rpcnum
== RPCSEC_GSS
) {
209 to
->s_secinfo
.sc_service
= from
->s_secinfo
.sc_service
;
210 bcopy(from
->s_secinfo
.sc_name
, to
->s_secinfo
.sc_name
,
211 strlen(from
->s_secinfo
.sc_name
));
212 bcopy(from
->s_secinfo
.sc_gss_mech
, to
->s_secinfo
.sc_gss_mech
,
213 strlen(from
->s_secinfo
.sc_gss_mech
));
215 /* copy mechanism oid */
216 to
->s_secinfo
.sc_gss_mech_type
=
217 kmem_alloc(sizeof (rpc_gss_OID_desc
), KM_SLEEP
);
218 to
->s_secinfo
.sc_gss_mech_type
->length
=
219 from
->s_secinfo
.sc_gss_mech_type
->length
;
220 to
->s_secinfo
.sc_gss_mech_type
->elements
=
221 kmem_alloc(from
->s_secinfo
.sc_gss_mech_type
->length
,
223 bcopy(from
->s_secinfo
.sc_gss_mech_type
->elements
,
224 to
->s_secinfo
.sc_gss_mech_type
->elements
,
225 from
->s_secinfo
.sc_gss_mech_type
->length
);
228 to
->s_refcnt
= from
->s_refcnt
;
229 to
->s_window
= from
->s_window
;
230 /* no need to copy the mode bits - s_flags */
234 * Create a secinfo array without duplicates. The condensed
235 * flavor list is used to propagate flavor ref counts to an
236 * export's ancestor pseudonodes.
239 build_seclist_nodups(exportdata_t
*exd
, secinfo_t
*nodups
, int exponly
)
243 struct secinfo
*cursec
;
246 ccnt
= exd
->ex_seccnt
;
247 cursec
= exd
->ex_secinfo
;
249 for (c
= 0; c
< ccnt
; c
++) {
251 if (exponly
&& ! SEC_REF_EXPORTED(&cursec
[c
]))
254 for (n
= 0; n
< ncnt
; n
++) {
255 if (nodups
[n
].s_secinfo
.sc_nfsnum
==
256 cursec
[c
].s_secinfo
.sc_nfsnum
)
261 * The structure copy below also copys ptrs embedded
262 * within struct secinfo. The ptrs are copied but
263 * they are never freed from the nodups array. If
264 * an ancestor's secinfo array doesn't contain one
265 * of the nodups flavors, then the entry is properly
266 * copied into the ancestor's secinfo array.
267 * (see srv_secinfo_copy)
270 nodups
[n
] = cursec
[c
];
278 * Add the new security flavors from newdata to the current list, pcursec.
279 * Upon return, *pcursec has the newly merged secinfo list.
281 * There should be at least 1 secinfo entry in newsec.
283 * This routine is used under the protection of exported_lock (RW_WRITER).
286 srv_secinfo_add(secinfo_t
**pcursec
, int *pcurcnt
, secinfo_t
*newsec
,
287 int newcnt
, int is_pseudo
)
289 int ccnt
, c
; /* sec count in current data - curdata */
290 int n
; /* index for newsec - newsecinfo */
291 int tcnt
; /* total sec count after merge */
292 int mcnt
; /* total sec count after merge */
293 struct secinfo
*msec
; /* merged secinfo list */
294 struct secinfo
*cursec
;
300 tcnt
= ccnt
+ newcnt
;
302 for (n
= 0; n
< newcnt
; n
++) {
303 for (c
= 0; c
< ccnt
; c
++) {
304 if (newsec
[n
].s_secinfo
.sc_nfsnum
==
305 cursec
[c
].s_secinfo
.sc_nfsnum
) {
306 cursec
[c
].s_refcnt
+= newsec
[n
].s_refcnt
;
307 SECREF_TRACE(cursec
, "add_ref",
308 cursec
[c
].s_secinfo
.sc_nfsnum
,
317 return; /* no change; no new flavors */
319 msec
= kmem_zalloc(tcnt
* sizeof (struct secinfo
), KM_SLEEP
);
321 /* move current secinfo list data to the new list */
322 for (c
= 0; c
< ccnt
; c
++)
325 /* Add the flavor that's not in the current data */
327 for (n
= 0; n
< newcnt
; n
++) {
328 for (c
= 0; c
< ccnt
; c
++) {
329 if (newsec
[n
].s_secinfo
.sc_nfsnum
==
330 cursec
[c
].s_secinfo
.sc_nfsnum
)
334 /* This is the one. Add it. */
336 srv_secinfo_copy(&newsec
[n
], &msec
[mcnt
]);
339 msec
[mcnt
].s_flags
= M_RO
;
341 SECREF_TRACE(msec
, "new_ref",
342 msec
[mcnt
].s_secinfo
.sc_nfsnum
,
343 msec
[mcnt
].s_refcnt
);
348 ASSERT(mcnt
== tcnt
);
351 * Done. Update curdata. Free the old secinfo list in
352 * curdata and return the new sec array info
355 kmem_free(cursec
, ccnt
* sizeof (struct secinfo
));
362 * Remove the security data of the unexported node from its ancestors.
363 * Assume there is at least one flavor entry in the current sec list
366 * This routine is used under the protection of exported_lock (RW_WRITER).
368 * Every element of remsec is an explicitly exported flavor. If
369 * srv_secinfo_remove() is called fom an exportfs error path, then
370 * the flavor list was derived from the user's share cmdline,
371 * and all flavors are explicit. If it was called from the unshare path,
372 * build_seclist_nodups() was called with the exponly flag.
375 srv_secinfo_remove(secinfo_t
**pcursec
, int *pcurcnt
, secinfo_t
*remsec
,
378 int ccnt
, c
; /* sec count in current data - cursec */
379 int r
; /* sec count in removal data - remsec */
380 int tcnt
, mcnt
; /* total sec count after removing */
381 struct secinfo
*msec
; /* final secinfo list after removing */
382 struct secinfo
*cursec
;
388 for (r
= 0; r
< remcnt
; r
++) {
390 * At unshare/reshare time, only explicitly shared flavor ref
391 * counts are decremented and propagated to ancestors.
392 * Implicit flavor refs came from shared descendants, and
395 if (! SEC_REF_EXPORTED(&remsec
[r
]))
398 for (c
= 0; c
< ccnt
; c
++) {
399 if (remsec
[r
].s_secinfo
.sc_nfsnum
==
400 cursec
[c
].s_secinfo
.sc_nfsnum
) {
403 * Decrement secinfo reference count by 1.
404 * If this entry is invalid after decrementing
405 * the count (i.e. count < 1), this entry will
408 cursec
[c
].s_refcnt
--;
410 SECREF_TRACE(cursec
, "del_ref",
411 cursec
[c
].s_secinfo
.sc_nfsnum
,
414 ASSERT(cursec
[c
].s_refcnt
>= 0);
416 if (SEC_REF_INVALID(&cursec
[c
]))
425 return; /* no change; no flavors to remove */
428 srv_secinfo_list_free(cursec
, ccnt
);
434 msec
= kmem_zalloc(tcnt
* sizeof (struct secinfo
), KM_SLEEP
);
436 /* walk thru the given secinfo list to remove the flavors */
438 for (c
= 0; c
< ccnt
; c
++) {
439 if (SEC_REF_INVALID(&cursec
[c
])) {
440 srv_secinfo_entry_free(&cursec
[c
]);
442 msec
[mcnt
] = cursec
[c
];
447 ASSERT(mcnt
== tcnt
);
449 * Done. Update curdata.
450 * Free the existing secinfo list in curdata. All pointers
451 * within the list have either been moved to msec or freed
454 kmem_free(*pcursec
, ccnt
* sizeof (struct secinfo
));
461 * For the reshare case, sec flavor accounting happens in 3 steps:
462 * 1) propagate addition of new flavor refs up the ancestor tree
463 * 2) transfer flavor refs of descendants to new/reshared exportdata
464 * 3) propagate removal of old flavor refs up the ancestor tree
466 * srv_secinfo_exp2exp() implements step 2 of a reshare. At this point,
467 * the new flavor list has already been propagated up through the
468 * ancestor tree via srv_secinfo_treeclimb().
470 * If there is more than 1 export reference to an old flavor (i.e. some
471 * of its children shared with this flavor), this flavor information
472 * needs to be transferred to the new exportdata struct. A flavor in
473 * the old exportdata has descendant refs when its s_refcnt > 1 or it
474 * is implicitly shared (M_SEC4_EXPORTED not set in s_flags).
476 * SEC_REF_EXPORTED() is only true when M_SEC4_EXPORTED is set
477 * SEC_REF_SELF() is only true when both M_SEC4_EXPORTED is set and s_refcnt==1
479 * Transferring descendant flavor refcnts happens in 2 passes:
480 * a) flavors used before (oldsecinfo) and after (curdata->ex_secinfo) reshare
481 * b) flavors used before but not after reshare
483 * This routine is used under the protection of exported_lock (RW_WRITER).
486 srv_secinfo_exp2exp(exportdata_t
*curdata
, secinfo_t
*oldsecinfo
, int ocnt
)
488 int ccnt
, c
; /* sec count in current data - curdata */
489 int o
; /* sec count in old data - oldsecinfo */
490 int tcnt
, mcnt
; /* total sec count after the transfer */
491 struct secinfo
*msec
; /* merged secinfo list */
493 ccnt
= curdata
->ex_seccnt
;
496 ASSERT(!(curdata
->ex_flags
& EX_PSEUDO
));
499 * If the oldsecinfo has flavors with more than 1 reference count
500 * and the flavor is specified in the reshare, transfer the flavor
501 * refs to the new seclist (curdata.ex_secinfo).
505 for (o
= 0; o
< ocnt
; o
++) {
507 if (SEC_REF_SELF(&oldsecinfo
[o
])) {
512 for (c
= 0; c
< ccnt
; c
++) {
513 if (oldsecinfo
[o
].s_secinfo
.sc_nfsnum
==
514 curdata
->ex_secinfo
[c
].s_secinfo
.sc_nfsnum
) {
517 * add old reference to the current
520 curdata
->ex_secinfo
[c
].s_refcnt
+=
521 oldsecinfo
[o
].s_refcnt
;
524 * Delete the old export flavor
525 * reference. The initial reference
526 * was created during srv_secinfo_add,
527 * and the count is decremented below
528 * to account for the initial reference.
530 if (SEC_REF_EXPORTED(&oldsecinfo
[o
]))
531 curdata
->ex_secinfo
[c
].s_refcnt
--;
533 SECREF_TRACE(curdata
->ex_path
,
534 "reshare_xfer_common_child_refs",
535 curdata
->ex_secinfo
[c
].s_secinfo
.sc_nfsnum
,
536 curdata
->ex_secinfo
[c
].s_refcnt
);
538 ASSERT(curdata
->ex_secinfo
[c
].s_refcnt
>= 0);
547 return; /* no more transfer to do */
550 * oldsecinfo has flavors referenced by its children that are not
551 * in the current (new) export flavor list. Add these flavors.
553 msec
= kmem_zalloc(tcnt
* sizeof (struct secinfo
), KM_SLEEP
);
555 /* move current secinfo list data to the new list */
556 for (c
= 0; c
< ccnt
; c
++)
557 msec
[c
] = curdata
->ex_secinfo
[c
];
560 * Add the flavor that's not in the new export, but still
561 * referenced by its children.
564 for (o
= 0; o
< ocnt
; o
++) {
565 if (! SEC_REF_SELF(&oldsecinfo
[o
])) {
566 for (c
= 0; c
< ccnt
; c
++) {
567 if (oldsecinfo
[o
].s_secinfo
.sc_nfsnum
==
568 curdata
->ex_secinfo
[c
].s_secinfo
.sc_nfsnum
)
573 * This is the one. Add it. Decrement the ref count
574 * by 1 if the flavor is an explicitly shared flavor
575 * for the oldsecinfo export node.
578 srv_secinfo_copy(&oldsecinfo
[o
], &msec
[mcnt
]);
579 if (SEC_REF_EXPORTED(&oldsecinfo
[o
]))
580 msec
[mcnt
].s_refcnt
--;
582 SECREF_TRACE(curdata
,
583 "reshare_xfer_implicit_child_refs",
584 msec
[mcnt
].s_secinfo
.sc_nfsnum
,
585 msec
[mcnt
].s_refcnt
);
587 ASSERT(msec
[mcnt
].s_refcnt
>= 0);
593 ASSERT(mcnt
== tcnt
);
595 * Done. Update curdata, free the existing secinfo list in
596 * curdata and set the new value.
599 kmem_free(curdata
->ex_secinfo
, ccnt
* sizeof (struct secinfo
));
600 curdata
->ex_seccnt
= tcnt
;
601 curdata
->ex_secinfo
= msec
;
605 * When unsharing an old export node and the old node becomes a pseudo node,
606 * if there is more than 1 export reference to an old flavor (i.e. some of
607 * its children shared with this flavor), this flavor information needs to
608 * be transferred to the new shared node.
610 * This routine is used under the protection of exported_lock (RW_WRITER).
613 srv_secinfo_exp2pseu(exportdata_t
*curdata
, exportdata_t
*olddata
)
615 int ocnt
, o
; /* sec count in transfer data - trandata */
616 int tcnt
, mcnt
; /* total sec count after transfer */
617 struct secinfo
*msec
; /* merged secinfo list */
619 ASSERT(curdata
->ex_flags
& EX_PSEUDO
);
620 ASSERT(curdata
->ex_seccnt
== 0);
622 ocnt
= olddata
->ex_seccnt
;
625 * If the olddata has flavors with more than 1 reference count,
626 * transfer the information to the curdata.
630 for (o
= 0; o
< ocnt
; o
++) {
631 if (SEC_REF_SELF(&olddata
->ex_secinfo
[o
]))
636 return; /* no transfer to do */
638 msec
= kmem_zalloc(tcnt
* sizeof (struct secinfo
), KM_SLEEP
);
641 for (o
= 0; o
< ocnt
; o
++) {
642 if (! SEC_REF_SELF(&olddata
->ex_secinfo
[o
])) {
645 * Decrement the reference count by 1 if the flavor is
646 * an explicitly shared flavor for the olddata export
649 srv_secinfo_copy(&olddata
->ex_secinfo
[o
], &msec
[mcnt
]);
650 msec
[mcnt
].s_flags
= M_RO
;
651 if (SEC_REF_EXPORTED(&olddata
->ex_secinfo
[o
]))
652 msec
[mcnt
].s_refcnt
--;
654 SECREF_TRACE(curdata
, "unshare_morph_pseudo",
655 msec
[mcnt
].s_secinfo
.sc_nfsnum
,
656 msec
[mcnt
].s_refcnt
);
658 ASSERT(msec
[mcnt
].s_refcnt
>= 0);
663 ASSERT(mcnt
== tcnt
);
665 * Done. Update curdata.
666 * Free up the existing secinfo list in curdata and
669 curdata
->ex_seccnt
= tcnt
;
670 curdata
->ex_secinfo
= msec
;
674 * Find for given treenode the exportinfo which has its
675 * exp_visible linked on its exi_visible list.
677 * Note: We could add new pointer either to treenode or
678 * to exp_visible, which will point there directly.
679 * This would buy some speed for some memory.
682 vis2exi(treenode_t
*tnode
)
684 exportinfo_t
*exi_ret
= NULL
;
687 tnode
= tnode
->tree_parent
;
688 if (TREE_ROOT(tnode
)) {
689 exi_ret
= tnode
->tree_exi
;
694 ASSERT(exi_ret
); /* Every visible should have its home exportinfo */
700 * Add or remove the newly exported or unexported security flavors of the
701 * given exportinfo from its ancestors upto the system root.
704 srv_secinfo_treeclimb(exportinfo_t
*exip
, secinfo_t
*sec
, int seccnt
, int isadd
)
706 treenode_t
*tnode
= exip
->exi_tree
;
708 ASSERT(RW_WRITE_HELD(&exported_lock
));
715 * If flavors are being added and the new export root isn't
716 * also VROOT, its implicitly allowed flavors are inherited from
717 * from its pseudonode.
718 * Note - for VROOT exports the implicitly allowed flavors were
719 * transferred from the PSEUDO export in exportfs()
721 if (isadd
&& !(exip
->exi_vp
->v_flag
& VROOT
) &&
722 tnode
->tree_vis
->vis_seccnt
> 0) {
723 srv_secinfo_add(&exip
->exi_export
.ex_secinfo
,
724 &exip
->exi_export
.ex_seccnt
, tnode
->tree_vis
->vis_secinfo
,
725 tnode
->tree_vis
->vis_seccnt
, FALSE
);
729 * Move to parent node and propagate sec flavor
730 * to exportinfo and to visible structures.
732 tnode
= tnode
->tree_parent
;
736 /* If there is exportinfo, update it */
737 if (tnode
->tree_exi
) {
739 &tnode
->tree_exi
->exi_export
.ex_secinfo
;
740 int *pxcnt
= &tnode
->tree_exi
->exi_export
.ex_seccnt
;
741 int is_pseudo
= PSEUDO(tnode
->tree_exi
);
743 srv_secinfo_add(pxsec
, pxcnt
, sec
, seccnt
,
746 srv_secinfo_remove(pxsec
, pxcnt
, sec
, seccnt
);
749 /* Update every visible - only root node has no visible */
750 if (tnode
->tree_vis
) {
751 secinfo_t
**pxsec
= &tnode
->tree_vis
->vis_secinfo
;
752 int *pxcnt
= &tnode
->tree_vis
->vis_seccnt
;
754 srv_secinfo_add(pxsec
, pxcnt
, sec
, seccnt
,
757 srv_secinfo_remove(pxsec
, pxcnt
, sec
, seccnt
);
759 tnode
= tnode
->tree_parent
;
763 /* hash_name is a text substitution for either fid_hash or path_hash */
764 #define exp_hash_unlink(exi, hash_name) \
765 if (*(exi)->hash_name.bckt == (exi)) \
766 *(exi)->hash_name.bckt = (exi)->hash_name.next; \
767 if ((exi)->hash_name.prev) \
768 (exi)->hash_name.prev->hash_name.next = (exi)->hash_name.next; \
769 if ((exi)->hash_name.next) \
770 (exi)->hash_name.next->hash_name.prev = (exi)->hash_name.prev; \
771 (exi)->hash_name.bckt = NULL;
773 #define exp_hash_link(exi, hash_name, bucket) \
774 (exi)->hash_name.bckt = (bucket); \
775 (exi)->hash_name.prev = NULL; \
776 (exi)->hash_name.next = *(bucket); \
777 if ((exi)->hash_name.next) \
778 (exi)->hash_name.next->hash_name.prev = (exi); \
782 export_link(exportinfo_t
*exi
)
786 bckt
= &exptable
[exptablehash(&exi
->exi_fsid
, &exi
->exi_fid
)];
787 exp_hash_link(exi
, fid_hash
, bckt
);
789 bckt
= &exptable_path_hash
[pkp_tab_hash(exi
->exi_export
.ex_path
,
790 strlen(exi
->exi_export
.ex_path
))];
791 exp_hash_link(exi
, path_hash
, bckt
);
795 * Initialization routine for export routines. Should only be called once.
802 rw_init(&exported_lock
, NULL
, RW_DEFAULT
, NULL
);
805 * Allocate the place holder for the public file handle, which
806 * is all zeroes. It is initially set to the root filesystem.
808 exi_root
= kmem_zalloc(sizeof (*exi_root
), KM_SLEEP
);
809 exi_public
= exi_root
;
811 exi_root
->exi_export
.ex_flags
= EX_PUBLIC
;
812 exi_root
->exi_export
.ex_pathlen
= 1; /* length of "/" */
813 exi_root
->exi_export
.ex_path
=
814 kmem_alloc(exi_root
->exi_export
.ex_pathlen
+ 1, KM_SLEEP
);
815 exi_root
->exi_export
.ex_path
[0] = '/';
816 exi_root
->exi_export
.ex_path
[1] = '\0';
818 exi_root
->exi_count
= 1;
819 mutex_init(&exi_root
->exi_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
821 exi_root
->exi_vp
= rootdir
;
822 exi_rootfid
.fid_len
= MAXFIDSZ
;
823 error
= vop_fid_pseudo(exi_root
->exi_vp
, &exi_rootfid
);
825 mutex_destroy(&exi_root
->exi_lock
);
826 kmem_free(exi_root
, sizeof (*exi_root
));
830 /* setup the fhandle template */
831 exi_root
->exi_fh
.fh_fsid
= rootdir
->v_vfsp
->vfs_fsid
;
832 exi_root
->exi_fh
.fh_xlen
= exi_rootfid
.fid_len
;
833 bcopy(exi_rootfid
.fid_data
, exi_root
->exi_fh
.fh_xdata
,
834 exi_rootfid
.fid_len
);
835 exi_root
->exi_fh
.fh_len
= sizeof (exi_root
->exi_fh
.fh_data
);
838 * Publish the exportinfo in the hash table
840 export_link(exi_root
);
849 * Finalization routine for export routines. Called to cleanup previously
850 * initialization work when the NFS server module could not be loaded correctly.
856 * Deallocate the place holder for the public file handle.
858 srv_secinfo_list_free(exi_root
->exi_export
.ex_secinfo
,
859 exi_root
->exi_export
.ex_seccnt
);
860 mutex_destroy(&exi_root
->exi_lock
);
861 kmem_free(exi_root
, sizeof (*exi_root
));
863 rw_destroy(&exported_lock
);
867 * Check if 2 gss mechanism identifiers are the same.
869 * return FALSE if not the same.
870 * return TRUE if the same.
873 nfs_mech_equal(rpc_gss_OID mech1
, rpc_gss_OID mech2
)
875 if ((mech1
->length
== 0) && (mech2
->length
== 0))
878 if (mech1
->length
!= mech2
->length
)
881 return (bcmp(mech1
->elements
, mech2
->elements
, mech1
->length
) == 0);
885 * This routine is used by rpc to map rpc security number
886 * to nfs specific security flavor number.
888 * The gss callback prototype is
889 * callback(struct svc_req *, gss_cred_id_t *, gss_ctx_id_t *,
890 * rpc_gss_lock_t *, void **),
891 * since nfs does not use the gss_cred_id_t/gss_ctx_id_t arguments
892 * we cast them to void.
896 rfs_gsscallback(struct svc_req
*req
, gss_cred_id_t deleg
, void *gss_context
,
897 rpc_gss_lock_t
*lock
, void **cookie
)
900 rpc_gss_rawcred_t
*raw_cred
;
901 struct exportinfo
*exi
;
904 * We don't deal with delegated credentials.
906 if (deleg
!= GSS_C_NO_CREDENTIAL
)
909 raw_cred
= lock
->raw_cred
;
912 rw_enter(&exported_lock
, RW_READER
);
913 for (i
= 0; i
< EXPTABLESIZE
; i
++) {
916 if (exi
->exi_export
.ex_seccnt
> 0) {
917 struct secinfo
*secp
;
921 secp
= exi
->exi_export
.ex_secinfo
;
922 seccnt
= exi
->exi_export
.ex_seccnt
;
923 for (j
= 0; j
< seccnt
; j
++) {
925 * If there is a map of the triplet
926 * (mechanism, service, qop) between
927 * raw_cred and the exported flavor,
928 * get the psudo flavor number.
929 * Also qop should not be NULL, it
930 * should be "default" or something
933 se
= &secp
[j
].s_secinfo
;
934 if ((se
->sc_rpcnum
== RPCSEC_GSS
) &&
937 se
->sc_gss_mech_type
,
938 raw_cred
->mechanism
)) &&
941 raw_cred
->service
) &&
942 (raw_cred
->qop
== se
->sc_qop
)) {
944 *cookie
= (void *)(uintptr_t)
950 exi
= exi
->fid_hash
.next
;
954 rw_exit(&exported_lock
);
957 * If no nfs pseudo number mapping can be found in the export
958 * table, assign the nfsflavor to NFS_FLAVOR_NOMAP. In V4, we may
959 * recover the flavor mismatch from NFS layer (NFS4ERR_WRONGSEC).
962 * server first shares with krb5i;
963 * client mounts with krb5i;
964 * server re-shares with krb5p;
965 * client tries with krb5i, but no mapping can be found;
966 * rpcsec_gss module calls this routine to do the mapping,
967 * if this routine fails, request is rejected from
969 * What we need is to let the nfs layer rejects the request.
970 * For V4, we can reject with NFS4ERR_WRONGSEC and the client
971 * may recover from it by getting the new flavor via SECINFO.
973 * nfs pseudo number for RPCSEC_GSS mapping (see nfssec.conf)
974 * is owned by IANA (see RFC 2623).
976 * XXX NFS_FLAVOR_NOMAP is defined in Solaris to work around
977 * the implementation issue. This number should not overlap with
978 * any new IANA defined pseudo flavor numbers.
981 *cookie
= (void *)NFS_FLAVOR_NOMAP
;
990 * Exportfs system call; credentials should be checked before
991 * calling this function.
994 exportfs(struct exportfs_args
*args
, model_t model
, cred_t
*cr
)
998 struct exportdata
*kex
;
999 struct exportinfo
*exi
= NULL
;
1000 struct exportinfo
*ex
, *ex1
, *ex2
;
1006 struct secinfo
*exs
;
1007 rpc_gss_callback_t cb
;
1013 STRUCT_HANDLE(exportfs_args
, uap
);
1014 STRUCT_DECL(exportdata
, uexi
);
1015 struct secinfo newsec
[MAX_FLAVORS
];
1017 struct secinfo oldsec
[MAX_FLAVORS
];
1020 struct pathname lookpn
;
1022 STRUCT_SET_HANDLE(uap
, model
, args
);
1024 /* Read in pathname from userspace */
1025 if (error
= pn_get(STRUCT_FGETP(uap
, dname
), UIO_USERSPACE
, &lookpn
))
1028 /* Walk the export list looking for that pathname */
1029 rw_enter(&exported_lock
, RW_READER
);
1030 DTRACE_PROBE(nfss__i__exported_lock1_start
);
1031 for (ex1
= exptable_path_hash
[pkp_tab_hash(lookpn
.pn_path
,
1032 strlen(lookpn
.pn_path
))]; ex1
; ex1
= ex1
->path_hash
.next
) {
1033 if (ex1
!= exi_root
&& 0 ==
1034 strcmp(ex1
->exi_export
.ex_path
, lookpn
.pn_path
)) {
1039 DTRACE_PROBE(nfss__i__exported_lock1_stop
);
1040 rw_exit(&exported_lock
);
1042 /* Is this an unshare? */
1043 if (STRUCT_FGETP(uap
, uex
) == NULL
) {
1047 error
= unexport(ex1
);
1052 /* It is a share or a re-share */
1053 error
= lookupname(STRUCT_FGETP(uap
, dname
), UIO_USERSPACE
,
1055 if (error
== EINVAL
) {
1057 * if fname resolves to / we get EINVAL error
1058 * since we wanted the parent vnode. Try again
1061 error
= lookupname(STRUCT_FGETP(uap
, dname
), UIO_USERSPACE
,
1065 if (!error
&& vp
== NULL
) {
1066 /* Last component of fname not found */
1079 * 'vp' may be an AUTOFS node, so we perform a
1080 * VOP_ACCESS() to trigger the mount of the
1081 * intended filesystem, so we can share the intended
1082 * filesystem instead of the AUTOFS filesystem.
1084 (void) VOP_ACCESS(vp
, 0, 0, cr
, NULL
);
1087 * We're interested in the top most filesystem.
1088 * This is specially important when uap->dname is a trigger
1089 * AUTOFS node, since we're really interested in sharing the
1090 * filesystem AUTOFS mounted as result of the VOP_ACCESS()
1091 * call not the AUTOFS node itself.
1093 if (vn_mountedvfs(vp
) != NULL
) {
1094 if (error
= traverse(&vp
)) {
1105 /* Do not allow sharing another vnode for already shared path */
1106 if (ex1
&& !PSEUDO(ex1
) && !VN_CMP(ex1
->exi_vp
, vp
)) {
1120 bzero(&fid
, sizeof (fid
));
1121 fid
.fid_len
= MAXFIDSZ
;
1122 error
= VOP_FID(vp
, &fid
, NULL
);
1123 fsid
= vp
->v_vfsp
->vfs_fsid
;
1130 * If VOP_FID returns ENOSPC then the fid supplied
1131 * is too small. For now we simply return EREMOTE.
1133 if (error
== ENOSPC
)
1140 * Do not allow re-sharing a shared vnode under a different path
1141 * PSEUDO export has ex_path fabricated, e.g. "/tmp (pseudo)", skip it.
1143 rw_enter(&exported_lock
, RW_READER
);
1144 DTRACE_PROBE(nfss__i__exported_lock2_start
);
1145 for (ex2
= exptable
[exptablehash(&fsid
, &fid
)]; ex2
;
1146 ex2
= ex2
->fid_hash
.next
) {
1147 if (ex2
!= exi_root
&& !PSEUDO(ex2
) &&
1148 VN_CMP(ex2
->exi_vp
, vp
) &&
1149 strcmp(ex2
->exi_export
.ex_path
, lookpn
.pn_path
) != 0) {
1150 DTRACE_PROBE(nfss__i__exported_lock2_stop
);
1151 rw_exit(&exported_lock
);
1159 DTRACE_PROBE(nfss__i__exported_lock2_stop
);
1160 rw_exit(&exported_lock
);
1163 exi
= kmem_zalloc(sizeof (*exi
), KM_SLEEP
);
1164 exi
->exi_fsid
= fsid
;
1168 exi
->exi_volatile_dev
= (vfssw
[vp
->v_vfsp
->vfs_fstype
].vsw_flag
&
1169 VSW_VOLATILEDEV
) ? 1 : 0;
1170 mutex_init(&exi
->exi_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
1174 * Initialize auth cache lock
1176 rw_init(&exi
->exi_cache_lock
, NULL
, RW_DEFAULT
, NULL
);
1179 * Build up the template fhandle
1181 exi
->exi_fh
.fh_fsid
= fsid
;
1182 if (exi
->exi_fid
.fid_len
> sizeof (exi
->exi_fh
.fh_xdata
)) {
1186 exi
->exi_fh
.fh_xlen
= exi
->exi_fid
.fid_len
;
1187 bcopy(exi
->exi_fid
.fid_data
, exi
->exi_fh
.fh_xdata
,
1188 exi
->exi_fid
.fid_len
);
1190 exi
->exi_fh
.fh_len
= sizeof (exi
->exi_fh
.fh_data
);
1192 kex
= &exi
->exi_export
;
1195 * Load in everything, and do sanity checking
1197 STRUCT_INIT(uexi
, model
);
1198 if (copyin(STRUCT_FGETP(uap
, uex
), STRUCT_BUF(uexi
),
1199 STRUCT_SIZE(uexi
))) {
1204 kex
->ex_version
= STRUCT_FGET(uexi
, ex_version
);
1205 if (kex
->ex_version
!= EX_CURRENT_VERSION
) {
1208 "NFS: exportfs requires export struct version 2 - got %d\n",
1214 * Must have at least one security entry
1216 kex
->ex_seccnt
= STRUCT_FGET(uexi
, ex_seccnt
);
1217 if (kex
->ex_seccnt
< 1) {
1222 kex
->ex_path
= STRUCT_FGETP(uexi
, ex_path
);
1223 kex
->ex_pathlen
= STRUCT_FGET(uexi
, ex_pathlen
);
1224 kex
->ex_flags
= STRUCT_FGET(uexi
, ex_flags
);
1225 kex
->ex_anon
= STRUCT_FGET(uexi
, ex_anon
);
1226 kex
->ex_secinfo
= STRUCT_FGETP(uexi
, ex_secinfo
);
1227 kex
->ex_index
= STRUCT_FGETP(uexi
, ex_index
);
1228 kex
->ex_log_buffer
= STRUCT_FGETP(uexi
, ex_log_buffer
);
1229 kex
->ex_log_bufferlen
= STRUCT_FGET(uexi
, ex_log_bufferlen
);
1230 kex
->ex_tag
= STRUCT_FGETP(uexi
, ex_tag
);
1231 kex
->ex_taglen
= STRUCT_FGET(uexi
, ex_taglen
);
1234 * Copy the exported pathname into
1235 * an appropriately sized buffer.
1237 pathbuf
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
1238 if (copyinstr(kex
->ex_path
, pathbuf
, MAXPATHLEN
, &kex
->ex_pathlen
)) {
1239 kmem_free(pathbuf
, MAXPATHLEN
);
1243 kex
->ex_path
= kmem_alloc(kex
->ex_pathlen
+ 1, KM_SLEEP
);
1244 bcopy(pathbuf
, kex
->ex_path
, kex
->ex_pathlen
);
1245 kex
->ex_path
[kex
->ex_pathlen
] = '\0';
1246 kmem_free(pathbuf
, MAXPATHLEN
);
1249 * Get the path to the logging buffer and the tag
1251 if (kex
->ex_flags
& EX_LOG
) {
1252 log_buffer
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
1253 if (copyinstr(kex
->ex_log_buffer
, log_buffer
, MAXPATHLEN
,
1254 &kex
->ex_log_bufferlen
)) {
1255 kmem_free(log_buffer
, MAXPATHLEN
);
1259 kex
->ex_log_buffer
=
1260 kmem_alloc(kex
->ex_log_bufferlen
+ 1, KM_SLEEP
);
1261 bcopy(log_buffer
, kex
->ex_log_buffer
, kex
->ex_log_bufferlen
);
1262 kex
->ex_log_buffer
[kex
->ex_log_bufferlen
] = '\0';
1263 kmem_free(log_buffer
, MAXPATHLEN
);
1265 tagbuf
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
1266 if (copyinstr(kex
->ex_tag
, tagbuf
, MAXPATHLEN
,
1268 kmem_free(tagbuf
, MAXPATHLEN
);
1272 kex
->ex_tag
= kmem_alloc(kex
->ex_taglen
+ 1, KM_SLEEP
);
1273 bcopy(tagbuf
, kex
->ex_tag
, kex
->ex_taglen
);
1274 kex
->ex_tag
[kex
->ex_taglen
] = '\0';
1275 kmem_free(tagbuf
, MAXPATHLEN
);
1279 * Load the security information for each flavor
1281 allocsize
= kex
->ex_seccnt
* SIZEOF_STRUCT(secinfo
, model
);
1282 sp
= kmem_zalloc(allocsize
, KM_SLEEP
);
1283 if (copyin(kex
->ex_secinfo
, sp
, allocsize
)) {
1284 kmem_free(sp
, allocsize
);
1290 * All of these nested structures need to be converted to
1291 * the kernel native format.
1293 if (model
!= DATAMODEL_NATIVE
) {
1295 struct secinfo
*sp2
;
1297 allocsize2
= kex
->ex_seccnt
* sizeof (struct secinfo
);
1298 sp2
= kmem_zalloc(allocsize2
, KM_SLEEP
);
1300 for (i
= 0; i
< kex
->ex_seccnt
; i
++) {
1301 STRUCT_HANDLE(secinfo
, usi
);
1303 STRUCT_SET_HANDLE(usi
, model
,
1304 (struct secinfo
*)((caddr_t
)sp
+
1305 (i
* SIZEOF_STRUCT(secinfo
, model
))));
1306 bcopy(STRUCT_FGET(usi
, s_secinfo
.sc_name
),
1307 sp2
[i
].s_secinfo
.sc_name
, MAX_NAME_LEN
);
1308 sp2
[i
].s_secinfo
.sc_nfsnum
=
1309 STRUCT_FGET(usi
, s_secinfo
.sc_nfsnum
);
1310 sp2
[i
].s_secinfo
.sc_rpcnum
=
1311 STRUCT_FGET(usi
, s_secinfo
.sc_rpcnum
);
1312 bcopy(STRUCT_FGET(usi
, s_secinfo
.sc_gss_mech
),
1313 sp2
[i
].s_secinfo
.sc_gss_mech
, MAX_NAME_LEN
);
1314 sp2
[i
].s_secinfo
.sc_gss_mech_type
=
1315 STRUCT_FGETP(usi
, s_secinfo
.sc_gss_mech_type
);
1316 sp2
[i
].s_secinfo
.sc_qop
=
1317 STRUCT_FGET(usi
, s_secinfo
.sc_qop
);
1318 sp2
[i
].s_secinfo
.sc_service
=
1319 STRUCT_FGET(usi
, s_secinfo
.sc_service
);
1321 sp2
[i
].s_flags
= STRUCT_FGET(usi
, s_flags
);
1322 sp2
[i
].s_window
= STRUCT_FGET(usi
, s_window
);
1323 sp2
[i
].s_rootid
= STRUCT_FGET(usi
, s_rootid
);
1324 sp2
[i
].s_rootcnt
= STRUCT_FGET(usi
, s_rootcnt
);
1325 sp2
[i
].s_rootnames
= STRUCT_FGETP(usi
, s_rootnames
);
1327 kmem_free(sp
, allocsize
);
1329 allocsize
= allocsize2
;
1332 kex
->ex_secinfo
= sp
;
1335 * And now copy rootnames for each individual secinfo.
1339 while (allocd_seccnt
< kex
->ex_seccnt
) {
1341 exs
= &sp
[allocd_seccnt
];
1342 if (exs
->s_rootcnt
> 0) {
1343 if (!sec_svc_loadrootnames(exs
->s_secinfo
.sc_rpcnum
,
1344 exs
->s_rootcnt
, &exs
->s_rootnames
, model
)) {
1350 if (exs
->s_secinfo
.sc_rpcnum
== RPCSEC_GSS
) {
1351 rpc_gss_OID mech_tmp
;
1352 STRUCT_DECL(rpc_gss_OID_s
, umech_tmp
);
1353 caddr_t elements_tmp
;
1355 /* Copyin mechanism type */
1356 STRUCT_INIT(umech_tmp
, model
);
1357 mech_tmp
= kmem_alloc(sizeof (*mech_tmp
), KM_SLEEP
);
1358 if (copyin(exs
->s_secinfo
.sc_gss_mech_type
,
1359 STRUCT_BUF(umech_tmp
), STRUCT_SIZE(umech_tmp
))) {
1360 kmem_free(mech_tmp
, sizeof (*mech_tmp
));
1364 mech_tmp
->length
= STRUCT_FGET(umech_tmp
, length
);
1365 mech_tmp
->elements
= STRUCT_FGETP(umech_tmp
, elements
);
1367 elements_tmp
= kmem_alloc(mech_tmp
->length
, KM_SLEEP
);
1368 if (copyin(mech_tmp
->elements
, elements_tmp
,
1369 mech_tmp
->length
)) {
1370 kmem_free(elements_tmp
, mech_tmp
->length
);
1371 kmem_free(mech_tmp
, sizeof (*mech_tmp
));
1375 mech_tmp
->elements
= elements_tmp
;
1376 exs
->s_secinfo
.sc_gss_mech_type
= mech_tmp
;
1385 * Init the secinfo reference count and mark these flavors
1386 * explicitly exported flavors.
1388 for (i
= 0; i
< kex
->ex_seccnt
; i
++) {
1389 kex
->ex_secinfo
[i
].s_flags
|= M_4SEC_EXPORTED
;
1390 kex
->ex_secinfo
[i
].s_refcnt
= 1;
1394 * Set up rpcsec_gss callback routine entry if any.
1397 cb
.callback
= rfs_gsscallback
;
1398 cb
.program
= NFS_ACL_PROGRAM
;
1399 for (cb
.version
= NFS_ACL_VERSMIN
;
1400 cb
.version
<= NFS_ACL_VERSMAX
; cb
.version
++) {
1401 (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK
,
1405 cb
.program
= NFS_PROGRAM
;
1406 for (cb
.version
= NFS_VERSMIN
;
1407 cb
.version
<= NFS_VERSMAX
; cb
.version
++) {
1408 (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK
,
1414 * Check the index flag. Do this here to avoid holding the
1415 * lock while dealing with the index option (as we do with
1416 * the public option).
1418 if (kex
->ex_flags
& EX_INDEX
) {
1419 if (!kex
->ex_index
) { /* sanity check */
1423 if (error
= loadindex(kex
))
1427 if (kex
->ex_flags
& EX_LOG
) {
1428 if (error
= nfslog_setup(exi
))
1433 * Insert the new entry at the front of the export list
1435 rw_enter(&exported_lock
, RW_WRITER
);
1436 DTRACE_PROBE(nfss__i__exported_lock3_start
);
1441 * Check the rest of the list for an old entry for the fs.
1442 * If one is found then unlink it, wait until this is the
1443 * only reference and then free it.
1445 for (ex
= exi
->fid_hash
.next
; ex
!= NULL
; ex
= ex
->fid_hash
.next
) {
1446 if (ex
!= exi_root
&& VN_CMP(ex
->exi_vp
, vp
)) {
1453 * If the public filehandle is pointing at the
1454 * old entry, then point it back at the root.
1456 if (ex
!= NULL
&& ex
== exi_public
)
1457 exi_public
= exi_root
;
1460 * If the public flag is on, make the global exi_public
1461 * point to this entry and turn off the public bit so that
1462 * we can distinguish it from the place holder export.
1464 if (kex
->ex_flags
& EX_PUBLIC
) {
1466 kex
->ex_flags
&= ~EX_PUBLIC
;
1469 #ifdef VOLATILE_FH_TEST
1471 * Set up the volatile_id value if volatile on share.
1472 * The list of volatile renamed filehandles is always destroyed,
1473 * if the fs was reshared.
1475 if (kex
->ex_flags
& EX_VOLFH
)
1476 exi
->exi_volatile_id
= gethrestime_sec();
1478 mutex_init(&exi
->exi_vol_rename_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
1479 #endif /* VOLATILE_FH_TEST */
1482 * If this is a new export, then climb up
1483 * the tree and check if any pseudo exports
1484 * need to be created to provide a path for
1488 error
= treeclimb_export(exi
);
1492 /* If it's a re-export update namespace tree */
1493 exi
->exi_tree
= ex
->exi_tree
;
1494 exi
->exi_tree
->tree_exi
= exi
;
1498 * build a unique flavor list from the flavors specified
1499 * in the share cmd. unique means that each flavor only
1500 * appears once in the secinfo list -- no duplicates allowed.
1502 newcnt
= build_seclist_nodups(&exi
->exi_export
, newsec
, FALSE
);
1504 srv_secinfo_treeclimb(exi
, newsec
, newcnt
, TRUE
);
1507 * If re-sharing an old export entry, update the secinfo data
1508 * depending on if the old entry is a pseudo node or not.
1511 oldcnt
= build_seclist_nodups(&ex
->exi_export
, oldsec
, FALSE
);
1514 * The dir being shared is a pseudo export root (which
1515 * will be transformed into a real export root). The
1516 * flavor(s) of the new share were propagated to the
1517 * ancestors by srv_secinfo_treeclimb() above. Now
1518 * transfer the implicit flavor refs from the old
1519 * pseudo exprot root to the new (real) export root.
1521 srv_secinfo_add(&exi
->exi_export
.ex_secinfo
,
1522 &exi
->exi_export
.ex_seccnt
, oldsec
, oldcnt
, TRUE
);
1525 * First transfer implicit flavor refs to new export.
1526 * Remove old flavor refs last.
1528 srv_secinfo_exp2exp(&exi
->exi_export
, oldsec
, oldcnt
);
1529 srv_secinfo_treeclimb(ex
, oldsec
, oldcnt
, FALSE
);
1534 * If it's a re-export and the old entry has a pseudonode list,
1535 * transfer it to the new export.
1537 if (ex
!= NULL
&& (ex
->exi_visible
!= NULL
)) {
1538 exi
->exi_visible
= ex
->exi_visible
;
1539 ex
->exi_visible
= NULL
;
1542 DTRACE_PROBE(nfss__i__exported_lock3_stop
);
1543 rw_exit(&exported_lock
);
1545 if (exi_public
== exi
|| kex
->ex_flags
& EX_LOG
) {
1547 * Log share operation to this buffer only.
1549 nfslog_share_record(exi
, cr
);
1558 /* Unlink the new export in exptable. */
1560 DTRACE_PROBE(nfss__i__exported_lock3_stop
);
1561 rw_exit(&exported_lock
);
1563 if (kex
->ex_flags
& EX_INDEX
)
1564 kmem_free(kex
->ex_index
, strlen(kex
->ex_index
) + 1);
1566 /* free partially completed allocation */
1567 while (--allocd_seccnt
>= 0) {
1568 exs
= &kex
->ex_secinfo
[allocd_seccnt
];
1569 srv_secinfo_entry_free(exs
);
1572 if (kex
->ex_secinfo
) {
1573 kmem_free(kex
->ex_secinfo
,
1574 kex
->ex_seccnt
* sizeof (struct secinfo
));
1578 if ((kex
->ex_flags
& EX_LOG
) && kex
->ex_tag
!= NULL
)
1579 kmem_free(kex
->ex_tag
, kex
->ex_taglen
+ 1);
1581 if ((kex
->ex_flags
& EX_LOG
) && kex
->ex_log_buffer
!= NULL
)
1582 kmem_free(kex
->ex_log_buffer
, kex
->ex_log_bufferlen
+ 1);
1584 kmem_free(kex
->ex_path
, kex
->ex_pathlen
+ 1);
1589 mutex_destroy(&exi
->exi_lock
);
1590 rw_destroy(&exi
->exi_cache_lock
);
1591 kmem_free(exi
, sizeof (*exi
));
1596 * Remove the exportinfo from the export list
1599 export_unlink(struct exportinfo
*exi
)
1601 ASSERT(RW_WRITE_HELD(&exported_lock
));
1603 exp_hash_unlink(exi
, fid_hash
);
1604 exp_hash_unlink(exi
, path_hash
);
1608 * Unexport an exported filesystem
1611 unexport(struct exportinfo
*exi
)
1613 struct secinfo cursec
[MAX_FLAVORS
];
1616 rw_enter(&exported_lock
, RW_WRITER
);
1618 /* Check if exi is still linked in the export table */
1619 if (!EXP_LINKED(exi
) || PSEUDO(exi
)) {
1620 rw_exit(&exported_lock
);
1627 * Remove security flavors before treeclimb_unexport() is called
1628 * because srv_secinfo_treeclimb needs the namespace tree
1630 curcnt
= build_seclist_nodups(&exi
->exi_export
, cursec
, TRUE
);
1632 srv_secinfo_treeclimb(exi
, cursec
, curcnt
, FALSE
);
1635 * If there's a visible list, then need to leave
1636 * a pseudo export here to retain the visible list
1637 * for paths to exports below.
1639 if (exi
->exi_visible
) {
1640 struct exportinfo
*newexi
;
1642 newexi
= pseudo_exportfs(exi
->exi_vp
, &exi
->exi_fid
,
1643 exi
->exi_visible
, &exi
->exi_export
);
1644 exi
->exi_visible
= NULL
;
1646 /* interconnect the existing treenode with the new exportinfo */
1647 newexi
->exi_tree
= exi
->exi_tree
;
1648 newexi
->exi_tree
->tree_exi
= newexi
;
1650 treeclimb_unexport(exi
);
1653 rw_exit(&exported_lock
);
1656 * Need to call into the NFSv4 server and release all data
1657 * held on this particular export. This is important since
1658 * the v4 server may be holding file locks or vnodes under
1661 rfs4_clean_state_exi(exi
);
1664 * Notify the lock manager that the filesystem is being
1670 * If this was a public export, restore
1671 * the public filehandle to the root.
1673 if (exi
== exi_public
) {
1674 exi_public
= exi_root
;
1676 nfslog_share_record(exi_public
, CRED());
1679 if (exi
->exi_export
.ex_flags
& EX_LOG
) {
1680 nfslog_unshare_record(exi
, CRED());
1688 * Get file handle system call.
1689 * Takes file name and returns a file handle for it.
1690 * Credentials must be verified before calling.
1693 nfs_getfh(struct nfs_getfh_args
*args
, model_t model
, cred_t
*cr
)
1696 char buf
[NFS3_MAXFHSIZE
];
1697 char *logptr
, logbuf
[NFS3_MAXFHSIZE
];
1698 int l
= NFS3_MAXFHSIZE
;
1701 struct exportinfo
*exi
;
1704 STRUCT_HANDLE(nfs_getfh_args
, uap
);
1707 model
= model
; /* STRUCT macros don't always use it */
1710 STRUCT_SET_HANDLE(uap
, model
, args
);
1712 error
= lookupname(STRUCT_FGETP(uap
, fname
), UIO_USERSPACE
,
1714 if (error
== EINVAL
) {
1716 * if fname resolves to / we get EINVAL error
1717 * since we wanted the parent vnode. Try again
1720 error
= lookupname(STRUCT_FGETP(uap
, fname
), UIO_USERSPACE
,
1724 if (!error
&& vp
== NULL
) {
1726 * Last component of fname not found
1737 * 'vp' may be an AUTOFS node, so we perform a
1738 * VOP_ACCESS() to trigger the mount of the
1739 * intended filesystem, so we can share the intended
1740 * filesystem instead of the AUTOFS filesystem.
1742 (void) VOP_ACCESS(vp
, 0, 0, cr
, NULL
);
1745 * We're interested in the top most filesystem.
1746 * This is specially important when uap->dname is a trigger
1747 * AUTOFS node, since we're really interested in sharing the
1748 * filesystem AUTOFS mounted as result of the VOP_ACCESS()
1749 * call not the AUTOFS node itself.
1751 if (vn_mountedvfs(vp
) != NULL
) {
1752 if (error
= traverse(&vp
)) {
1760 vers
= STRUCT_FGET(uap
, vers
);
1761 exi
= nfs_vptoexi(dvp
, vp
, cr
, NULL
, &error
, FALSE
);
1763 if (vers
== NFS_VERSION
) {
1764 error
= makefh((fhandle_t
*)buf
, vp
, exi
);
1767 } else if (vers
== NFS_V3
) {
1770 error
= makefh3(&fh
, vp
, exi
);
1771 l
= RNDUP(fh
.fh3_length
);
1772 if (!error
&& (l
> sizeof (fhandle3_t
)))
1777 sz
= sizeof (fsid_t
);
1778 bcopy(&fh
.fh3_fsid
, &buf
[i
], sz
);
1782 * For backwards compatibility, the
1783 * fid length may be less than
1784 * NFS_FHMAXDATA, but it was always
1785 * encoded as NFS_FHMAXDATA bytes.
1788 sz
= sizeof (ushort_t
);
1789 bcopy(&fh
.fh3_len
, &buf
[i
], sz
);
1791 bcopy(fh
.fh3_data
, &buf
[i
], fh
.fh3_len
);
1793 pad
= (NFS_FHMAXDATA
- fh
.fh3_len
);
1795 bzero(&buf
[i
], pad
);
1800 sz
= sizeof (ushort_t
);
1801 bcopy(&fh
.fh3_xlen
, &buf
[i
], sz
);
1803 bcopy(fh
.fh3_xdata
, &buf
[i
], fh
.fh3_xlen
);
1805 pad
= (NFS_FHMAXDATA
- fh
.fh3_xlen
);
1807 bzero(&buf
[i
], pad
);
1813 * If we need to do NFS logging, the filehandle
1814 * must be downsized to 32 bytes.
1816 if (!error
&& exi
->exi_export
.ex_flags
& EX_LOG
) {
1818 sz
= sizeof (fsid_t
);
1819 bcopy(&fh
.fh3_fsid
, &logbuf
[i
], sz
);
1821 sz
= sizeof (ushort_t
);
1822 bcopy(&fh
.fh3_len
, &logbuf
[i
], sz
);
1825 bcopy(fh
.fh3_data
, &logbuf
[i
], sz
);
1827 sz
= sizeof (ushort_t
);
1828 bcopy(&fh
.fh3_xlen
, &logbuf
[i
], sz
);
1831 bcopy(fh
.fh3_xdata
, &logbuf
[i
], sz
);
1835 if (!error
&& exi
->exi_export
.ex_flags
& EX_LOG
) {
1836 nfslog_getfh(exi
, (fhandle_t
*)logptr
,
1837 STRUCT_FGETP(uap
, fname
), UIO_USERSPACE
, cr
);
1841 if (copyout(&l
, STRUCT_FGETP(uap
, lenp
), sizeof (int)))
1843 if (copyout(buf
, STRUCT_FGETP(uap
, fhp
), l
))
1855 * Strategy: if vp is in the export list, then
1856 * return the associated file handle. Otherwise, ".."
1857 * once up the vp and try again, until the root of the
1858 * filesystem is reached.
1861 nfs_vptoexi(vnode_t
*dvp
, vnode_t
*vp
, cred_t
*cr
, int *walk
,
1862 int *err
, bool_t v4srv
)
1866 struct exportinfo
*exi
;
1877 bzero(&fid
, sizeof (fid
));
1878 fid
.fid_len
= MAXFIDSZ
;
1879 error
= vop_fid_pseudo(vp
, &fid
);
1882 * If vop_fid_pseudo returns ENOSPC then the fid
1883 * supplied is too small. For now we simply
1886 if (error
== ENOSPC
)
1892 exi
= checkexport4(&vp
->v_vfsp
->vfs_fsid
, &fid
, vp
);
1894 exi
= checkexport(&vp
->v_vfsp
->vfs_fsid
, &fid
);
1898 * Found the export info
1904 * We have just failed finding a matching export.
1905 * If we're at the root of this filesystem, then
1906 * it's time to stop (with failure).
1908 if (vp
->v_flag
& VROOT
) {
1917 * Now, do a ".." up vp. If dvp is supplied, use it,
1918 * otherwise, look it up.
1921 error
= VOP_LOOKUP(vp
, "..", &dvp
, NULL
, 0, NULL
, cr
,
1943 chk_clnt_sec(exportinfo_t
*exi
, struct svc_req
*req
)
1949 * Get the nfs flavor number from xprt.
1951 nfsflavor
= (int)(uintptr_t)req
->rq_xprt
->xp_cookie
;
1953 sp
= exi
->exi_export
.ex_secinfo
;
1954 for (i
= 0; i
< exi
->exi_export
.ex_seccnt
; i
++) {
1955 if ((nfsflavor
== sp
[i
].s_secinfo
.sc_nfsnum
) &&
1956 SEC_REF_EXPORTED(sp
+ i
))
1963 * Make an fhandle from a vnode
1966 makefh(fhandle_t
*fh
, vnode_t
*vp
, exportinfo_t
*exi
)
1970 *fh
= exi
->exi_fh
; /* struct copy */
1972 error
= VOP_FID(vp
, (fid_t
*)&fh
->fh_len
, NULL
);
1975 * Should be something other than EREMOTE
1983 * This routine makes an overloaded V2 fhandle which contains
1986 * Note that the first four octets contain the length octet,
1987 * the status octet, and two padded octets to make them XDR
1988 * four-octet aligned.
1991 * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+
1992 * | l | s | | | sec_1 |...| sec_n |...| |
1993 * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+
1997 * the status octet s indicates whether there are more security
1998 * flavors (1 means yes, 0 means no) that require the client to
1999 * perform another 0x81 LOOKUP to get them,
2001 * the length octet l is the length describing the number of
2002 * valid octets that follow. (l = 4 * n, where n is the number
2003 * of security flavors sent in the current overloaded filehandle.)
2005 * sec_index should always be in the inclusive range: [1 - ex_seccnt],
2006 * and it tells server where to start within the secinfo array.
2007 * Usually it will always be 1; however, if more flavors are used
2008 * for the public export than can be encoded in the overloaded FH
2009 * (7 for NFS2), subsequent SNEGO MCLs will have a larger index
2010 * so the server will pick up where it left off from the previous
2013 * With NFS4 support, implicitly allowed flavors are also in
2014 * the secinfo array; however, they should not be returned in
2015 * SNEGO MCL replies.
2018 makefh_ol(fhandle_t
*fh
, exportinfo_t
*exi
, uint_t sec_index
)
2020 secinfo_t sec
[MAX_FLAVORS
];
2021 int totalcnt
, i
, *ipt
, cnt
, seccnt
, secidx
, fh_max_cnt
;
2024 if (fh
== NULL
|| exi
== NULL
|| sec_index
< 1)
2028 * WebNFS clients need to know the unique set of explicitly
2029 * shared flavors in used for the public export. When
2030 * "TRUE" is passed to build_seclist_nodups(), only explicitly
2031 * shared flavors are included in the list.
2033 seccnt
= build_seclist_nodups(&exi
->exi_export
, sec
, TRUE
);
2034 if (sec_index
> seccnt
)
2037 fh_max_cnt
= (NFS_FHSIZE
/ sizeof (int)) - 1;
2038 totalcnt
= seccnt
- sec_index
+ 1;
2039 cnt
= totalcnt
> fh_max_cnt
? fh_max_cnt
: totalcnt
;
2043 * Encode the length octet representing the number of
2044 * security flavors (in bytes) in this overloaded fh.
2046 *c
= cnt
* sizeof (int);
2049 * Encode the status octet that indicates whether there
2050 * are more security flavors the client needs to get.
2052 *(c
+ 1) = totalcnt
> fh_max_cnt
;
2055 * put security flavors in the overloaded fh
2057 ipt
= (int *)(c
+ sizeof (int32_t));
2058 secidx
= sec_index
- 1;
2059 for (i
= 0; i
< cnt
; i
++) {
2060 ipt
[i
] = htonl(sec
[i
+ secidx
].s_secinfo
.sc_nfsnum
);
2066 * Make an nfs_fh3 from a vnode
2069 makefh3(nfs_fh3
*fh
, vnode_t
*vp
, struct exportinfo
*exi
)
2074 bzero(&fid
, sizeof (fid
));
2075 fid
.fid_len
= sizeof (fh
->fh3_data
);
2076 error
= VOP_FID(vp
, &fid
, NULL
);
2080 bzero(fh
, sizeof (nfs_fh3
));
2081 fh
->fh3_fsid
= exi
->exi_fsid
;
2082 fh
->fh3_len
= fid
.fid_len
;
2083 bcopy(fid
.fid_data
, fh
->fh3_data
, fh
->fh3_len
);
2085 fh
->fh3_xlen
= exi
->exi_fid
.fid_len
;
2086 ASSERT(fh
->fh3_xlen
<= sizeof (fh
->fh3_xdata
));
2087 bcopy(exi
->exi_fid
.fid_data
, fh
->fh3_xdata
, fh
->fh3_xlen
);
2089 fh
->fh3_length
= sizeof (fh
->fh3_fsid
)
2090 + sizeof (fh
->fh3_len
) + fh
->fh3_len
2091 + sizeof (fh
->fh3_xlen
) + fh
->fh3_xlen
;
2098 * This routine makes an overloaded V3 fhandle which contains
2106 * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+
2107 * |s | | | | sec_1 | sec_2 | ... | sec_n |
2108 * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+
2110 * len = 4 * (n+1), where n is the number of security flavors
2111 * sent in the current overloaded filehandle.
2113 * the status octet s indicates whether there are more security
2114 * mechanisms (1 means yes, 0 means no) that require the client
2115 * to perform another 0x81 LOOKUP to get them.
2117 * Three octets are padded after the status octet.
2120 makefh3_ol(nfs_fh3
*fh
, struct exportinfo
*exi
, uint_t sec_index
)
2122 secinfo_t sec
[MAX_FLAVORS
];
2123 int totalcnt
, cnt
, *ipt
, i
, seccnt
, fh_max_cnt
, secidx
;
2126 if (fh
== NULL
|| exi
== NULL
|| sec_index
< 1)
2130 * WebNFS clients need to know the unique set of explicitly
2131 * shared flavors in used for the public export. When
2132 * "TRUE" is passed to build_seclist_nodups(), only explicitly
2133 * shared flavors are included in the list.
2135 seccnt
= build_seclist_nodups(&exi
->exi_export
, sec
, TRUE
);
2137 if (sec_index
> seccnt
)
2140 fh_max_cnt
= (NFS3_FHSIZE
/ sizeof (int)) - 1;
2141 totalcnt
= seccnt
- sec_index
+ 1;
2142 cnt
= totalcnt
> fh_max_cnt
? fh_max_cnt
: totalcnt
;
2145 * Place the length in fh3_length representing the number
2146 * of security flavors (in bytes) in this overloaded fh.
2148 fh
->fh3_flags
= FH_WEBNFS
;
2149 fh
->fh3_length
= (cnt
+1) * sizeof (int32_t);
2151 c
= (char *)&fh
->fh3_u
.nfs_fh3_i
.fh3_i
;
2153 * Encode the status octet that indicates whether there
2154 * are more security flavors the client needs to get.
2156 *c
= totalcnt
> fh_max_cnt
;
2159 * put security flavors in the overloaded fh
2161 secidx
= sec_index
- 1;
2162 ipt
= (int *)(c
+ sizeof (int32_t));
2163 for (i
= 0; i
< cnt
; i
++) {
2164 ipt
[i
] = htonl(sec
[i
+ secidx
].s_secinfo
.sc_nfsnum
);
2170 * Make an nfs_fh4 from a vnode
2173 makefh4(nfs_fh4
*fh
, vnode_t
*vp
, struct exportinfo
*exi
)
2176 nfs_fh4_fmt_t
*fh_fmtp
= (nfs_fh4_fmt_t
*)fh
->nfs_fh4_val
;
2179 bzero(&fid
, sizeof (fid
));
2180 fid
.fid_len
= MAXFIDSZ
;
2182 * vop_fid_pseudo() is used to set up NFSv4 namespace, so
2183 * use vop_fid_pseudo() here to get the fid instead of VOP_FID.
2185 error
= vop_fid_pseudo(vp
, &fid
);
2189 fh
->nfs_fh4_len
= NFS_FH4_LEN
;
2191 fh_fmtp
->fh4_i
.fhx_fsid
= exi
->exi_fh
.fh_fsid
;
2192 fh_fmtp
->fh4_i
.fhx_xlen
= exi
->exi_fh
.fh_xlen
;
2194 bzero(fh_fmtp
->fh4_i
.fhx_data
, sizeof (fh_fmtp
->fh4_i
.fhx_data
));
2195 bzero(fh_fmtp
->fh4_i
.fhx_xdata
, sizeof (fh_fmtp
->fh4_i
.fhx_xdata
));
2196 ASSERT(exi
->exi_fh
.fh_xlen
<= sizeof (fh_fmtp
->fh4_i
.fhx_xdata
));
2197 bcopy(exi
->exi_fh
.fh_xdata
, fh_fmtp
->fh4_i
.fhx_xdata
,
2198 exi
->exi_fh
.fh_xlen
);
2200 fh_fmtp
->fh4_len
= fid
.fid_len
;
2201 ASSERT(fid
.fid_len
<= sizeof (fh_fmtp
->fh4_data
));
2202 bcopy(fid
.fid_data
, fh_fmtp
->fh4_data
, fid
.fid_len
);
2203 fh_fmtp
->fh4_flag
= 0;
2205 #ifdef VOLATILE_FH_TEST
2208 * Use the rnode volatile_id value to add volatility to the fh.
2210 * For testing purposes there are currently two scenarios, based
2211 * on whether the filesystem was shared with "volatile_fh"
2212 * or "expire_on_rename". In the first case, use the value of
2213 * export struct share_time as the volatile_id. In the second
2214 * case use the vnode volatile_id value (which is set to the
2215 * time in which the file was renamed).
2217 * Note that the above are temporary constructs for testing only
2220 if (exi
->exi_export
.ex_flags
& EX_VOLRNM
) {
2221 fh_fmtp
->fh4_volatile_id
= find_volrnm_fh_id(exi
, fh
);
2222 } else if (exi
->exi_export
.ex_flags
& EX_VOLFH
) {
2223 fh_fmtp
->fh4_volatile_id
= exi
->exi_volatile_id
;
2225 fh_fmtp
->fh4_volatile_id
= 0;
2227 #endif /* VOLATILE_FH_TEST */
2233 * Convert an fhandle into a vnode.
2234 * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode.
2235 * WARNING: users of this routine must do a VN_RELE on the vnode when they
2239 nfs_fhtovp(fhandle_t
*fh
, struct exportinfo
*exi
)
2246 TRACE_0(TR_FAC_NFS
, TR_FHTOVP_START
,
2250 TRACE_1(TR_FAC_NFS
, TR_FHTOVP_END
,
2251 "fhtovp_end:(%S)", "exi NULL");
2252 return (NULL
); /* not exported */
2255 ASSERT(exi
->exi_vp
!= NULL
);
2257 if (PUBLIC_FH2(fh
)) {
2258 if (exi
->exi_export
.ex_flags
& EX_PUBLIC
) {
2259 TRACE_1(TR_FAC_NFS
, TR_FHTOVP_END
,
2260 "fhtovp_end:(%S)", "root not exported");
2268 vfsp
= exi
->exi_vp
->v_vfsp
;
2269 ASSERT(vfsp
!= NULL
);
2270 fidp
= (fid_t
*)&fh
->fh_len
;
2272 error
= VFS_VGET(vfsp
, &vp
, fidp
);
2273 if (error
|| vp
== NULL
) {
2274 TRACE_1(TR_FAC_NFS
, TR_FHTOVP_END
,
2275 "fhtovp_end:(%S)", "VFS_GET failed or vp NULL");
2278 TRACE_1(TR_FAC_NFS
, TR_FHTOVP_END
,
2279 "fhtovp_end:(%S)", "end");
2284 * Convert an fhandle into a vnode.
2285 * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode.
2286 * WARNING: users of this routine must do a VN_RELE on the vnode when they
2288 * This is just like nfs_fhtovp() but without the exportinfo argument.
2292 lm_fhtovp(fhandle_t
*fh
)
2294 register vfs_t
*vfsp
;
2298 vfsp
= getvfs(&fh
->fh_fsid
);
2302 error
= VFS_VGET(vfsp
, &vp
, (fid_t
*)&(fh
->fh_len
));
2304 if (error
|| vp
== NULL
)
2311 * Convert an nfs_fh3 into a vnode.
2312 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2313 * WARNING: users of this routine must do a VN_RELE on the vnode when they
2317 nfs3_fhtovp(nfs_fh3
*fh
, struct exportinfo
*exi
)
2325 return (NULL
); /* not exported */
2327 ASSERT(exi
->exi_vp
!= NULL
);
2329 if (PUBLIC_FH3(fh
)) {
2330 if (exi
->exi_export
.ex_flags
& EX_PUBLIC
)
2337 if (fh
->fh3_length
< NFS3_OLDFHSIZE
||
2338 fh
->fh3_length
> NFS3_MAXFHSIZE
)
2341 vfsp
= exi
->exi_vp
->v_vfsp
;
2342 ASSERT(vfsp
!= NULL
);
2343 fidp
= FH3TOFIDP(fh
);
2345 error
= VFS_VGET(vfsp
, &vp
, fidp
);
2346 if (error
|| vp
== NULL
)
2353 * Convert an nfs_fh3 into a vnode.
2354 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2355 * WARNING: users of this routine must do a VN_RELE on the vnode when they
2357 * BTW: This is just like nfs3_fhtovp() but without the exportinfo arg.
2358 * Also, vfsp is accessed through getvfs() rather using exportinfo !!
2362 lm_nfs3_fhtovp(nfs_fh3
*fh
)
2369 if (fh
->fh3_length
< NFS3_OLDFHSIZE
||
2370 fh
->fh3_length
> NFS3_MAXFHSIZE
)
2373 vfsp
= getvfs(&fh
->fh3_fsid
);
2376 fidp
= FH3TOFIDP(fh
);
2378 error
= VFS_VGET(vfsp
, &vp
, fidp
);
2380 if (error
|| vp
== NULL
)
2387 * Convert an nfs_fh4 into a vnode.
2388 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2389 * WARNING: users of this routine must do a VN_RELE on the vnode when they
2393 nfs4_fhtovp(nfs_fh4
*fh
, struct exportinfo
*exi
, nfsstat4
*statp
)
2399 nfs_fh4_fmt_t
*fh_fmtp
;
2400 #ifdef VOLATILE_FH_TEST
2401 uint32_t volatile_id
= 0;
2402 #endif /* VOLATILE_FH_TEST */
2405 *statp
= NFS4ERR_STALE
;
2406 return (NULL
); /* not exported */
2408 ASSERT(exi
->exi_vp
!= NULL
);
2410 /* caller should have checked this */
2411 ASSERT(fh
->nfs_fh4_len
>= NFS_FH4_LEN
);
2413 fh_fmtp
= (nfs_fh4_fmt_t
*)fh
->nfs_fh4_val
;
2414 vfsp
= exi
->exi_vp
->v_vfsp
;
2415 ASSERT(vfsp
!= NULL
);
2416 fidp
= (fid_t
*)&fh_fmtp
->fh4_len
;
2418 #ifdef VOLATILE_FH_TEST
2419 /* XXX check if volatile - should be changed later */
2420 if (exi
->exi_export
.ex_flags
& (EX_VOLRNM
| EX_VOLFH
)) {
2422 * Filesystem is shared with volatile filehandles
2424 if (exi
->exi_export
.ex_flags
& EX_VOLRNM
)
2425 volatile_id
= find_volrnm_fh_id(exi
, fh
);
2427 volatile_id
= exi
->exi_volatile_id
;
2429 if (fh_fmtp
->fh4_volatile_id
!= volatile_id
) {
2430 *statp
= NFS4ERR_FHEXPIRED
;
2435 * XXX even if test_volatile_fh false, the fh may contain a
2436 * volatile id if obtained when the test was set.
2438 fh_fmtp
->fh4_volatile_id
= (uchar_t
)0;
2439 #endif /* VOLATILE_FH_TEST */
2441 error
= VFS_VGET(vfsp
, &vp
, fidp
);
2443 * If we can not get vp from VFS_VGET, perhaps this is
2444 * an nfs v2/v3/v4 node in an nfsv4 pseudo filesystem.
2447 if (error
&& PSEUDO(exi
))
2448 error
= nfs4_vget_pseudo(exi
, &vp
, fidp
);
2450 if (error
|| vp
== NULL
) {
2451 *statp
= NFS4ERR_STALE
;
2454 /* XXX - disgusting hack */
2455 if (vp
->v_type
== VNON
&& vp
->v_flag
& V_XATTRDIR
)
2462 * Find the export structure associated with the given filesystem.
2463 * If found, then increment the ref count (exi_count).
2466 checkexport(fsid_t
*fsid
, fid_t
*fid
)
2468 struct exportinfo
*exi
;
2470 rw_enter(&exported_lock
, RW_READER
);
2471 for (exi
= exptable
[exptablehash(fsid
, fid
)];
2473 exi
= exi
->fid_hash
.next
) {
2474 if (exportmatch(exi
, fsid
, fid
)) {
2476 * If this is the place holder for the
2477 * public file handle, then return the
2478 * real export entry for the public file
2481 if (exi
->exi_export
.ex_flags
& EX_PUBLIC
) {
2486 rw_exit(&exported_lock
);
2490 rw_exit(&exported_lock
);
2496 * "old school" version of checkexport() for NFS4. NFS4
2497 * rfs4_compound holds exported_lock for duration of compound
2498 * processing. This version doesn't manipulate exi_count
2499 * since NFS4 breaks fundamental assumptions in the exi_count
2503 checkexport4(fsid_t
*fsid
, fid_t
*fid
, vnode_t
*vp
)
2505 struct exportinfo
*exi
;
2507 ASSERT(RW_LOCK_HELD(&exported_lock
));
2509 for (exi
= exptable
[exptablehash(fsid
, fid
)];
2511 exi
= exi
->fid_hash
.next
) {
2512 if (exportmatch(exi
, fsid
, fid
)) {
2514 * If this is the place holder for the
2515 * public file handle, then return the
2516 * real export entry for the public file
2519 if (exi
->exi_export
.ex_flags
& EX_PUBLIC
) {
2524 * If vp is given, check if vp is the
2525 * same vnode as the exported node.
2527 * Since VOP_FID of a lofs node returns the
2528 * fid of its real node (ufs), the exported
2529 * node for lofs and (pseudo) ufs may have
2530 * the same fsid and fid.
2532 if (vp
== NULL
|| vp
== exi
->exi_vp
)
2541 * Free an entire export list node
2544 exportfree(struct exportinfo
*exi
)
2546 struct exportdata
*ex
;
2547 struct charset_cache
*cache
;
2549 ex
= &exi
->exi_export
;
2551 ASSERT(exi
->exi_vp
!= NULL
&& !(exi
->exi_export
.ex_flags
& EX_PUBLIC
));
2552 VN_RELE(exi
->exi_vp
);
2553 if (exi
->exi_dvp
!= NULL
)
2554 VN_RELE(exi
->exi_dvp
);
2556 if (ex
->ex_flags
& EX_INDEX
)
2557 kmem_free(ex
->ex_index
, strlen(ex
->ex_index
) + 1);
2559 kmem_free(ex
->ex_path
, ex
->ex_pathlen
+ 1);
2560 nfsauth_cache_free(exi
);
2563 * if there is a character set mapping cached, clean it up.
2565 for (cache
= exi
->exi_charset
; cache
!= NULL
;
2566 cache
= exi
->exi_charset
) {
2567 if (cache
->inbound
!= (kiconv_t
)-1)
2568 (void) kiconv_close(cache
->inbound
);
2569 if (cache
->outbound
!= (kiconv_t
)-1)
2570 (void) kiconv_close(cache
->outbound
);
2571 exi
->exi_charset
= cache
->next
;
2572 kmem_free(cache
, sizeof (struct charset_cache
));
2575 if (exi
->exi_logbuffer
!= NULL
)
2576 nfslog_disable(exi
);
2578 if (ex
->ex_flags
& EX_LOG
) {
2579 kmem_free(ex
->ex_log_buffer
, ex
->ex_log_bufferlen
+ 1);
2580 kmem_free(ex
->ex_tag
, ex
->ex_taglen
+ 1);
2583 if (exi
->exi_visible
)
2584 free_visible(exi
->exi_visible
);
2586 srv_secinfo_list_free(ex
->ex_secinfo
, ex
->ex_seccnt
);
2588 #ifdef VOLATILE_FH_TEST
2589 free_volrnm_list(exi
);
2590 mutex_destroy(&exi
->exi_vol_rename_lock
);
2591 #endif /* VOLATILE_FH_TEST */
2593 mutex_destroy(&exi
->exi_lock
);
2594 rw_destroy(&exi
->exi_cache_lock
);
2596 kmem_free(exi
, sizeof (*exi
));
2600 * load the index file from user space into kernel space.
2603 loadindex(struct exportdata
*kex
)
2606 char index
[MAXNAMELEN
+1];
2610 * copyinstr copies the complete string including the NULL and
2611 * returns the len with the NULL byte included in the calculation
2612 * as long as the max length is not exceeded.
2614 if (error
= copyinstr(kex
->ex_index
, index
, sizeof (index
), &len
))
2617 kex
->ex_index
= kmem_alloc(len
, KM_SLEEP
);
2618 bcopy(index
, kex
->ex_index
, len
);
2624 exi_hold(struct exportinfo
*exi
)
2626 mutex_enter(&exi
->exi_lock
);
2628 mutex_exit(&exi
->exi_lock
);
2632 * When a thread completes using exi, it should call exi_rele().
2633 * exi_rele() decrements exi_count. It releases exi if exi_count == 0, i.e.
2634 * if this is the last user of exi and exi is not on exportinfo list anymore
2637 exi_rele(struct exportinfo
*exi
)
2639 mutex_enter(&exi
->exi_lock
);
2641 if (exi
->exi_count
== 0) {
2642 mutex_exit(&exi
->exi_lock
);
2645 mutex_exit(&exi
->exi_lock
);
2648 #ifdef VOLATILE_FH_TEST
2650 * Test for volatile fh's - add file handle to list and set its volatile id
2651 * to time it was renamed. If EX_VOLFH is also on and the fs is reshared,
2652 * the vol_rename queue is purged.
2654 * XXX This code is for unit testing purposes only... To correctly use it, it
2655 * needs to tie a rename list to the export struct and (more
2656 * important), protect access to the exi rename list using a write lock.
2660 * get the fh vol record if it's in the volatile on rename list. Don't check
2661 * volatile_id in the file handle - compare only the file handles.
2663 static struct ex_vol_rename
*
2664 find_volrnm_fh(struct exportinfo
*exi
, nfs_fh4
*fh4p
)
2666 struct ex_vol_rename
*p
= NULL
;
2669 /* XXX shouldn't we assert &exported_lock held? */
2670 ASSERT(MUTEX_HELD(&exi
->exi_vol_rename_lock
));
2672 if (fh4p
->nfs_fh4_len
!= NFS_FH4_LEN
) {
2675 fhp
= &((nfs_fh4_fmt_t
*)fh4p
->nfs_fh4_val
)->fh4_i
;
2676 for (p
= exi
->exi_vol_rename
; p
!= NULL
; p
= p
->vrn_next
) {
2677 if (bcmp(fhp
, &p
->vrn_fh_fmt
.fh4_i
,
2678 sizeof (fhandle4_t
)) == 0)
2685 * get the volatile id for the fh (if there is - else return 0). Ignore the
2686 * volatile_id in the file handle - compare only the file handles.
2689 find_volrnm_fh_id(struct exportinfo
*exi
, nfs_fh4
*fh4p
)
2691 struct ex_vol_rename
*p
;
2692 uint32_t volatile_id
;
2694 mutex_enter(&exi
->exi_vol_rename_lock
);
2695 p
= find_volrnm_fh(exi
, fh4p
);
2696 volatile_id
= (p
? p
->vrn_fh_fmt
.fh4_volatile_id
:
2697 exi
->exi_volatile_id
);
2698 mutex_exit(&exi
->exi_vol_rename_lock
);
2699 return (volatile_id
);
2703 * Free the volatile on rename list - will be called if a filesystem is
2704 * unshared or reshared without EX_VOLRNM
2707 free_volrnm_list(struct exportinfo
*exi
)
2709 struct ex_vol_rename
*p
, *pnext
;
2711 /* no need to hold mutex lock - this one is called from exportfree */
2712 for (p
= exi
->exi_vol_rename
; p
!= NULL
; p
= pnext
) {
2713 pnext
= p
->vrn_next
;
2714 kmem_free(p
, sizeof (*p
));
2716 exi
->exi_vol_rename
= NULL
;
2720 * Add a file handle to the volatile on rename list.
2723 add_volrnm_fh(struct exportinfo
*exi
, vnode_t
*vp
)
2725 struct ex_vol_rename
*p
;
2726 char fhbuf
[NFS4_FHSIZE
];
2730 fh4
.nfs_fh4_val
= fhbuf
;
2731 error
= makefh4(&fh4
, vp
, exi
);
2732 if ((error
) || (fh4
.nfs_fh4_len
!= sizeof (p
->vrn_fh_fmt
))) {
2736 mutex_enter(&exi
->exi_vol_rename_lock
);
2738 p
= find_volrnm_fh(exi
, &fh4
);
2741 p
= kmem_alloc(sizeof (*p
), KM_SLEEP
);
2742 bcopy(fh4
.nfs_fh4_val
, &p
->vrn_fh_fmt
, sizeof (p
->vrn_fh_fmt
));
2743 p
->vrn_next
= exi
->exi_vol_rename
;
2744 exi
->exi_vol_rename
= p
;
2747 p
->vrn_fh_fmt
.fh4_volatile_id
= gethrestime_sec();
2748 mutex_exit(&exi
->exi_vol_rename_lock
);
2751 #endif /* VOLATILE_FH_TEST */