2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
30 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
32 * Copyright (c) 1989, 1993
33 * The Regents of the University of California. All rights reserved.
35 * This code is derived from software contributed to Berkeley by
36 * Rick Macklem at The University of Guelph.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by the University of
49 * California, Berkeley and its contributors.
50 * 4. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95
67 * FreeBSD-Id: nfs_subs.c,v 1.47 1997/11/07 08:53:24 phk Exp $
71 * These functions support the macros and help fiddle mbuf chains for
72 * the nfs op functions. They do things like create the rpc header and
73 * copy data between mbuf chains and uio lists.
75 #include <sys/param.h>
77 #include <sys/kauth.h>
78 #include <sys/systm.h>
79 #include <sys/kernel.h>
80 #include <sys/mount_internal.h>
81 #include <sys/vnode_internal.h>
82 #include <sys/kpi_mbuf.h>
83 #include <sys/socket.h>
85 #include <sys/malloc.h>
86 #include <sys/syscall.h>
87 #include <sys/sysctl.h>
88 #include <sys/ubc_internal.h>
89 #include <sys/fcntl.h>
90 #include <sys/uio_internal.h>
91 #include <sys/domain.h>
92 #include <libkern/OSAtomic.h>
95 #include <sys/vmparam.h>
98 #include <kern/clock.h>
100 #include <nfs/rpcv2.h>
101 #include <nfs/nfsproto.h>
103 #include <nfs/nfsnode.h>
104 #include <nfs/xdr_subs.h>
105 #include <nfs/nfsm_subs.h>
106 #include <nfs/nfsmount.h>
107 #include <nfs/nfsrtt.h>
108 #include <nfs/nfs_lock.h>
110 #include <miscfs/specfs/specdev.h>
112 #include <netinet/in.h>
114 #include <netiso/iso.h>
117 #include <sys/kdebug.h>
119 SYSCTL_DECL(_vfs_generic
);
120 SYSCTL_NODE(_vfs_generic
, OID_AUTO
, nfs
, CTLFLAG_RW
, 0, "nfs hinge");
122 #define FSDBG(A, B, C, D, E) \
123 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_NONE, \
124 (int)(B), (int)(C), (int)(D), (int)(E), 0)
125 #define FSDBG_TOP(A, B, C, D, E) \
126 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_START, \
127 (int)(B), (int)(C), (int)(D), (int)(E), 0)
128 #define FSDBG_BOT(A, B, C, D, E) \
129 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_END, \
130 (int)(B), (int)(C), (int)(D), (int)(E), 0)
132 * Data items converted to xdr at startup, since they are constant
133 * This is kinda hokey, but may save a little time doing byte swaps
136 u_long rpc_call
, rpc_vers
, rpc_reply
, rpc_msgdenied
, rpc_autherr
,
137 rpc_mismatch
, rpc_auth_unix
, rpc_msgaccepted
,
139 u_long nfs_prog
, nfs_true
, nfs_false
;
140 __private_extern__
int nfs_mbuf_mlen
= 0, nfs_mbuf_mhlen
= 0,
141 nfs_mbuf_minclsize
= 0, nfs_mbuf_mclbytes
= 0;
143 /* And other global data */
144 static u_long nfs_xid
= 0;
145 u_long nfs_xidwrap
= 0; /* to build a (non-wwrapping) 64 bit xid */
146 static enum vtype nv2tov_type
[8]= {
147 VNON
, VREG
, VDIR
, VBLK
, VCHR
, VLNK
, VNON
, VNON
149 enum vtype nv3tov_type
[8]= {
150 VNON
, VREG
, VDIR
, VBLK
, VCHR
, VLNK
, VSOCK
, VFIFO
156 lck_grp_t
*nfsd_lck_grp
;
157 lck_grp_attr_t
*nfsd_lck_grp_attr
;
158 lck_attr_t
*nfsd_lck_attr
;
159 lck_mtx_t
*nfsd_mutex
;
161 lck_grp_attr_t
*nfs_slp_group_attr
;
162 lck_attr_t
*nfs_slp_lock_attr
;
163 lck_grp_t
*nfs_slp_rwlock_group
;
164 lck_grp_t
*nfs_slp_mutex_group
;
166 struct nfs_reqq nfs_reqq
;
167 struct nfssvc_sockhead nfssvc_sockhead
, nfssvc_deadsockhead
;
168 struct nfsd_head nfsd_head
;
171 struct nfsexpfslist nfs_exports
;
172 struct nfsexphashhead
*nfsexphashtbl
;
174 lck_grp_attr_t
*nfs_export_group_attr
;
175 lck_attr_t
*nfs_export_lock_attr
;
176 lck_grp_t
*nfs_export_rwlock_group
;
177 lck_rw_t nfs_export_rwlock
;
181 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
183 int nfsv3_procid
[NFS_NPROCS
] = {
209 #endif /* NFS_NOSERVER */
211 * and the reverse mapping from generic to Version 2 procedure numbers
213 int nfsv2_procid
[NFS_NPROCS
] = {
241 * Maps errno values to nfs error numbers.
242 * Use NFSERR_IO as the catch all for ones not specifically defined in
245 static u_char nfsrv_v2errmap
[ELAST
] = {
246 NFSERR_PERM
, NFSERR_NOENT
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
247 NFSERR_NXIO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
248 NFSERR_IO
, NFSERR_IO
, NFSERR_ACCES
, NFSERR_IO
, NFSERR_IO
,
249 NFSERR_IO
, NFSERR_EXIST
, NFSERR_IO
, NFSERR_NODEV
, NFSERR_NOTDIR
,
250 NFSERR_ISDIR
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
251 NFSERR_IO
, NFSERR_FBIG
, NFSERR_NOSPC
, NFSERR_IO
, NFSERR_ROFS
,
252 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
253 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
254 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
255 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
256 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
257 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
258 NFSERR_IO
, NFSERR_IO
, NFSERR_NAMETOL
, NFSERR_IO
, NFSERR_IO
,
259 NFSERR_NOTEMPTY
, NFSERR_IO
, NFSERR_IO
, NFSERR_DQUOT
, NFSERR_STALE
,
260 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
261 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
262 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
266 * Maps errno values to nfs error numbers.
267 * Although it is not obvious whether or not NFS clients really care if
268 * a returned error value is in the specified list for the procedure, the
269 * safest thing to do is filter them appropriately. For Version 2, the
270 * X/Open XNFS document is the only specification that defines error values
271 * for each RPC (The RFC simply lists all possible error values for all RPCs),
272 * so I have decided to not do this for Version 2.
273 * The first entry is the default error return and the rest are the valid
274 * errors for that RPC in increasing numeric order.
276 static short nfsv3err_null
[] = {
281 static short nfsv3err_getattr
[] = {
290 static short nfsv3err_setattr
[] = {
306 static short nfsv3err_lookup
[] = {
319 static short nfsv3err_access
[] = {
328 static short nfsv3err_readlink
[] = {
340 static short nfsv3err_read
[] = {
352 static short nfsv3err_write
[] = {
367 static short nfsv3err_create
[] = {
384 static short nfsv3err_mkdir
[] = {
401 static short nfsv3err_symlink
[] = {
418 static short nfsv3err_mknod
[] = {
436 static short nfsv3err_remove
[] = {
450 static short nfsv3err_rmdir
[] = {
468 static short nfsv3err_rename
[] = {
491 static short nfsv3err_link
[] = {
511 static short nfsv3err_readdir
[] = {
524 static short nfsv3err_readdirplus
[] = {
538 static short nfsv3err_fsstat
[] = {
547 static short nfsv3err_fsinfo
[] = {
555 static short nfsv3err_pathconf
[] = {
563 static short nfsv3err_commit
[] = {
572 static short *nfsrv_v3errmap
[] = {
590 nfsv3err_readdirplus
,
597 #endif /* NFS_NOSERVER */
599 extern struct nfsrtt nfsrtt
;
600 extern struct nfsstats nfsstats
;
601 extern nfstype nfsv2_type
[9];
602 extern nfstype nfsv3_type
[9];
603 extern struct nfsnodehashhead
*nfsnodehashtbl
;
604 extern u_long nfsnodehash
;
607 LIST_HEAD(nfsnodehashhead
, nfsnode
);
610 * Create the header for an rpc request packet
611 * The hsiz is the size of the rest of the nfs request header.
612 * (just used to decide if a cluster is a good idea)
615 nfsm_reqh(int hsiz
, caddr_t
*bposp
, mbuf_t
*mbp
)
620 if (hsiz
>= nfs_mbuf_minclsize
)
621 error
= mbuf_mclget(MBUF_WAITOK
, MBUF_TYPE_DATA
, mbp
);
623 error
= mbuf_get(MBUF_WAITOK
, MBUF_TYPE_DATA
, mbp
);
626 *bposp
= mbuf_data(*mbp
);
631 * Build the RPC header and fill in the authorization info.
632 * The authorization string argument is only used when the credentials
633 * come from outside of the kernel.
634 * Returns the head of the mbuf list.
637 nfsm_rpchead(cr
, nmflag
, procid
, auth_type
, auth_len
, auth_str
, verf_len
,
638 verf_str
, mrest
, mrest_len
, mbp
, xidp
, mreqp
)
658 int siz
, grpsiz
, authsiz
, mlen
;
661 authsiz
= nfsm_rndup(auth_len
);
662 len
= authsiz
+ 10 * NFSX_UNSIGNED
;
663 if (len
>= nfs_mbuf_minclsize
) {
664 error
= mbuf_getpacket(MBUF_WAITOK
, &mb
);
666 error
= mbuf_gethdr(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mb
);
668 if (len
< nfs_mbuf_mhlen
)
669 mbuf_align_32(mb
, len
);
671 mbuf_align_32(mb
, 8 * NFSX_UNSIGNED
);
675 /* unable to allocate packet */
680 bpos
= mbuf_data(mb
);
683 * First the RPC header.
685 nfsm_build(tl
, u_long
*, 8 * NFSX_UNSIGNED
);
688 * derive initial xid from system time
692 * Note: it's OK if this code inits nfs_xid to 0 (for example,
693 * due to a broken clock) because we immediately increment it
694 * and we guarantee to never use xid 0. So, nfs_xid should only
695 * ever be 0 the first time this function is called.
698 nfs_xid
= tv
.tv_sec
<< 12;
701 * Skip zero xid if it should ever happen.
703 if (++nfs_xid
== 0) {
708 *tl
++ = *xidp
= txdr_unsigned(nfs_xid
);
711 *tl
++ = txdr_unsigned(NFS_PROG
);
712 if (nmflag
& NFSMNT_NFSV3
)
713 *tl
++ = txdr_unsigned(NFS_VER3
);
715 *tl
++ = txdr_unsigned(NFS_VER2
);
716 if (nmflag
& NFSMNT_NFSV3
)
717 *tl
++ = txdr_unsigned(procid
);
719 *tl
++ = txdr_unsigned(nfsv2_procid
[procid
]);
722 * And then the authorization cred.
724 *tl
++ = txdr_unsigned(auth_type
);
725 *tl
= txdr_unsigned(authsiz
);
728 nfsm_build(tl
, u_long
*, auth_len
);
729 *tl
++ = 0; /* stamp ?? */
730 *tl
++ = 0; /* NULL hostname */
731 *tl
++ = txdr_unsigned(kauth_cred_getuid(cr
));
732 *tl
++ = txdr_unsigned(cr
->cr_groups
[0]);
733 grpsiz
= (auth_len
>> 2) - 5;
734 *tl
++ = txdr_unsigned(grpsiz
);
735 for (i
= 1; i
<= grpsiz
; i
++)
736 *tl
++ = txdr_unsigned(cr
->cr_groups
[i
]);
742 if (mbuf_trailingspace(mb
) == 0) {
744 if (siz
>= nfs_mbuf_minclsize
)
745 error
= mbuf_mclget(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mb2
);
747 error
= mbuf_get(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mb2
);
749 error
= mbuf_setnext(mb
, mb2
);
756 bpos
= mbuf_data(mb
);
758 i
= min(siz
, mbuf_trailingspace(mb
));
759 bcopy(auth_str
, bpos
, i
);
761 mbuf_setlen(mb
, mlen
);
766 if ((siz
= (nfsm_rndup(auth_len
) - auth_len
)) > 0) {
767 for (i
= 0; i
< siz
; i
++)
770 mbuf_setlen(mb
, mlen
);
776 * And the verifier...
778 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
781 *tl
++ = txdr_unsigned(RPCAUTH_KERB4
);
782 *tl
= txdr_unsigned(verf_len
);
785 if (mbuf_trailingspace(mb
) == 0) {
787 if (siz
>= nfs_mbuf_minclsize
)
788 error
= mbuf_mclget(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mb2
);
790 error
= mbuf_get(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mb2
);
792 error
= mbuf_setnext(mb
, mb2
);
799 bpos
= mbuf_data(mb
);
801 i
= min(siz
, mbuf_trailingspace(mb
));
802 bcopy(verf_str
, bpos
, i
);
804 mbuf_setlen(mb
, mlen
);
809 if ((siz
= (nfsm_rndup(verf_len
) - verf_len
)) > 0) {
810 for (i
= 0; i
< siz
; i
++)
813 mbuf_setlen(mb
, mlen
);
816 *tl
++ = txdr_unsigned(RPCAUTH_NULL
);
819 error
= mbuf_pkthdr_setrcvif(mreq
, 0);
821 error
= mbuf_setnext(mb
, mrest
);
826 mbuf_pkthdr_setlen(mreq
, authsiz
+ 10 * NFSX_UNSIGNED
+ mrest_len
);
833 * copies mbuf chain to the uio scatter/gather list
836 nfsm_mbuftouio(mrep
, uiop
, siz
, dpos
)
842 char *mbufcp
, *uiocp
;
850 len
= (caddr_t
)mbuf_data(mp
) + mbuf_len(mp
) - mbufcp
;
851 rem
= nfsm_rndup(siz
)-siz
;
853 if (uiop
->uio_iovcnt
<= 0 || uiop
->uio_iovs
.iov32p
== NULL
)
855 // LP64todo - fix this!
856 left
= uio_iov_len(uiop
);
857 uiocp
= CAST_DOWN(caddr_t
, uio_iov_base(uiop
));
866 mbufcp
= mbuf_data(mp
);
869 xfer
= (left
> len
) ? len
: left
;
870 if (UIO_SEG_IS_USER_SPACE(uiop
->uio_segflg
))
871 copyout(mbufcp
, CAST_USER_ADDR_T(uiocp
), xfer
);
873 bcopy(mbufcp
, uiocp
, xfer
);
878 uiop
->uio_offset
+= xfer
;
879 uio_uio_resid_add(uiop
, -xfer
);
881 if (uio_iov_len(uiop
) <= (size_t)siz
) {
885 uio_iov_base_add(uiop
, uiosiz
);
886 uio_iov_len_add(uiop
, -uiosiz
);
894 error
= nfs_adv(mrep
, dpos
, rem
, len
);
902 * copies a uio scatter/gather list to an mbuf chain.
903 * NOTE: can ony handle iovcnt == 1
906 nfsm_uiotombuf(uiop
, mq
, siz
, bpos
)
914 int xfer
, left
, mlen
, mplen
;
915 int uiosiz
, clflg
, rem
, error
;
918 if (uiop
->uio_iovcnt
!= 1)
919 panic("nfsm_uiotombuf: iovcnt != 1");
921 if (siz
> nfs_mbuf_mlen
) /* or should it >= MCLBYTES ?? */
925 rem
= nfsm_rndup(siz
)-siz
;
927 mplen
= mbuf_len(mp
);
929 // LP64todo - fix this!
930 left
= uio_iov_len(uiop
);
931 uiocp
= CAST_DOWN(caddr_t
, uio_iov_base(uiop
));
936 mlen
= mbuf_trailingspace(mp
);
940 error
= mbuf_mclget(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mp
);
942 error
= mbuf_get(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mp
);
944 error
= mbuf_setnext(mp2
, mp
);
949 mlen
= mbuf_trailingspace(mp
);
951 xfer
= (left
> mlen
) ? mlen
: left
;
952 if (UIO_SEG_IS_USER_SPACE(uiop
->uio_segflg
))
953 copyin(CAST_USER_ADDR_T(uiocp
), (caddr_t
)mbuf_data(mp
) + mplen
, xfer
);
955 bcopy(uiocp
, (caddr_t
)mbuf_data(mp
) + mplen
, xfer
);
957 mbuf_setlen(mp
, mplen
);
960 uiop
->uio_offset
+= xfer
;
961 uio_uio_resid_add(uiop
, -xfer
);
963 uio_iov_base_add(uiop
, uiosiz
);
964 uio_iov_len_add(uiop
, -uiosiz
);
968 if (rem
> mbuf_trailingspace(mp
)) {
969 error
= mbuf_get(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mp
);
971 error
= mbuf_setnext(mp2
, mp
);
976 cp
= (caddr_t
)mbuf_data(mp
) + mplen
;
977 for (left
= 0; left
< rem
; left
++)
980 mbuf_setlen(mp
, mplen
);
983 *bpos
= (caddr_t
)mbuf_data(mp
) + mplen
;
990 * Help break down an mbuf chain by setting the first siz bytes contiguous
991 * pointed to by returned val.
992 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
993 * cases. (The macros use the vars. dpos and dpos2)
996 nfsm_disct(mdp
, dposp
, siz
, left
, cp2
)
1004 int siz2
, xfer
, error
, mp2len
;
1009 *mdp
= mp
= mbuf_next(mp
);
1012 left
= mbuf_len(mp
);
1013 *dposp
= mbuf_data(mp
);
1018 } else if (mbuf_next(mp
) == NULL
) {
1020 } else if (siz
> nfs_mbuf_mhlen
) {
1021 panic("nfs S too big");
1023 error
= mbuf_get(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mp2
);
1026 error
= mbuf_setnext(mp2
, mbuf_next(mp
));
1028 error
= mbuf_setnext(mp
, mp2
);
1033 mbuf_setlen(mp
, mbuf_len(mp
) - left
);
1035 *cp2
= p
= mbuf_data(mp
);
1036 bcopy(*dposp
, p
, left
); /* Copy what was left */
1039 mp2
= mbuf_next(mp
);
1040 mp2data
= mbuf_data(mp2
);
1041 mp2len
= mbuf_len(mp2
);
1042 /* Loop around copying up the siz2 bytes */
1046 xfer
= (siz2
> mp2len
) ? mp2len
: siz2
;
1048 bcopy(mp2data
, p
, xfer
);
1051 mbuf_setdata(mp2
, mp2data
, mp2len
);
1056 mp2
= mbuf_next(mp2
);
1057 mp2data
= mbuf_data(mp2
);
1058 mp2len
= mbuf_len(mp2
);
1061 mbuf_setlen(mp
, siz
);
1069 * Advance the position in the mbuf chain.
1072 nfs_adv(mdp
, dposp
, offs
, left
)
1091 *dposp
= (caddr_t
)mbuf_data(m
) + offs
;
1096 * Copy a string into mbufs for the hard cases...
1099 nfsm_strtmbuf(mb
, bpos
, cp
, siz
)
1105 mbuf_t m1
= NULL
, m2
;
1106 long left
, xfer
, len
, tlen
, mlen
;
1112 left
= mbuf_trailingspace(m2
);
1113 if (left
>= NFSX_UNSIGNED
) {
1114 tl
= ((u_long
*)(*bpos
));
1115 *tl
++ = txdr_unsigned(siz
);
1117 left
-= NFSX_UNSIGNED
;
1119 len
+= NFSX_UNSIGNED
;
1120 mbuf_setlen(m2
, len
);
1122 bcopy(cp
, (caddr_t
) tl
, left
);
1126 mbuf_setlen(m2
, len
);
1130 /* Loop around adding mbufs */
1133 if (siz
> nfs_mbuf_mlen
)
1134 error
= mbuf_mclget(MBUF_WAITOK
, MBUF_TYPE_DATA
, &m1
);
1136 error
= mbuf_get(MBUF_WAITOK
, MBUF_TYPE_DATA
, &m1
);
1138 error
= mbuf_setnext(m2
, m1
);
1141 mlen
= mbuf_maxlen(m1
);
1142 mbuf_setlen(m1
, mlen
);
1147 *tl
++ = txdr_unsigned(siz
);
1148 mlen
-= NFSX_UNSIGNED
;
1149 mbuf_setlen(m1
, mlen
);
1150 tlen
= NFSX_UNSIGNED
;
1154 len
= nfsm_rndup(siz
);
1157 *(tl
+(xfer
>>2)) = 0;
1161 bcopy(cp
, (caddr_t
) tl
, xfer
);
1162 mbuf_setlen(m1
, len
+ tlen
);
1167 *bpos
= (caddr_t
)mbuf_data(m1
) + mbuf_len(m1
);
1172 * Called once to initialize data structures...
1175 nfs_init(struct vfsconf
*vfsp
)
1180 * Check to see if major data structures haven't bloated.
1182 if (sizeof (struct nfsnode
) > NFS_NODEALLOC
) {
1183 printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC
);
1184 printf("Try reducing NFS_SMALLFH\n");
1186 if (sizeof (struct nfsmount
) > NFS_MNTALLOC
) {
1187 printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC
);
1188 printf("Try reducing NFS_MUIDHASHSIZ\n");
1190 if (sizeof (struct nfssvc_sock
) > NFS_SVCALLOC
) {
1191 printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC
);
1192 printf("Try reducing NFS_UIDHASHSIZ\n");
1194 if (sizeof (struct nfsuid
) > NFS_UIDALLOC
) {
1195 printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC
);
1196 printf("Try unionizing the nu_nickname and nu_flag fields\n");
1199 nfs_mount_type
= vfsp
->vfc_typenum
;
1201 rpc_vers
= txdr_unsigned(RPC_VER2
);
1202 rpc_call
= txdr_unsigned(RPC_CALL
);
1203 rpc_reply
= txdr_unsigned(RPC_REPLY
);
1204 rpc_msgdenied
= txdr_unsigned(RPC_MSGDENIED
);
1205 rpc_msgaccepted
= txdr_unsigned(RPC_MSGACCEPTED
);
1206 rpc_mismatch
= txdr_unsigned(RPC_MISMATCH
);
1207 rpc_autherr
= txdr_unsigned(RPC_AUTHERR
);
1208 rpc_auth_unix
= txdr_unsigned(RPCAUTH_UNIX
);
1209 rpc_auth_kerb
= txdr_unsigned(RPCAUTH_KERB4
);
1210 nfs_prog
= txdr_unsigned(NFS_PROG
);
1211 nfs_true
= txdr_unsigned(TRUE
);
1212 nfs_false
= txdr_unsigned(FALSE
);
1213 nfs_xdrneg1
= txdr_unsigned(-1);
1215 nfs_ticks
= (hz
* NFS_TICKINTVL
+ 500) / 1000;
1218 /* Ensure async daemons disabled */
1219 for (i
= 0; i
< NFS_MAXASYNCDAEMON
; i
++) {
1220 nfs_iodwant
[i
] = NULL
;
1221 nfs_iodmount
[i
] = (struct nfsmount
*)0;
1223 /* init nfsiod mutex */
1224 nfs_iod_lck_grp_attr
= lck_grp_attr_alloc_init();
1225 lck_grp_attr_setstat(nfs_iod_lck_grp_attr
);
1226 nfs_iod_lck_grp
= lck_grp_alloc_init("nfs_iod", nfs_iod_lck_grp_attr
);
1227 nfs_iod_lck_attr
= lck_attr_alloc_init();
1228 nfs_iod_mutex
= lck_mtx_alloc_init(nfs_iod_lck_grp
, nfs_iod_lck_attr
);
1230 nfs_nbinit(); /* Init the nfsbuf table */
1231 nfs_nhinit(); /* Init the nfsnode table */
1232 nfs_lockinit(); /* Init the nfs lock state */
1234 #ifndef NFS_NOSERVER
1235 /* init nfsd mutex */
1236 nfsd_lck_grp_attr
= lck_grp_attr_alloc_init();
1237 lck_grp_attr_setstat(nfsd_lck_grp_attr
);
1238 nfsd_lck_grp
= lck_grp_alloc_init("nfsd", nfsd_lck_grp_attr
);
1239 nfsd_lck_attr
= lck_attr_alloc_init();
1240 nfsd_mutex
= lck_mtx_alloc_init(nfsd_lck_grp
, nfsd_lck_attr
);
1242 /* init slp rwlock */
1243 nfs_slp_lock_attr
= lck_attr_alloc_init();
1244 nfs_slp_group_attr
= lck_grp_attr_alloc_init();
1245 nfs_slp_rwlock_group
= lck_grp_alloc_init("nfs-slp-rwlock", nfs_slp_group_attr
);
1246 nfs_slp_mutex_group
= lck_grp_alloc_init("nfs-slp-mutex", nfs_slp_group_attr
);
1248 /* init export data structures */
1249 nfsexphashtbl
= hashinit(8, M_TEMP
, &nfsexphash
);
1250 LIST_INIT(&nfs_exports
);
1251 nfs_export_lock_attr
= lck_attr_alloc_init();
1252 nfs_export_group_attr
= lck_grp_attr_alloc_init();
1253 nfs_export_rwlock_group
= lck_grp_alloc_init("nfs-export-rwlock", nfs_export_group_attr
);
1254 lck_rw_init(&nfs_export_rwlock
, nfs_export_rwlock_group
, nfs_export_lock_attr
);
1256 lck_mtx_lock(nfsd_mutex
);
1257 nfsrv_init(0); /* Init server data structures */
1258 nfsrv_initcache(); /* Init the server request cache */
1259 lck_mtx_unlock(nfsd_mutex
);
1263 * Initialize reply list and start timer
1265 TAILQ_INIT(&nfs_reqq
);
1269 vfsp
->vfc_refcount
++; /* make us non-unloadable */
1274 * initialize NFS's cache of mbuf constants
1279 struct mbuf_stat ms
;
1282 nfs_mbuf_mlen
= ms
.mlen
;
1283 nfs_mbuf_mhlen
= ms
.mhlen
;
1284 nfs_mbuf_minclsize
= ms
.minclsize
;
1285 nfs_mbuf_mclbytes
= ms
.mclbytes
;
1289 * Parse the attributes that are in the mbuf list and store them in *nvap.
1292 nfs_parsefattr(mbuf_t
*mdp
, caddr_t
*dposp
, int v3
, struct nfs_vattr
*nvap
)
1294 struct nfs_fattr
*fp
;
1297 int error
= 0, rdev
;
1303 t1
= ((caddr_t
)mbuf_data(md
) + mbuf_len(md
)) - *dposp
;
1304 if ((error
= nfsm_disct(mdp
, dposp
, NFSX_FATTR(v3
), t1
, &cp2
))) {
1307 fp
= (struct nfs_fattr
*)cp2
;
1309 vtype
= nfsv3tov_type(fp
->fa_type
);
1310 vmode
= fxdr_unsigned(u_short
, fp
->fa_mode
);
1311 rdev
= makedev(fxdr_unsigned(int, fp
->fa3_rdev
.specdata1
),
1312 fxdr_unsigned(int, fp
->fa3_rdev
.specdata2
));
1314 vtype
= nfsv2tov_type(fp
->fa_type
);
1315 vmode
= fxdr_unsigned(u_short
, fp
->fa_mode
);
1319 * The duplicate information returned in fa_type and fa_mode
1320 * is an ambiguity in the NFS version 2 protocol.
1322 * VREG should be taken literally as a regular file. If a
1323 * server intents to return some type information differently
1324 * in the upper bits of the mode field (e.g. for sockets, or
1325 * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we
1326 * leave the examination of the mode bits even in the VREG
1327 * case to avoid breakage for bogus servers, but we make sure
1328 * that there are actually type bits set in the upper part of
1329 * fa_mode (and failing that, trust the va_type field).
1331 * NFSv3 cleared the issue, and requires fa_mode to not
1332 * contain any type information (while also introduing sockets
1333 * and FIFOs for fa_type).
1335 if (vtype
== VNON
|| (vtype
== VREG
&& (vmode
& S_IFMT
) != 0))
1336 vtype
= IFTOVT(vmode
);
1337 rdev
= fxdr_unsigned(long, fp
->fa2_rdev
);
1339 * Really ugly NFSv2 kludge.
1341 if (vtype
== VCHR
&& rdev
== (int)0xffffffff)
1345 nvap
->nva_type
= vtype
;
1346 nvap
->nva_mode
= (vmode
& 07777);
1347 nvap
->nva_rdev
= (dev_t
)rdev
;
1348 nvap
->nva_nlink
= (uint64_t)fxdr_unsigned(u_long
, fp
->fa_nlink
);
1349 nvap
->nva_uid
= fxdr_unsigned(uid_t
, fp
->fa_uid
);
1350 nvap
->nva_gid
= fxdr_unsigned(gid_t
, fp
->fa_gid
);
1352 fxdr_hyper(&fp
->fa3_size
, &nvap
->nva_size
);
1353 nvap
->nva_blocksize
= 16*1024;
1354 fxdr_hyper(&fp
->fa3_used
, &nvap
->nva_bytes
);
1355 fxdr_hyper(&fp
->fa3_fileid
, &nvap
->nva_fileid
);
1356 fxdr_nfsv3time(&fp
->fa3_atime
, &nvap
->nva_atime
);
1357 fxdr_nfsv3time(&fp
->fa3_mtime
, &nvap
->nva_mtime
);
1358 fxdr_nfsv3time(&fp
->fa3_ctime
, &nvap
->nva_ctime
);
1360 nvap
->nva_size
= fxdr_unsigned(u_long
, fp
->fa2_size
);
1361 nvap
->nva_blocksize
= fxdr_unsigned(long, fp
->fa2_blocksize
);
1362 nvap
->nva_bytes
= fxdr_unsigned(long, fp
->fa2_blocks
) * NFS_FABLKSIZE
;
1363 nvap
->nva_fileid
= (uint64_t)fxdr_unsigned(u_long
, fp
->fa2_fileid
);
1364 fxdr_nfsv2time(&fp
->fa2_atime
, &nvap
->nva_atime
);
1365 fxdr_nfsv2time(&fp
->fa2_mtime
, &nvap
->nva_mtime
);
1366 fxdr_nfsv2time(&fp
->fa2_ctime
, &nvap
->nva_ctime
);
1373 * Load the attribute cache (that lives in the nfsnode entry) with
1374 * the value pointed to by nvap, unless the file type in the attribute
1375 * cache doesn't match the file type in the nvap, in which case log a
1376 * warning and return ESTALE.
1378 * If the dontshrink flag is set, then it's not safe to call ubc_setsize()
1379 * to shrink the size of the file.
1384 struct nfs_vattr
*nvap
,
1391 struct nfs_vattr
*npnvap
;
1393 if (np
->n_flag
& NINIT
) {
1398 mp
= vnode_mount(vp
);
1401 FSDBG_TOP(527, vp
, np
, *xidp
>> 32, *xidp
);
1403 if (!VFSTONFS(mp
)) {
1404 FSDBG_BOT(527, ENXIO
, 1, 0, *xidp
);
1408 if (*xidp
< np
->n_xid
) {
1410 * We have already updated attributes with a response from
1411 * a later request. The attributes we have here are probably
1412 * stale so we drop them (just return). However, our
1413 * out-of-order receipt could be correct - if the requests were
1414 * processed out of order at the server. Given the uncertainty
1415 * we invalidate our cached attributes. *xidp is zeroed here
1416 * to indicate the attributes were dropped - only getattr
1417 * cares - it needs to retry the rpc.
1419 NATTRINVALIDATE(np
);
1420 FSDBG_BOT(527, 0, np
, np
->n_xid
, *xidp
);
1425 if (vp
&& (nvap
->nva_type
!= vnode_vtype(vp
))) {
1427 * The filehandle has changed type on us. This can be
1428 * caused by either the server not having unique filehandles
1429 * or because another client has removed the previous
1430 * filehandle and a new object (of a different type)
1431 * has been created with the same filehandle.
1433 * We can't simply switch the type on the vnode because
1434 * there may be type-specific fields that need to be
1435 * cleaned up or set up.
1437 * So, what should we do with this vnode?
1439 * About the best we can do is log a warning and return
1440 * an error. ESTALE is about the closest error, but it
1441 * is a little strange that we come up with this error
1442 * internally instead of simply passing it through from
1443 * the server. Hopefully, the vnode will be reclaimed
1444 * soon so the filehandle can be reincarnated as the new
1447 printf("nfs loadattrcache vnode changed type, was %d now %d\n",
1448 vnode_vtype(vp
), nvap
->nva_type
);
1449 FSDBG_BOT(527, ESTALE
, 3, 0, *xidp
);
1454 np
->n_attrstamp
= now
.tv_sec
;
1457 npnvap
= &np
->n_vattr
;
1458 nvap
->nva_fsid
= vfs_statfs(mp
)->f_fsid
.val
[0];
1459 bcopy((caddr_t
)nvap
, (caddr_t
)npnvap
, sizeof(*nvap
));
1462 if (nvap
->nva_size
!= np
->n_size
) {
1463 FSDBG(527, vp
, nvap
->nva_size
, np
->n_size
,
1464 (nvap
->nva_type
== VREG
) |
1465 (np
->n_flag
& NMODIFIED
? 6 : 4));
1466 if (nvap
->nva_type
== VREG
) {
1467 u_quad_t orig_size
= np
->n_size
;
1468 if (np
->n_flag
& NMODIFIED
) {
1469 if (nvap
->nva_size
< np
->n_size
)
1470 nvap
->nva_size
= np
->n_size
;
1472 np
->n_size
= nvap
->nva_size
;
1474 np
->n_size
= nvap
->nva_size
;
1475 if (!UBCINFOEXISTS(vp
) ||
1476 (dontshrink
&& np
->n_size
< (u_quad_t
)ubc_getsize(vp
))) {
1477 nvap
->nva_size
= np
->n_size
= orig_size
;
1478 NATTRINVALIDATE(np
);
1480 ubc_setsize(vp
, (off_t
)np
->n_size
); /* XXX */
1483 np
->n_size
= nvap
->nva_size
;
1486 np
->n_size
= nvap
->nva_size
;
1489 if (np
->n_flag
& NCHG
) {
1490 if (np
->n_flag
& NACC
)
1491 nvap
->nva_atime
= np
->n_atim
;
1492 if (np
->n_flag
& NUPD
)
1493 nvap
->nva_mtime
= np
->n_mtim
;
1496 FSDBG_BOT(527, 0, np
, 0, *xidp
);
1501 * Calculate the attribute timeout based on
1502 * how recently the file has been modified.
1505 nfs_attrcachetimeout(vnode_t vp
)
1507 struct nfsnode
*np
= VTONFS(vp
);
1508 struct nfsmount
*nmp
;
1512 if (!(nmp
= VFSTONFS(vnode_mount(vp
))))
1515 isdir
= vnode_isdir(vp
);
1517 if ((np
)->n_flag
& NMODIFIED
)
1518 timeo
= isdir
? nmp
->nm_acdirmin
: nmp
->nm_acregmin
;
1520 /* Note that if the client and server clocks are way out of sync, */
1521 /* timeout will probably get clamped to a min or max value */
1523 timeo
= (now
.tv_sec
- (np
)->n_mtime
.tv_sec
) / 10;
1525 if (timeo
< nmp
->nm_acdirmin
)
1526 timeo
= nmp
->nm_acdirmin
;
1527 else if (timeo
> nmp
->nm_acdirmax
)
1528 timeo
= nmp
->nm_acdirmax
;
1530 if (timeo
< nmp
->nm_acregmin
)
1531 timeo
= nmp
->nm_acregmin
;
1532 else if (timeo
> nmp
->nm_acregmax
)
1533 timeo
= nmp
->nm_acregmax
;
1541 * Check the time stamp
1542 * If the cache is valid, copy contents to *nvaper and return 0
1543 * otherwise return an error
1546 nfs_getattrcache(vp
, nvaper
)
1548 struct nfs_vattr
*nvaper
;
1550 struct nfsnode
*np
= VTONFS(vp
);
1551 struct nfs_vattr
*nvap
;
1552 struct timeval nowup
;
1555 if (!NATTRVALID(np
)) {
1556 FSDBG(528, vp
, 0, 0, 0);
1557 OSAddAtomic(1, (SInt32
*)&nfsstats
.attrcache_misses
);
1561 timeo
= nfs_attrcachetimeout(vp
);
1563 microuptime(&nowup
);
1564 if ((nowup
.tv_sec
- np
->n_attrstamp
) >= timeo
) {
1565 FSDBG(528, vp
, 0, 0, 1);
1566 OSAddAtomic(1, (SInt32
*)&nfsstats
.attrcache_misses
);
1569 FSDBG(528, vp
, 0, 0, 2);
1570 OSAddAtomic(1, (SInt32
*)&nfsstats
.attrcache_hits
);
1571 nvap
= &np
->n_vattr
;
1573 if (nvap
->nva_size
!= np
->n_size
) {
1574 FSDBG(528, vp
, nvap
->nva_size
, np
->n_size
,
1575 (nvap
->nva_type
== VREG
) |
1576 (np
->n_flag
& NMODIFIED
? 6 : 4));
1577 if (nvap
->nva_type
== VREG
) {
1578 if (np
->n_flag
& NMODIFIED
) {
1579 if (nvap
->nva_size
< np
->n_size
)
1580 nvap
->nva_size
= np
->n_size
;
1582 np
->n_size
= nvap
->nva_size
;
1584 np
->n_size
= nvap
->nva_size
;
1585 ubc_setsize(vp
, (off_t
)np
->n_size
); /* XXX */
1587 np
->n_size
= nvap
->nva_size
;
1590 bcopy((caddr_t
)nvap
, (caddr_t
)nvaper
, sizeof(struct nfs_vattr
));
1591 if (np
->n_flag
& NCHG
) {
1592 if (np
->n_flag
& NACC
)
1593 nvaper
->nva_atime
= np
->n_atim
;
1594 if (np
->n_flag
& NUPD
)
1595 nvaper
->nva_mtime
= np
->n_mtim
;
1600 #ifndef NFS_NOSERVER
1602 * Extract a lookup path from the given mbufs and store it in
1603 * a newly allocated buffer saved in the given nameidata structure.
1604 * exptected string length given as *lenp and final string length
1605 * (after any WebNFS processing) is returned in *lenp.
1612 __unused
int pubflag
,
1614 struct nameidata
*ndp
)
1616 int i
, len
, len2
, rem
, error
= 0;
1618 char *fromcp
, *tocp
;
1619 struct componentname
*cnp
= &ndp
->ni_cnd
;
1620 /* XXX Revisit when enabling WebNFS */
1621 #ifdef WEBNFS_ENABLED
1622 int webcnt
= 0, digitcnt
= 0;
1627 if (len
> (MAXPATHLEN
- 1))
1628 return (ENAMETOOLONG
);
1631 * Get a buffer for the name to be translated, and copy the
1632 * name into the buffer.
1634 MALLOC_ZONE(cnp
->cn_pnbuf
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1637 cnp
->cn_pnlen
= MAXPATHLEN
;
1638 cnp
->cn_flags
|= HASBUF
;
1641 * Copy the name from the mbuf list to the string
1643 * Along the way, take note of any WebNFS characters
1644 * and convert any % escapes.
1647 tocp
= cnp
->cn_pnbuf
;
1649 rem
= (caddr_t
)mbuf_data(md
) + mbuf_len(md
) - fromcp
;
1650 for (i
= 1; i
<= len
; i
++) {
1657 fromcp
= mbuf_data(md
);
1660 /* XXX Revisit when enabling WebNFS */
1661 #ifdef WEBNFS_ENABLED
1663 if ((i
== 1) && ((unsigned char)*fromcp
>= WEBNFS_SPECCHAR_START
)) {
1664 switch ((unsigned char)*fromcp
) {
1665 case WEBNFS_NATIVE_CHAR
:
1667 * 'Native' path for us is the same
1668 * as a path according to the NFS spec,
1669 * just skip the escape char.
1674 /* next iteration of for loop */
1677 * More may be added in the future, range 0x80-0xff.
1678 * Don't currently support security query lookup (0x81).
1686 /* We're expecting hex digits */
1687 if (!ISHEX(*fromcp
)) {
1692 hexdigits
[digitcnt
? 0 : 1] = *fromcp
++;
1694 *tocp
++ = HEXSTRTOI(hexdigits
);
1696 /* next iteration of for loop */
1698 } else if (*fromcp
== WEBNFS_ESC_CHAR
) {
1700 * We can't really look at the next couple
1701 * bytes here safely/easily, so we note that
1702 * the next two characters should be hex
1703 * digits and later save them in hexdigits[].
1704 * When we've got both, we'll convert it.
1710 /* next iteration of for loop */
1714 if (*fromcp
== '\0' || (!pubflag
&& *fromcp
== '/'))
1716 if (*fromcp
== '\0' || *fromcp
== '/')
1722 *tocp
++ = *fromcp
++;
1728 len2
= nfsm_rndup(len
)-len
;
1732 else if ((error
= nfs_adv(mdp
, dposp
, len2
, rem
)) != 0)
1736 /* XXX Revisit when enabling WebNFS */
1737 #ifdef WEBNFS_ENABLED
1740 /* The string ended in the middle of an escape! */
1751 FREE_ZONE(cnp
->cn_pnbuf
, MAXPATHLEN
, M_NAMEI
);
1752 cnp
->cn_flags
&= ~HASBUF
;
1754 ndp
->ni_pathlen
= len
;
1761 * Set up nameidata for a lookup() call and do it.
1763 * If pubflag is set, this call is done for a lookup operation on the
1764 * public filehandle. In that case we allow crossing mountpoints and
1765 * absolute pathnames. However, the caller is expected to check that
1766 * the lookup result is within the public fs, and deny access if
1771 struct nfsrv_descript
*nfsd
,
1772 struct vfs_context
*ctx
,
1773 struct nameidata
*ndp
,
1774 struct nfs_filehandle
*nfhp
,
1778 struct nfs_export
**nxp
,
1779 struct nfs_export_options
**nxop
)
1781 /* XXX Revisit when enabling WebNFS */
1782 #ifdef WEBNFS_ENABLED
1785 char uio_buf
[ UIO_SIZEOF(1) ];
1786 int linklen
, olen
= ndp
->ni_pathlen
;
1790 struct componentname
*cnp
= &ndp
->ni_cnd
;
1796 * Extract and set starting directory.
1798 error
= nfsrv_fhtovp(nfhp
, nam
, pubflag
, &dp
, nxp
, nxop
);
1801 error
= nfsrv_credcheck(nfsd
, *nxp
, *nxop
);
1802 if (error
|| (vnode_vtype(dp
) != VDIR
)) {
1808 ctx
->vc_ucred
= nfsd
->nd_cr
;
1809 ndp
->ni_cnd
.cn_context
= ctx
;
1811 if (*nxop
&& ((*nxop
)->nxo_flags
& NX_READONLY
))
1812 cnp
->cn_flags
|= RDONLY
;
1816 /* XXX Revisit when enabling WebNFS */
1817 #ifdef WEBNFS_ENABLED
1819 ndp
->ni_rootdir
= rootvnode
;
1820 ndp
->ni_loopcnt
= 0;
1821 if (cnp
->cn_pnbuf
[0] == '/') {
1824 error
= vnode_get(dp
);
1831 cnp
->cn_flags
|= NOCROSSMOUNT
;
1834 cnp
->cn_flags
|= NOCROSSMOUNT
;
1837 ndp
->ni_usedvp
= dp
;
1840 cnp
->cn_nameptr
= cnp
->cn_pnbuf
;
1841 ndp
->ni_startdir
= dp
;
1843 * And call lookup() to do the real work
1845 error
= lookup(ndp
);
1849 * Check for encountering a symbolic link
1851 if ((cnp
->cn_flags
& ISSYMLINK
) == 0) {
1854 if ((cnp
->cn_flags
& FSNODELOCKHELD
)) {
1855 cnp
->cn_flags
&= ~FSNODELOCKHELD
;
1856 unlock_fsnode(ndp
->ni_dvp
, NULL
);
1858 /* XXX Revisit when enabling WebNFS */
1859 #ifdef WEBNFS_ENABLED
1862 if (cnp
->cn_flags
& (LOCKPARENT
| WANTPARENT
))
1863 vnode_put(ndp
->ni_dvp
);
1865 vnode_put(ndp
->ni_vp
);
1870 /* XXX Revisit when enabling WebNFS */
1871 #ifdef WEBNFS_ENABLED
1874 if (ndp
->ni_loopcnt
++ >= MAXSYMLINKS
) {
1875 vnode_put(ndp
->ni_vp
);
1880 /* XXX assert(olen <= MAXPATHLEN - 1); */
1881 if (ndp
->ni_pathlen
> 1) {
1882 MALLOC_ZONE(cp
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1884 vnode_put(ndp
->ni_vp
);
1892 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
1893 &uio_buf
[0], sizeof(uio_buf
));
1895 vnode_put(ndp
->ni_vp
);
1897 if (ndp
->ni_pathlen
> 1)
1898 FREE_ZONE(cp
, MAXPATHLEN
, M_NAMEI
);
1902 uio_addiov(auio
, CAST_USER_ADDR_T(cp
), MAXPATHLEN
);
1903 error
= VNOP_READLINK(ndp
->ni_vp
, auio
, cnp
->cn_context
);
1906 vnode_put(ndp
->ni_vp
);
1908 if (ndp
->ni_pathlen
> 1)
1909 FREE_ZONE(cp
, MAXPATHLEN
, M_NAMEI
);
1912 linklen
= MAXPATHLEN
- uio_resid(auio
);
1917 if (linklen
+ ndp
->ni_pathlen
>= MAXPATHLEN
) {
1918 error
= ENAMETOOLONG
;
1921 if (ndp
->ni_pathlen
> 1) {
1922 long len
= cnp
->cn_pnlen
;
1923 tmppn
= cnp
->cn_pnbuf
;
1925 cnp
->cn_pnlen
= olen
+ 1;
1926 bcopy(ndp
->ni_next
, cp
+ linklen
, ndp
->ni_pathlen
);
1927 FREE_ZONE(tmppn
, len
, M_NAMEI
);
1929 cnp
->cn_pnbuf
[linklen
] = '\0';
1930 ndp
->ni_pathlen
+= linklen
;
1932 vnode_put(ndp
->ni_vp
);
1937 * Check if root directory should replace current directory.
1939 if (cnp
->cn_pnbuf
[0] == '/') {
1941 dp
= ndp
->ni_rootdir
;
1942 error
= vnode_get(dp
);
1950 tmppn
= cnp
->cn_pnbuf
;
1951 cnp
->cn_pnbuf
= NULL
;
1952 cnp
->cn_flags
&= ~HASBUF
;
1953 FREE_ZONE(tmppn
, cnp
->cn_pnlen
, M_NAMEI
);
1959 * A fiddled version of m_adj() that ensures null fill to a long
1960 * boundary and only trims off the back end
1963 nfsm_adj(mp
, len
, nul
)
1973 * Trim from tail. Scan the mbuf chain,
1974 * calculating its length and finding the last mbuf.
1975 * If the adjustment only affects this mbuf, then just
1976 * adjust and return. Otherwise, rescan and truncate
1977 * after the remaining size.
1984 mnext
= mbuf_next(m
);
1991 mbuf_setlen(m
, mlen
);
1993 cp
= (caddr_t
)mbuf_data(m
) + mlen
- nul
;
1994 for (i
= 0; i
< nul
; i
++)
2003 * Correct length for chain is "count".
2004 * Find the mbuf with last data, adjust its length,
2005 * and toss data from remaining mbufs on chain.
2007 for (m
= mp
; m
; m
= mbuf_next(m
)) {
2009 if (mlen
>= count
) {
2011 mbuf_setlen(m
, count
);
2013 cp
= (caddr_t
)mbuf_data(m
) + mlen
- nul
;
2014 for (i
= 0; i
< nul
; i
++)
2021 for (m
= mbuf_next(m
); m
; m
= mbuf_next(m
))
2026 * Make these functions instead of macros, so that the kernel text size
2027 * doesn't get too big...
2030 nfsm_srvwcc(nfsd
, before_ret
, before_vap
, after_ret
, after_vap
, mbp
, bposp
)
2031 struct nfsrv_descript
*nfsd
;
2033 struct vnode_attr
*before_vap
;
2035 struct vnode_attr
*after_vap
;
2039 mbuf_t mb
= *mbp
, mb2
;
2040 char *bpos
= *bposp
;
2044 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
2047 nfsm_build(tl
, u_long
*, 7 * NFSX_UNSIGNED
);
2049 txdr_hyper(&(before_vap
->va_data_size
), tl
);
2051 txdr_nfsv3time(&(before_vap
->va_modify_time
), tl
);
2053 txdr_nfsv3time(&(before_vap
->va_change_time
), tl
);
2057 nfsm_srvpostopattr(nfsd
, after_ret
, after_vap
, mbp
, bposp
);
2061 nfsm_srvpostopattr(nfsd
, after_ret
, after_vap
, mbp
, bposp
)
2062 struct nfsrv_descript
*nfsd
;
2064 struct vnode_attr
*after_vap
;
2068 mbuf_t mb
= *mbp
, mb2
;
2069 char *bpos
= *bposp
;
2071 struct nfs_fattr
*fp
;
2074 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
2077 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
+ NFSX_V3FATTR
);
2079 fp
= (struct nfs_fattr
*)tl
;
2080 nfsm_srvfattr(nfsd
, after_vap
, fp
);
2087 nfsm_srvfattr(nfsd
, vap
, fp
)
2088 struct nfsrv_descript
*nfsd
;
2089 struct vnode_attr
*vap
;
2090 struct nfs_fattr
*fp
;
2093 // XXX Should we assert here that all fields are supported?
2095 fp
->fa_nlink
= txdr_unsigned(vap
->va_nlink
);
2096 fp
->fa_uid
= txdr_unsigned(vap
->va_uid
);
2097 fp
->fa_gid
= txdr_unsigned(vap
->va_gid
);
2098 if (nfsd
->nd_flag
& ND_NFSV3
) {
2099 fp
->fa_type
= vtonfsv3_type(vap
->va_type
);
2100 fp
->fa_mode
= vtonfsv3_mode(vap
->va_mode
);
2101 txdr_hyper(&vap
->va_data_size
, &fp
->fa3_size
);
2102 txdr_hyper(&vap
->va_data_alloc
, &fp
->fa3_used
);
2103 fp
->fa3_rdev
.specdata1
= txdr_unsigned(major(vap
->va_rdev
));
2104 fp
->fa3_rdev
.specdata2
= txdr_unsigned(minor(vap
->va_rdev
));
2105 fp
->fa3_fsid
.nfsuquad
[0] = 0;
2106 fp
->fa3_fsid
.nfsuquad
[1] = txdr_unsigned(vap
->va_fsid
);
2107 txdr_hyper(&vap
->va_fileid
, &fp
->fa3_fileid
);
2108 txdr_nfsv3time(&vap
->va_access_time
, &fp
->fa3_atime
);
2109 txdr_nfsv3time(&vap
->va_modify_time
, &fp
->fa3_mtime
);
2110 txdr_nfsv3time(&vap
->va_change_time
, &fp
->fa3_ctime
);
2112 fp
->fa_type
= vtonfsv2_type(vap
->va_type
);
2113 fp
->fa_mode
= vtonfsv2_mode(vap
->va_type
, vap
->va_mode
);
2114 fp
->fa2_size
= txdr_unsigned(vap
->va_data_size
);
2115 fp
->fa2_blocksize
= txdr_unsigned(vap
->va_iosize
);
2116 if (vap
->va_type
== VFIFO
)
2117 fp
->fa2_rdev
= 0xffffffff;
2119 fp
->fa2_rdev
= txdr_unsigned(vap
->va_rdev
);
2120 fp
->fa2_blocks
= txdr_unsigned(vap
->va_data_alloc
/ NFS_FABLKSIZE
);
2121 fp
->fa2_fsid
= txdr_unsigned(vap
->va_fsid
);
2122 fp
->fa2_fileid
= txdr_unsigned(vap
->va_fileid
);
2123 txdr_nfsv2time(&vap
->va_access_time
, &fp
->fa2_atime
);
2124 txdr_nfsv2time(&vap
->va_modify_time
, &fp
->fa2_mtime
);
2125 txdr_nfsv2time(&vap
->va_change_time
, &fp
->fa2_ctime
);
2130 * Build hash lists of net addresses and hang them off the NFS export.
2131 * Called by nfsrv_export() to set up the lists of export addresses.
2134 nfsrv_hang_addrlist(struct nfs_export
*nx
, struct user_nfs_export_args
*unxa
)
2136 struct nfs_export_net_args nxna
;
2137 struct nfs_netopt
*no
;
2138 struct radix_node_head
*rnh
;
2139 struct radix_node
*rn
;
2140 struct sockaddr
*saddr
, *smask
;
2146 struct ucred temp_cred
;
2148 uaddr
= unxa
->nxa_nets
;
2149 for (net
= 0; net
< unxa
->nxa_netcount
; net
++, uaddr
+= sizeof(nxna
)) {
2150 error
= copyin(uaddr
, &nxna
, sizeof(nxna
));
2154 if (nxna
.nxna_flags
& (NX_MAPROOT
|NX_MAPALL
)) {
2155 bzero(&temp_cred
, sizeof(temp_cred
));
2156 temp_cred
.cr_uid
= nxna
.nxna_cred
.cr_uid
;
2157 temp_cred
.cr_ngroups
= nxna
.nxna_cred
.cr_ngroups
;
2158 for (i
=0; i
< nxna
.nxna_cred
.cr_ngroups
&& i
< NGROUPS
; i
++)
2159 temp_cred
.cr_groups
[i
] = nxna
.nxna_cred
.cr_groups
[i
];
2161 cred
= kauth_cred_create(&temp_cred
);
2168 if (nxna
.nxna_addr
.ss_len
== 0) {
2169 /* No address means this is a default/world export */
2170 if (nx
->nx_flags
& NX_DEFAULTEXPORT
)
2172 nx
->nx_flags
|= NX_DEFAULTEXPORT
;
2173 nx
->nx_defopt
.nxo_flags
= nxna
.nxna_flags
;
2174 nx
->nx_defopt
.nxo_cred
= cred
;
2179 i
= sizeof(struct nfs_netopt
);
2180 i
+= nxna
.nxna_addr
.ss_len
+ nxna
.nxna_mask
.ss_len
;
2181 MALLOC(no
, struct nfs_netopt
*, i
, M_NETADDR
, M_WAITOK
);
2184 bzero(no
, sizeof(struct nfs_netopt
));
2185 no
->no_opt
.nxo_flags
= nxna
.nxna_flags
;
2186 no
->no_opt
.nxo_cred
= cred
;
2188 saddr
= (struct sockaddr
*)(no
+ 1);
2189 bcopy(&nxna
.nxna_addr
, saddr
, nxna
.nxna_addr
.ss_len
);
2190 if (nxna
.nxna_mask
.ss_len
) {
2191 smask
= (struct sockaddr
*)((caddr_t
)saddr
+ nxna
.nxna_addr
.ss_len
);
2192 bcopy(&nxna
.nxna_mask
, smask
, nxna
.nxna_mask
.ss_len
);
2196 i
= saddr
->sa_family
;
2197 if ((rnh
= nx
->nx_rtable
[i
]) == 0) {
2199 * Seems silly to initialize every AF when most are not
2200 * used, do so on demand here
2202 for (dom
= domains
; dom
; dom
= dom
->dom_next
)
2203 if (dom
->dom_family
== i
&& dom
->dom_rtattach
) {
2204 dom
->dom_rtattach((void **)&nx
->nx_rtable
[i
],
2208 if ((rnh
= nx
->nx_rtable
[i
]) == 0) {
2209 kauth_cred_rele(cred
);
2210 _FREE(no
, M_NETADDR
);
2214 rn
= (*rnh
->rnh_addaddr
)((caddr_t
)saddr
, (caddr_t
)smask
, rnh
, no
->no_rnodes
);
2217 * One of the reasons that rnh_addaddr may fail is that
2218 * the entry already exists. To check for this case, we
2219 * look up the entry to see if it is there. If so, we
2220 * do not need to make a new entry but do continue.
2223 rn
= (*rnh
->rnh_matchaddr
)((caddr_t
)saddr
, rnh
);
2224 if (rn
!= 0 && (rn
->rn_flags
& RNF_ROOT
) == 0 &&
2225 (((struct nfs_netopt
*)rn
)->no_opt
.nxo_flags
== nxna
.nxna_flags
)) {
2226 kauth_cred_t cred2
= ((struct nfs_netopt
*)rn
)->no_opt
.nxo_cred
;
2227 if (cred
&& cred2
&& (cred
->cr_uid
== cred2
->cr_uid
) &&
2228 (cred
->cr_ngroups
== cred2
->cr_ngroups
)) {
2229 for (i
=0; i
< cred2
->cr_ngroups
&& i
< NGROUPS
; i
++)
2230 if (cred
->cr_groups
[i
] != cred2
->cr_groups
[i
])
2232 if (i
>= cred2
->cr_ngroups
|| i
>= NGROUPS
)
2236 kauth_cred_rele(cred
);
2237 _FREE(no
, M_NETADDR
);
2249 * In order to properly track an export's netopt count, we need to pass
2250 * an additional argument to nfsrv_free_netopt() so that it can decrement
2251 * the export's netopt count.
2253 struct nfsrv_free_netopt_arg
{
2255 struct radix_node_head
*rnh
;
2259 nfsrv_free_netopt(struct radix_node
*rn
, void *w
)
2261 struct nfsrv_free_netopt_arg
*fna
= (struct nfsrv_free_netopt_arg
*)w
;
2262 struct radix_node_head
*rnh
= fna
->rnh
;
2263 uint32_t *cnt
= fna
->cnt
;
2264 struct nfs_netopt
*nno
= (struct nfs_netopt
*)rn
;
2266 (*rnh
->rnh_deladdr
)(rn
->rn_key
, rn
->rn_mask
, rnh
);
2267 if (nno
->no_opt
.nxo_cred
)
2268 kauth_cred_rele(nno
->no_opt
.nxo_cred
);
2269 _FREE((caddr_t
)rn
, M_NETADDR
);
2275 * Free the net address hash lists that are hanging off the mount points.
2278 nfsrv_free_addrlist(struct nfs_export
*nx
)
2281 struct radix_node_head
*rnh
;
2282 struct nfsrv_free_netopt_arg fna
;
2284 for (i
= 0; i
<= AF_MAX
; i
++)
2285 if ( (rnh
= nx
->nx_rtable
[i
]) ) {
2287 fna
.cnt
= &nx
->nx_expcnt
;
2288 (*rnh
->rnh_walktree
)(rnh
, nfsrv_free_netopt
, (caddr_t
)&fna
);
2289 _FREE((caddr_t
)rnh
, M_RTABLE
);
2290 nx
->nx_rtable
[i
] = 0;
2294 void enablequotas(struct mount
*mp
, vfs_context_t ctx
); // XXX
2297 nfsrv_export(struct user_nfs_export_args
*unxa
, struct vfs_context
*ctx
)
2299 int error
= 0, pathlen
;
2300 struct nfs_exportfs
*nxfs
, *nxfs2
, *nxfs3
;
2301 struct nfs_export
*nx
, *nx2
, *nx3
;
2302 struct nfs_filehandle nfh
;
2303 struct nameidata mnd
, xnd
;
2304 vnode_t mvp
= NULL
, xvp
= NULL
;
2306 char path
[MAXPATHLEN
];
2309 if (unxa
->nxa_flags
& NXA_DELETE_ALL
) {
2310 /* delete all exports on all file systems */
2311 lck_rw_lock_exclusive(&nfs_export_rwlock
);
2312 while ((nxfs
= LIST_FIRST(&nfs_exports
))) {
2313 mp
= vfs_getvfs_by_mntonname(nxfs
->nxfs_path
);
2315 mp
->mnt_flag
&= ~MNT_EXPORTED
;
2316 /* delete all exports on this file system */
2317 while ((nx
= LIST_FIRST(&nxfs
->nxfs_exports
))) {
2318 LIST_REMOVE(nx
, nx_next
);
2319 LIST_REMOVE(nx
, nx_hash
);
2320 /* delete all netopts for this export */
2321 nfsrv_free_addrlist(nx
);
2322 nx
->nx_flags
&= ~NX_DEFAULTEXPORT
;
2323 if (nx
->nx_defopt
.nxo_cred
) {
2324 kauth_cred_rele(nx
->nx_defopt
.nxo_cred
);
2325 nx
->nx_defopt
.nxo_cred
= NULL
;
2327 FREE(nx
->nx_path
, M_TEMP
);
2330 LIST_REMOVE(nxfs
, nxfs_next
);
2331 FREE(nxfs
->nxfs_path
, M_TEMP
);
2334 lck_rw_done(&nfs_export_rwlock
);
2338 error
= copyinstr(unxa
->nxa_fspath
, path
, MAXPATHLEN
, (size_t *)&pathlen
);
2342 lck_rw_lock_exclusive(&nfs_export_rwlock
);
2344 // first check if we've already got an exportfs with the given ID
2345 LIST_FOREACH(nxfs
, &nfs_exports
, nxfs_next
) {
2346 if (nxfs
->nxfs_id
== unxa
->nxa_fsid
)
2350 /* verify exported FS path matches given path */
2351 if (strcmp(path
, nxfs
->nxfs_path
)) {
2355 mp
= vfs_getvfs_by_mntonname(nxfs
->nxfs_path
);
2356 /* find exported FS root vnode */
2357 NDINIT(&mnd
, LOOKUP
, FOLLOW
| LOCKLEAF
| AUDITVNPATH1
,
2358 UIO_SYSSPACE
, nxfs
->nxfs_path
, ctx
);
2359 error
= namei(&mnd
);
2363 /* make sure it's (still) the root of a file system */
2364 if ((mvp
->v_flag
& VROOT
) == 0) {
2368 /* sanity check: this should be same mount */
2369 if (mp
!= vnode_mount(mvp
)) {
2374 /* no current exported file system with that ID */
2375 if (!(unxa
->nxa_flags
& NXA_ADD
)) {
2380 /* find exported FS root vnode */
2381 NDINIT(&mnd
, LOOKUP
, FOLLOW
| LOCKLEAF
| AUDITVNPATH1
,
2382 UIO_SYSSPACE
, path
, ctx
);
2383 error
= namei(&mnd
);
2387 /* make sure it's the root of a file system */
2388 if ((mvp
->v_flag
& VROOT
) == 0) {
2392 mp
= vnode_mount(mvp
);
2394 /* make sure the file system is NFS-exportable */
2395 nfh
.nfh_len
= NFS_MAX_FID_SIZE
;
2396 error
= VFS_VPTOFH(mvp
, &nfh
.nfh_len
, &nfh
.nfh_fid
[0], NULL
);
2397 if (!error
&& (nfh
.nfh_len
> (int)NFS_MAX_FID_SIZE
))
2402 /* add an exportfs for it */
2403 MALLOC(nxfs
, struct nfs_exportfs
*, sizeof(struct nfs_exportfs
), M_TEMP
, M_WAITOK
);
2408 bzero(nxfs
, sizeof(struct nfs_exportfs
));
2409 nxfs
->nxfs_id
= unxa
->nxa_fsid
;
2410 MALLOC(nxfs
->nxfs_path
, char*, pathlen
, M_TEMP
, M_WAITOK
);
2411 if (!nxfs
->nxfs_path
) {
2416 bcopy(path
, nxfs
->nxfs_path
, pathlen
);
2417 /* insert into list in reverse-sorted order */
2419 LIST_FOREACH(nxfs2
, &nfs_exports
, nxfs_next
) {
2420 if (strcmp(nxfs
->nxfs_path
, nxfs2
->nxfs_path
) > 0)
2425 LIST_INSERT_BEFORE(nxfs2
, nxfs
, nxfs_next
);
2427 LIST_INSERT_AFTER(nxfs3
, nxfs
, nxfs_next
);
2429 LIST_INSERT_HEAD(&nfs_exports
, nxfs
, nxfs_next
);
2431 /* make sure any quotas are enabled before we export the file system */
2432 enablequotas(mp
, ctx
);
2435 if (unxa
->nxa_exppath
) {
2436 error
= copyinstr(unxa
->nxa_exppath
, path
, MAXPATHLEN
, (size_t *)&pathlen
);
2439 LIST_FOREACH(nx
, &nxfs
->nxfs_exports
, nx_next
) {
2440 if (nx
->nx_id
== unxa
->nxa_expid
)
2444 /* verify exported FS path matches given path */
2445 if (strcmp(path
, nx
->nx_path
)) {
2450 /* no current export with that ID */
2451 if (!(unxa
->nxa_flags
& NXA_ADD
)) {
2455 /* add an export for it */
2456 MALLOC(nx
, struct nfs_export
*, sizeof(struct nfs_export
), M_TEMP
, M_WAITOK
);
2461 bzero(nx
, sizeof(struct nfs_export
));
2462 nx
->nx_id
= unxa
->nxa_expid
;
2464 MALLOC(nx
->nx_path
, char*, pathlen
, M_TEMP
, M_WAITOK
);
2471 bcopy(path
, nx
->nx_path
, pathlen
);
2472 /* insert into list in reverse-sorted order */
2474 LIST_FOREACH(nx2
, &nxfs
->nxfs_exports
, nx_next
) {
2475 if (strcmp(nx
->nx_path
, nx2
->nx_path
) > 0)
2480 LIST_INSERT_BEFORE(nx2
, nx
, nx_next
);
2482 LIST_INSERT_AFTER(nx3
, nx
, nx_next
);
2484 LIST_INSERT_HEAD(&nxfs
->nxfs_exports
, nx
, nx_next
);
2485 /* insert into hash */
2486 LIST_INSERT_HEAD(NFSEXPHASH(nxfs
->nxfs_id
, nx
->nx_id
), nx
, nx_hash
);
2489 * We don't allow nested exports. Check if the new entry
2490 * nests with the entries before and after or if there's an
2491 * entry for the file system root and subdirs.
2494 if ((nx3
&& !strncmp(nx3
->nx_path
, nx
->nx_path
, pathlen
- 1) &&
2495 (nx3
->nx_path
[pathlen
-1] == '/')) ||
2496 (nx2
&& !strncmp(nx2
->nx_path
, nx
->nx_path
, strlen(nx2
->nx_path
)) &&
2497 (nx
->nx_path
[strlen(nx2
->nx_path
)] == '/')))
2500 /* check export conflict with fs root export and vice versa */
2501 expisroot
= !nx
->nx_path
[0] ||
2502 ((nx
->nx_path
[0] == '.') && !nx
->nx_path
[1]);
2503 LIST_FOREACH(nx2
, &nxfs
->nxfs_exports
, nx_next
) {
2507 } else if (!nx2
->nx_path
[0])
2509 else if ((nx2
->nx_path
[0] == '.') && !nx2
->nx_path
[1])
2516 printf("nfsrv_export: attempt to register nested exports: %s/%s\n",
2517 nxfs
->nxfs_path
, nx
->nx_path
);
2521 /* find export root vnode */
2522 if (!nx
->nx_path
[0] || ((nx
->nx_path
[0] == '.') && !nx
->nx_path
[1])) {
2523 /* exporting file system's root directory */
2527 xnd
.ni_cnd
.cn_nameiop
= LOOKUP
;
2528 xnd
.ni_cnd
.cn_flags
= LOCKLEAF
;
2529 xnd
.ni_pathlen
= pathlen
- 1;
2530 xnd
.ni_cnd
.cn_nameptr
= xnd
.ni_cnd
.cn_pnbuf
= path
;
2531 xnd
.ni_startdir
= mvp
;
2532 xnd
.ni_usedvp
= mvp
;
2533 xnd
.ni_cnd
.cn_context
= ctx
;
2534 error
= lookup(&xnd
);
2540 if (vnode_vtype(xvp
) != VDIR
) {
2546 /* grab file handle */
2547 nx
->nx_fh
.nfh_xh
.nxh_version
= NFS_FH_VERSION
;
2548 nx
->nx_fh
.nfh_xh
.nxh_fsid
= nx
->nx_fs
->nxfs_id
;
2549 nx
->nx_fh
.nfh_xh
.nxh_expid
= nx
->nx_id
;
2550 nx
->nx_fh
.nfh_xh
.nxh_flags
= 0;
2551 nx
->nx_fh
.nfh_xh
.nxh_reserved
= 0;
2552 nx
->nx_fh
.nfh_len
= NFS_MAX_FID_SIZE
;
2553 error
= VFS_VPTOFH(xvp
, &nx
->nx_fh
.nfh_len
, &nx
->nx_fh
.nfh_fid
[0], NULL
);
2554 if (!error
&& (nx
->nx_fh
.nfh_len
> (int)NFS_MAX_FID_SIZE
)) {
2557 nx
->nx_fh
.nfh_xh
.nxh_fidlen
= nx
->nx_fh
.nfh_len
;
2558 nx
->nx_fh
.nfh_len
+= sizeof(nx
->nx_fh
.nfh_xh
);
2569 /* perform the export changes */
2570 if (unxa
->nxa_flags
& NXA_DELETE
) {
2572 /* delete all exports on this file system */
2573 while ((nx
= LIST_FIRST(&nxfs
->nxfs_exports
))) {
2574 LIST_REMOVE(nx
, nx_next
);
2575 LIST_REMOVE(nx
, nx_hash
);
2576 /* delete all netopts for this export */
2577 nfsrv_free_addrlist(nx
);
2578 nx
->nx_flags
&= ~NX_DEFAULTEXPORT
;
2579 if (nx
->nx_defopt
.nxo_cred
) {
2580 kauth_cred_rele(nx
->nx_defopt
.nxo_cred
);
2581 nx
->nx_defopt
.nxo_cred
= NULL
;
2583 FREE(nx
->nx_path
, M_TEMP
);
2588 /* delete all netopts for this export */
2589 nfsrv_free_addrlist(nx
);
2590 nx
->nx_flags
&= ~NX_DEFAULTEXPORT
;
2591 if (nx
->nx_defopt
.nxo_cred
) {
2592 kauth_cred_rele(nx
->nx_defopt
.nxo_cred
);
2593 nx
->nx_defopt
.nxo_cred
= NULL
;
2597 if (unxa
->nxa_flags
& NXA_ADD
) {
2598 error
= nfsrv_hang_addrlist(nx
, unxa
);
2600 mp
->mnt_flag
|= MNT_EXPORTED
;
2604 if (nx
&& !nx
->nx_expcnt
) {
2605 /* export has no export options */
2606 LIST_REMOVE(nx
, nx_next
);
2607 LIST_REMOVE(nx
, nx_hash
);
2608 FREE(nx
->nx_path
, M_TEMP
);
2611 if (LIST_EMPTY(&nxfs
->nxfs_exports
)) {
2612 /* exported file system has no more exports */
2613 LIST_REMOVE(nxfs
, nxfs_next
);
2614 FREE(nxfs
->nxfs_path
, M_TEMP
);
2616 mp
->mnt_flag
&= ~MNT_EXPORTED
;
2625 lck_rw_done(&nfs_export_rwlock
);
2629 static struct nfs_export_options
*
2630 nfsrv_export_lookup(struct nfs_export
*nx
, mbuf_t nam
)
2632 struct nfs_export_options
*nxo
= NULL
;
2633 struct nfs_netopt
*no
= NULL
;
2634 struct radix_node_head
*rnh
;
2635 struct sockaddr
*saddr
;
2637 /* Lookup in the export list first. */
2639 saddr
= mbuf_data(nam
);
2640 rnh
= nx
->nx_rtable
[saddr
->sa_family
];
2642 no
= (struct nfs_netopt
*)
2643 (*rnh
->rnh_matchaddr
)((caddr_t
)saddr
, rnh
);
2644 if (no
&& no
->no_rnodes
->rn_flags
& RNF_ROOT
)
2650 /* If no address match, use the default if it exists. */
2651 if ((nxo
== NULL
) && (nx
->nx_flags
& NX_DEFAULTEXPORT
))
2652 nxo
= &nx
->nx_defopt
;
2656 /* find an export for the given handle */
2657 static struct nfs_export
*
2658 nfsrv_fhtoexport(struct nfs_filehandle
*nfhp
)
2660 struct nfs_export
*nx
;
2661 nx
= NFSEXPHASH(nfhp
->nfh_xh
.nxh_fsid
, nfhp
->nfh_xh
.nxh_expid
)->lh_first
;
2662 for (; nx
; nx
= LIST_NEXT(nx
, nx_hash
)) {
2663 if (nx
->nx_fs
->nxfs_id
!= nfhp
->nfh_xh
.nxh_fsid
)
2665 if (nx
->nx_id
!= nfhp
->nfh_xh
.nxh_expid
)
2673 * nfsrv_fhtovp() - convert FH to vnode and export info
2677 struct nfs_filehandle
*nfhp
,
2679 __unused
int pubflag
,
2681 struct nfs_export
**nxp
,
2682 struct nfs_export_options
**nxop
)
2691 if (nfhp
->nfh_xh
.nxh_version
!= NFS_FH_VERSION
) {
2692 /* file handle format not supported */
2695 if (nfhp
->nfh_len
> NFS_MAX_FH_SIZE
)
2697 if (nfhp
->nfh_len
< (int)sizeof(nfhp
->nfh_xh
))
2699 if (nfhp
->nfh_xh
.nxh_flags
& NXHF_INVALIDFH
)
2702 /* XXX Revisit when enabling WebNFS */
2703 #ifdef WEBNFS_ENABLED
2704 if (nfs_ispublicfh(nfhp
)) {
2705 if (!pubflag
|| !nfs_pub
.np_valid
)
2707 nfhp
= &nfs_pub
.np_handle
;
2711 *nxp
= nfsrv_fhtoexport(nfhp
);
2715 /* Get the export option structure for this <export, client> tuple. */
2716 *nxop
= nfsrv_export_lookup(*nxp
, nam
);
2717 if (nam
&& (*nxop
== NULL
))
2720 /* find mount structure */
2721 mp
= vfs_getvfs_by_mntonname((*nxp
)->nx_fs
->nxfs_path
);
2725 error
= VFS_FHTOVP(mp
, nfhp
->nfh_xh
.nxh_fidlen
, &nfhp
->nfh_fid
[0], vpp
, NULL
);
2728 /* vnode pointer should be good at this point or ... */
2735 * nfsrv_credcheck() - check/map credentials according to given export options
2739 struct nfsrv_descript
*nfsd
,
2740 __unused
struct nfs_export
*nx
,
2741 struct nfs_export_options
*nxo
)
2743 if (nxo
&& nxo
->nxo_cred
) {
2744 if ((nxo
->nxo_flags
& NX_MAPALL
) ||
2745 ((nxo
->nxo_flags
& NX_MAPROOT
) && !suser(nfsd
->nd_cr
, NULL
))) {
2746 kauth_cred_rele(nfsd
->nd_cr
);
2747 nfsd
->nd_cr
= nxo
->nxo_cred
;
2748 kauth_cred_ref(nfsd
->nd_cr
);
2756 * WebNFS: check if a filehandle is a public filehandle. For v3, this
2757 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
2758 * transformed this to all zeroes in both cases, so check for it.
2761 nfs_ispublicfh(struct nfs_filehandle
*nfhp
)
2763 char *cp
= (char *)nfhp
;
2766 if (nfhp
->nfh_len
== 0)
2768 if (nfhp
->nfh_len
!= NFSX_V2FH
)
2770 for (i
= 0; i
< NFSX_V2FH
; i
++)
2777 * nfsrv_vptofh() - convert vnode to file handle for given export
2779 * If the caller is passing in a vnode for a ".." directory entry,
2780 * they can pass a directory NFS file handle (dnfhp) which will be
2781 * checked against the root export file handle. If it matches, we
2782 * refuse to provide the file handle for the out-of-export directory.
2786 struct nfs_export
*nx
,
2788 struct nfs_filehandle
*dnfhp
,
2790 struct vfs_context
*ctx
,
2791 struct nfs_filehandle
*nfhp
)
2795 nfhp
->nfh_xh
.nxh_version
= NFS_FH_VERSION
;
2796 nfhp
->nfh_xh
.nxh_fsid
= nx
->nx_fs
->nxfs_id
;
2797 nfhp
->nfh_xh
.nxh_expid
= nx
->nx_id
;
2798 nfhp
->nfh_xh
.nxh_flags
= 0;
2799 nfhp
->nfh_xh
.nxh_reserved
= 0;
2802 bzero(&nfhp
->nfh_fid
[0], NFSV2_MAX_FID_SIZE
);
2804 /* if directory FH matches export root, return invalid FH */
2805 if (dnfhp
&& nfsrv_fhmatch(dnfhp
, &nx
->nx_fh
)) {
2806 nfhp
->nfh_len
= v2
? NFSX_V2FH
: sizeof(nfhp
->nfh_xh
);
2807 nfhp
->nfh_xh
.nxh_fidlen
= 0;
2808 nfhp
->nfh_xh
.nxh_flags
= NXHF_INVALIDFH
;
2812 nfhp
->nfh_len
= v2
? NFSV2_MAX_FID_SIZE
: NFS_MAX_FID_SIZE
;
2813 error
= VFS_VPTOFH(vp
, &nfhp
->nfh_len
, &nfhp
->nfh_fid
[0], ctx
);
2816 if (nfhp
->nfh_len
> (int)(v2
? NFSV2_MAX_FID_SIZE
: NFS_MAX_FID_SIZE
))
2818 nfhp
->nfh_xh
.nxh_fidlen
= nfhp
->nfh_len
;
2819 nfhp
->nfh_len
+= sizeof(nfhp
->nfh_xh
);
2820 if (v2
&& (nfhp
->nfh_len
< NFSX_V2FH
))
2821 nfhp
->nfh_len
= NFSX_V2FH
;
2827 nfsrv_fhmatch(struct nfs_filehandle
*fh1
, struct nfs_filehandle
*fh2
)
2831 len1
= sizeof(fh1
->nfh_xh
) + fh1
->nfh_xh
.nxh_fidlen
;
2832 len2
= sizeof(fh2
->nfh_xh
) + fh2
->nfh_xh
.nxh_fidlen
;
2835 if (bcmp(&fh1
->nfh_xh
, &fh2
->nfh_xh
, len1
))
2840 #endif /* NFS_NOSERVER */
2842 * This function compares two net addresses by family and returns TRUE
2843 * if they are the same host.
2844 * If there is any doubt, return FALSE.
2845 * The AF_INET family is handled as a special case so that address mbufs
2846 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
2849 netaddr_match(family
, haddr
, nam
)
2851 union nethostaddr
*haddr
;
2854 struct sockaddr_in
*inetaddr
;
2858 inetaddr
= mbuf_data(nam
);
2859 if (inetaddr
->sin_family
== AF_INET
&&
2860 inetaddr
->sin_addr
.s_addr
== haddr
->had_inetaddr
)
2866 struct sockaddr_iso
*isoaddr1
, *isoaddr2
;
2868 isoaddr1
= mbuf_data(nam
);
2869 isoaddr2
= mbuf_data(haddr
->had_nam
);
2870 if (isoaddr1
->siso_family
== AF_ISO
&&
2871 isoaddr1
->siso_nlen
> 0 &&
2872 isoaddr1
->siso_nlen
== isoaddr2
->siso_nlen
&&
2873 SAME_ISOADDR(isoaddr1
, isoaddr2
))
2884 static nfsuint64 nfs_nullcookie
= { { 0, 0 } };
2886 * This function finds the directory cookie that corresponds to the
2887 * logical byte offset given.
2890 nfs_getcookie(np
, off
, add
)
2895 struct nfsdmap
*dp
, *dp2
;
2898 pos
= off
/ NFS_DIRBLKSIZ
;
2902 panic("nfs getcookie add at 0");
2904 return (&nfs_nullcookie
);
2907 dp
= np
->n_cookies
.lh_first
;
2910 MALLOC_ZONE(dp
, struct nfsdmap
*, sizeof(struct nfsdmap
),
2911 M_NFSDIROFF
, M_WAITOK
);
2913 return ((nfsuint64
*)0);
2914 dp
->ndm_eocookie
= 0;
2915 LIST_INSERT_HEAD(&np
->n_cookies
, dp
, ndm_list
);
2917 return ((nfsuint64
*)0);
2919 while (pos
>= NFSNUMCOOKIES
) {
2920 pos
-= NFSNUMCOOKIES
;
2921 if (dp
->ndm_list
.le_next
) {
2922 if (!add
&& dp
->ndm_eocookie
< NFSNUMCOOKIES
&&
2923 pos
>= dp
->ndm_eocookie
)
2924 return ((nfsuint64
*)0);
2925 dp
= dp
->ndm_list
.le_next
;
2927 MALLOC_ZONE(dp2
, struct nfsdmap
*, sizeof(struct nfsdmap
),
2928 M_NFSDIROFF
, M_WAITOK
);
2930 return ((nfsuint64
*)0);
2931 dp2
->ndm_eocookie
= 0;
2932 LIST_INSERT_AFTER(dp
, dp2
, ndm_list
);
2935 return ((nfsuint64
*)0);
2937 if (pos
>= dp
->ndm_eocookie
) {
2939 dp
->ndm_eocookie
= pos
+ 1;
2941 return ((nfsuint64
*)0);
2943 return (&dp
->ndm_cookies
[pos
]);
2947 * Invalidate cached directory information, except for the actual directory
2948 * blocks (which are invalidated separately).
2949 * Done mainly to avoid the use of stale offset cookies.
2955 struct nfsnode
*np
= VTONFS(vp
);
2958 if (vnode_vtype(vp
) != VDIR
)
2959 panic("nfs: invaldir not dir");
2961 np
->n_direofoffset
= 0;
2962 np
->n_cookieverf
.nfsuquad
[0] = 0;
2963 np
->n_cookieverf
.nfsuquad
[1] = 0;
2964 if (np
->n_cookies
.lh_first
)
2965 np
->n_cookies
.lh_first
->ndm_eocookie
= 0;
2969 * The write verifier has changed (probably due to a server reboot), so all
2970 * NB_NEEDCOMMIT blocks will have to be written again. Since they are on the
2971 * dirty block list as NB_DELWRI, all this takes is clearing the NB_NEEDCOMMIT
2972 * flag. Once done the new write verifier can be set for the mount point.
2975 nfs_clearcommit_callout(vnode_t vp
, __unused
void *arg
)
2977 struct nfsnode
*np
= VTONFS(vp
);
2978 struct nfsbuflists blist
;
2981 lck_mtx_lock(nfs_buf_mutex
);
2982 if (nfs_buf_iterprepare(np
, &blist
, NBI_DIRTY
)) {
2983 lck_mtx_unlock(nfs_buf_mutex
);
2984 return (VNODE_RETURNED
);
2986 LIST_FOREACH(bp
, &blist
, nb_vnbufs
) {
2987 if (nfs_buf_acquire(bp
, NBAC_NOWAIT
, 0, 0))
2989 if ((bp
->nb_flags
& (NB_DELWRI
| NB_NEEDCOMMIT
))
2990 == (NB_DELWRI
| NB_NEEDCOMMIT
)) {
2991 bp
->nb_flags
&= ~NB_NEEDCOMMIT
;
2992 np
->n_needcommitcnt
--;
2996 CHECK_NEEDCOMMITCNT(np
);
2997 nfs_buf_itercomplete(np
, &blist
, NBI_DIRTY
);
2998 lck_mtx_unlock(nfs_buf_mutex
);
2999 return (VNODE_RETURNED
);
3003 nfs_clearcommit(mount_t mp
)
3005 vnode_iterate(mp
, VNODE_NOLOCK_INTERNAL
, nfs_clearcommit_callout
, NULL
);
3008 #ifndef NFS_NOSERVER
3010 * Map errnos to NFS error numbers. For Version 3 also filter out error
3011 * numbers not specified for the associated procedure.
3014 nfsrv_errmap(nd
, err
)
3015 struct nfsrv_descript
*nd
;
3018 short *defaulterrp
, *errp
;
3020 if (nd
->nd_flag
& ND_NFSV3
) {
3021 if (nd
->nd_procnum
<= NFSPROC_COMMIT
) {
3022 errp
= defaulterrp
= nfsrv_v3errmap
[nd
->nd_procnum
];
3026 else if (*errp
> err
)
3029 return ((int)*defaulterrp
);
3031 return (err
& 0xffff);
3034 return ((int)nfsrv_v2errmap
[err
- 1]);
3038 #endif /* NFS_NOSERVER */