2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_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 License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
30 * Copyright (c) 1989, 1993
31 * The Regents of the University of California. All rights reserved.
33 * This code is derived from software contributed to Berkeley by
34 * Rick Macklem at The University of Guelph.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by the University of
47 * California, Berkeley and its contributors.
48 * 4. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95
65 * FreeBSD-Id: nfs_subs.c,v 1.47 1997/11/07 08:53:24 phk Exp $
69 * These functions support the macros and help fiddle mbuf chains for
70 * the nfs op functions. They do things like create the rpc header and
71 * copy data between mbuf chains and uio lists.
73 #include <sys/param.h>
75 #include <sys/kauth.h>
76 #include <sys/systm.h>
77 #include <sys/kernel.h>
78 #include <sys/mount_internal.h>
79 #include <sys/vnode_internal.h>
80 #include <sys/kpi_mbuf.h>
81 #include <sys/socket.h>
83 #include <sys/malloc.h>
84 #include <sys/syscall.h>
85 #include <sys/sysctl.h>
86 #include <sys/ubc_internal.h>
87 #include <sys/fcntl.h>
88 #include <sys/uio_internal.h>
89 #include <sys/domain.h>
90 #include <libkern/OSAtomic.h>
93 #include <sys/vmparam.h>
96 #include <kern/clock.h>
98 #include <nfs/rpcv2.h>
99 #include <nfs/nfsproto.h>
101 #include <nfs/nfsnode.h>
102 #include <nfs/xdr_subs.h>
103 #include <nfs/nfsm_subs.h>
104 #include <nfs/nfsmount.h>
105 #include <nfs/nfsrtt.h>
106 #include <nfs/nfs_lock.h>
108 #include <miscfs/specfs/specdev.h>
110 #include <netinet/in.h>
112 #include <netiso/iso.h>
115 #include <sys/kdebug.h>
117 SYSCTL_DECL(_vfs_generic
);
118 SYSCTL_NODE(_vfs_generic
, OID_AUTO
, nfs
, CTLFLAG_RW
, 0, "nfs hinge");
120 #define FSDBG(A, B, C, D, E) \
121 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_NONE, \
122 (int)(B), (int)(C), (int)(D), (int)(E), 0)
123 #define FSDBG_TOP(A, B, C, D, E) \
124 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_START, \
125 (int)(B), (int)(C), (int)(D), (int)(E), 0)
126 #define FSDBG_BOT(A, B, C, D, E) \
127 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_END, \
128 (int)(B), (int)(C), (int)(D), (int)(E), 0)
130 * Data items converted to xdr at startup, since they are constant
131 * This is kinda hokey, but may save a little time doing byte swaps
134 u_long rpc_call
, rpc_vers
, rpc_reply
, rpc_msgdenied
, rpc_autherr
,
135 rpc_mismatch
, rpc_auth_unix
, rpc_msgaccepted
,
137 u_long nfs_prog
, nfs_true
, nfs_false
;
138 __private_extern__
int nfs_mbuf_mlen
= 0, nfs_mbuf_mhlen
= 0,
139 nfs_mbuf_minclsize
= 0, nfs_mbuf_mclbytes
= 0;
141 /* And other global data */
142 static u_long nfs_xid
= 0;
143 u_long nfs_xidwrap
= 0; /* to build a (non-wwrapping) 64 bit xid */
144 static enum vtype nv2tov_type
[8]= {
145 VNON
, VREG
, VDIR
, VBLK
, VCHR
, VLNK
, VNON
, VNON
147 enum vtype nv3tov_type
[8]= {
148 VNON
, VREG
, VDIR
, VBLK
, VCHR
, VLNK
, VSOCK
, VFIFO
154 lck_grp_t
*nfsd_lck_grp
;
155 lck_grp_attr_t
*nfsd_lck_grp_attr
;
156 lck_attr_t
*nfsd_lck_attr
;
157 lck_mtx_t
*nfsd_mutex
;
159 lck_grp_attr_t
*nfs_slp_group_attr
;
160 lck_attr_t
*nfs_slp_lock_attr
;
161 lck_grp_t
*nfs_slp_rwlock_group
;
162 lck_grp_t
*nfs_slp_mutex_group
;
164 struct nfs_reqq nfs_reqq
;
165 struct nfssvc_sockhead nfssvc_sockhead
, nfssvc_deadsockhead
;
166 struct nfsd_head nfsd_head
;
169 struct nfsexpfslist nfs_exports
;
170 struct nfsexphashhead
*nfsexphashtbl
;
172 lck_grp_attr_t
*nfs_export_group_attr
;
173 lck_attr_t
*nfs_export_lock_attr
;
174 lck_grp_t
*nfs_export_rwlock_group
;
175 lck_rw_t nfs_export_rwlock
;
179 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
181 int nfsv3_procid
[NFS_NPROCS
] = {
207 #endif /* NFS_NOSERVER */
209 * and the reverse mapping from generic to Version 2 procedure numbers
211 int nfsv2_procid
[NFS_NPROCS
] = {
239 * Maps errno values to nfs error numbers.
240 * Use NFSERR_IO as the catch all for ones not specifically defined in
243 static u_char nfsrv_v2errmap
[ELAST
] = {
244 NFSERR_PERM
, NFSERR_NOENT
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
245 NFSERR_NXIO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
246 NFSERR_IO
, NFSERR_IO
, NFSERR_ACCES
, NFSERR_IO
, NFSERR_IO
,
247 NFSERR_IO
, NFSERR_EXIST
, NFSERR_IO
, NFSERR_NODEV
, NFSERR_NOTDIR
,
248 NFSERR_ISDIR
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
249 NFSERR_IO
, NFSERR_FBIG
, NFSERR_NOSPC
, NFSERR_IO
, NFSERR_ROFS
,
250 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
251 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
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_NAMETOL
, NFSERR_IO
, NFSERR_IO
,
257 NFSERR_NOTEMPTY
, NFSERR_IO
, NFSERR_IO
, NFSERR_DQUOT
, NFSERR_STALE
,
258 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
259 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
260 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
264 * Maps errno values to nfs error numbers.
265 * Although it is not obvious whether or not NFS clients really care if
266 * a returned error value is in the specified list for the procedure, the
267 * safest thing to do is filter them appropriately. For Version 2, the
268 * X/Open XNFS document is the only specification that defines error values
269 * for each RPC (The RFC simply lists all possible error values for all RPCs),
270 * so I have decided to not do this for Version 2.
271 * The first entry is the default error return and the rest are the valid
272 * errors for that RPC in increasing numeric order.
274 static short nfsv3err_null
[] = {
279 static short nfsv3err_getattr
[] = {
288 static short nfsv3err_setattr
[] = {
304 static short nfsv3err_lookup
[] = {
317 static short nfsv3err_access
[] = {
326 static short nfsv3err_readlink
[] = {
338 static short nfsv3err_read
[] = {
350 static short nfsv3err_write
[] = {
365 static short nfsv3err_create
[] = {
382 static short nfsv3err_mkdir
[] = {
399 static short nfsv3err_symlink
[] = {
416 static short nfsv3err_mknod
[] = {
434 static short nfsv3err_remove
[] = {
448 static short nfsv3err_rmdir
[] = {
466 static short nfsv3err_rename
[] = {
489 static short nfsv3err_link
[] = {
509 static short nfsv3err_readdir
[] = {
522 static short nfsv3err_readdirplus
[] = {
536 static short nfsv3err_fsstat
[] = {
545 static short nfsv3err_fsinfo
[] = {
553 static short nfsv3err_pathconf
[] = {
561 static short nfsv3err_commit
[] = {
570 static short *nfsrv_v3errmap
[] = {
588 nfsv3err_readdirplus
,
595 #endif /* NFS_NOSERVER */
597 extern struct nfsrtt nfsrtt
;
598 extern struct nfsstats nfsstats
;
599 extern nfstype nfsv2_type
[9];
600 extern nfstype nfsv3_type
[9];
601 extern struct nfsnodehashhead
*nfsnodehashtbl
;
602 extern u_long nfsnodehash
;
605 LIST_HEAD(nfsnodehashhead
, nfsnode
);
608 * Create the header for an rpc request packet
609 * The hsiz is the size of the rest of the nfs request header.
610 * (just used to decide if a cluster is a good idea)
613 nfsm_reqh(int hsiz
, caddr_t
*bposp
, mbuf_t
*mbp
)
618 if (hsiz
>= nfs_mbuf_minclsize
)
619 error
= mbuf_mclget(MBUF_WAITOK
, MBUF_TYPE_DATA
, mbp
);
621 error
= mbuf_get(MBUF_WAITOK
, MBUF_TYPE_DATA
, mbp
);
624 *bposp
= mbuf_data(*mbp
);
629 * Build the RPC header and fill in the authorization info.
630 * The authorization string argument is only used when the credentials
631 * come from outside of the kernel.
632 * Returns the head of the mbuf list.
635 nfsm_rpchead(cr
, nmflag
, procid
, auth_type
, auth_len
, auth_str
, verf_len
,
636 verf_str
, mrest
, mrest_len
, mbp
, xidp
, mreqp
)
656 int siz
, grpsiz
, authsiz
, mlen
;
659 authsiz
= nfsm_rndup(auth_len
);
660 len
= authsiz
+ 10 * NFSX_UNSIGNED
;
661 if (len
>= nfs_mbuf_minclsize
) {
662 error
= mbuf_getpacket(MBUF_WAITOK
, &mb
);
664 error
= mbuf_gethdr(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mb
);
666 if (len
< nfs_mbuf_mhlen
)
667 mbuf_align_32(mb
, len
);
669 mbuf_align_32(mb
, 8 * NFSX_UNSIGNED
);
673 /* unable to allocate packet */
678 bpos
= mbuf_data(mb
);
681 * First the RPC header.
683 nfsm_build(tl
, u_long
*, 8 * NFSX_UNSIGNED
);
686 * derive initial xid from system time
690 * Note: it's OK if this code inits nfs_xid to 0 (for example,
691 * due to a broken clock) because we immediately increment it
692 * and we guarantee to never use xid 0. So, nfs_xid should only
693 * ever be 0 the first time this function is called.
696 nfs_xid
= tv
.tv_sec
<< 12;
699 * Skip zero xid if it should ever happen.
701 if (++nfs_xid
== 0) {
706 *tl
++ = *xidp
= txdr_unsigned(nfs_xid
);
709 *tl
++ = txdr_unsigned(NFS_PROG
);
710 if (nmflag
& NFSMNT_NFSV3
)
711 *tl
++ = txdr_unsigned(NFS_VER3
);
713 *tl
++ = txdr_unsigned(NFS_VER2
);
714 if (nmflag
& NFSMNT_NFSV3
)
715 *tl
++ = txdr_unsigned(procid
);
717 *tl
++ = txdr_unsigned(nfsv2_procid
[procid
]);
720 * And then the authorization cred.
722 *tl
++ = txdr_unsigned(auth_type
);
723 *tl
= txdr_unsigned(authsiz
);
726 nfsm_build(tl
, u_long
*, auth_len
);
727 *tl
++ = 0; /* stamp ?? */
728 *tl
++ = 0; /* NULL hostname */
729 *tl
++ = txdr_unsigned(kauth_cred_getuid(cr
));
730 *tl
++ = txdr_unsigned(cr
->cr_groups
[0]);
731 grpsiz
= (auth_len
>> 2) - 5;
732 *tl
++ = txdr_unsigned(grpsiz
);
733 for (i
= 1; i
<= grpsiz
; i
++)
734 *tl
++ = txdr_unsigned(cr
->cr_groups
[i
]);
740 if (mbuf_trailingspace(mb
) == 0) {
742 if (siz
>= nfs_mbuf_minclsize
)
743 error
= mbuf_mclget(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mb2
);
745 error
= mbuf_get(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mb2
);
747 error
= mbuf_setnext(mb
, mb2
);
754 bpos
= mbuf_data(mb
);
756 i
= min(siz
, mbuf_trailingspace(mb
));
757 bcopy(auth_str
, bpos
, i
);
759 mbuf_setlen(mb
, mlen
);
764 if ((siz
= (nfsm_rndup(auth_len
) - auth_len
)) > 0) {
765 for (i
= 0; i
< siz
; i
++)
768 mbuf_setlen(mb
, mlen
);
774 * And the verifier...
776 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
779 *tl
++ = txdr_unsigned(RPCAUTH_KERB4
);
780 *tl
= txdr_unsigned(verf_len
);
783 if (mbuf_trailingspace(mb
) == 0) {
785 if (siz
>= nfs_mbuf_minclsize
)
786 error
= mbuf_mclget(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mb2
);
788 error
= mbuf_get(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mb2
);
790 error
= mbuf_setnext(mb
, mb2
);
797 bpos
= mbuf_data(mb
);
799 i
= min(siz
, mbuf_trailingspace(mb
));
800 bcopy(verf_str
, bpos
, i
);
802 mbuf_setlen(mb
, mlen
);
807 if ((siz
= (nfsm_rndup(verf_len
) - verf_len
)) > 0) {
808 for (i
= 0; i
< siz
; i
++)
811 mbuf_setlen(mb
, mlen
);
814 *tl
++ = txdr_unsigned(RPCAUTH_NULL
);
817 error
= mbuf_pkthdr_setrcvif(mreq
, 0);
819 error
= mbuf_setnext(mb
, mrest
);
824 mbuf_pkthdr_setlen(mreq
, authsiz
+ 10 * NFSX_UNSIGNED
+ mrest_len
);
831 * copies mbuf chain to the uio scatter/gather list
834 nfsm_mbuftouio(mrep
, uiop
, siz
, dpos
)
840 char *mbufcp
, *uiocp
;
848 len
= (caddr_t
)mbuf_data(mp
) + mbuf_len(mp
) - mbufcp
;
849 rem
= nfsm_rndup(siz
)-siz
;
851 if (uiop
->uio_iovcnt
<= 0 || uiop
->uio_iovs
.iov32p
== NULL
)
853 // LP64todo - fix this!
854 left
= uio_iov_len(uiop
);
855 uiocp
= CAST_DOWN(caddr_t
, uio_iov_base(uiop
));
864 mbufcp
= mbuf_data(mp
);
867 xfer
= (left
> len
) ? len
: left
;
868 if (UIO_SEG_IS_USER_SPACE(uiop
->uio_segflg
))
869 copyout(mbufcp
, CAST_USER_ADDR_T(uiocp
), xfer
);
871 bcopy(mbufcp
, uiocp
, xfer
);
876 uiop
->uio_offset
+= xfer
;
877 uio_uio_resid_add(uiop
, -xfer
);
879 if (uio_iov_len(uiop
) <= (size_t)siz
) {
883 uio_iov_base_add(uiop
, uiosiz
);
884 uio_iov_len_add(uiop
, -uiosiz
);
892 error
= nfs_adv(mrep
, dpos
, rem
, len
);
900 * copies a uio scatter/gather list to an mbuf chain.
901 * NOTE: can ony handle iovcnt == 1
904 nfsm_uiotombuf(uiop
, mq
, siz
, bpos
)
912 int xfer
, left
, mlen
, mplen
;
913 int uiosiz
, clflg
, rem
, error
;
916 if (uiop
->uio_iovcnt
!= 1)
917 panic("nfsm_uiotombuf: iovcnt != 1");
919 if (siz
> nfs_mbuf_mlen
) /* or should it >= MCLBYTES ?? */
923 rem
= nfsm_rndup(siz
)-siz
;
925 mplen
= mbuf_len(mp
);
927 // LP64todo - fix this!
928 left
= uio_iov_len(uiop
);
929 uiocp
= CAST_DOWN(caddr_t
, uio_iov_base(uiop
));
934 mlen
= mbuf_trailingspace(mp
);
938 error
= mbuf_mclget(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mp
);
940 error
= mbuf_get(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mp
);
942 error
= mbuf_setnext(mp2
, mp
);
947 mlen
= mbuf_trailingspace(mp
);
949 xfer
= (left
> mlen
) ? mlen
: left
;
950 if (UIO_SEG_IS_USER_SPACE(uiop
->uio_segflg
))
951 copyin(CAST_USER_ADDR_T(uiocp
), (caddr_t
)mbuf_data(mp
) + mplen
, xfer
);
953 bcopy(uiocp
, (caddr_t
)mbuf_data(mp
) + mplen
, xfer
);
955 mbuf_setlen(mp
, mplen
);
958 uiop
->uio_offset
+= xfer
;
959 uio_uio_resid_add(uiop
, -xfer
);
961 uio_iov_base_add(uiop
, uiosiz
);
962 uio_iov_len_add(uiop
, -uiosiz
);
966 if (rem
> mbuf_trailingspace(mp
)) {
967 error
= mbuf_get(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mp
);
969 error
= mbuf_setnext(mp2
, mp
);
974 cp
= (caddr_t
)mbuf_data(mp
) + mplen
;
975 for (left
= 0; left
< rem
; left
++)
978 mbuf_setlen(mp
, mplen
);
981 *bpos
= (caddr_t
)mbuf_data(mp
) + mplen
;
988 * Help break down an mbuf chain by setting the first siz bytes contiguous
989 * pointed to by returned val.
990 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
991 * cases. (The macros use the vars. dpos and dpos2)
994 nfsm_disct(mdp
, dposp
, siz
, left
, cp2
)
1002 int siz2
, xfer
, error
, mp2len
;
1007 *mdp
= mp
= mbuf_next(mp
);
1010 left
= mbuf_len(mp
);
1011 *dposp
= mbuf_data(mp
);
1016 } else if (mbuf_next(mp
) == NULL
) {
1018 } else if (siz
> nfs_mbuf_mhlen
) {
1019 panic("nfs S too big");
1021 error
= mbuf_get(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mp2
);
1024 error
= mbuf_setnext(mp2
, mbuf_next(mp
));
1026 error
= mbuf_setnext(mp
, mp2
);
1031 mbuf_setlen(mp
, mbuf_len(mp
) - left
);
1033 *cp2
= p
= mbuf_data(mp
);
1034 bcopy(*dposp
, p
, left
); /* Copy what was left */
1037 mp2
= mbuf_next(mp
);
1038 mp2data
= mbuf_data(mp2
);
1039 mp2len
= mbuf_len(mp2
);
1040 /* Loop around copying up the siz2 bytes */
1044 xfer
= (siz2
> mp2len
) ? mp2len
: siz2
;
1046 bcopy(mp2data
, p
, xfer
);
1049 mbuf_setdata(mp2
, mp2data
, mp2len
);
1054 mp2
= mbuf_next(mp2
);
1055 mp2data
= mbuf_data(mp2
);
1056 mp2len
= mbuf_len(mp2
);
1059 mbuf_setlen(mp
, siz
);
1067 * Advance the position in the mbuf chain.
1070 nfs_adv(mdp
, dposp
, offs
, left
)
1089 *dposp
= (caddr_t
)mbuf_data(m
) + offs
;
1094 * Copy a string into mbufs for the hard cases...
1097 nfsm_strtmbuf(mb
, bpos
, cp
, siz
)
1103 mbuf_t m1
= NULL
, m2
;
1104 long left
, xfer
, len
, tlen
, mlen
;
1110 left
= mbuf_trailingspace(m2
);
1111 if (left
>= NFSX_UNSIGNED
) {
1112 tl
= ((u_long
*)(*bpos
));
1113 *tl
++ = txdr_unsigned(siz
);
1115 left
-= NFSX_UNSIGNED
;
1117 len
+= NFSX_UNSIGNED
;
1118 mbuf_setlen(m2
, len
);
1120 bcopy(cp
, (caddr_t
) tl
, left
);
1124 mbuf_setlen(m2
, len
);
1128 /* Loop around adding mbufs */
1131 if (siz
> nfs_mbuf_mlen
)
1132 error
= mbuf_mclget(MBUF_WAITOK
, MBUF_TYPE_DATA
, &m1
);
1134 error
= mbuf_get(MBUF_WAITOK
, MBUF_TYPE_DATA
, &m1
);
1136 error
= mbuf_setnext(m2
, m1
);
1139 mlen
= mbuf_maxlen(m1
);
1140 mbuf_setlen(m1
, mlen
);
1145 *tl
++ = txdr_unsigned(siz
);
1146 mlen
-= NFSX_UNSIGNED
;
1147 mbuf_setlen(m1
, mlen
);
1148 tlen
= NFSX_UNSIGNED
;
1152 len
= nfsm_rndup(siz
);
1155 *(tl
+(xfer
>>2)) = 0;
1159 bcopy(cp
, (caddr_t
) tl
, xfer
);
1160 mbuf_setlen(m1
, len
+ tlen
);
1165 *bpos
= (caddr_t
)mbuf_data(m1
) + mbuf_len(m1
);
1170 * Called once to initialize data structures...
1173 nfs_init(struct vfsconf
*vfsp
)
1178 * Check to see if major data structures haven't bloated.
1180 if (sizeof (struct nfsnode
) > NFS_NODEALLOC
) {
1181 printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC
);
1182 printf("Try reducing NFS_SMALLFH\n");
1184 if (sizeof (struct nfsmount
) > NFS_MNTALLOC
) {
1185 printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC
);
1186 printf("Try reducing NFS_MUIDHASHSIZ\n");
1188 if (sizeof (struct nfssvc_sock
) > NFS_SVCALLOC
) {
1189 printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC
);
1190 printf("Try reducing NFS_UIDHASHSIZ\n");
1192 if (sizeof (struct nfsuid
) > NFS_UIDALLOC
) {
1193 printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC
);
1194 printf("Try unionizing the nu_nickname and nu_flag fields\n");
1197 nfs_mount_type
= vfsp
->vfc_typenum
;
1199 rpc_vers
= txdr_unsigned(RPC_VER2
);
1200 rpc_call
= txdr_unsigned(RPC_CALL
);
1201 rpc_reply
= txdr_unsigned(RPC_REPLY
);
1202 rpc_msgdenied
= txdr_unsigned(RPC_MSGDENIED
);
1203 rpc_msgaccepted
= txdr_unsigned(RPC_MSGACCEPTED
);
1204 rpc_mismatch
= txdr_unsigned(RPC_MISMATCH
);
1205 rpc_autherr
= txdr_unsigned(RPC_AUTHERR
);
1206 rpc_auth_unix
= txdr_unsigned(RPCAUTH_UNIX
);
1207 rpc_auth_kerb
= txdr_unsigned(RPCAUTH_KERB4
);
1208 nfs_prog
= txdr_unsigned(NFS_PROG
);
1209 nfs_true
= txdr_unsigned(TRUE
);
1210 nfs_false
= txdr_unsigned(FALSE
);
1211 nfs_xdrneg1
= txdr_unsigned(-1);
1213 nfs_ticks
= (hz
* NFS_TICKINTVL
+ 500) / 1000;
1216 /* Ensure async daemons disabled */
1217 for (i
= 0; i
< NFS_MAXASYNCDAEMON
; i
++) {
1218 nfs_iodwant
[i
] = NULL
;
1219 nfs_iodmount
[i
] = (struct nfsmount
*)0;
1221 /* init nfsiod mutex */
1222 nfs_iod_lck_grp_attr
= lck_grp_attr_alloc_init();
1223 nfs_iod_lck_grp
= lck_grp_alloc_init("nfs_iod", nfs_iod_lck_grp_attr
);
1224 nfs_iod_lck_attr
= lck_attr_alloc_init();
1225 nfs_iod_mutex
= lck_mtx_alloc_init(nfs_iod_lck_grp
, nfs_iod_lck_attr
);
1227 nfs_nbinit(); /* Init the nfsbuf table */
1228 nfs_nhinit(); /* Init the nfsnode table */
1229 nfs_lockinit(); /* Init the nfs lock state */
1231 #ifndef NFS_NOSERVER
1232 /* init nfsd mutex */
1233 nfsd_lck_grp_attr
= lck_grp_attr_alloc_init();
1234 nfsd_lck_grp
= lck_grp_alloc_init("nfsd", nfsd_lck_grp_attr
);
1235 nfsd_lck_attr
= lck_attr_alloc_init();
1236 nfsd_mutex
= lck_mtx_alloc_init(nfsd_lck_grp
, nfsd_lck_attr
);
1238 /* init slp rwlock */
1239 nfs_slp_lock_attr
= lck_attr_alloc_init();
1240 nfs_slp_group_attr
= lck_grp_attr_alloc_init();
1241 nfs_slp_rwlock_group
= lck_grp_alloc_init("nfs-slp-rwlock", nfs_slp_group_attr
);
1242 nfs_slp_mutex_group
= lck_grp_alloc_init("nfs-slp-mutex", nfs_slp_group_attr
);
1244 /* init export data structures */
1245 nfsexphashtbl
= hashinit(8, M_TEMP
, &nfsexphash
);
1246 LIST_INIT(&nfs_exports
);
1247 nfs_export_lock_attr
= lck_attr_alloc_init();
1248 nfs_export_group_attr
= lck_grp_attr_alloc_init();
1249 nfs_export_rwlock_group
= lck_grp_alloc_init("nfs-export-rwlock", nfs_export_group_attr
);
1250 lck_rw_init(&nfs_export_rwlock
, nfs_export_rwlock_group
, nfs_export_lock_attr
);
1252 lck_mtx_lock(nfsd_mutex
);
1253 nfsrv_init(0); /* Init server data structures */
1254 nfsrv_initcache(); /* Init the server request cache */
1255 lck_mtx_unlock(nfsd_mutex
);
1259 * Initialize reply list and start timer
1261 TAILQ_INIT(&nfs_reqq
);
1265 vfsp
->vfc_refcount
++; /* make us non-unloadable */
1270 * initialize NFS's cache of mbuf constants
1275 struct mbuf_stat ms
;
1278 nfs_mbuf_mlen
= ms
.mlen
;
1279 nfs_mbuf_mhlen
= ms
.mhlen
;
1280 nfs_mbuf_minclsize
= ms
.minclsize
;
1281 nfs_mbuf_mclbytes
= ms
.mclbytes
;
1285 * Parse the attributes that are in the mbuf list and store them in *nvap.
1288 nfs_parsefattr(mbuf_t
*mdp
, caddr_t
*dposp
, int v3
, struct nfs_vattr
*nvap
)
1290 struct nfs_fattr
*fp
;
1293 int error
= 0, rdev
;
1299 t1
= ((caddr_t
)mbuf_data(md
) + mbuf_len(md
)) - *dposp
;
1300 if ((error
= nfsm_disct(mdp
, dposp
, NFSX_FATTR(v3
), t1
, &cp2
))) {
1303 fp
= (struct nfs_fattr
*)cp2
;
1305 vtype
= nfsv3tov_type(fp
->fa_type
);
1306 vmode
= fxdr_unsigned(u_short
, fp
->fa_mode
);
1307 rdev
= makedev(fxdr_unsigned(int, fp
->fa3_rdev
.specdata1
),
1308 fxdr_unsigned(int, fp
->fa3_rdev
.specdata2
));
1310 vtype
= nfsv2tov_type(fp
->fa_type
);
1311 vmode
= fxdr_unsigned(u_short
, fp
->fa_mode
);
1315 * The duplicate information returned in fa_type and fa_mode
1316 * is an ambiguity in the NFS version 2 protocol.
1318 * VREG should be taken literally as a regular file. If a
1319 * server intents to return some type information differently
1320 * in the upper bits of the mode field (e.g. for sockets, or
1321 * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we
1322 * leave the examination of the mode bits even in the VREG
1323 * case to avoid breakage for bogus servers, but we make sure
1324 * that there are actually type bits set in the upper part of
1325 * fa_mode (and failing that, trust the va_type field).
1327 * NFSv3 cleared the issue, and requires fa_mode to not
1328 * contain any type information (while also introduing sockets
1329 * and FIFOs for fa_type).
1331 if (vtype
== VNON
|| (vtype
== VREG
&& (vmode
& S_IFMT
) != 0))
1332 vtype
= IFTOVT(vmode
);
1333 rdev
= fxdr_unsigned(long, fp
->fa2_rdev
);
1335 * Really ugly NFSv2 kludge.
1337 if (vtype
== VCHR
&& rdev
== (int)0xffffffff)
1341 nvap
->nva_type
= vtype
;
1342 nvap
->nva_mode
= (vmode
& 07777);
1343 nvap
->nva_rdev
= (dev_t
)rdev
;
1344 nvap
->nva_nlink
= (uint64_t)fxdr_unsigned(u_long
, fp
->fa_nlink
);
1345 nvap
->nva_uid
= fxdr_unsigned(uid_t
, fp
->fa_uid
);
1346 nvap
->nva_gid
= fxdr_unsigned(gid_t
, fp
->fa_gid
);
1348 fxdr_hyper(&fp
->fa3_size
, &nvap
->nva_size
);
1349 nvap
->nva_blocksize
= 16*1024;
1350 fxdr_hyper(&fp
->fa3_used
, &nvap
->nva_bytes
);
1351 fxdr_hyper(&fp
->fa3_fileid
, &nvap
->nva_fileid
);
1352 fxdr_nfsv3time(&fp
->fa3_atime
, &nvap
->nva_atime
);
1353 fxdr_nfsv3time(&fp
->fa3_mtime
, &nvap
->nva_mtime
);
1354 fxdr_nfsv3time(&fp
->fa3_ctime
, &nvap
->nva_ctime
);
1356 nvap
->nva_size
= fxdr_unsigned(u_long
, fp
->fa2_size
);
1357 nvap
->nva_blocksize
= fxdr_unsigned(long, fp
->fa2_blocksize
);
1358 nvap
->nva_bytes
= fxdr_unsigned(long, fp
->fa2_blocks
) * NFS_FABLKSIZE
;
1359 nvap
->nva_fileid
= (uint64_t)fxdr_unsigned(u_long
, fp
->fa2_fileid
);
1360 fxdr_nfsv2time(&fp
->fa2_atime
, &nvap
->nva_atime
);
1361 fxdr_nfsv2time(&fp
->fa2_mtime
, &nvap
->nva_mtime
);
1362 fxdr_nfsv2time(&fp
->fa2_ctime
, &nvap
->nva_ctime
);
1369 * Load the attribute cache (that lives in the nfsnode entry) with
1370 * the value pointed to by nvap, unless the file type in the attribute
1371 * cache doesn't match the file type in the nvap, in which case log a
1372 * warning and return ESTALE.
1374 * If the dontshrink flag is set, then it's not safe to call ubc_setsize()
1375 * to shrink the size of the file.
1380 struct nfs_vattr
*nvap
,
1387 struct nfs_vattr
*npnvap
;
1389 if (np
->n_flag
& NINIT
) {
1394 mp
= vnode_mount(vp
);
1397 FSDBG_TOP(527, vp
, np
, *xidp
>> 32, *xidp
);
1399 if (!VFSTONFS(mp
)) {
1400 FSDBG_BOT(527, ENXIO
, 1, 0, *xidp
);
1404 if (*xidp
< np
->n_xid
) {
1406 * We have already updated attributes with a response from
1407 * a later request. The attributes we have here are probably
1408 * stale so we drop them (just return). However, our
1409 * out-of-order receipt could be correct - if the requests were
1410 * processed out of order at the server. Given the uncertainty
1411 * we invalidate our cached attributes. *xidp is zeroed here
1412 * to indicate the attributes were dropped - only getattr
1413 * cares - it needs to retry the rpc.
1415 NATTRINVALIDATE(np
);
1416 FSDBG_BOT(527, 0, np
, np
->n_xid
, *xidp
);
1421 if (vp
&& (nvap
->nva_type
!= vnode_vtype(vp
))) {
1423 * The filehandle has changed type on us. This can be
1424 * caused by either the server not having unique filehandles
1425 * or because another client has removed the previous
1426 * filehandle and a new object (of a different type)
1427 * has been created with the same filehandle.
1429 * We can't simply switch the type on the vnode because
1430 * there may be type-specific fields that need to be
1431 * cleaned up or set up.
1433 * So, what should we do with this vnode?
1435 * About the best we can do is log a warning and return
1436 * an error. ESTALE is about the closest error, but it
1437 * is a little strange that we come up with this error
1438 * internally instead of simply passing it through from
1439 * the server. Hopefully, the vnode will be reclaimed
1440 * soon so the filehandle can be reincarnated as the new
1443 printf("nfs loadattrcache vnode changed type, was %d now %d\n",
1444 vnode_vtype(vp
), nvap
->nva_type
);
1445 FSDBG_BOT(527, ESTALE
, 3, 0, *xidp
);
1450 np
->n_attrstamp
= now
.tv_sec
;
1453 npnvap
= &np
->n_vattr
;
1454 nvap
->nva_fsid
= vfs_statfs(mp
)->f_fsid
.val
[0];
1455 bcopy((caddr_t
)nvap
, (caddr_t
)npnvap
, sizeof(*nvap
));
1458 if (nvap
->nva_size
!= np
->n_size
) {
1459 FSDBG(527, vp
, nvap
->nva_size
, np
->n_size
,
1460 (nvap
->nva_type
== VREG
) |
1461 (np
->n_flag
& NMODIFIED
? 6 : 4));
1462 if (nvap
->nva_type
== VREG
) {
1463 u_quad_t orig_size
= np
->n_size
;
1464 if (np
->n_flag
& NMODIFIED
) {
1465 if (nvap
->nva_size
< np
->n_size
)
1466 nvap
->nva_size
= np
->n_size
;
1468 np
->n_size
= nvap
->nva_size
;
1470 np
->n_size
= nvap
->nva_size
;
1471 if (!UBCINFOEXISTS(vp
) ||
1472 (dontshrink
&& np
->n_size
< (u_quad_t
)ubc_getsize(vp
))) {
1473 nvap
->nva_size
= np
->n_size
= orig_size
;
1474 NATTRINVALIDATE(np
);
1476 ubc_setsize(vp
, (off_t
)np
->n_size
); /* XXX */
1479 np
->n_size
= nvap
->nva_size
;
1482 np
->n_size
= nvap
->nva_size
;
1485 if (np
->n_flag
& NCHG
) {
1486 if (np
->n_flag
& NACC
)
1487 nvap
->nva_atime
= np
->n_atim
;
1488 if (np
->n_flag
& NUPD
)
1489 nvap
->nva_mtime
= np
->n_mtim
;
1492 FSDBG_BOT(527, 0, np
, 0, *xidp
);
1497 * Calculate the attribute timeout based on
1498 * how recently the file has been modified.
1501 nfs_attrcachetimeout(vnode_t vp
)
1503 struct nfsnode
*np
= VTONFS(vp
);
1504 struct nfsmount
*nmp
;
1508 if (!(nmp
= VFSTONFS(vnode_mount(vp
))))
1511 isdir
= vnode_isdir(vp
);
1513 if ((np
)->n_flag
& NMODIFIED
)
1514 timeo
= isdir
? nmp
->nm_acdirmin
: nmp
->nm_acregmin
;
1516 /* Note that if the client and server clocks are way out of sync, */
1517 /* timeout will probably get clamped to a min or max value */
1519 timeo
= (now
.tv_sec
- (np
)->n_mtime
.tv_sec
) / 10;
1521 if (timeo
< nmp
->nm_acdirmin
)
1522 timeo
= nmp
->nm_acdirmin
;
1523 else if (timeo
> nmp
->nm_acdirmax
)
1524 timeo
= nmp
->nm_acdirmax
;
1526 if (timeo
< nmp
->nm_acregmin
)
1527 timeo
= nmp
->nm_acregmin
;
1528 else if (timeo
> nmp
->nm_acregmax
)
1529 timeo
= nmp
->nm_acregmax
;
1537 * Check the time stamp
1538 * If the cache is valid, copy contents to *nvaper and return 0
1539 * otherwise return an error
1542 nfs_getattrcache(vp
, nvaper
)
1544 struct nfs_vattr
*nvaper
;
1546 struct nfsnode
*np
= VTONFS(vp
);
1547 struct nfs_vattr
*nvap
;
1548 struct timeval nowup
;
1551 if (!NATTRVALID(np
)) {
1552 FSDBG(528, vp
, 0, 0, 0);
1553 OSAddAtomic(1, (SInt32
*)&nfsstats
.attrcache_misses
);
1557 timeo
= nfs_attrcachetimeout(vp
);
1559 microuptime(&nowup
);
1560 if ((nowup
.tv_sec
- np
->n_attrstamp
) >= timeo
) {
1561 FSDBG(528, vp
, 0, 0, 1);
1562 OSAddAtomic(1, (SInt32
*)&nfsstats
.attrcache_misses
);
1565 FSDBG(528, vp
, 0, 0, 2);
1566 OSAddAtomic(1, (SInt32
*)&nfsstats
.attrcache_hits
);
1567 nvap
= &np
->n_vattr
;
1569 if (nvap
->nva_size
!= np
->n_size
) {
1570 FSDBG(528, vp
, nvap
->nva_size
, np
->n_size
,
1571 (nvap
->nva_type
== VREG
) |
1572 (np
->n_flag
& NMODIFIED
? 6 : 4));
1573 if (nvap
->nva_type
== VREG
) {
1574 if (np
->n_flag
& NMODIFIED
) {
1575 if (nvap
->nva_size
< np
->n_size
)
1576 nvap
->nva_size
= np
->n_size
;
1578 np
->n_size
= nvap
->nva_size
;
1580 np
->n_size
= nvap
->nva_size
;
1581 ubc_setsize(vp
, (off_t
)np
->n_size
); /* XXX */
1583 np
->n_size
= nvap
->nva_size
;
1586 bcopy((caddr_t
)nvap
, (caddr_t
)nvaper
, sizeof(struct nfs_vattr
));
1587 if (np
->n_flag
& NCHG
) {
1588 if (np
->n_flag
& NACC
)
1589 nvaper
->nva_atime
= np
->n_atim
;
1590 if (np
->n_flag
& NUPD
)
1591 nvaper
->nva_mtime
= np
->n_mtim
;
1596 #ifndef NFS_NOSERVER
1598 * Extract a lookup path from the given mbufs and store it in
1599 * a newly allocated buffer saved in the given nameidata structure.
1600 * exptected string length given as *lenp and final string length
1601 * (after any WebNFS processing) is returned in *lenp.
1608 __unused
int pubflag
,
1610 struct nameidata
*ndp
)
1612 int i
, len
, len2
, rem
, error
= 0;
1614 char *fromcp
, *tocp
;
1615 struct componentname
*cnp
= &ndp
->ni_cnd
;
1616 /* XXX Revisit when enabling WebNFS */
1617 #ifdef WEBNFS_ENABLED
1618 int webcnt
= 0, digitcnt
= 0;
1623 if (len
> (MAXPATHLEN
- 1))
1624 return (ENAMETOOLONG
);
1627 * Get a buffer for the name to be translated, and copy the
1628 * name into the buffer.
1630 MALLOC_ZONE(cnp
->cn_pnbuf
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1633 cnp
->cn_pnlen
= MAXPATHLEN
;
1634 cnp
->cn_flags
|= HASBUF
;
1637 * Copy the name from the mbuf list to the string
1639 * Along the way, take note of any WebNFS characters
1640 * and convert any % escapes.
1643 tocp
= cnp
->cn_pnbuf
;
1645 rem
= (caddr_t
)mbuf_data(md
) + mbuf_len(md
) - fromcp
;
1646 for (i
= 1; i
<= len
; i
++) {
1653 fromcp
= mbuf_data(md
);
1656 /* XXX Revisit when enabling WebNFS */
1657 #ifdef WEBNFS_ENABLED
1659 if ((i
== 1) && ((unsigned char)*fromcp
>= WEBNFS_SPECCHAR_START
)) {
1660 switch ((unsigned char)*fromcp
) {
1661 case WEBNFS_NATIVE_CHAR
:
1663 * 'Native' path for us is the same
1664 * as a path according to the NFS spec,
1665 * just skip the escape char.
1670 /* next iteration of for loop */
1673 * More may be added in the future, range 0x80-0xff.
1674 * Don't currently support security query lookup (0x81).
1682 /* We're expecting hex digits */
1683 if (!ISHEX(*fromcp
)) {
1688 hexdigits
[digitcnt
? 0 : 1] = *fromcp
++;
1690 *tocp
++ = HEXSTRTOI(hexdigits
);
1692 /* next iteration of for loop */
1694 } else if (*fromcp
== WEBNFS_ESC_CHAR
) {
1696 * We can't really look at the next couple
1697 * bytes here safely/easily, so we note that
1698 * the next two characters should be hex
1699 * digits and later save them in hexdigits[].
1700 * When we've got both, we'll convert it.
1706 /* next iteration of for loop */
1710 if (*fromcp
== '\0' || (!pubflag
&& *fromcp
== '/'))
1712 if (*fromcp
== '\0' || *fromcp
== '/')
1718 *tocp
++ = *fromcp
++;
1724 len2
= nfsm_rndup(len
)-len
;
1728 else if ((error
= nfs_adv(mdp
, dposp
, len2
, rem
)) != 0)
1732 /* XXX Revisit when enabling WebNFS */
1733 #ifdef WEBNFS_ENABLED
1736 /* The string ended in the middle of an escape! */
1747 FREE_ZONE(cnp
->cn_pnbuf
, MAXPATHLEN
, M_NAMEI
);
1748 cnp
->cn_flags
&= ~HASBUF
;
1750 ndp
->ni_pathlen
= len
;
1757 * Set up nameidata for a lookup() call and do it.
1759 * If pubflag is set, this call is done for a lookup operation on the
1760 * public filehandle. In that case we allow crossing mountpoints and
1761 * absolute pathnames. However, the caller is expected to check that
1762 * the lookup result is within the public fs, and deny access if
1767 struct nfsrv_descript
*nfsd
,
1768 struct vfs_context
*ctx
,
1769 struct nameidata
*ndp
,
1770 struct nfs_filehandle
*nfhp
,
1774 struct nfs_export
**nxp
,
1775 struct nfs_export_options
**nxop
)
1777 /* XXX Revisit when enabling WebNFS */
1778 #ifdef WEBNFS_ENABLED
1781 char uio_buf
[ UIO_SIZEOF(1) ];
1782 int linklen
, olen
= ndp
->ni_pathlen
;
1786 struct componentname
*cnp
= &ndp
->ni_cnd
;
1792 * Extract and set starting directory.
1794 error
= nfsrv_fhtovp(nfhp
, nam
, pubflag
, &dp
, nxp
, nxop
);
1797 error
= nfsrv_credcheck(nfsd
, *nxp
, *nxop
);
1798 if (error
|| (vnode_vtype(dp
) != VDIR
)) {
1804 ctx
->vc_ucred
= nfsd
->nd_cr
;
1805 ndp
->ni_cnd
.cn_context
= ctx
;
1807 if (*nxop
&& ((*nxop
)->nxo_flags
& NX_READONLY
))
1808 cnp
->cn_flags
|= RDONLY
;
1812 /* XXX Revisit when enabling WebNFS */
1813 #ifdef WEBNFS_ENABLED
1815 ndp
->ni_rootdir
= rootvnode
;
1816 ndp
->ni_loopcnt
= 0;
1817 if (cnp
->cn_pnbuf
[0] == '/') {
1820 error
= vnode_get(dp
);
1827 cnp
->cn_flags
|= NOCROSSMOUNT
;
1830 cnp
->cn_flags
|= NOCROSSMOUNT
;
1833 ndp
->ni_usedvp
= dp
;
1836 cnp
->cn_nameptr
= cnp
->cn_pnbuf
;
1837 ndp
->ni_startdir
= dp
;
1839 * And call lookup() to do the real work
1841 error
= lookup(ndp
);
1845 * Check for encountering a symbolic link
1847 if ((cnp
->cn_flags
& ISSYMLINK
) == 0) {
1850 if ((cnp
->cn_flags
& FSNODELOCKHELD
)) {
1851 cnp
->cn_flags
&= ~FSNODELOCKHELD
;
1852 unlock_fsnode(ndp
->ni_dvp
, NULL
);
1854 /* XXX Revisit when enabling WebNFS */
1855 #ifdef WEBNFS_ENABLED
1858 if (cnp
->cn_flags
& (LOCKPARENT
| WANTPARENT
))
1859 vnode_put(ndp
->ni_dvp
);
1861 vnode_put(ndp
->ni_vp
);
1866 /* XXX Revisit when enabling WebNFS */
1867 #ifdef WEBNFS_ENABLED
1870 if (ndp
->ni_loopcnt
++ >= MAXSYMLINKS
) {
1871 vnode_put(ndp
->ni_vp
);
1876 /* XXX assert(olen <= MAXPATHLEN - 1); */
1877 if (ndp
->ni_pathlen
> 1) {
1878 MALLOC_ZONE(cp
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1880 vnode_put(ndp
->ni_vp
);
1888 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
1889 &uio_buf
[0], sizeof(uio_buf
));
1891 vnode_put(ndp
->ni_vp
);
1893 if (ndp
->ni_pathlen
> 1)
1894 FREE_ZONE(cp
, MAXPATHLEN
, M_NAMEI
);
1898 uio_addiov(auio
, CAST_USER_ADDR_T(cp
), MAXPATHLEN
);
1899 error
= VNOP_READLINK(ndp
->ni_vp
, auio
, cnp
->cn_context
);
1902 vnode_put(ndp
->ni_vp
);
1904 if (ndp
->ni_pathlen
> 1)
1905 FREE_ZONE(cp
, MAXPATHLEN
, M_NAMEI
);
1908 linklen
= MAXPATHLEN
- uio_resid(auio
);
1913 if (linklen
+ ndp
->ni_pathlen
>= MAXPATHLEN
) {
1914 error
= ENAMETOOLONG
;
1917 if (ndp
->ni_pathlen
> 1) {
1918 long len
= cnp
->cn_pnlen
;
1919 tmppn
= cnp
->cn_pnbuf
;
1921 cnp
->cn_pnlen
= olen
+ 1;
1922 bcopy(ndp
->ni_next
, cp
+ linklen
, ndp
->ni_pathlen
);
1923 FREE_ZONE(tmppn
, len
, M_NAMEI
);
1925 cnp
->cn_pnbuf
[linklen
] = '\0';
1926 ndp
->ni_pathlen
+= linklen
;
1928 vnode_put(ndp
->ni_vp
);
1933 * Check if root directory should replace current directory.
1935 if (cnp
->cn_pnbuf
[0] == '/') {
1937 dp
= ndp
->ni_rootdir
;
1938 error
= vnode_get(dp
);
1946 tmppn
= cnp
->cn_pnbuf
;
1947 cnp
->cn_pnbuf
= NULL
;
1948 cnp
->cn_flags
&= ~HASBUF
;
1949 FREE_ZONE(tmppn
, cnp
->cn_pnlen
, M_NAMEI
);
1955 * A fiddled version of m_adj() that ensures null fill to a long
1956 * boundary and only trims off the back end
1959 nfsm_adj(mp
, len
, nul
)
1969 * Trim from tail. Scan the mbuf chain,
1970 * calculating its length and finding the last mbuf.
1971 * If the adjustment only affects this mbuf, then just
1972 * adjust and return. Otherwise, rescan and truncate
1973 * after the remaining size.
1980 mnext
= mbuf_next(m
);
1987 mbuf_setlen(m
, mlen
);
1989 cp
= (caddr_t
)mbuf_data(m
) + mlen
- nul
;
1990 for (i
= 0; i
< nul
; i
++)
1999 * Correct length for chain is "count".
2000 * Find the mbuf with last data, adjust its length,
2001 * and toss data from remaining mbufs on chain.
2003 for (m
= mp
; m
; m
= mbuf_next(m
)) {
2005 if (mlen
>= count
) {
2007 mbuf_setlen(m
, count
);
2009 cp
= (caddr_t
)mbuf_data(m
) + mlen
- nul
;
2010 for (i
= 0; i
< nul
; i
++)
2017 for (m
= mbuf_next(m
); m
; m
= mbuf_next(m
))
2022 * Make these functions instead of macros, so that the kernel text size
2023 * doesn't get too big...
2026 nfsm_srvwcc(nfsd
, before_ret
, before_vap
, after_ret
, after_vap
, mbp
, bposp
)
2027 struct nfsrv_descript
*nfsd
;
2029 struct vnode_attr
*before_vap
;
2031 struct vnode_attr
*after_vap
;
2035 mbuf_t mb
= *mbp
, mb2
;
2036 char *bpos
= *bposp
;
2040 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
2043 nfsm_build(tl
, u_long
*, 7 * NFSX_UNSIGNED
);
2045 txdr_hyper(&(before_vap
->va_data_size
), tl
);
2047 txdr_nfsv3time(&(before_vap
->va_modify_time
), tl
);
2049 txdr_nfsv3time(&(before_vap
->va_change_time
), tl
);
2053 nfsm_srvpostopattr(nfsd
, after_ret
, after_vap
, mbp
, bposp
);
2057 nfsm_srvpostopattr(nfsd
, after_ret
, after_vap
, mbp
, bposp
)
2058 struct nfsrv_descript
*nfsd
;
2060 struct vnode_attr
*after_vap
;
2064 mbuf_t mb
= *mbp
, mb2
;
2065 char *bpos
= *bposp
;
2067 struct nfs_fattr
*fp
;
2070 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
2073 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
+ NFSX_V3FATTR
);
2075 fp
= (struct nfs_fattr
*)tl
;
2076 nfsm_srvfattr(nfsd
, after_vap
, fp
);
2083 nfsm_srvfattr(nfsd
, vap
, fp
)
2084 struct nfsrv_descript
*nfsd
;
2085 struct vnode_attr
*vap
;
2086 struct nfs_fattr
*fp
;
2089 // XXX Should we assert here that all fields are supported?
2091 fp
->fa_nlink
= txdr_unsigned(vap
->va_nlink
);
2092 fp
->fa_uid
= txdr_unsigned(vap
->va_uid
);
2093 fp
->fa_gid
= txdr_unsigned(vap
->va_gid
);
2094 if (nfsd
->nd_flag
& ND_NFSV3
) {
2095 fp
->fa_type
= vtonfsv3_type(vap
->va_type
);
2096 fp
->fa_mode
= vtonfsv3_mode(vap
->va_mode
);
2097 txdr_hyper(&vap
->va_data_size
, &fp
->fa3_size
);
2098 txdr_hyper(&vap
->va_data_alloc
, &fp
->fa3_used
);
2099 fp
->fa3_rdev
.specdata1
= txdr_unsigned(major(vap
->va_rdev
));
2100 fp
->fa3_rdev
.specdata2
= txdr_unsigned(minor(vap
->va_rdev
));
2101 fp
->fa3_fsid
.nfsuquad
[0] = 0;
2102 fp
->fa3_fsid
.nfsuquad
[1] = txdr_unsigned(vap
->va_fsid
);
2103 txdr_hyper(&vap
->va_fileid
, &fp
->fa3_fileid
);
2104 txdr_nfsv3time(&vap
->va_access_time
, &fp
->fa3_atime
);
2105 txdr_nfsv3time(&vap
->va_modify_time
, &fp
->fa3_mtime
);
2106 txdr_nfsv3time(&vap
->va_change_time
, &fp
->fa3_ctime
);
2108 fp
->fa_type
= vtonfsv2_type(vap
->va_type
);
2109 fp
->fa_mode
= vtonfsv2_mode(vap
->va_type
, vap
->va_mode
);
2110 fp
->fa2_size
= txdr_unsigned(vap
->va_data_size
);
2111 fp
->fa2_blocksize
= txdr_unsigned(vap
->va_iosize
);
2112 if (vap
->va_type
== VFIFO
)
2113 fp
->fa2_rdev
= 0xffffffff;
2115 fp
->fa2_rdev
= txdr_unsigned(vap
->va_rdev
);
2116 fp
->fa2_blocks
= txdr_unsigned(vap
->va_data_alloc
/ NFS_FABLKSIZE
);
2117 fp
->fa2_fsid
= txdr_unsigned(vap
->va_fsid
);
2118 fp
->fa2_fileid
= txdr_unsigned(vap
->va_fileid
);
2119 txdr_nfsv2time(&vap
->va_access_time
, &fp
->fa2_atime
);
2120 txdr_nfsv2time(&vap
->va_modify_time
, &fp
->fa2_mtime
);
2121 txdr_nfsv2time(&vap
->va_change_time
, &fp
->fa2_ctime
);
2126 * Build hash lists of net addresses and hang them off the NFS export.
2127 * Called by nfsrv_export() to set up the lists of export addresses.
2130 nfsrv_hang_addrlist(struct nfs_export
*nx
, struct user_nfs_export_args
*unxa
)
2132 struct nfs_export_net_args nxna
;
2133 struct nfs_netopt
*no
;
2134 struct radix_node_head
*rnh
;
2135 struct radix_node
*rn
;
2136 struct sockaddr
*saddr
, *smask
;
2142 struct ucred temp_cred
;
2144 uaddr
= unxa
->nxa_nets
;
2145 for (net
= 0; net
< unxa
->nxa_netcount
; net
++, uaddr
+= sizeof(nxna
)) {
2146 error
= copyin(uaddr
, &nxna
, sizeof(nxna
));
2150 if (nxna
.nxna_flags
& (NX_MAPROOT
|NX_MAPALL
)) {
2151 bzero(&temp_cred
, sizeof(temp_cred
));
2152 temp_cred
.cr_uid
= nxna
.nxna_cred
.cr_uid
;
2153 temp_cred
.cr_ngroups
= nxna
.nxna_cred
.cr_ngroups
;
2154 for (i
=0; i
< nxna
.nxna_cred
.cr_ngroups
&& i
< NGROUPS
; i
++)
2155 temp_cred
.cr_groups
[i
] = nxna
.nxna_cred
.cr_groups
[i
];
2157 cred
= kauth_cred_create(&temp_cred
);
2164 if (nxna
.nxna_addr
.ss_len
== 0) {
2165 /* No address means this is a default/world export */
2166 if (nx
->nx_flags
& NX_DEFAULTEXPORT
)
2168 nx
->nx_flags
|= NX_DEFAULTEXPORT
;
2169 nx
->nx_defopt
.nxo_flags
= nxna
.nxna_flags
;
2170 nx
->nx_defopt
.nxo_cred
= cred
;
2175 i
= sizeof(struct nfs_netopt
);
2176 i
+= nxna
.nxna_addr
.ss_len
+ nxna
.nxna_mask
.ss_len
;
2177 MALLOC(no
, struct nfs_netopt
*, i
, M_NETADDR
, M_WAITOK
);
2180 bzero(no
, sizeof(struct nfs_netopt
));
2181 no
->no_opt
.nxo_flags
= nxna
.nxna_flags
;
2182 no
->no_opt
.nxo_cred
= cred
;
2184 saddr
= (struct sockaddr
*)(no
+ 1);
2185 bcopy(&nxna
.nxna_addr
, saddr
, nxna
.nxna_addr
.ss_len
);
2186 if (nxna
.nxna_mask
.ss_len
) {
2187 smask
= (struct sockaddr
*)((caddr_t
)saddr
+ nxna
.nxna_addr
.ss_len
);
2188 bcopy(&nxna
.nxna_mask
, smask
, nxna
.nxna_mask
.ss_len
);
2192 i
= saddr
->sa_family
;
2193 if ((rnh
= nx
->nx_rtable
[i
]) == 0) {
2195 * Seems silly to initialize every AF when most are not
2196 * used, do so on demand here
2198 for (dom
= domains
; dom
; dom
= dom
->dom_next
)
2199 if (dom
->dom_family
== i
&& dom
->dom_rtattach
) {
2200 dom
->dom_rtattach((void **)&nx
->nx_rtable
[i
],
2204 if ((rnh
= nx
->nx_rtable
[i
]) == 0) {
2205 if (IS_VALID_CRED(cred
))
2206 kauth_cred_unref(&cred
);
2207 _FREE(no
, M_NETADDR
);
2211 rn
= (*rnh
->rnh_addaddr
)((caddr_t
)saddr
, (caddr_t
)smask
, rnh
, no
->no_rnodes
);
2214 * One of the reasons that rnh_addaddr may fail is that
2215 * the entry already exists. To check for this case, we
2216 * look up the entry to see if it is there. If so, we
2217 * do not need to make a new entry but do continue.
2220 rn
= (*rnh
->rnh_matchaddr
)((caddr_t
)saddr
, rnh
);
2221 if (rn
!= 0 && (rn
->rn_flags
& RNF_ROOT
) == 0 &&
2222 (((struct nfs_netopt
*)rn
)->no_opt
.nxo_flags
== nxna
.nxna_flags
)) {
2223 kauth_cred_t cred2
= ((struct nfs_netopt
*)rn
)->no_opt
.nxo_cred
;
2224 if (cred
&& cred2
&& (cred
->cr_uid
== cred2
->cr_uid
) &&
2225 (cred
->cr_ngroups
== cred2
->cr_ngroups
)) {
2226 for (i
=0; i
< cred2
->cr_ngroups
&& i
< NGROUPS
; i
++)
2227 if (cred
->cr_groups
[i
] != cred2
->cr_groups
[i
])
2229 if (i
>= cred2
->cr_ngroups
|| i
>= NGROUPS
)
2233 if (IS_VALID_CRED(cred
))
2234 kauth_cred_unref(&cred
);
2235 _FREE(no
, M_NETADDR
);
2247 * In order to properly track an export's netopt count, we need to pass
2248 * an additional argument to nfsrv_free_netopt() so that it can decrement
2249 * the export's netopt count.
2251 struct nfsrv_free_netopt_arg
{
2253 struct radix_node_head
*rnh
;
2257 nfsrv_free_netopt(struct radix_node
*rn
, void *w
)
2259 struct nfsrv_free_netopt_arg
*fna
= (struct nfsrv_free_netopt_arg
*)w
;
2260 struct radix_node_head
*rnh
= fna
->rnh
;
2261 uint32_t *cnt
= fna
->cnt
;
2262 struct nfs_netopt
*nno
= (struct nfs_netopt
*)rn
;
2264 (*rnh
->rnh_deladdr
)(rn
->rn_key
, rn
->rn_mask
, rnh
);
2265 if (IS_VALID_CRED(nno
->no_opt
.nxo_cred
))
2266 kauth_cred_unref(&nno
->no_opt
.nxo_cred
);
2267 _FREE((caddr_t
)rn
, M_NETADDR
);
2273 * Free the net address hash lists that are hanging off the mount points.
2276 nfsrv_free_addrlist(struct nfs_export
*nx
)
2279 struct radix_node_head
*rnh
;
2280 struct nfsrv_free_netopt_arg fna
;
2282 for (i
= 0; i
<= AF_MAX
; i
++)
2283 if ( (rnh
= nx
->nx_rtable
[i
]) ) {
2285 fna
.cnt
= &nx
->nx_expcnt
;
2286 (*rnh
->rnh_walktree
)(rnh
, nfsrv_free_netopt
, (caddr_t
)&fna
);
2287 _FREE((caddr_t
)rnh
, M_RTABLE
);
2288 nx
->nx_rtable
[i
] = 0;
2292 void enablequotas(struct mount
*mp
, vfs_context_t ctx
); // XXX
2295 nfsrv_export(struct user_nfs_export_args
*unxa
, struct vfs_context
*ctx
)
2297 int error
= 0, pathlen
;
2298 struct nfs_exportfs
*nxfs
, *nxfs2
, *nxfs3
;
2299 struct nfs_export
*nx
, *nx2
, *nx3
;
2300 struct nfs_filehandle nfh
;
2301 struct nameidata mnd
, xnd
;
2302 vnode_t mvp
= NULL
, xvp
= NULL
;
2304 char path
[MAXPATHLEN
];
2307 if (unxa
->nxa_flags
& NXA_DELETE_ALL
) {
2308 /* delete all exports on all file systems */
2309 lck_rw_lock_exclusive(&nfs_export_rwlock
);
2310 while ((nxfs
= LIST_FIRST(&nfs_exports
))) {
2311 mp
= vfs_getvfs_by_mntonname(nxfs
->nxfs_path
);
2313 mp
->mnt_flag
&= ~MNT_EXPORTED
;
2314 /* delete all exports on this file system */
2315 while ((nx
= LIST_FIRST(&nxfs
->nxfs_exports
))) {
2316 LIST_REMOVE(nx
, nx_next
);
2317 LIST_REMOVE(nx
, nx_hash
);
2318 /* delete all netopts for this export */
2319 nfsrv_free_addrlist(nx
);
2320 nx
->nx_flags
&= ~NX_DEFAULTEXPORT
;
2321 if (IS_VALID_CRED(nx
->nx_defopt
.nxo_cred
)) {
2322 kauth_cred_unref(&nx
->nx_defopt
.nxo_cred
);
2324 FREE(nx
->nx_path
, M_TEMP
);
2327 LIST_REMOVE(nxfs
, nxfs_next
);
2328 FREE(nxfs
->nxfs_path
, M_TEMP
);
2331 lck_rw_done(&nfs_export_rwlock
);
2335 error
= copyinstr(unxa
->nxa_fspath
, path
, MAXPATHLEN
, (size_t *)&pathlen
);
2339 lck_rw_lock_exclusive(&nfs_export_rwlock
);
2341 // first check if we've already got an exportfs with the given ID
2342 LIST_FOREACH(nxfs
, &nfs_exports
, nxfs_next
) {
2343 if (nxfs
->nxfs_id
== unxa
->nxa_fsid
)
2347 /* verify exported FS path matches given path */
2348 if (strcmp(path
, nxfs
->nxfs_path
)) {
2352 mp
= vfs_getvfs_by_mntonname(nxfs
->nxfs_path
);
2353 /* find exported FS root vnode */
2354 NDINIT(&mnd
, LOOKUP
, FOLLOW
| LOCKLEAF
| AUDITVNPATH1
,
2355 UIO_SYSSPACE
, nxfs
->nxfs_path
, ctx
);
2356 error
= namei(&mnd
);
2360 /* make sure it's (still) the root of a file system */
2361 if ((mvp
->v_flag
& VROOT
) == 0) {
2365 /* sanity check: this should be same mount */
2366 if (mp
!= vnode_mount(mvp
)) {
2371 /* no current exported file system with that ID */
2372 if (!(unxa
->nxa_flags
& NXA_ADD
)) {
2377 /* find exported FS root vnode */
2378 NDINIT(&mnd
, LOOKUP
, FOLLOW
| LOCKLEAF
| AUDITVNPATH1
,
2379 UIO_SYSSPACE
, path
, ctx
);
2380 error
= namei(&mnd
);
2384 /* make sure it's the root of a file system */
2385 if ((mvp
->v_flag
& VROOT
) == 0) {
2389 mp
= vnode_mount(mvp
);
2391 /* make sure the file system is NFS-exportable */
2392 nfh
.nfh_len
= NFS_MAX_FID_SIZE
;
2393 error
= VFS_VPTOFH(mvp
, &nfh
.nfh_len
, &nfh
.nfh_fid
[0], NULL
);
2394 if (!error
&& (nfh
.nfh_len
> (int)NFS_MAX_FID_SIZE
))
2399 /* add an exportfs for it */
2400 MALLOC(nxfs
, struct nfs_exportfs
*, sizeof(struct nfs_exportfs
), M_TEMP
, M_WAITOK
);
2405 bzero(nxfs
, sizeof(struct nfs_exportfs
));
2406 nxfs
->nxfs_id
= unxa
->nxa_fsid
;
2407 MALLOC(nxfs
->nxfs_path
, char*, pathlen
, M_TEMP
, M_WAITOK
);
2408 if (!nxfs
->nxfs_path
) {
2413 bcopy(path
, nxfs
->nxfs_path
, pathlen
);
2414 /* insert into list in reverse-sorted order */
2416 LIST_FOREACH(nxfs2
, &nfs_exports
, nxfs_next
) {
2417 if (strcmp(nxfs
->nxfs_path
, nxfs2
->nxfs_path
) > 0)
2422 LIST_INSERT_BEFORE(nxfs2
, nxfs
, nxfs_next
);
2424 LIST_INSERT_AFTER(nxfs3
, nxfs
, nxfs_next
);
2426 LIST_INSERT_HEAD(&nfs_exports
, nxfs
, nxfs_next
);
2428 /* make sure any quotas are enabled before we export the file system */
2429 enablequotas(mp
, ctx
);
2432 if (unxa
->nxa_exppath
) {
2433 error
= copyinstr(unxa
->nxa_exppath
, path
, MAXPATHLEN
, (size_t *)&pathlen
);
2436 LIST_FOREACH(nx
, &nxfs
->nxfs_exports
, nx_next
) {
2437 if (nx
->nx_id
== unxa
->nxa_expid
)
2441 /* verify exported FS path matches given path */
2442 if (strcmp(path
, nx
->nx_path
)) {
2447 /* no current export with that ID */
2448 if (!(unxa
->nxa_flags
& NXA_ADD
)) {
2452 /* add an export for it */
2453 MALLOC(nx
, struct nfs_export
*, sizeof(struct nfs_export
), M_TEMP
, M_WAITOK
);
2458 bzero(nx
, sizeof(struct nfs_export
));
2459 nx
->nx_id
= unxa
->nxa_expid
;
2461 MALLOC(nx
->nx_path
, char*, pathlen
, M_TEMP
, M_WAITOK
);
2468 bcopy(path
, nx
->nx_path
, pathlen
);
2469 /* insert into list in reverse-sorted order */
2471 LIST_FOREACH(nx2
, &nxfs
->nxfs_exports
, nx_next
) {
2472 if (strcmp(nx
->nx_path
, nx2
->nx_path
) > 0)
2477 LIST_INSERT_BEFORE(nx2
, nx
, nx_next
);
2479 LIST_INSERT_AFTER(nx3
, nx
, nx_next
);
2481 LIST_INSERT_HEAD(&nxfs
->nxfs_exports
, nx
, nx_next
);
2482 /* insert into hash */
2483 LIST_INSERT_HEAD(NFSEXPHASH(nxfs
->nxfs_id
, nx
->nx_id
), nx
, nx_hash
);
2486 * We don't allow nested exports. Check if the new entry
2487 * nests with the entries before and after or if there's an
2488 * entry for the file system root and subdirs.
2491 if ((nx3
&& !strncmp(nx3
->nx_path
, nx
->nx_path
, pathlen
- 1) &&
2492 (nx3
->nx_path
[pathlen
-1] == '/')) ||
2493 (nx2
&& !strncmp(nx2
->nx_path
, nx
->nx_path
, strlen(nx2
->nx_path
)) &&
2494 (nx
->nx_path
[strlen(nx2
->nx_path
)] == '/')))
2497 /* check export conflict with fs root export and vice versa */
2498 expisroot
= !nx
->nx_path
[0] ||
2499 ((nx
->nx_path
[0] == '.') && !nx
->nx_path
[1]);
2500 LIST_FOREACH(nx2
, &nxfs
->nxfs_exports
, nx_next
) {
2504 } else if (!nx2
->nx_path
[0])
2506 else if ((nx2
->nx_path
[0] == '.') && !nx2
->nx_path
[1])
2513 printf("nfsrv_export: attempt to register nested exports: %s/%s\n",
2514 nxfs
->nxfs_path
, nx
->nx_path
);
2518 /* find export root vnode */
2519 if (!nx
->nx_path
[0] || ((nx
->nx_path
[0] == '.') && !nx
->nx_path
[1])) {
2520 /* exporting file system's root directory */
2524 xnd
.ni_cnd
.cn_nameiop
= LOOKUP
;
2525 xnd
.ni_cnd
.cn_flags
= LOCKLEAF
;
2526 xnd
.ni_pathlen
= pathlen
- 1;
2527 xnd
.ni_cnd
.cn_nameptr
= xnd
.ni_cnd
.cn_pnbuf
= path
;
2528 xnd
.ni_startdir
= mvp
;
2529 xnd
.ni_usedvp
= mvp
;
2530 xnd
.ni_cnd
.cn_context
= ctx
;
2531 error
= lookup(&xnd
);
2537 if (vnode_vtype(xvp
) != VDIR
) {
2543 /* grab file handle */
2544 nx
->nx_fh
.nfh_xh
.nxh_version
= htonl(NFS_FH_VERSION
);
2545 nx
->nx_fh
.nfh_xh
.nxh_fsid
= htonl(nx
->nx_fs
->nxfs_id
);
2546 nx
->nx_fh
.nfh_xh
.nxh_expid
= htonl(nx
->nx_id
);
2547 nx
->nx_fh
.nfh_xh
.nxh_flags
= 0;
2548 nx
->nx_fh
.nfh_xh
.nxh_reserved
= 0;
2549 nx
->nx_fh
.nfh_len
= NFS_MAX_FID_SIZE
;
2550 error
= VFS_VPTOFH(xvp
, &nx
->nx_fh
.nfh_len
, &nx
->nx_fh
.nfh_fid
[0], NULL
);
2551 if (!error
&& (nx
->nx_fh
.nfh_len
> (int)NFS_MAX_FID_SIZE
)) {
2554 nx
->nx_fh
.nfh_xh
.nxh_fidlen
= nx
->nx_fh
.nfh_len
;
2555 nx
->nx_fh
.nfh_len
+= sizeof(nx
->nx_fh
.nfh_xh
);
2566 /* perform the export changes */
2567 if (unxa
->nxa_flags
& NXA_DELETE
) {
2569 /* delete all exports on this file system */
2570 while ((nx
= LIST_FIRST(&nxfs
->nxfs_exports
))) {
2571 LIST_REMOVE(nx
, nx_next
);
2572 LIST_REMOVE(nx
, nx_hash
);
2573 /* delete all netopts for this export */
2574 nfsrv_free_addrlist(nx
);
2575 nx
->nx_flags
&= ~NX_DEFAULTEXPORT
;
2576 if (IS_VALID_CRED(nx
->nx_defopt
.nxo_cred
)) {
2577 kauth_cred_unref(&nx
->nx_defopt
.nxo_cred
);
2579 FREE(nx
->nx_path
, M_TEMP
);
2584 /* delete all netopts for this export */
2585 nfsrv_free_addrlist(nx
);
2586 nx
->nx_flags
&= ~NX_DEFAULTEXPORT
;
2587 if (IS_VALID_CRED(nx
->nx_defopt
.nxo_cred
)) {
2588 kauth_cred_unref(&nx
->nx_defopt
.nxo_cred
);
2592 if (unxa
->nxa_flags
& NXA_ADD
) {
2593 error
= nfsrv_hang_addrlist(nx
, unxa
);
2595 mp
->mnt_flag
|= MNT_EXPORTED
;
2599 if (nx
&& !nx
->nx_expcnt
) {
2600 /* export has no export options */
2601 LIST_REMOVE(nx
, nx_next
);
2602 LIST_REMOVE(nx
, nx_hash
);
2603 FREE(nx
->nx_path
, M_TEMP
);
2606 if (LIST_EMPTY(&nxfs
->nxfs_exports
)) {
2607 /* exported file system has no more exports */
2608 LIST_REMOVE(nxfs
, nxfs_next
);
2609 FREE(nxfs
->nxfs_path
, M_TEMP
);
2611 mp
->mnt_flag
&= ~MNT_EXPORTED
;
2620 lck_rw_done(&nfs_export_rwlock
);
2624 static struct nfs_export_options
*
2625 nfsrv_export_lookup(struct nfs_export
*nx
, mbuf_t nam
)
2627 struct nfs_export_options
*nxo
= NULL
;
2628 struct nfs_netopt
*no
= NULL
;
2629 struct radix_node_head
*rnh
;
2630 struct sockaddr
*saddr
;
2632 /* Lookup in the export list first. */
2634 saddr
= mbuf_data(nam
);
2635 rnh
= nx
->nx_rtable
[saddr
->sa_family
];
2637 no
= (struct nfs_netopt
*)
2638 (*rnh
->rnh_matchaddr
)((caddr_t
)saddr
, rnh
);
2639 if (no
&& no
->no_rnodes
->rn_flags
& RNF_ROOT
)
2645 /* If no address match, use the default if it exists. */
2646 if ((nxo
== NULL
) && (nx
->nx_flags
& NX_DEFAULTEXPORT
))
2647 nxo
= &nx
->nx_defopt
;
2651 /* find an export for the given handle */
2652 static struct nfs_export
*
2653 nfsrv_fhtoexport(struct nfs_filehandle
*nfhp
)
2655 struct nfs_export
*nx
;
2656 uint32_t fsid
, expid
;
2658 fsid
= ntohl(nfhp
->nfh_xh
.nxh_fsid
);
2659 expid
= ntohl(nfhp
->nfh_xh
.nxh_expid
);
2660 nx
= NFSEXPHASH(fsid
, expid
)->lh_first
;
2661 for (; nx
; nx
= LIST_NEXT(nx
, nx_hash
)) {
2662 if (nx
->nx_fs
->nxfs_id
!= fsid
)
2664 if (nx
->nx_id
!= expid
)
2672 * nfsrv_fhtovp() - convert FH to vnode and export info
2676 struct nfs_filehandle
*nfhp
,
2678 __unused
int pubflag
,
2680 struct nfs_export
**nxp
,
2681 struct nfs_export_options
**nxop
)
2691 v
= ntohl(nfhp
->nfh_xh
.nxh_version
);
2692 if (v
!= NFS_FH_VERSION
) {
2693 /* file handle format not supported */
2696 if (nfhp
->nfh_len
> NFS_MAX_FH_SIZE
)
2698 if (nfhp
->nfh_len
< (int)sizeof(nfhp
->nfh_xh
))
2700 v
= ntohs(nfhp
->nfh_xh
.nxh_flags
);
2701 if (v
& NXHF_INVALIDFH
)
2704 /* XXX Revisit when enabling WebNFS */
2705 #ifdef WEBNFS_ENABLED
2706 if (nfs_ispublicfh(nfhp
)) {
2707 if (!pubflag
|| !nfs_pub
.np_valid
)
2709 nfhp
= &nfs_pub
.np_handle
;
2713 *nxp
= nfsrv_fhtoexport(nfhp
);
2717 /* Get the export option structure for this <export, client> tuple. */
2718 *nxop
= nfsrv_export_lookup(*nxp
, nam
);
2719 if (nam
&& (*nxop
== NULL
))
2722 /* find mount structure */
2723 mp
= vfs_getvfs_by_mntonname((*nxp
)->nx_fs
->nxfs_path
);
2727 error
= VFS_FHTOVP(mp
, nfhp
->nfh_xh
.nxh_fidlen
, &nfhp
->nfh_fid
[0], vpp
, NULL
);
2730 /* vnode pointer should be good at this point or ... */
2737 * nfsrv_credcheck() - check/map credentials according to given export options
2741 struct nfsrv_descript
*nfsd
,
2742 __unused
struct nfs_export
*nx
,
2743 struct nfs_export_options
*nxo
)
2745 if (nxo
&& nxo
->nxo_cred
) {
2746 if ((nxo
->nxo_flags
& NX_MAPALL
) ||
2747 ((nxo
->nxo_flags
& NX_MAPROOT
) && !suser(nfsd
->nd_cr
, NULL
))) {
2748 kauth_cred_ref(nxo
->nxo_cred
);
2749 kauth_cred_unref(&nfsd
->nd_cr
);
2750 nfsd
->nd_cr
= nxo
->nxo_cred
;
2758 * WebNFS: check if a filehandle is a public filehandle. For v3, this
2759 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
2760 * transformed this to all zeroes in both cases, so check for it.
2763 nfs_ispublicfh(struct nfs_filehandle
*nfhp
)
2765 char *cp
= (char *)nfhp
;
2768 if (nfhp
->nfh_len
== 0)
2770 if (nfhp
->nfh_len
!= NFSX_V2FH
)
2772 for (i
= 0; i
< NFSX_V2FH
; i
++)
2779 * nfsrv_vptofh() - convert vnode to file handle for given export
2781 * If the caller is passing in a vnode for a ".." directory entry,
2782 * they can pass a directory NFS file handle (dnfhp) which will be
2783 * checked against the root export file handle. If it matches, we
2784 * refuse to provide the file handle for the out-of-export directory.
2788 struct nfs_export
*nx
,
2790 struct nfs_filehandle
*dnfhp
,
2792 struct vfs_context
*ctx
,
2793 struct nfs_filehandle
*nfhp
)
2797 nfhp
->nfh_xh
.nxh_version
= htonl(NFS_FH_VERSION
);
2798 nfhp
->nfh_xh
.nxh_fsid
= htonl(nx
->nx_fs
->nxfs_id
);
2799 nfhp
->nfh_xh
.nxh_expid
= htonl(nx
->nx_id
);
2800 nfhp
->nfh_xh
.nxh_flags
= 0;
2801 nfhp
->nfh_xh
.nxh_reserved
= 0;
2804 bzero(&nfhp
->nfh_fid
[0], NFSV2_MAX_FID_SIZE
);
2806 /* if directory FH matches export root, return invalid FH */
2807 if (dnfhp
&& nfsrv_fhmatch(dnfhp
, &nx
->nx_fh
)) {
2808 nfhp
->nfh_len
= v2
? NFSX_V2FH
: sizeof(nfhp
->nfh_xh
);
2809 nfhp
->nfh_xh
.nxh_fidlen
= 0;
2810 nfhp
->nfh_xh
.nxh_flags
= htons(NXHF_INVALIDFH
);
2814 nfhp
->nfh_len
= v2
? NFSV2_MAX_FID_SIZE
: NFS_MAX_FID_SIZE
;
2815 error
= VFS_VPTOFH(vp
, &nfhp
->nfh_len
, &nfhp
->nfh_fid
[0], ctx
);
2818 if (nfhp
->nfh_len
> (int)(v2
? NFSV2_MAX_FID_SIZE
: NFS_MAX_FID_SIZE
))
2820 nfhp
->nfh_xh
.nxh_fidlen
= nfhp
->nfh_len
;
2821 nfhp
->nfh_len
+= sizeof(nfhp
->nfh_xh
);
2822 if (v2
&& (nfhp
->nfh_len
< NFSX_V2FH
))
2823 nfhp
->nfh_len
= NFSX_V2FH
;
2829 nfsrv_fhmatch(struct nfs_filehandle
*fh1
, struct nfs_filehandle
*fh2
)
2833 len1
= sizeof(fh1
->nfh_xh
) + fh1
->nfh_xh
.nxh_fidlen
;
2834 len2
= sizeof(fh2
->nfh_xh
) + fh2
->nfh_xh
.nxh_fidlen
;
2837 if (bcmp(&fh1
->nfh_xh
, &fh2
->nfh_xh
, len1
))
2842 #endif /* NFS_NOSERVER */
2844 * This function compares two net addresses by family and returns TRUE
2845 * if they are the same host.
2846 * If there is any doubt, return FALSE.
2847 * The AF_INET family is handled as a special case so that address mbufs
2848 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
2851 netaddr_match(family
, haddr
, nam
)
2853 union nethostaddr
*haddr
;
2856 struct sockaddr_in
*inetaddr
;
2860 inetaddr
= mbuf_data(nam
);
2861 if (inetaddr
->sin_family
== AF_INET
&&
2862 inetaddr
->sin_addr
.s_addr
== haddr
->had_inetaddr
)
2868 struct sockaddr_iso
*isoaddr1
, *isoaddr2
;
2870 isoaddr1
= mbuf_data(nam
);
2871 isoaddr2
= mbuf_data(haddr
->had_nam
);
2872 if (isoaddr1
->siso_family
== AF_ISO
&&
2873 isoaddr1
->siso_nlen
> 0 &&
2874 isoaddr1
->siso_nlen
== isoaddr2
->siso_nlen
&&
2875 SAME_ISOADDR(isoaddr1
, isoaddr2
))
2886 static nfsuint64 nfs_nullcookie
= { { 0, 0 } };
2888 * This function finds the directory cookie that corresponds to the
2889 * logical byte offset given.
2892 nfs_getcookie(np
, off
, add
)
2897 struct nfsdmap
*dp
, *dp2
;
2900 pos
= off
/ NFS_DIRBLKSIZ
;
2904 panic("nfs getcookie add at 0");
2906 return (&nfs_nullcookie
);
2909 dp
= np
->n_cookies
.lh_first
;
2912 MALLOC_ZONE(dp
, struct nfsdmap
*, sizeof(struct nfsdmap
),
2913 M_NFSDIROFF
, M_WAITOK
);
2915 return ((nfsuint64
*)0);
2916 dp
->ndm_eocookie
= 0;
2917 LIST_INSERT_HEAD(&np
->n_cookies
, dp
, ndm_list
);
2919 return ((nfsuint64
*)0);
2921 while (pos
>= NFSNUMCOOKIES
) {
2922 pos
-= NFSNUMCOOKIES
;
2923 if (dp
->ndm_list
.le_next
) {
2924 if (!add
&& dp
->ndm_eocookie
< NFSNUMCOOKIES
&&
2925 pos
>= dp
->ndm_eocookie
)
2926 return ((nfsuint64
*)0);
2927 dp
= dp
->ndm_list
.le_next
;
2929 MALLOC_ZONE(dp2
, struct nfsdmap
*, sizeof(struct nfsdmap
),
2930 M_NFSDIROFF
, M_WAITOK
);
2932 return ((nfsuint64
*)0);
2933 dp2
->ndm_eocookie
= 0;
2934 LIST_INSERT_AFTER(dp
, dp2
, ndm_list
);
2937 return ((nfsuint64
*)0);
2939 if (pos
>= dp
->ndm_eocookie
) {
2941 dp
->ndm_eocookie
= pos
+ 1;
2943 return ((nfsuint64
*)0);
2945 return (&dp
->ndm_cookies
[pos
]);
2949 * Invalidate cached directory information, except for the actual directory
2950 * blocks (which are invalidated separately).
2951 * Done mainly to avoid the use of stale offset cookies.
2957 struct nfsnode
*np
= VTONFS(vp
);
2960 if (vnode_vtype(vp
) != VDIR
)
2961 panic("nfs: invaldir not dir");
2963 np
->n_direofoffset
= 0;
2964 np
->n_cookieverf
.nfsuquad
[0] = 0;
2965 np
->n_cookieverf
.nfsuquad
[1] = 0;
2966 if (np
->n_cookies
.lh_first
)
2967 np
->n_cookies
.lh_first
->ndm_eocookie
= 0;
2970 #ifndef NFS_NOSERVER
2972 * Map errnos to NFS error numbers. For Version 3 also filter out error
2973 * numbers not specified for the associated procedure.
2976 nfsrv_errmap(nd
, err
)
2977 struct nfsrv_descript
*nd
;
2980 short *defaulterrp
, *errp
;
2982 if (nd
->nd_flag
& ND_NFSV3
) {
2983 if (nd
->nd_procnum
<= NFSPROC_COMMIT
) {
2984 errp
= defaulterrp
= nfsrv_v3errmap
[nd
->nd_procnum
];
2988 else if (*errp
> err
)
2991 return ((int)*defaulterrp
);
2993 return (err
& 0xffff);
2996 return ((int)nfsrv_v2errmap
[err
- 1]);
3000 #endif /* NFS_NOSERVER */