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 lck_grp_attr_setstat(nfs_iod_lck_grp_attr
);
1224 nfs_iod_lck_grp
= lck_grp_alloc_init("nfs_iod", nfs_iod_lck_grp_attr
);
1225 nfs_iod_lck_attr
= lck_attr_alloc_init();
1226 nfs_iod_mutex
= lck_mtx_alloc_init(nfs_iod_lck_grp
, nfs_iod_lck_attr
);
1228 nfs_nbinit(); /* Init the nfsbuf table */
1229 nfs_nhinit(); /* Init the nfsnode table */
1230 nfs_lockinit(); /* Init the nfs lock state */
1232 #ifndef NFS_NOSERVER
1233 /* init nfsd mutex */
1234 nfsd_lck_grp_attr
= lck_grp_attr_alloc_init();
1235 lck_grp_attr_setstat(nfsd_lck_grp_attr
);
1236 nfsd_lck_grp
= lck_grp_alloc_init("nfsd", nfsd_lck_grp_attr
);
1237 nfsd_lck_attr
= lck_attr_alloc_init();
1238 nfsd_mutex
= lck_mtx_alloc_init(nfsd_lck_grp
, nfsd_lck_attr
);
1240 /* init slp rwlock */
1241 nfs_slp_lock_attr
= lck_attr_alloc_init();
1242 nfs_slp_group_attr
= lck_grp_attr_alloc_init();
1243 nfs_slp_rwlock_group
= lck_grp_alloc_init("nfs-slp-rwlock", nfs_slp_group_attr
);
1244 nfs_slp_mutex_group
= lck_grp_alloc_init("nfs-slp-mutex", nfs_slp_group_attr
);
1246 /* init export data structures */
1247 nfsexphashtbl
= hashinit(8, M_TEMP
, &nfsexphash
);
1248 LIST_INIT(&nfs_exports
);
1249 nfs_export_lock_attr
= lck_attr_alloc_init();
1250 nfs_export_group_attr
= lck_grp_attr_alloc_init();
1251 nfs_export_rwlock_group
= lck_grp_alloc_init("nfs-export-rwlock", nfs_export_group_attr
);
1252 lck_rw_init(&nfs_export_rwlock
, nfs_export_rwlock_group
, nfs_export_lock_attr
);
1254 lck_mtx_lock(nfsd_mutex
);
1255 nfsrv_init(0); /* Init server data structures */
1256 nfsrv_initcache(); /* Init the server request cache */
1257 lck_mtx_unlock(nfsd_mutex
);
1261 * Initialize reply list and start timer
1263 TAILQ_INIT(&nfs_reqq
);
1267 vfsp
->vfc_refcount
++; /* make us non-unloadable */
1272 * initialize NFS's cache of mbuf constants
1277 struct mbuf_stat ms
;
1280 nfs_mbuf_mlen
= ms
.mlen
;
1281 nfs_mbuf_mhlen
= ms
.mhlen
;
1282 nfs_mbuf_minclsize
= ms
.minclsize
;
1283 nfs_mbuf_mclbytes
= ms
.mclbytes
;
1287 * Parse the attributes that are in the mbuf list and store them in *nvap.
1290 nfs_parsefattr(mbuf_t
*mdp
, caddr_t
*dposp
, int v3
, struct nfs_vattr
*nvap
)
1292 struct nfs_fattr
*fp
;
1295 int error
= 0, rdev
;
1301 t1
= ((caddr_t
)mbuf_data(md
) + mbuf_len(md
)) - *dposp
;
1302 if ((error
= nfsm_disct(mdp
, dposp
, NFSX_FATTR(v3
), t1
, &cp2
))) {
1305 fp
= (struct nfs_fattr
*)cp2
;
1307 vtype
= nfsv3tov_type(fp
->fa_type
);
1308 vmode
= fxdr_unsigned(u_short
, fp
->fa_mode
);
1309 rdev
= makedev(fxdr_unsigned(int, fp
->fa3_rdev
.specdata1
),
1310 fxdr_unsigned(int, fp
->fa3_rdev
.specdata2
));
1312 vtype
= nfsv2tov_type(fp
->fa_type
);
1313 vmode
= fxdr_unsigned(u_short
, fp
->fa_mode
);
1317 * The duplicate information returned in fa_type and fa_mode
1318 * is an ambiguity in the NFS version 2 protocol.
1320 * VREG should be taken literally as a regular file. If a
1321 * server intents to return some type information differently
1322 * in the upper bits of the mode field (e.g. for sockets, or
1323 * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we
1324 * leave the examination of the mode bits even in the VREG
1325 * case to avoid breakage for bogus servers, but we make sure
1326 * that there are actually type bits set in the upper part of
1327 * fa_mode (and failing that, trust the va_type field).
1329 * NFSv3 cleared the issue, and requires fa_mode to not
1330 * contain any type information (while also introduing sockets
1331 * and FIFOs for fa_type).
1333 if (vtype
== VNON
|| (vtype
== VREG
&& (vmode
& S_IFMT
) != 0))
1334 vtype
= IFTOVT(vmode
);
1335 rdev
= fxdr_unsigned(long, fp
->fa2_rdev
);
1337 * Really ugly NFSv2 kludge.
1339 if (vtype
== VCHR
&& rdev
== (int)0xffffffff)
1343 nvap
->nva_type
= vtype
;
1344 nvap
->nva_mode
= (vmode
& 07777);
1345 nvap
->nva_rdev
= (dev_t
)rdev
;
1346 nvap
->nva_nlink
= (uint64_t)fxdr_unsigned(u_long
, fp
->fa_nlink
);
1347 nvap
->nva_uid
= fxdr_unsigned(uid_t
, fp
->fa_uid
);
1348 nvap
->nva_gid
= fxdr_unsigned(gid_t
, fp
->fa_gid
);
1350 fxdr_hyper(&fp
->fa3_size
, &nvap
->nva_size
);
1351 nvap
->nva_blocksize
= 16*1024;
1352 fxdr_hyper(&fp
->fa3_used
, &nvap
->nva_bytes
);
1353 fxdr_hyper(&fp
->fa3_fileid
, &nvap
->nva_fileid
);
1354 fxdr_nfsv3time(&fp
->fa3_atime
, &nvap
->nva_atime
);
1355 fxdr_nfsv3time(&fp
->fa3_mtime
, &nvap
->nva_mtime
);
1356 fxdr_nfsv3time(&fp
->fa3_ctime
, &nvap
->nva_ctime
);
1358 nvap
->nva_size
= fxdr_unsigned(u_long
, fp
->fa2_size
);
1359 nvap
->nva_blocksize
= fxdr_unsigned(long, fp
->fa2_blocksize
);
1360 nvap
->nva_bytes
= fxdr_unsigned(long, fp
->fa2_blocks
) * NFS_FABLKSIZE
;
1361 nvap
->nva_fileid
= (uint64_t)fxdr_unsigned(u_long
, fp
->fa2_fileid
);
1362 fxdr_nfsv2time(&fp
->fa2_atime
, &nvap
->nva_atime
);
1363 fxdr_nfsv2time(&fp
->fa2_mtime
, &nvap
->nva_mtime
);
1364 fxdr_nfsv2time(&fp
->fa2_ctime
, &nvap
->nva_ctime
);
1371 * Load the attribute cache (that lives in the nfsnode entry) with
1372 * the value pointed to by nvap, unless the file type in the attribute
1373 * cache doesn't match the file type in the nvap, in which case log a
1374 * warning and return ESTALE.
1376 * If the dontshrink flag is set, then it's not safe to call ubc_setsize()
1377 * to shrink the size of the file.
1382 struct nfs_vattr
*nvap
,
1389 struct nfs_vattr
*npnvap
;
1391 if (np
->n_flag
& NINIT
) {
1396 mp
= vnode_mount(vp
);
1399 FSDBG_TOP(527, vp
, np
, *xidp
>> 32, *xidp
);
1401 if (!VFSTONFS(mp
)) {
1402 FSDBG_BOT(527, ENXIO
, 1, 0, *xidp
);
1406 if (*xidp
< np
->n_xid
) {
1408 * We have already updated attributes with a response from
1409 * a later request. The attributes we have here are probably
1410 * stale so we drop them (just return). However, our
1411 * out-of-order receipt could be correct - if the requests were
1412 * processed out of order at the server. Given the uncertainty
1413 * we invalidate our cached attributes. *xidp is zeroed here
1414 * to indicate the attributes were dropped - only getattr
1415 * cares - it needs to retry the rpc.
1417 NATTRINVALIDATE(np
);
1418 FSDBG_BOT(527, 0, np
, np
->n_xid
, *xidp
);
1423 if (vp
&& (nvap
->nva_type
!= vnode_vtype(vp
))) {
1425 * The filehandle has changed type on us. This can be
1426 * caused by either the server not having unique filehandles
1427 * or because another client has removed the previous
1428 * filehandle and a new object (of a different type)
1429 * has been created with the same filehandle.
1431 * We can't simply switch the type on the vnode because
1432 * there may be type-specific fields that need to be
1433 * cleaned up or set up.
1435 * So, what should we do with this vnode?
1437 * About the best we can do is log a warning and return
1438 * an error. ESTALE is about the closest error, but it
1439 * is a little strange that we come up with this error
1440 * internally instead of simply passing it through from
1441 * the server. Hopefully, the vnode will be reclaimed
1442 * soon so the filehandle can be reincarnated as the new
1445 printf("nfs loadattrcache vnode changed type, was %d now %d\n",
1446 vnode_vtype(vp
), nvap
->nva_type
);
1447 FSDBG_BOT(527, ESTALE
, 3, 0, *xidp
);
1452 np
->n_attrstamp
= now
.tv_sec
;
1455 npnvap
= &np
->n_vattr
;
1456 nvap
->nva_fsid
= vfs_statfs(mp
)->f_fsid
.val
[0];
1457 bcopy((caddr_t
)nvap
, (caddr_t
)npnvap
, sizeof(*nvap
));
1460 if (nvap
->nva_size
!= np
->n_size
) {
1461 FSDBG(527, vp
, nvap
->nva_size
, np
->n_size
,
1462 (nvap
->nva_type
== VREG
) |
1463 (np
->n_flag
& NMODIFIED
? 6 : 4));
1464 if (nvap
->nva_type
== VREG
) {
1465 u_quad_t orig_size
= np
->n_size
;
1466 if (np
->n_flag
& NMODIFIED
) {
1467 if (nvap
->nva_size
< np
->n_size
)
1468 nvap
->nva_size
= np
->n_size
;
1470 np
->n_size
= nvap
->nva_size
;
1472 np
->n_size
= nvap
->nva_size
;
1473 if (!UBCINFOEXISTS(vp
) ||
1474 (dontshrink
&& np
->n_size
< (u_quad_t
)ubc_getsize(vp
))) {
1475 nvap
->nva_size
= np
->n_size
= orig_size
;
1476 NATTRINVALIDATE(np
);
1478 ubc_setsize(vp
, (off_t
)np
->n_size
); /* XXX */
1481 np
->n_size
= nvap
->nva_size
;
1484 np
->n_size
= nvap
->nva_size
;
1487 if (np
->n_flag
& NCHG
) {
1488 if (np
->n_flag
& NACC
)
1489 nvap
->nva_atime
= np
->n_atim
;
1490 if (np
->n_flag
& NUPD
)
1491 nvap
->nva_mtime
= np
->n_mtim
;
1494 FSDBG_BOT(527, 0, np
, 0, *xidp
);
1499 * Calculate the attribute timeout based on
1500 * how recently the file has been modified.
1503 nfs_attrcachetimeout(vnode_t vp
)
1505 struct nfsnode
*np
= VTONFS(vp
);
1506 struct nfsmount
*nmp
;
1510 if (!(nmp
= VFSTONFS(vnode_mount(vp
))))
1513 isdir
= vnode_isdir(vp
);
1515 if ((np
)->n_flag
& NMODIFIED
)
1516 timeo
= isdir
? nmp
->nm_acdirmin
: nmp
->nm_acregmin
;
1518 /* Note that if the client and server clocks are way out of sync, */
1519 /* timeout will probably get clamped to a min or max value */
1521 timeo
= (now
.tv_sec
- (np
)->n_mtime
.tv_sec
) / 10;
1523 if (timeo
< nmp
->nm_acdirmin
)
1524 timeo
= nmp
->nm_acdirmin
;
1525 else if (timeo
> nmp
->nm_acdirmax
)
1526 timeo
= nmp
->nm_acdirmax
;
1528 if (timeo
< nmp
->nm_acregmin
)
1529 timeo
= nmp
->nm_acregmin
;
1530 else if (timeo
> nmp
->nm_acregmax
)
1531 timeo
= nmp
->nm_acregmax
;
1539 * Check the time stamp
1540 * If the cache is valid, copy contents to *nvaper and return 0
1541 * otherwise return an error
1544 nfs_getattrcache(vp
, nvaper
)
1546 struct nfs_vattr
*nvaper
;
1548 struct nfsnode
*np
= VTONFS(vp
);
1549 struct nfs_vattr
*nvap
;
1550 struct timeval nowup
;
1553 if (!NATTRVALID(np
)) {
1554 FSDBG(528, vp
, 0, 0, 0);
1555 OSAddAtomic(1, (SInt32
*)&nfsstats
.attrcache_misses
);
1559 timeo
= nfs_attrcachetimeout(vp
);
1561 microuptime(&nowup
);
1562 if ((nowup
.tv_sec
- np
->n_attrstamp
) >= timeo
) {
1563 FSDBG(528, vp
, 0, 0, 1);
1564 OSAddAtomic(1, (SInt32
*)&nfsstats
.attrcache_misses
);
1567 FSDBG(528, vp
, 0, 0, 2);
1568 OSAddAtomic(1, (SInt32
*)&nfsstats
.attrcache_hits
);
1569 nvap
= &np
->n_vattr
;
1571 if (nvap
->nva_size
!= np
->n_size
) {
1572 FSDBG(528, vp
, nvap
->nva_size
, np
->n_size
,
1573 (nvap
->nva_type
== VREG
) |
1574 (np
->n_flag
& NMODIFIED
? 6 : 4));
1575 if (nvap
->nva_type
== VREG
) {
1576 if (np
->n_flag
& NMODIFIED
) {
1577 if (nvap
->nva_size
< np
->n_size
)
1578 nvap
->nva_size
= np
->n_size
;
1580 np
->n_size
= nvap
->nva_size
;
1582 np
->n_size
= nvap
->nva_size
;
1583 ubc_setsize(vp
, (off_t
)np
->n_size
); /* XXX */
1585 np
->n_size
= nvap
->nva_size
;
1588 bcopy((caddr_t
)nvap
, (caddr_t
)nvaper
, sizeof(struct nfs_vattr
));
1589 if (np
->n_flag
& NCHG
) {
1590 if (np
->n_flag
& NACC
)
1591 nvaper
->nva_atime
= np
->n_atim
;
1592 if (np
->n_flag
& NUPD
)
1593 nvaper
->nva_mtime
= np
->n_mtim
;
1598 #ifndef NFS_NOSERVER
1600 * Extract a lookup path from the given mbufs and store it in
1601 * a newly allocated buffer saved in the given nameidata structure.
1602 * exptected string length given as *lenp and final string length
1603 * (after any WebNFS processing) is returned in *lenp.
1610 __unused
int pubflag
,
1612 struct nameidata
*ndp
)
1614 int i
, len
, len2
, rem
, error
= 0;
1616 char *fromcp
, *tocp
;
1617 struct componentname
*cnp
= &ndp
->ni_cnd
;
1618 /* XXX Revisit when enabling WebNFS */
1619 #ifdef WEBNFS_ENABLED
1620 int webcnt
= 0, digitcnt
= 0;
1625 if (len
> (MAXPATHLEN
- 1))
1626 return (ENAMETOOLONG
);
1629 * Get a buffer for the name to be translated, and copy the
1630 * name into the buffer.
1632 MALLOC_ZONE(cnp
->cn_pnbuf
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1635 cnp
->cn_pnlen
= MAXPATHLEN
;
1636 cnp
->cn_flags
|= HASBUF
;
1639 * Copy the name from the mbuf list to the string
1641 * Along the way, take note of any WebNFS characters
1642 * and convert any % escapes.
1645 tocp
= cnp
->cn_pnbuf
;
1647 rem
= (caddr_t
)mbuf_data(md
) + mbuf_len(md
) - fromcp
;
1648 for (i
= 1; i
<= len
; i
++) {
1655 fromcp
= mbuf_data(md
);
1658 /* XXX Revisit when enabling WebNFS */
1659 #ifdef WEBNFS_ENABLED
1661 if ((i
== 1) && ((unsigned char)*fromcp
>= WEBNFS_SPECCHAR_START
)) {
1662 switch ((unsigned char)*fromcp
) {
1663 case WEBNFS_NATIVE_CHAR
:
1665 * 'Native' path for us is the same
1666 * as a path according to the NFS spec,
1667 * just skip the escape char.
1672 /* next iteration of for loop */
1675 * More may be added in the future, range 0x80-0xff.
1676 * Don't currently support security query lookup (0x81).
1684 /* We're expecting hex digits */
1685 if (!ISHEX(*fromcp
)) {
1690 hexdigits
[digitcnt
? 0 : 1] = *fromcp
++;
1692 *tocp
++ = HEXSTRTOI(hexdigits
);
1694 /* next iteration of for loop */
1696 } else if (*fromcp
== WEBNFS_ESC_CHAR
) {
1698 * We can't really look at the next couple
1699 * bytes here safely/easily, so we note that
1700 * the next two characters should be hex
1701 * digits and later save them in hexdigits[].
1702 * When we've got both, we'll convert it.
1708 /* next iteration of for loop */
1712 if (*fromcp
== '\0' || (!pubflag
&& *fromcp
== '/'))
1714 if (*fromcp
== '\0' || *fromcp
== '/')
1720 *tocp
++ = *fromcp
++;
1726 len2
= nfsm_rndup(len
)-len
;
1730 else if ((error
= nfs_adv(mdp
, dposp
, len2
, rem
)) != 0)
1734 /* XXX Revisit when enabling WebNFS */
1735 #ifdef WEBNFS_ENABLED
1738 /* The string ended in the middle of an escape! */
1749 FREE_ZONE(cnp
->cn_pnbuf
, MAXPATHLEN
, M_NAMEI
);
1750 cnp
->cn_flags
&= ~HASBUF
;
1752 ndp
->ni_pathlen
= len
;
1759 * Set up nameidata for a lookup() call and do it.
1761 * If pubflag is set, this call is done for a lookup operation on the
1762 * public filehandle. In that case we allow crossing mountpoints and
1763 * absolute pathnames. However, the caller is expected to check that
1764 * the lookup result is within the public fs, and deny access if
1769 struct nfsrv_descript
*nfsd
,
1770 struct vfs_context
*ctx
,
1771 struct nameidata
*ndp
,
1772 struct nfs_filehandle
*nfhp
,
1776 struct nfs_export
**nxp
,
1777 struct nfs_export_options
**nxop
)
1779 /* XXX Revisit when enabling WebNFS */
1780 #ifdef WEBNFS_ENABLED
1783 char uio_buf
[ UIO_SIZEOF(1) ];
1784 int linklen
, olen
= ndp
->ni_pathlen
;
1788 struct componentname
*cnp
= &ndp
->ni_cnd
;
1794 * Extract and set starting directory.
1796 error
= nfsrv_fhtovp(nfhp
, nam
, pubflag
, &dp
, nxp
, nxop
);
1799 error
= nfsrv_credcheck(nfsd
, *nxp
, *nxop
);
1800 if (error
|| (vnode_vtype(dp
) != VDIR
)) {
1806 ctx
->vc_ucred
= nfsd
->nd_cr
;
1807 ndp
->ni_cnd
.cn_context
= ctx
;
1809 if (*nxop
&& ((*nxop
)->nxo_flags
& NX_READONLY
))
1810 cnp
->cn_flags
|= RDONLY
;
1814 /* XXX Revisit when enabling WebNFS */
1815 #ifdef WEBNFS_ENABLED
1817 ndp
->ni_rootdir
= rootvnode
;
1818 ndp
->ni_loopcnt
= 0;
1819 if (cnp
->cn_pnbuf
[0] == '/') {
1822 error
= vnode_get(dp
);
1829 cnp
->cn_flags
|= NOCROSSMOUNT
;
1832 cnp
->cn_flags
|= NOCROSSMOUNT
;
1835 ndp
->ni_usedvp
= dp
;
1838 cnp
->cn_nameptr
= cnp
->cn_pnbuf
;
1839 ndp
->ni_startdir
= dp
;
1841 * And call lookup() to do the real work
1843 error
= lookup(ndp
);
1847 * Check for encountering a symbolic link
1849 if ((cnp
->cn_flags
& ISSYMLINK
) == 0) {
1852 if ((cnp
->cn_flags
& FSNODELOCKHELD
)) {
1853 cnp
->cn_flags
&= ~FSNODELOCKHELD
;
1854 unlock_fsnode(ndp
->ni_dvp
, NULL
);
1856 /* XXX Revisit when enabling WebNFS */
1857 #ifdef WEBNFS_ENABLED
1860 if (cnp
->cn_flags
& (LOCKPARENT
| WANTPARENT
))
1861 vnode_put(ndp
->ni_dvp
);
1863 vnode_put(ndp
->ni_vp
);
1868 /* XXX Revisit when enabling WebNFS */
1869 #ifdef WEBNFS_ENABLED
1872 if (ndp
->ni_loopcnt
++ >= MAXSYMLINKS
) {
1873 vnode_put(ndp
->ni_vp
);
1878 /* XXX assert(olen <= MAXPATHLEN - 1); */
1879 if (ndp
->ni_pathlen
> 1) {
1880 MALLOC_ZONE(cp
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1882 vnode_put(ndp
->ni_vp
);
1890 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
1891 &uio_buf
[0], sizeof(uio_buf
));
1893 vnode_put(ndp
->ni_vp
);
1895 if (ndp
->ni_pathlen
> 1)
1896 FREE_ZONE(cp
, MAXPATHLEN
, M_NAMEI
);
1900 uio_addiov(auio
, CAST_USER_ADDR_T(cp
), MAXPATHLEN
);
1901 error
= VNOP_READLINK(ndp
->ni_vp
, auio
, cnp
->cn_context
);
1904 vnode_put(ndp
->ni_vp
);
1906 if (ndp
->ni_pathlen
> 1)
1907 FREE_ZONE(cp
, MAXPATHLEN
, M_NAMEI
);
1910 linklen
= MAXPATHLEN
- uio_resid(auio
);
1915 if (linklen
+ ndp
->ni_pathlen
>= MAXPATHLEN
) {
1916 error
= ENAMETOOLONG
;
1919 if (ndp
->ni_pathlen
> 1) {
1920 long len
= cnp
->cn_pnlen
;
1921 tmppn
= cnp
->cn_pnbuf
;
1923 cnp
->cn_pnlen
= olen
+ 1;
1924 bcopy(ndp
->ni_next
, cp
+ linklen
, ndp
->ni_pathlen
);
1925 FREE_ZONE(tmppn
, len
, M_NAMEI
);
1927 cnp
->cn_pnbuf
[linklen
] = '\0';
1928 ndp
->ni_pathlen
+= linklen
;
1930 vnode_put(ndp
->ni_vp
);
1935 * Check if root directory should replace current directory.
1937 if (cnp
->cn_pnbuf
[0] == '/') {
1939 dp
= ndp
->ni_rootdir
;
1940 error
= vnode_get(dp
);
1948 tmppn
= cnp
->cn_pnbuf
;
1949 cnp
->cn_pnbuf
= NULL
;
1950 cnp
->cn_flags
&= ~HASBUF
;
1951 FREE_ZONE(tmppn
, cnp
->cn_pnlen
, M_NAMEI
);
1957 * A fiddled version of m_adj() that ensures null fill to a long
1958 * boundary and only trims off the back end
1961 nfsm_adj(mp
, len
, nul
)
1971 * Trim from tail. Scan the mbuf chain,
1972 * calculating its length and finding the last mbuf.
1973 * If the adjustment only affects this mbuf, then just
1974 * adjust and return. Otherwise, rescan and truncate
1975 * after the remaining size.
1982 mnext
= mbuf_next(m
);
1989 mbuf_setlen(m
, mlen
);
1991 cp
= (caddr_t
)mbuf_data(m
) + mlen
- nul
;
1992 for (i
= 0; i
< nul
; i
++)
2001 * Correct length for chain is "count".
2002 * Find the mbuf with last data, adjust its length,
2003 * and toss data from remaining mbufs on chain.
2005 for (m
= mp
; m
; m
= mbuf_next(m
)) {
2007 if (mlen
>= count
) {
2009 mbuf_setlen(m
, count
);
2011 cp
= (caddr_t
)mbuf_data(m
) + mlen
- nul
;
2012 for (i
= 0; i
< nul
; i
++)
2019 for (m
= mbuf_next(m
); m
; m
= mbuf_next(m
))
2024 * Make these functions instead of macros, so that the kernel text size
2025 * doesn't get too big...
2028 nfsm_srvwcc(nfsd
, before_ret
, before_vap
, after_ret
, after_vap
, mbp
, bposp
)
2029 struct nfsrv_descript
*nfsd
;
2031 struct vnode_attr
*before_vap
;
2033 struct vnode_attr
*after_vap
;
2037 mbuf_t mb
= *mbp
, mb2
;
2038 char *bpos
= *bposp
;
2042 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
2045 nfsm_build(tl
, u_long
*, 7 * NFSX_UNSIGNED
);
2047 txdr_hyper(&(before_vap
->va_data_size
), tl
);
2049 txdr_nfsv3time(&(before_vap
->va_modify_time
), tl
);
2051 txdr_nfsv3time(&(before_vap
->va_change_time
), tl
);
2055 nfsm_srvpostopattr(nfsd
, after_ret
, after_vap
, mbp
, bposp
);
2059 nfsm_srvpostopattr(nfsd
, after_ret
, after_vap
, mbp
, bposp
)
2060 struct nfsrv_descript
*nfsd
;
2062 struct vnode_attr
*after_vap
;
2066 mbuf_t mb
= *mbp
, mb2
;
2067 char *bpos
= *bposp
;
2069 struct nfs_fattr
*fp
;
2072 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
2075 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
+ NFSX_V3FATTR
);
2077 fp
= (struct nfs_fattr
*)tl
;
2078 nfsm_srvfattr(nfsd
, after_vap
, fp
);
2085 nfsm_srvfattr(nfsd
, vap
, fp
)
2086 struct nfsrv_descript
*nfsd
;
2087 struct vnode_attr
*vap
;
2088 struct nfs_fattr
*fp
;
2091 // XXX Should we assert here that all fields are supported?
2093 fp
->fa_nlink
= txdr_unsigned(vap
->va_nlink
);
2094 fp
->fa_uid
= txdr_unsigned(vap
->va_uid
);
2095 fp
->fa_gid
= txdr_unsigned(vap
->va_gid
);
2096 if (nfsd
->nd_flag
& ND_NFSV3
) {
2097 fp
->fa_type
= vtonfsv3_type(vap
->va_type
);
2098 fp
->fa_mode
= vtonfsv3_mode(vap
->va_mode
);
2099 txdr_hyper(&vap
->va_data_size
, &fp
->fa3_size
);
2100 txdr_hyper(&vap
->va_data_alloc
, &fp
->fa3_used
);
2101 fp
->fa3_rdev
.specdata1
= txdr_unsigned(major(vap
->va_rdev
));
2102 fp
->fa3_rdev
.specdata2
= txdr_unsigned(minor(vap
->va_rdev
));
2103 fp
->fa3_fsid
.nfsuquad
[0] = 0;
2104 fp
->fa3_fsid
.nfsuquad
[1] = txdr_unsigned(vap
->va_fsid
);
2105 txdr_hyper(&vap
->va_fileid
, &fp
->fa3_fileid
);
2106 txdr_nfsv3time(&vap
->va_access_time
, &fp
->fa3_atime
);
2107 txdr_nfsv3time(&vap
->va_modify_time
, &fp
->fa3_mtime
);
2108 txdr_nfsv3time(&vap
->va_change_time
, &fp
->fa3_ctime
);
2110 fp
->fa_type
= vtonfsv2_type(vap
->va_type
);
2111 fp
->fa_mode
= vtonfsv2_mode(vap
->va_type
, vap
->va_mode
);
2112 fp
->fa2_size
= txdr_unsigned(vap
->va_data_size
);
2113 fp
->fa2_blocksize
= txdr_unsigned(vap
->va_iosize
);
2114 if (vap
->va_type
== VFIFO
)
2115 fp
->fa2_rdev
= 0xffffffff;
2117 fp
->fa2_rdev
= txdr_unsigned(vap
->va_rdev
);
2118 fp
->fa2_blocks
= txdr_unsigned(vap
->va_data_alloc
/ NFS_FABLKSIZE
);
2119 fp
->fa2_fsid
= txdr_unsigned(vap
->va_fsid
);
2120 fp
->fa2_fileid
= txdr_unsigned(vap
->va_fileid
);
2121 txdr_nfsv2time(&vap
->va_access_time
, &fp
->fa2_atime
);
2122 txdr_nfsv2time(&vap
->va_modify_time
, &fp
->fa2_mtime
);
2123 txdr_nfsv2time(&vap
->va_change_time
, &fp
->fa2_ctime
);
2128 * Build hash lists of net addresses and hang them off the NFS export.
2129 * Called by nfsrv_export() to set up the lists of export addresses.
2132 nfsrv_hang_addrlist(struct nfs_export
*nx
, struct user_nfs_export_args
*unxa
)
2134 struct nfs_export_net_args nxna
;
2135 struct nfs_netopt
*no
;
2136 struct radix_node_head
*rnh
;
2137 struct radix_node
*rn
;
2138 struct sockaddr
*saddr
, *smask
;
2144 struct ucred temp_cred
;
2146 uaddr
= unxa
->nxa_nets
;
2147 for (net
= 0; net
< unxa
->nxa_netcount
; net
++, uaddr
+= sizeof(nxna
)) {
2148 error
= copyin(uaddr
, &nxna
, sizeof(nxna
));
2152 if (nxna
.nxna_flags
& (NX_MAPROOT
|NX_MAPALL
)) {
2153 bzero(&temp_cred
, sizeof(temp_cred
));
2154 temp_cred
.cr_uid
= nxna
.nxna_cred
.cr_uid
;
2155 temp_cred
.cr_ngroups
= nxna
.nxna_cred
.cr_ngroups
;
2156 for (i
=0; i
< nxna
.nxna_cred
.cr_ngroups
&& i
< NGROUPS
; i
++)
2157 temp_cred
.cr_groups
[i
] = nxna
.nxna_cred
.cr_groups
[i
];
2159 cred
= kauth_cred_create(&temp_cred
);
2166 if (nxna
.nxna_addr
.ss_len
== 0) {
2167 /* No address means this is a default/world export */
2168 if (nx
->nx_flags
& NX_DEFAULTEXPORT
)
2170 nx
->nx_flags
|= NX_DEFAULTEXPORT
;
2171 nx
->nx_defopt
.nxo_flags
= nxna
.nxna_flags
;
2172 nx
->nx_defopt
.nxo_cred
= cred
;
2177 i
= sizeof(struct nfs_netopt
);
2178 i
+= nxna
.nxna_addr
.ss_len
+ nxna
.nxna_mask
.ss_len
;
2179 MALLOC(no
, struct nfs_netopt
*, i
, M_NETADDR
, M_WAITOK
);
2182 bzero(no
, sizeof(struct nfs_netopt
));
2183 no
->no_opt
.nxo_flags
= nxna
.nxna_flags
;
2184 no
->no_opt
.nxo_cred
= cred
;
2186 saddr
= (struct sockaddr
*)(no
+ 1);
2187 bcopy(&nxna
.nxna_addr
, saddr
, nxna
.nxna_addr
.ss_len
);
2188 if (nxna
.nxna_mask
.ss_len
) {
2189 smask
= (struct sockaddr
*)((caddr_t
)saddr
+ nxna
.nxna_addr
.ss_len
);
2190 bcopy(&nxna
.nxna_mask
, smask
, nxna
.nxna_mask
.ss_len
);
2194 i
= saddr
->sa_family
;
2195 if ((rnh
= nx
->nx_rtable
[i
]) == 0) {
2197 * Seems silly to initialize every AF when most are not
2198 * used, do so on demand here
2200 for (dom
= domains
; dom
; dom
= dom
->dom_next
)
2201 if (dom
->dom_family
== i
&& dom
->dom_rtattach
) {
2202 dom
->dom_rtattach((void **)&nx
->nx_rtable
[i
],
2206 if ((rnh
= nx
->nx_rtable
[i
]) == 0) {
2207 kauth_cred_rele(cred
);
2208 _FREE(no
, M_NETADDR
);
2212 rn
= (*rnh
->rnh_addaddr
)((caddr_t
)saddr
, (caddr_t
)smask
, rnh
, no
->no_rnodes
);
2215 * One of the reasons that rnh_addaddr may fail is that
2216 * the entry already exists. To check for this case, we
2217 * look up the entry to see if it is there. If so, we
2218 * do not need to make a new entry but do continue.
2221 rn
= (*rnh
->rnh_matchaddr
)((caddr_t
)saddr
, rnh
);
2222 if (rn
!= 0 && (rn
->rn_flags
& RNF_ROOT
) == 0 &&
2223 (((struct nfs_netopt
*)rn
)->no_opt
.nxo_flags
== nxna
.nxna_flags
)) {
2224 kauth_cred_t cred2
= ((struct nfs_netopt
*)rn
)->no_opt
.nxo_cred
;
2225 if (cred
&& cred2
&& (cred
->cr_uid
== cred2
->cr_uid
) &&
2226 (cred
->cr_ngroups
== cred2
->cr_ngroups
)) {
2227 for (i
=0; i
< cred2
->cr_ngroups
&& i
< NGROUPS
; i
++)
2228 if (cred
->cr_groups
[i
] != cred2
->cr_groups
[i
])
2230 if (i
>= cred2
->cr_ngroups
|| i
>= NGROUPS
)
2234 kauth_cred_rele(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 (nno
->no_opt
.nxo_cred
)
2266 kauth_cred_rele(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 (nx
->nx_defopt
.nxo_cred
) {
2322 kauth_cred_rele(nx
->nx_defopt
.nxo_cred
);
2323 nx
->nx_defopt
.nxo_cred
= NULL
;
2325 FREE(nx
->nx_path
, M_TEMP
);
2328 LIST_REMOVE(nxfs
, nxfs_next
);
2329 FREE(nxfs
->nxfs_path
, M_TEMP
);
2332 lck_rw_done(&nfs_export_rwlock
);
2336 error
= copyinstr(unxa
->nxa_fspath
, path
, MAXPATHLEN
, (size_t *)&pathlen
);
2340 lck_rw_lock_exclusive(&nfs_export_rwlock
);
2342 // first check if we've already got an exportfs with the given ID
2343 LIST_FOREACH(nxfs
, &nfs_exports
, nxfs_next
) {
2344 if (nxfs
->nxfs_id
== unxa
->nxa_fsid
)
2348 /* verify exported FS path matches given path */
2349 if (strcmp(path
, nxfs
->nxfs_path
)) {
2353 mp
= vfs_getvfs_by_mntonname(nxfs
->nxfs_path
);
2354 /* find exported FS root vnode */
2355 NDINIT(&mnd
, LOOKUP
, FOLLOW
| LOCKLEAF
| AUDITVNPATH1
,
2356 UIO_SYSSPACE
, nxfs
->nxfs_path
, ctx
);
2357 error
= namei(&mnd
);
2361 /* make sure it's (still) the root of a file system */
2362 if ((mvp
->v_flag
& VROOT
) == 0) {
2366 /* sanity check: this should be same mount */
2367 if (mp
!= vnode_mount(mvp
)) {
2372 /* no current exported file system with that ID */
2373 if (!(unxa
->nxa_flags
& NXA_ADD
)) {
2378 /* find exported FS root vnode */
2379 NDINIT(&mnd
, LOOKUP
, FOLLOW
| LOCKLEAF
| AUDITVNPATH1
,
2380 UIO_SYSSPACE
, path
, ctx
);
2381 error
= namei(&mnd
);
2385 /* make sure it's the root of a file system */
2386 if ((mvp
->v_flag
& VROOT
) == 0) {
2390 mp
= vnode_mount(mvp
);
2392 /* make sure the file system is NFS-exportable */
2393 nfh
.nfh_len
= NFS_MAX_FID_SIZE
;
2394 error
= VFS_VPTOFH(mvp
, &nfh
.nfh_len
, &nfh
.nfh_fid
[0], NULL
);
2395 if (!error
&& (nfh
.nfh_len
> (int)NFS_MAX_FID_SIZE
))
2400 /* add an exportfs for it */
2401 MALLOC(nxfs
, struct nfs_exportfs
*, sizeof(struct nfs_exportfs
), M_TEMP
, M_WAITOK
);
2406 bzero(nxfs
, sizeof(struct nfs_exportfs
));
2407 nxfs
->nxfs_id
= unxa
->nxa_fsid
;
2408 MALLOC(nxfs
->nxfs_path
, char*, pathlen
, M_TEMP
, M_WAITOK
);
2409 if (!nxfs
->nxfs_path
) {
2414 bcopy(path
, nxfs
->nxfs_path
, pathlen
);
2415 /* insert into list in reverse-sorted order */
2417 LIST_FOREACH(nxfs2
, &nfs_exports
, nxfs_next
) {
2418 if (strcmp(nxfs
->nxfs_path
, nxfs2
->nxfs_path
) > 0)
2423 LIST_INSERT_BEFORE(nxfs2
, nxfs
, nxfs_next
);
2425 LIST_INSERT_AFTER(nxfs3
, nxfs
, nxfs_next
);
2427 LIST_INSERT_HEAD(&nfs_exports
, nxfs
, nxfs_next
);
2429 /* make sure any quotas are enabled before we export the file system */
2430 enablequotas(mp
, ctx
);
2433 if (unxa
->nxa_exppath
) {
2434 error
= copyinstr(unxa
->nxa_exppath
, path
, MAXPATHLEN
, (size_t *)&pathlen
);
2437 LIST_FOREACH(nx
, &nxfs
->nxfs_exports
, nx_next
) {
2438 if (nx
->nx_id
== unxa
->nxa_expid
)
2442 /* verify exported FS path matches given path */
2443 if (strcmp(path
, nx
->nx_path
)) {
2448 /* no current export with that ID */
2449 if (!(unxa
->nxa_flags
& NXA_ADD
)) {
2453 /* add an export for it */
2454 MALLOC(nx
, struct nfs_export
*, sizeof(struct nfs_export
), M_TEMP
, M_WAITOK
);
2459 bzero(nx
, sizeof(struct nfs_export
));
2460 nx
->nx_id
= unxa
->nxa_expid
;
2462 MALLOC(nx
->nx_path
, char*, pathlen
, M_TEMP
, M_WAITOK
);
2469 bcopy(path
, nx
->nx_path
, pathlen
);
2470 /* insert into list in reverse-sorted order */
2472 LIST_FOREACH(nx2
, &nxfs
->nxfs_exports
, nx_next
) {
2473 if (strcmp(nx
->nx_path
, nx2
->nx_path
) > 0)
2478 LIST_INSERT_BEFORE(nx2
, nx
, nx_next
);
2480 LIST_INSERT_AFTER(nx3
, nx
, nx_next
);
2482 LIST_INSERT_HEAD(&nxfs
->nxfs_exports
, nx
, nx_next
);
2483 /* insert into hash */
2484 LIST_INSERT_HEAD(NFSEXPHASH(nxfs
->nxfs_id
, nx
->nx_id
), nx
, nx_hash
);
2487 * We don't allow nested exports. Check if the new entry
2488 * nests with the entries before and after or if there's an
2489 * entry for the file system root and subdirs.
2492 if ((nx3
&& !strncmp(nx3
->nx_path
, nx
->nx_path
, pathlen
- 1) &&
2493 (nx3
->nx_path
[pathlen
-1] == '/')) ||
2494 (nx2
&& !strncmp(nx2
->nx_path
, nx
->nx_path
, strlen(nx2
->nx_path
)) &&
2495 (nx
->nx_path
[strlen(nx2
->nx_path
)] == '/')))
2498 /* check export conflict with fs root export and vice versa */
2499 expisroot
= !nx
->nx_path
[0] ||
2500 ((nx
->nx_path
[0] == '.') && !nx
->nx_path
[1]);
2501 LIST_FOREACH(nx2
, &nxfs
->nxfs_exports
, nx_next
) {
2505 } else if (!nx2
->nx_path
[0])
2507 else if ((nx2
->nx_path
[0] == '.') && !nx2
->nx_path
[1])
2514 printf("nfsrv_export: attempt to register nested exports: %s/%s\n",
2515 nxfs
->nxfs_path
, nx
->nx_path
);
2519 /* find export root vnode */
2520 if (!nx
->nx_path
[0] || ((nx
->nx_path
[0] == '.') && !nx
->nx_path
[1])) {
2521 /* exporting file system's root directory */
2525 xnd
.ni_cnd
.cn_nameiop
= LOOKUP
;
2526 xnd
.ni_cnd
.cn_flags
= LOCKLEAF
;
2527 xnd
.ni_pathlen
= pathlen
- 1;
2528 xnd
.ni_cnd
.cn_nameptr
= xnd
.ni_cnd
.cn_pnbuf
= path
;
2529 xnd
.ni_startdir
= mvp
;
2530 xnd
.ni_usedvp
= mvp
;
2531 xnd
.ni_cnd
.cn_context
= ctx
;
2532 error
= lookup(&xnd
);
2538 if (vnode_vtype(xvp
) != VDIR
) {
2544 /* grab file handle */
2545 nx
->nx_fh
.nfh_xh
.nxh_version
= NFS_FH_VERSION
;
2546 nx
->nx_fh
.nfh_xh
.nxh_fsid
= nx
->nx_fs
->nxfs_id
;
2547 nx
->nx_fh
.nfh_xh
.nxh_expid
= nx
->nx_id
;
2548 nx
->nx_fh
.nfh_xh
.nxh_flags
= 0;
2549 nx
->nx_fh
.nfh_xh
.nxh_reserved
= 0;
2550 nx
->nx_fh
.nfh_len
= NFS_MAX_FID_SIZE
;
2551 error
= VFS_VPTOFH(xvp
, &nx
->nx_fh
.nfh_len
, &nx
->nx_fh
.nfh_fid
[0], NULL
);
2552 if (!error
&& (nx
->nx_fh
.nfh_len
> (int)NFS_MAX_FID_SIZE
)) {
2555 nx
->nx_fh
.nfh_xh
.nxh_fidlen
= nx
->nx_fh
.nfh_len
;
2556 nx
->nx_fh
.nfh_len
+= sizeof(nx
->nx_fh
.nfh_xh
);
2567 /* perform the export changes */
2568 if (unxa
->nxa_flags
& NXA_DELETE
) {
2570 /* delete all exports on this file system */
2571 while ((nx
= LIST_FIRST(&nxfs
->nxfs_exports
))) {
2572 LIST_REMOVE(nx
, nx_next
);
2573 LIST_REMOVE(nx
, nx_hash
);
2574 /* delete all netopts for this export */
2575 nfsrv_free_addrlist(nx
);
2576 nx
->nx_flags
&= ~NX_DEFAULTEXPORT
;
2577 if (nx
->nx_defopt
.nxo_cred
) {
2578 kauth_cred_rele(nx
->nx_defopt
.nxo_cred
);
2579 nx
->nx_defopt
.nxo_cred
= NULL
;
2581 FREE(nx
->nx_path
, M_TEMP
);
2586 /* delete all netopts for this export */
2587 nfsrv_free_addrlist(nx
);
2588 nx
->nx_flags
&= ~NX_DEFAULTEXPORT
;
2589 if (nx
->nx_defopt
.nxo_cred
) {
2590 kauth_cred_rele(nx
->nx_defopt
.nxo_cred
);
2591 nx
->nx_defopt
.nxo_cred
= NULL
;
2595 if (unxa
->nxa_flags
& NXA_ADD
) {
2596 error
= nfsrv_hang_addrlist(nx
, unxa
);
2598 mp
->mnt_flag
|= MNT_EXPORTED
;
2602 if (nx
&& !nx
->nx_expcnt
) {
2603 /* export has no export options */
2604 LIST_REMOVE(nx
, nx_next
);
2605 LIST_REMOVE(nx
, nx_hash
);
2606 FREE(nx
->nx_path
, M_TEMP
);
2609 if (LIST_EMPTY(&nxfs
->nxfs_exports
)) {
2610 /* exported file system has no more exports */
2611 LIST_REMOVE(nxfs
, nxfs_next
);
2612 FREE(nxfs
->nxfs_path
, M_TEMP
);
2614 mp
->mnt_flag
&= ~MNT_EXPORTED
;
2623 lck_rw_done(&nfs_export_rwlock
);
2627 static struct nfs_export_options
*
2628 nfsrv_export_lookup(struct nfs_export
*nx
, mbuf_t nam
)
2630 struct nfs_export_options
*nxo
= NULL
;
2631 struct nfs_netopt
*no
= NULL
;
2632 struct radix_node_head
*rnh
;
2633 struct sockaddr
*saddr
;
2635 /* Lookup in the export list first. */
2637 saddr
= mbuf_data(nam
);
2638 rnh
= nx
->nx_rtable
[saddr
->sa_family
];
2640 no
= (struct nfs_netopt
*)
2641 (*rnh
->rnh_matchaddr
)((caddr_t
)saddr
, rnh
);
2642 if (no
&& no
->no_rnodes
->rn_flags
& RNF_ROOT
)
2648 /* If no address match, use the default if it exists. */
2649 if ((nxo
== NULL
) && (nx
->nx_flags
& NX_DEFAULTEXPORT
))
2650 nxo
= &nx
->nx_defopt
;
2654 /* find an export for the given handle */
2655 static struct nfs_export
*
2656 nfsrv_fhtoexport(struct nfs_filehandle
*nfhp
)
2658 struct nfs_export
*nx
;
2659 nx
= NFSEXPHASH(nfhp
->nfh_xh
.nxh_fsid
, nfhp
->nfh_xh
.nxh_expid
)->lh_first
;
2660 for (; nx
; nx
= LIST_NEXT(nx
, nx_hash
)) {
2661 if (nx
->nx_fs
->nxfs_id
!= nfhp
->nfh_xh
.nxh_fsid
)
2663 if (nx
->nx_id
!= nfhp
->nfh_xh
.nxh_expid
)
2671 * nfsrv_fhtovp() - convert FH to vnode and export info
2675 struct nfs_filehandle
*nfhp
,
2677 __unused
int pubflag
,
2679 struct nfs_export
**nxp
,
2680 struct nfs_export_options
**nxop
)
2689 if (nfhp
->nfh_xh
.nxh_version
!= NFS_FH_VERSION
) {
2690 /* file handle format not supported */
2693 if (nfhp
->nfh_len
> NFS_MAX_FH_SIZE
)
2695 if (nfhp
->nfh_len
< (int)sizeof(nfhp
->nfh_xh
))
2697 if (nfhp
->nfh_xh
.nxh_flags
& NXHF_INVALIDFH
)
2700 /* XXX Revisit when enabling WebNFS */
2701 #ifdef WEBNFS_ENABLED
2702 if (nfs_ispublicfh(nfhp
)) {
2703 if (!pubflag
|| !nfs_pub
.np_valid
)
2705 nfhp
= &nfs_pub
.np_handle
;
2709 *nxp
= nfsrv_fhtoexport(nfhp
);
2713 /* Get the export option structure for this <export, client> tuple. */
2714 *nxop
= nfsrv_export_lookup(*nxp
, nam
);
2715 if (nam
&& (*nxop
== NULL
))
2718 /* find mount structure */
2719 mp
= vfs_getvfs_by_mntonname((*nxp
)->nx_fs
->nxfs_path
);
2723 error
= VFS_FHTOVP(mp
, nfhp
->nfh_xh
.nxh_fidlen
, &nfhp
->nfh_fid
[0], vpp
, NULL
);
2726 /* vnode pointer should be good at this point or ... */
2733 * nfsrv_credcheck() - check/map credentials according to given export options
2737 struct nfsrv_descript
*nfsd
,
2738 __unused
struct nfs_export
*nx
,
2739 struct nfs_export_options
*nxo
)
2741 if (nxo
&& nxo
->nxo_cred
) {
2742 if ((nxo
->nxo_flags
& NX_MAPALL
) ||
2743 ((nxo
->nxo_flags
& NX_MAPROOT
) && !suser(nfsd
->nd_cr
, NULL
))) {
2744 kauth_cred_rele(nfsd
->nd_cr
);
2745 nfsd
->nd_cr
= nxo
->nxo_cred
;
2746 kauth_cred_ref(nfsd
->nd_cr
);
2754 * WebNFS: check if a filehandle is a public filehandle. For v3, this
2755 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
2756 * transformed this to all zeroes in both cases, so check for it.
2759 nfs_ispublicfh(struct nfs_filehandle
*nfhp
)
2761 char *cp
= (char *)nfhp
;
2764 if (nfhp
->nfh_len
== 0)
2766 if (nfhp
->nfh_len
!= NFSX_V2FH
)
2768 for (i
= 0; i
< NFSX_V2FH
; i
++)
2775 * nfsrv_vptofh() - convert vnode to file handle for given export
2777 * If the caller is passing in a vnode for a ".." directory entry,
2778 * they can pass a directory NFS file handle (dnfhp) which will be
2779 * checked against the root export file handle. If it matches, we
2780 * refuse to provide the file handle for the out-of-export directory.
2784 struct nfs_export
*nx
,
2786 struct nfs_filehandle
*dnfhp
,
2788 struct vfs_context
*ctx
,
2789 struct nfs_filehandle
*nfhp
)
2793 nfhp
->nfh_xh
.nxh_version
= NFS_FH_VERSION
;
2794 nfhp
->nfh_xh
.nxh_fsid
= nx
->nx_fs
->nxfs_id
;
2795 nfhp
->nfh_xh
.nxh_expid
= nx
->nx_id
;
2796 nfhp
->nfh_xh
.nxh_flags
= 0;
2797 nfhp
->nfh_xh
.nxh_reserved
= 0;
2800 bzero(&nfhp
->nfh_fid
[0], NFSV2_MAX_FID_SIZE
);
2802 /* if directory FH matches export root, return invalid FH */
2803 if (dnfhp
&& nfsrv_fhmatch(dnfhp
, &nx
->nx_fh
)) {
2804 nfhp
->nfh_len
= v2
? NFSX_V2FH
: sizeof(nfhp
->nfh_xh
);
2805 nfhp
->nfh_xh
.nxh_fidlen
= 0;
2806 nfhp
->nfh_xh
.nxh_flags
= NXHF_INVALIDFH
;
2810 nfhp
->nfh_len
= v2
? NFSV2_MAX_FID_SIZE
: NFS_MAX_FID_SIZE
;
2811 error
= VFS_VPTOFH(vp
, &nfhp
->nfh_len
, &nfhp
->nfh_fid
[0], ctx
);
2814 if (nfhp
->nfh_len
> (int)(v2
? NFSV2_MAX_FID_SIZE
: NFS_MAX_FID_SIZE
))
2816 nfhp
->nfh_xh
.nxh_fidlen
= nfhp
->nfh_len
;
2817 nfhp
->nfh_len
+= sizeof(nfhp
->nfh_xh
);
2818 if (v2
&& (nfhp
->nfh_len
< NFSX_V2FH
))
2819 nfhp
->nfh_len
= NFSX_V2FH
;
2825 nfsrv_fhmatch(struct nfs_filehandle
*fh1
, struct nfs_filehandle
*fh2
)
2829 len1
= sizeof(fh1
->nfh_xh
) + fh1
->nfh_xh
.nxh_fidlen
;
2830 len2
= sizeof(fh2
->nfh_xh
) + fh2
->nfh_xh
.nxh_fidlen
;
2833 if (bcmp(&fh1
->nfh_xh
, &fh2
->nfh_xh
, len1
))
2838 #endif /* NFS_NOSERVER */
2840 * This function compares two net addresses by family and returns TRUE
2841 * if they are the same host.
2842 * If there is any doubt, return FALSE.
2843 * The AF_INET family is handled as a special case so that address mbufs
2844 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
2847 netaddr_match(family
, haddr
, nam
)
2849 union nethostaddr
*haddr
;
2852 struct sockaddr_in
*inetaddr
;
2856 inetaddr
= mbuf_data(nam
);
2857 if (inetaddr
->sin_family
== AF_INET
&&
2858 inetaddr
->sin_addr
.s_addr
== haddr
->had_inetaddr
)
2864 struct sockaddr_iso
*isoaddr1
, *isoaddr2
;
2866 isoaddr1
= mbuf_data(nam
);
2867 isoaddr2
= mbuf_data(haddr
->had_nam
);
2868 if (isoaddr1
->siso_family
== AF_ISO
&&
2869 isoaddr1
->siso_nlen
> 0 &&
2870 isoaddr1
->siso_nlen
== isoaddr2
->siso_nlen
&&
2871 SAME_ISOADDR(isoaddr1
, isoaddr2
))
2882 static nfsuint64 nfs_nullcookie
= { { 0, 0 } };
2884 * This function finds the directory cookie that corresponds to the
2885 * logical byte offset given.
2888 nfs_getcookie(np
, off
, add
)
2893 struct nfsdmap
*dp
, *dp2
;
2896 pos
= off
/ NFS_DIRBLKSIZ
;
2900 panic("nfs getcookie add at 0");
2902 return (&nfs_nullcookie
);
2905 dp
= np
->n_cookies
.lh_first
;
2908 MALLOC_ZONE(dp
, struct nfsdmap
*, sizeof(struct nfsdmap
),
2909 M_NFSDIROFF
, M_WAITOK
);
2911 return ((nfsuint64
*)0);
2912 dp
->ndm_eocookie
= 0;
2913 LIST_INSERT_HEAD(&np
->n_cookies
, dp
, ndm_list
);
2915 return ((nfsuint64
*)0);
2917 while (pos
>= NFSNUMCOOKIES
) {
2918 pos
-= NFSNUMCOOKIES
;
2919 if (dp
->ndm_list
.le_next
) {
2920 if (!add
&& dp
->ndm_eocookie
< NFSNUMCOOKIES
&&
2921 pos
>= dp
->ndm_eocookie
)
2922 return ((nfsuint64
*)0);
2923 dp
= dp
->ndm_list
.le_next
;
2925 MALLOC_ZONE(dp2
, struct nfsdmap
*, sizeof(struct nfsdmap
),
2926 M_NFSDIROFF
, M_WAITOK
);
2928 return ((nfsuint64
*)0);
2929 dp2
->ndm_eocookie
= 0;
2930 LIST_INSERT_AFTER(dp
, dp2
, ndm_list
);
2933 return ((nfsuint64
*)0);
2935 if (pos
>= dp
->ndm_eocookie
) {
2937 dp
->ndm_eocookie
= pos
+ 1;
2939 return ((nfsuint64
*)0);
2941 return (&dp
->ndm_cookies
[pos
]);
2945 * Invalidate cached directory information, except for the actual directory
2946 * blocks (which are invalidated separately).
2947 * Done mainly to avoid the use of stale offset cookies.
2953 struct nfsnode
*np
= VTONFS(vp
);
2956 if (vnode_vtype(vp
) != VDIR
)
2957 panic("nfs: invaldir not dir");
2959 np
->n_direofoffset
= 0;
2960 np
->n_cookieverf
.nfsuquad
[0] = 0;
2961 np
->n_cookieverf
.nfsuquad
[1] = 0;
2962 if (np
->n_cookies
.lh_first
)
2963 np
->n_cookies
.lh_first
->ndm_eocookie
= 0;
2966 #ifndef NFS_NOSERVER
2968 * Map errnos to NFS error numbers. For Version 3 also filter out error
2969 * numbers not specified for the associated procedure.
2972 nfsrv_errmap(nd
, err
)
2973 struct nfsrv_descript
*nd
;
2976 short *defaulterrp
, *errp
;
2978 if (nd
->nd_flag
& ND_NFSV3
) {
2979 if (nd
->nd_procnum
<= NFSPROC_COMMIT
) {
2980 errp
= defaulterrp
= nfsrv_v3errmap
[nd
->nd_procnum
];
2984 else if (*errp
> err
)
2987 return ((int)*defaulterrp
);
2989 return (err
& 0xffff);
2992 return ((int)nfsrv_v2errmap
[err
- 1]);
2996 #endif /* NFS_NOSERVER */