2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
24 * Copyright (c) 1989, 1993
25 * The Regents of the University of California. All rights reserved.
27 * This code is derived from software contributed to Berkeley by
28 * Rick Macklem at The University of Guelph.
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by the University of
41 * California, Berkeley and its contributors.
42 * 4. Neither the name of the University nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95
59 * FreeBSD-Id: nfs_subs.c,v 1.47 1997/11/07 08:53:24 phk Exp $
63 * These functions support the macros and help fiddle mbuf chains for
64 * the nfs op functions. They do things like create the rpc header and
65 * copy data between mbuf chains and uio lists.
67 #include <sys/param.h>
69 #include <sys/systm.h>
70 #include <sys/kernel.h>
71 #include <sys/mount.h>
72 #include <sys/vnode.h>
73 #include <sys/namei.h>
75 #include <sys/socket.h>
77 #include <sys/malloc.h>
78 #include <sys/syscall.h>
79 #include <sys/sysctl.h>
81 #include <sys/fcntl.h>
84 #include <sys/vmparam.h>
85 #include <machine/spl.h>
90 #include <kern/clock.h>
92 #include <nfs/rpcv2.h>
93 #include <nfs/nfsproto.h>
95 #include <nfs/nfsnode.h>
96 #include <nfs/xdr_subs.h>
97 #include <nfs/nfsm_subs.h>
98 #include <nfs/nfsmount.h>
99 #include <nfs/nqnfs.h>
100 #include <nfs/nfsrtt.h>
101 #include <nfs/nfs_lock.h>
103 #include <miscfs/specfs/specdev.h>
105 #include <netinet/in.h>
107 #include <netiso/iso.h>
110 #include <sys/kdebug.h>
112 SYSCTL_DECL(_vfs_generic
);
113 SYSCTL_NODE(_vfs_generic
, OID_AUTO
, nfs
, CTLFLAG_RW
, 0, "nfs hinge");
115 #define FSDBG(A, B, C, D, E) \
116 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_NONE, \
117 (int)(B), (int)(C), (int)(D), (int)(E), 0)
118 #define FSDBG_TOP(A, B, C, D, E) \
119 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_START, \
120 (int)(B), (int)(C), (int)(D), (int)(E), 0)
121 #define FSDBG_BOT(A, B, C, D, E) \
122 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_END, \
123 (int)(B), (int)(C), (int)(D), (int)(E), 0)
125 * Data items converted to xdr at startup, since they are constant
126 * This is kinda hokey, but may save a little time doing byte swaps
129 u_long rpc_call
, rpc_vers
, rpc_reply
, rpc_msgdenied
, rpc_autherr
,
130 rpc_mismatch
, rpc_auth_unix
, rpc_msgaccepted
,
132 u_long nfs_prog
, nqnfs_prog
, nfs_true
, nfs_false
;
134 /* And other global data */
135 static u_long nfs_xid
= 0;
136 u_long nfs_xidwrap
= 0; /* to build a (non-wwrapping) 64 bit xid */
137 static enum vtype nv2tov_type
[8]= {
138 VNON
, VREG
, VDIR
, VBLK
, VCHR
, VLNK
, VNON
, VNON
140 enum vtype nv3tov_type
[8]= {
141 VNON
, VREG
, VDIR
, VBLK
, VCHR
, VLNK
, VSOCK
, VFIFO
147 struct nfs_reqq nfs_reqq
;
148 struct nfssvc_sockhead nfssvc_sockhead
;
149 int nfssvc_sockhead_flag
;
150 struct nfsd_head nfsd_head
;
152 struct nfs_bufq nfs_bufq
;
153 struct nqtimerhead nqtimerhead
;
154 struct nqfhhashhead
*nqfhhashtbl
;
159 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
161 int nfsv3_procid
[NFS_NPROCS
] = {
190 #endif /* NFS_NOSERVER */
192 * and the reverse mapping from generic to Version 2 procedure numbers
194 int nfsv2_procid
[NFS_NPROCS
] = {
225 * Maps errno values to nfs error numbers.
226 * Use NFSERR_IO as the catch all for ones not specifically defined in
229 static u_char nfsrv_v2errmap
[ELAST
] = {
230 NFSERR_PERM
, NFSERR_NOENT
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
231 NFSERR_NXIO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
232 NFSERR_IO
, NFSERR_IO
, NFSERR_ACCES
, NFSERR_IO
, NFSERR_IO
,
233 NFSERR_IO
, NFSERR_EXIST
, NFSERR_IO
, NFSERR_NODEV
, NFSERR_NOTDIR
,
234 NFSERR_ISDIR
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
235 NFSERR_IO
, NFSERR_FBIG
, NFSERR_NOSPC
, NFSERR_IO
, NFSERR_ROFS
,
236 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
237 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
238 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
239 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
240 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
241 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
242 NFSERR_IO
, NFSERR_IO
, NFSERR_NAMETOL
, NFSERR_IO
, NFSERR_IO
,
243 NFSERR_NOTEMPTY
, NFSERR_IO
, NFSERR_IO
, NFSERR_DQUOT
, NFSERR_STALE
,
244 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
245 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
246 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
250 * Maps errno values to nfs error numbers.
251 * Although it is not obvious whether or not NFS clients really care if
252 * a returned error value is in the specified list for the procedure, the
253 * safest thing to do is filter them appropriately. For Version 2, the
254 * X/Open XNFS document is the only specification that defines error values
255 * for each RPC (The RFC simply lists all possible error values for all RPCs),
256 * so I have decided to not do this for Version 2.
257 * The first entry is the default error return and the rest are the valid
258 * errors for that RPC in increasing numeric order.
260 static short nfsv3err_null
[] = {
265 static short nfsv3err_getattr
[] = {
274 static short nfsv3err_setattr
[] = {
290 static short nfsv3err_lookup
[] = {
303 static short nfsv3err_access
[] = {
312 static short nfsv3err_readlink
[] = {
324 static short nfsv3err_read
[] = {
336 static short nfsv3err_write
[] = {
351 static short nfsv3err_create
[] = {
368 static short nfsv3err_mkdir
[] = {
385 static short nfsv3err_symlink
[] = {
402 static short nfsv3err_mknod
[] = {
420 static short nfsv3err_remove
[] = {
434 static short nfsv3err_rmdir
[] = {
452 static short nfsv3err_rename
[] = {
475 static short nfsv3err_link
[] = {
495 static short nfsv3err_readdir
[] = {
508 static short nfsv3err_readdirplus
[] = {
522 static short nfsv3err_fsstat
[] = {
531 static short nfsv3err_fsinfo
[] = {
539 static short nfsv3err_pathconf
[] = {
547 static short nfsv3err_commit
[] = {
556 static short *nfsrv_v3errmap
[] = {
574 nfsv3err_readdirplus
,
581 #endif /* NFS_NOSERVER */
583 extern struct nfsrtt nfsrtt
;
584 extern time_t nqnfsstarttime
;
585 extern int nqsrv_clockskew
;
586 extern int nqsrv_writeslack
;
587 extern int nqsrv_maxlease
;
588 extern struct nfsstats nfsstats
;
589 extern int nqnfs_piggy
[NFS_NPROCS
];
590 extern nfstype nfsv2_type
[9];
591 extern nfstype nfsv3_type
[9];
592 extern struct nfsnodehashhead
*nfsnodehashtbl
;
593 extern u_long nfsnodehash
;
596 LIST_HEAD(nfsnodehashhead
, nfsnode
);
599 * Create the header for an rpc request packet
600 * The hsiz is the size of the rest of the nfs request header.
601 * (just used to decide if a cluster is a good idea)
604 nfsm_reqh(vp
, procid
, hsiz
, bposp
)
610 register struct mbuf
*mb
;
612 register caddr_t bpos
;
614 struct nfsmount
*nmp
;
617 MGET(mb
, M_WAIT
, MT_DATA
);
618 if (hsiz
>= MINCLSIZE
)
621 bpos
= mtod(mb
, caddr_t
);
624 * For NQNFS, add lease request.
627 nmp
= VFSTONFS(vp
->v_mount
);
628 if (nmp
&& (nmp
->nm_flag
& NFSMNT_NQNFS
)) {
629 nqflag
= NQNFS_NEEDLEASE(vp
, procid
);
631 nfsm_build(tl
, u_long
*, 2*NFSX_UNSIGNED
);
632 *tl
++ = txdr_unsigned(nqflag
);
633 *tl
= txdr_unsigned(nmp
->nm_leaseterm
);
635 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
640 /* Finally, return values */
646 * Build the RPC header and fill in the authorization info.
647 * The authorization string argument is only used when the credentials
648 * come from outside of the kernel.
649 * Returns the head of the mbuf list.
652 nfsm_rpchead(cr
, nmflag
, procid
, auth_type
, auth_len
, auth_str
, verf_len
,
653 verf_str
, mrest
, mrest_len
, mbp
, xidp
)
654 register struct ucred
*cr
;
667 register struct mbuf
*mb
;
669 register caddr_t bpos
;
671 struct mbuf
*mreq
, *mb2
;
672 int siz
, grpsiz
, authsiz
;
675 authsiz
= nfsm_rndup(auth_len
);
676 MGETHDR(mb
, M_WAIT
, MT_DATA
);
677 if ((authsiz
+ 10 * NFSX_UNSIGNED
) >= MINCLSIZE
) {
679 } else if ((authsiz
+ 10 * NFSX_UNSIGNED
) < MHLEN
) {
680 MH_ALIGN(mb
, authsiz
+ 10 * NFSX_UNSIGNED
);
682 MH_ALIGN(mb
, 8 * NFSX_UNSIGNED
);
686 bpos
= mtod(mb
, caddr_t
);
689 * First the RPC header.
691 nfsm_build(tl
, u_long
*, 8 * NFSX_UNSIGNED
);
694 * derive initial xid from system time
698 * Note: it's OK if this code inits nfs_xid to 0 (for example,
699 * due to a broken clock) because we immediately increment it
700 * and we guarantee to never use xid 0. So, nfs_xid should only
701 * ever be 0 the first time this function is called.
704 nfs_xid
= tv
.tv_sec
<< 12;
707 * Skip zero xid if it should ever happen.
709 if (++nfs_xid
== 0) {
714 *tl
++ = *xidp
= txdr_unsigned(nfs_xid
);
717 if (nmflag
& NFSMNT_NQNFS
) {
718 *tl
++ = txdr_unsigned(NQNFS_PROG
);
719 *tl
++ = txdr_unsigned(NQNFS_VER3
);
721 *tl
++ = txdr_unsigned(NFS_PROG
);
722 if (nmflag
& NFSMNT_NFSV3
)
723 *tl
++ = txdr_unsigned(NFS_VER3
);
725 *tl
++ = txdr_unsigned(NFS_VER2
);
727 if (nmflag
& NFSMNT_NFSV3
)
728 *tl
++ = txdr_unsigned(procid
);
730 *tl
++ = txdr_unsigned(nfsv2_procid
[procid
]);
733 * And then the authorization cred.
735 *tl
++ = txdr_unsigned(auth_type
);
736 *tl
= txdr_unsigned(authsiz
);
739 nfsm_build(tl
, u_long
*, auth_len
);
740 *tl
++ = 0; /* stamp ?? */
741 *tl
++ = 0; /* NULL hostname */
742 *tl
++ = txdr_unsigned(cr
->cr_uid
);
743 *tl
++ = txdr_unsigned(cr
->cr_groups
[0]);
744 grpsiz
= (auth_len
>> 2) - 5;
745 *tl
++ = txdr_unsigned(grpsiz
);
746 for (i
= 1; i
<= grpsiz
; i
++)
747 *tl
++ = txdr_unsigned(cr
->cr_groups
[i
]);
752 if (M_TRAILINGSPACE(mb
) == 0) {
753 MGET(mb2
, M_WAIT
, MT_DATA
);
754 if (siz
>= MINCLSIZE
)
759 bpos
= mtod(mb
, caddr_t
);
761 i
= min(siz
, M_TRAILINGSPACE(mb
));
762 bcopy(auth_str
, bpos
, i
);
768 if ((siz
= (nfsm_rndup(auth_len
) - auth_len
)) > 0) {
769 for (i
= 0; i
< siz
; i
++)
777 * And the verifier...
779 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
781 *tl
++ = txdr_unsigned(RPCAUTH_KERB4
);
782 *tl
= txdr_unsigned(verf_len
);
785 if (M_TRAILINGSPACE(mb
) == 0) {
786 MGET(mb2
, M_WAIT
, MT_DATA
);
787 if (siz
>= MINCLSIZE
)
792 bpos
= mtod(mb
, caddr_t
);
794 i
= min(siz
, M_TRAILINGSPACE(mb
));
795 bcopy(verf_str
, bpos
, i
);
801 if ((siz
= (nfsm_rndup(verf_len
) - verf_len
)) > 0) {
802 for (i
= 0; i
< siz
; i
++)
807 *tl
++ = txdr_unsigned(RPCAUTH_NULL
);
811 mreq
->m_pkthdr
.len
= authsiz
+ 10 * NFSX_UNSIGNED
+ mrest_len
;
812 mreq
->m_pkthdr
.rcvif
= (struct ifnet
*)0;
818 * copies mbuf chain to the uio scatter/gather list
821 nfsm_mbuftouio(mrep
, uiop
, siz
, dpos
)
823 register struct uio
*uiop
;
827 register char *mbufcp
, *uiocp
;
828 register int xfer
, left
, len
;
829 register struct mbuf
*mp
;
835 len
= mtod(mp
, caddr_t
)+mp
->m_len
-mbufcp
;
836 rem
= nfsm_rndup(siz
)-siz
;
838 if (uiop
->uio_iovcnt
<= 0 || uiop
->uio_iov
== NULL
)
840 left
= uiop
->uio_iov
->iov_len
;
841 uiocp
= uiop
->uio_iov
->iov_base
;
850 mbufcp
= mtod(mp
, caddr_t
);
853 xfer
= (left
> len
) ? len
: left
;
856 if (uiop
->uio_iov
->iov_op
!= NULL
)
857 (*(uiop
->uio_iov
->iov_op
))
858 (mbufcp
, uiocp
, xfer
);
861 if (uiop
->uio_segflg
== UIO_SYSSPACE
)
862 bcopy(mbufcp
, uiocp
, xfer
);
864 copyout(mbufcp
, uiocp
, xfer
);
869 uiop
->uio_offset
+= xfer
;
870 uiop
->uio_resid
-= xfer
;
872 if (uiop
->uio_iov
->iov_len
<= siz
) {
876 uiop
->uio_iov
->iov_base
+= uiosiz
;
877 uiop
->uio_iov
->iov_len
-= uiosiz
;
885 error
= nfs_adv(mrep
, dpos
, rem
, len
);
893 * copies a uio scatter/gather list to an mbuf chain.
894 * NOTE: can ony handle iovcnt == 1
897 nfsm_uiotombuf(uiop
, mq
, siz
, bpos
)
898 register struct uio
*uiop
;
903 register char *uiocp
;
904 register struct mbuf
*mp
, *mp2
;
905 register int xfer
, left
, mlen
;
906 int uiosiz
, clflg
, rem
;
909 if (uiop
->uio_iovcnt
!= 1)
910 panic("nfsm_uiotombuf: iovcnt != 1");
912 if (siz
> MLEN
) /* or should it >= MCLBYTES ?? */
916 rem
= nfsm_rndup(siz
)-siz
;
919 left
= uiop
->uio_iov
->iov_len
;
920 uiocp
= uiop
->uio_iov
->iov_base
;
925 mlen
= M_TRAILINGSPACE(mp
);
927 MGET(mp
, M_WAIT
, MT_DATA
);
933 mlen
= M_TRAILINGSPACE(mp
);
935 xfer
= (left
> mlen
) ? mlen
: left
;
938 if (uiop
->uio_iov
->iov_op
!= NULL
)
939 (*(uiop
->uio_iov
->iov_op
))
940 (uiocp
, mtod(mp
, caddr_t
)+mp
->m_len
, xfer
);
943 if (uiop
->uio_segflg
== UIO_SYSSPACE
)
944 bcopy(uiocp
, mtod(mp
, caddr_t
)+mp
->m_len
, xfer
);
946 copyin(uiocp
, mtod(mp
, caddr_t
)+mp
->m_len
, xfer
);
950 uiop
->uio_offset
+= xfer
;
951 uiop
->uio_resid
-= xfer
;
953 uiop
->uio_iov
->iov_base
+= uiosiz
;
954 uiop
->uio_iov
->iov_len
-= uiosiz
;
958 if (rem
> M_TRAILINGSPACE(mp
)) {
959 MGET(mp
, M_WAIT
, MT_DATA
);
963 cp
= mtod(mp
, caddr_t
)+mp
->m_len
;
964 for (left
= 0; left
< rem
; left
++)
969 *bpos
= mtod(mp
, caddr_t
)+mp
->m_len
;
975 * Help break down an mbuf chain by setting the first siz bytes contiguous
976 * pointed to by returned val.
977 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
978 * cases. (The macros use the vars. dpos and dpos2)
981 nfsm_disct(mdp
, dposp
, siz
, left
, cp2
)
988 register struct mbuf
*mp
, *mp2
;
989 register int siz2
, xfer
;
994 *mdp
= mp
= mp
->m_next
;
998 *dposp
= mtod(mp
, caddr_t
);
1003 } else if (mp
->m_next
== NULL
) {
1005 } else if (siz
> MHLEN
) {
1006 panic("nfs S too big");
1008 MGET(mp2
, M_WAIT
, MT_DATA
);
1009 mp2
->m_next
= mp
->m_next
;
1013 *cp2
= p
= mtod(mp
, caddr_t
);
1014 bcopy(*dposp
, p
, left
); /* Copy what was left */
1018 /* Loop around copying up the siz2 bytes */
1022 xfer
= (siz2
> mp2
->m_len
) ? mp2
->m_len
: siz2
;
1024 bcopy(mtod(mp2
, caddr_t
), p
, xfer
);
1035 *dposp
= mtod(mp2
, caddr_t
);
1041 * Advance the position in the mbuf chain.
1044 nfs_adv(mdp
, dposp
, offs
, left
)
1050 register struct mbuf
*m
;
1063 *dposp
= mtod(m
, caddr_t
)+offs
;
1068 * Copy a string into mbufs for the hard cases...
1071 nfsm_strtmbuf(mb
, bpos
, cp
, siz
)
1077 register struct mbuf
*m1
= 0, *m2
;
1078 long left
, xfer
, len
, tlen
;
1084 left
= M_TRAILINGSPACE(m2
);
1086 tl
= ((u_long
*)(*bpos
));
1087 *tl
++ = txdr_unsigned(siz
);
1089 left
-= NFSX_UNSIGNED
;
1090 m2
->m_len
+= NFSX_UNSIGNED
;
1092 bcopy(cp
, (caddr_t
) tl
, left
);
1099 /* Loop around adding mbufs */
1101 MGET(m1
, M_WAIT
, MT_DATA
);
1104 m1
->m_len
= NFSMSIZ(m1
);
1107 tl
= mtod(m1
, u_long
*);
1110 *tl
++ = txdr_unsigned(siz
);
1111 m1
->m_len
-= NFSX_UNSIGNED
;
1112 tlen
= NFSX_UNSIGNED
;
1115 if (siz
< m1
->m_len
) {
1116 len
= nfsm_rndup(siz
);
1119 *(tl
+(xfer
>>2)) = 0;
1121 xfer
= len
= m1
->m_len
;
1123 bcopy(cp
, (caddr_t
) tl
, xfer
);
1124 m1
->m_len
= len
+tlen
;
1129 *bpos
= mtod(m1
, caddr_t
)+m1
->m_len
;
1134 * Called once to initialize data structures...
1138 struct vfsconf
*vfsp
;
1143 * Check to see if major data structures haven't bloated.
1145 if (sizeof (struct nfsnode
) > NFS_NODEALLOC
) {
1146 printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC
);
1147 printf("Try reducing NFS_SMALLFH\n");
1149 if (sizeof (struct nfsmount
) > NFS_MNTALLOC
) {
1150 printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC
);
1151 printf("Try reducing NFS_MUIDHASHSIZ\n");
1153 if (sizeof (struct nfssvc_sock
) > NFS_SVCALLOC
) {
1154 printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC
);
1155 printf("Try reducing NFS_UIDHASHSIZ\n");
1157 if (sizeof (struct nfsuid
) > NFS_UIDALLOC
) {
1158 printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC
);
1159 printf("Try unionizing the nu_nickname and nu_flag fields\n");
1161 nfs_mount_type
= vfsp
->vfc_typenum
;
1163 rpc_vers
= txdr_unsigned(RPC_VER2
);
1164 rpc_call
= txdr_unsigned(RPC_CALL
);
1165 rpc_reply
= txdr_unsigned(RPC_REPLY
);
1166 rpc_msgdenied
= txdr_unsigned(RPC_MSGDENIED
);
1167 rpc_msgaccepted
= txdr_unsigned(RPC_MSGACCEPTED
);
1168 rpc_mismatch
= txdr_unsigned(RPC_MISMATCH
);
1169 rpc_autherr
= txdr_unsigned(RPC_AUTHERR
);
1170 rpc_auth_unix
= txdr_unsigned(RPCAUTH_UNIX
);
1171 rpc_auth_kerb
= txdr_unsigned(RPCAUTH_KERB4
);
1172 nfs_prog
= txdr_unsigned(NFS_PROG
);
1173 nqnfs_prog
= txdr_unsigned(NQNFS_PROG
);
1174 nfs_true
= txdr_unsigned(TRUE
);
1175 nfs_false
= txdr_unsigned(FALSE
);
1176 nfs_xdrneg1
= txdr_unsigned(-1);
1177 nfs_ticks
= (hz
* NFS_TICKINTVL
+ 500) / 1000;
1180 /* Ensure async daemons disabled */
1181 for (i
= 0; i
< NFS_MAXASYNCDAEMON
; i
++) {
1182 nfs_iodwant
[i
] = (struct proc
*)0;
1183 nfs_iodmount
[i
] = (struct nfsmount
*)0;
1185 nfs_nbinit(); /* Init the nfsbuf table */
1186 nfs_nhinit(); /* Init the nfsnode table */
1187 nfs_lockinit(); /* Init the nfs lock state */
1188 #ifndef NFS_NOSERVER
1189 nfsrv_init(0); /* Init server data structures */
1190 nfsrv_initcache(); /* Init the server request cache */
1194 * Initialize the nqnfs server stuff.
1196 if (nqnfsstarttime
== 0) {
1197 nqnfsstarttime
= boottime
.tv_sec
+ nqsrv_maxlease
1198 + nqsrv_clockskew
+ nqsrv_writeslack
;
1199 NQLOADNOVRAM(nqnfsstarttime
);
1200 CIRCLEQ_INIT(&nqtimerhead
);
1201 nqfhhashtbl
= hashinit(NQLCHSZ
, M_NQLEASE
, &nqfhhash
);
1205 * Initialize reply list and start timer
1207 TAILQ_INIT(&nfs_reqq
);
1212 /* XXX CSM 12/4/97 Where are these declared in FreeBSD? */
1215 * Set up lease_check and lease_updatetime so that other parts
1216 * of the system can call us, if we are loadable.
1218 #ifndef NFS_NOSERVER
1219 default_vnodeop_p
[VOFFSET(vop_lease
)] = (vop_t
*)nqnfs_vop_lease_check
;
1221 lease_updatetime
= nfs_lease_updatetime
;
1223 vfsp
->vfc_refcount
++; /* make us non-unloadable */
1228 * Attribute cache routines.
1229 * nfs_loadattrcache() - loads or updates the cache contents from attributes
1230 * that are on the mbuf list
1231 * nfs_getattrcache() - returns valid attributes if found in cache, returns
1236 * Load the attribute cache (that lives in the nfsnode entry) with
1237 * the values on the mbuf list and
1239 * copy the attributes to *vaper
1242 nfs_loadattrcache(vpp
, mdp
, dposp
, vaper
, dontshrink
, xidp
)
1246 struct vattr
*vaper
;
1250 register struct vnode
*vp
= *vpp
;
1251 register struct vattr
*vap
;
1252 register struct nfs_fattr
*fp
;
1253 register struct nfsnode
*np
;
1256 int error
= 0, rdev
;
1260 struct timespec mtime
;
1265 FSDBG_TOP(527, vp
, 0, *xidp
>> 32, *xidp
);
1267 if (!VFSTONFS(vp
->v_mount
)) {
1268 FSDBG_BOT(527, ENXIO
, 1, 0, *xidp
);
1274 t1
= (mtod(md
, caddr_t
) + md
->m_len
) - *dposp
;
1275 if ((error
= nfsm_disct(mdp
, dposp
, NFSX_FATTR(v3
), t1
, &cp2
))) {
1276 FSDBG_BOT(527, error
, 2, 0, *xidp
);
1279 fp
= (struct nfs_fattr
*)cp2
;
1281 vtyp
= nfsv3tov_type(fp
->fa_type
);
1282 vmode
= fxdr_unsigned(u_short
, fp
->fa_mode
);
1283 rdev
= makedev(fxdr_unsigned(int, fp
->fa3_rdev
.specdata1
),
1284 fxdr_unsigned(int, fp
->fa3_rdev
.specdata2
));
1285 fxdr_nfsv3time(&fp
->fa3_mtime
, &mtime
);
1287 vtyp
= nfsv2tov_type(fp
->fa_type
);
1288 vmode
= fxdr_unsigned(u_short
, fp
->fa_mode
);
1292 * The duplicate information returned in fa_type and fa_mode
1293 * is an ambiguity in the NFS version 2 protocol.
1295 * VREG should be taken literally as a regular file. If a
1296 * server intents to return some type information differently
1297 * in the upper bits of the mode field (e.g. for sockets, or
1298 * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we
1299 * leave the examination of the mode bits even in the VREG
1300 * case to avoid breakage for bogus servers, but we make sure
1301 * that there are actually type bits set in the upper part of
1302 * fa_mode (and failing that, trust the va_type field).
1304 * NFSv3 cleared the issue, and requires fa_mode to not
1305 * contain any type information (while also introduing sockets
1306 * and FIFOs for fa_type).
1308 if (vtyp
== VNON
|| (vtyp
== VREG
&& (vmode
& S_IFMT
) != 0))
1309 vtyp
= IFTOVT(vmode
);
1310 rdev
= fxdr_unsigned(long, fp
->fa2_rdev
);
1311 fxdr_nfsv2time(&fp
->fa2_mtime
, &mtime
);
1314 * Really ugly NFSv2 kludge.
1316 if (vtyp
== VCHR
&& rdev
== 0xffffffff)
1321 * If v_type == VNON it is a new node, so fill in the v_type,
1322 * n_mtime fields. Check to see if it represents a special
1323 * device, and if so, check for a possible alias. Once the
1324 * correct vnode has been obtained, fill in the rest of the
1328 if (*xidp
< np
->n_xid
) {
1330 * We have already updated attributes with a response from
1331 * a later request. The attributes we have here are probably
1332 * stale so we drop them (just return). However, our
1333 * out-of-order receipt could be correct - if the requests were
1334 * processed out of order at the server. Given the uncertainty
1335 * we invalidate our cached attributes. *xidp is zeroed here
1336 * to indicate the attributes were dropped - only getattr
1337 * cares - it needs to retry the rpc.
1340 FSDBG_BOT(527, 0, np
, np
->n_xid
, *xidp
);
1344 if (vp
->v_type
!= vtyp
) {
1345 if (vp
->v_type
!= VNON
) {
1347 * The filehandle has changed type on us. This can be
1348 * caused by either the server not having unique filehandles
1349 * or because another client has removed the previous
1350 * filehandle and a new object (of a different type)
1351 * has been created with the same filehandle.
1353 * We can't simply switch the type on the vnode because
1354 * there may be type-specific fields that need to be
1355 * cleaned up or set up.
1357 * So, what should we do with this vnode?
1359 * About the best we can do is log a warning and return
1360 * an error. ESTALE is about the closest error, but it
1361 * is a little strange that we come up with this error
1362 * internally instead of simply passing it through from
1363 * the server. Hopefully, the vnode will be reclaimed
1364 * soon so the filehandle can be reincarnated as the new
1367 printf("nfs loadattrcache vnode changed type, was %d now %d", vp
->v_type
, vtyp
);
1368 FSDBG_BOT(527, ESTALE
, 3, 0, *xidp
);
1374 if (vp
->v_type
== VFIFO
) {
1375 vp
->v_op
= fifo_nfsv2nodeop_p
;
1377 if (vp
->v_type
== VCHR
|| vp
->v_type
== VBLK
) {
1378 vp
->v_op
= spec_nfsv2nodeop_p
;
1379 nvp
= checkalias(vp
, (dev_t
)rdev
, vp
->v_mount
);
1382 * Discard unneeded vnode, but save its nfsnode.
1383 * Since the nfsnode does not have a lock, its
1384 * vnode lock has to be carried over.
1386 nvp
->v_vnlock
= vp
->v_vnlock
;
1387 vp
->v_vnlock
= NULL
;
1388 nvp
->v_data
= vp
->v_data
;
1390 vp
->v_op
= spec_vnodeop_p
;
1394 * Reinitialize aliased node.
1400 np
->n_mtime
= mtime
.tv_sec
;
1401 FSDBG(527, vp
, np
->n_mtime
, 0, 0);
1405 vap
->va_type
= vtyp
;
1406 vap
->va_mode
= (vmode
& 07777);
1407 vap
->va_rdev
= (dev_t
)rdev
;
1408 vap
->va_mtime
= mtime
;
1409 vap
->va_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
.val
[0];
1411 vap
->va_nlink
= fxdr_unsigned(u_short
, fp
->fa_nlink
);
1412 vap
->va_uid
= fxdr_unsigned(uid_t
, fp
->fa_uid
);
1413 vap
->va_gid
= fxdr_unsigned(gid_t
, fp
->fa_gid
);
1414 fxdr_hyper(&fp
->fa3_size
, &vap
->va_size
);
1415 vap
->va_blocksize
= 16*1024;
1416 fxdr_hyper(&fp
->fa3_used
, &vap
->va_bytes
);
1417 vap
->va_fileid
= fxdr_unsigned(int, fp
->fa3_fileid
.nfsuquad
[1]);
1418 fxdr_nfsv3time(&fp
->fa3_atime
, &vap
->va_atime
);
1419 fxdr_nfsv3time(&fp
->fa3_ctime
, &vap
->va_ctime
);
1421 vap
->va_filerev
= 0;
1423 vap
->va_nlink
= fxdr_unsigned(u_short
, fp
->fa_nlink
);
1424 vap
->va_uid
= fxdr_unsigned(uid_t
, fp
->fa_uid
);
1425 vap
->va_gid
= fxdr_unsigned(gid_t
, fp
->fa_gid
);
1426 vap
->va_size
= fxdr_unsigned(u_long
, fp
->fa2_size
);
1427 vap
->va_blocksize
= fxdr_unsigned(long, fp
->fa2_blocksize
);
1428 vap
->va_bytes
= fxdr_unsigned(long, fp
->fa2_blocks
) * NFS_FABLKSIZE
;
1429 vap
->va_fileid
= fxdr_unsigned(long, fp
->fa2_fileid
);
1430 fxdr_nfsv2time(&fp
->fa2_atime
, &vap
->va_atime
);
1432 vap
->va_ctime
.tv_sec
= fxdr_unsigned(long, fp
->fa2_ctime
.nfsv2_sec
);
1433 vap
->va_ctime
.tv_nsec
= 0;
1434 vap
->va_gen
= fxdr_unsigned(u_long
, fp
->fa2_ctime
.nfsv2_usec
);
1435 vap
->va_filerev
= 0;
1439 np
->n_attrstamp
= now
.tv_sec
;
1441 if (UBCINFOMISSING(vp
) || UBCINFORECLAIMED(vp
)) {
1442 if (UBCINFORECLAIMED(vp
) && ISSET(vp
->v_flag
, (VXLOCK
|VORECLAIM
))) {
1443 // vnode is being vclean'ed, abort
1444 FSDBG_BOT(527, ENXIO
, 1, 0, *xidp
);
1447 if ((error
= ubc_info_init(vp
))) { /* VREG */
1448 FSDBG_BOT(527, error
, 3, 0, *xidp
);
1453 if (vap
->va_size
!= np
->n_size
) {
1454 FSDBG(527, vp
, vap
->va_size
, np
->n_size
,
1455 (vap
->va_type
== VREG
) |
1456 (np
->n_flag
& NMODIFIED
? 6 : 4));
1457 if (vap
->va_type
== VREG
) {
1460 orig_size
= np
->n_size
;
1461 if (np
->n_flag
& NMODIFIED
) {
1462 if (vap
->va_size
< np
->n_size
)
1463 vap
->va_size
= np
->n_size
;
1465 np
->n_size
= vap
->va_size
;
1467 np
->n_size
= vap
->va_size
;
1468 if (!UBCINFOEXISTS(vp
) ||
1469 dontshrink
&& np
->n_size
< ubc_getsize(vp
)) {
1470 vap
->va_size
= np
->n_size
= orig_size
;
1473 ubc_setsize(vp
, (off_t
)np
->n_size
); /* XXX */
1476 np
->n_size
= vap
->va_size
;
1479 if (vaper
!= NULL
) {
1480 bcopy((caddr_t
)vap
, (caddr_t
)vaper
, sizeof(*vap
));
1481 if (np
->n_flag
& NCHG
) {
1482 if (np
->n_flag
& NACC
)
1483 vaper
->va_atime
= np
->n_atim
;
1484 if (np
->n_flag
& NUPD
)
1485 vaper
->va_mtime
= np
->n_mtim
;
1488 FSDBG_BOT(527, 0, np
, 0, *xidp
);
1493 * Check the time stamp
1494 * If the cache is valid, copy contents to *vap and return 0
1495 * otherwise return an error
1498 nfs_getattrcache(vp
, vaper
)
1499 register struct vnode
*vp
;
1500 struct vattr
*vaper
;
1502 register struct nfsnode
*np
= VTONFS(vp
);
1503 register struct vattr
*vap
;
1504 struct timeval now
, nowup
;
1507 if (np
->n_xid
== 0) {
1508 FSDBG(528, vp
, 0, 0, 0);
1509 nfsstats
.attrcache_misses
++;
1513 /* Set attribute timeout based on how recently the file has been modified. */
1514 if ((np
)->n_flag
& NMODIFIED
)
1515 timeo
= NFS_MINATTRTIMO
;
1517 /* Note that if the client and server clocks are way out of sync, */
1518 /* timeout will probably get clamped to a min or max value */
1520 timeo
= (now
.tv_sec
- (np
)->n_mtime
) / 10;
1521 if (timeo
< NFS_MINATTRTIMO
)
1522 timeo
= NFS_MINATTRTIMO
;
1523 else if (timeo
> NFS_MAXATTRTIMO
)
1524 timeo
= NFS_MAXATTRTIMO
;
1527 microuptime(&nowup
);
1528 if ((nowup
.tv_sec
- np
->n_attrstamp
) >= timeo
) {
1529 FSDBG(528, vp
, 0, 0, 1);
1530 nfsstats
.attrcache_misses
++;
1533 FSDBG(528, vp
, 0, 0, 2);
1534 nfsstats
.attrcache_hits
++;
1537 if (vap
->va_size
!= np
->n_size
) {
1538 FSDBG(528, vp
, vap
->va_size
, np
->n_size
,
1539 (vap
->va_type
== VREG
) |
1540 (np
->n_flag
& NMODIFIED
? 6 : 4));
1541 if (vap
->va_type
== VREG
) {
1542 if (np
->n_flag
& NMODIFIED
) {
1543 if (vap
->va_size
< np
->n_size
)
1544 vap
->va_size
= np
->n_size
;
1546 np
->n_size
= vap
->va_size
;
1548 np
->n_size
= vap
->va_size
;
1549 ubc_setsize(vp
, (off_t
)np
->n_size
); /* XXX */
1551 np
->n_size
= vap
->va_size
;
1554 bcopy((caddr_t
)vap
, (caddr_t
)vaper
, sizeof(struct vattr
));
1555 if (np
->n_flag
& NCHG
) {
1556 if (np
->n_flag
& NACC
)
1557 vaper
->va_atime
= np
->n_atim
;
1558 if (np
->n_flag
& NUPD
)
1559 vaper
->va_mtime
= np
->n_mtim
;
1564 #ifndef NFS_NOSERVER
1566 * Set up nameidata for a lookup() call and do it.
1568 * If pubflag is set, this call is done for a lookup operation on the
1569 * public filehandle. In that case we allow crossing mountpoints and
1570 * absolute pathnames. However, the caller is expected to check that
1571 * the lookup result is within the public fs, and deny access if
1575 nfs_namei(ndp
, fhp
, len
, slp
, nam
, mdp
, dposp
, retdirp
, p
, kerbflag
, pubflag
)
1576 register struct nameidata
*ndp
;
1579 struct nfssvc_sock
*slp
;
1583 struct vnode
**retdirp
;
1585 int kerbflag
, pubflag
;
1587 register int i
, rem
;
1588 register struct mbuf
*md
;
1589 register char *fromcp
, *tocp
, *cp
;
1593 int error
, rdonly
, linklen
;
1594 struct componentname
*cnp
= &ndp
->ni_cnd
;
1598 *retdirp
= (struct vnode
*)0;
1600 if (len
> MAXPATHLEN
- 1)
1601 return (ENAMETOOLONG
);
1603 MALLOC_ZONE(cnp
->cn_pnbuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1604 cnp
->cn_pnlen
= MAXPATHLEN
;
1607 * Copy the name from the mbuf list to ndp->ni_pnbuf
1608 * and set the various ndp fields appropriately.
1611 tocp
= cnp
->cn_pnbuf
;
1613 rem
= mtod(md
, caddr_t
) + md
->m_len
- fromcp
;
1615 for (i
= 1; i
<= len
; i
++) {
1622 fromcp
= mtod(md
, caddr_t
);
1625 /* XXX CSM 12/4/97 Revisit when enabling WebNFS */
1627 if (*fromcp
== '\0' || (!pubflag
&& *fromcp
== '/')) {
1629 if (*fromcp
== '\0' || *fromcp
== '/') {
1634 cnp
->cn_hash
+= (unsigned char)*fromcp
* i
;
1635 *tocp
++ = *fromcp
++;
1641 len
= nfsm_rndup(len
)-len
;
1645 else if ((error
= nfs_adv(mdp
, dposp
, len
, rem
)) != 0)
1650 * Extract and set starting directory.
1652 error
= nfsrv_fhtovp(fhp
, FALSE
, &dp
, ndp
->ni_cnd
.cn_cred
, slp
,
1653 nam
, &rdonly
, kerbflag
, pubflag
);
1656 if (dp
->v_type
!= VDIR
) {
1663 cnp
->cn_flags
|= RDONLY
;
1667 /* XXX CSM 12/4/97 Revisit when enabling WebNFS */
1671 * Oh joy. For WebNFS, handle those pesky '%' escapes,
1672 * and the 'native path' indicator.
1675 assert(olen
<= MAXPATHLEN
- 1);
1677 MALLOC_ZONE(cp
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1678 fromcp
= cnp
->cn_pnbuf
;
1680 if ((unsigned char)*fromcp
>= WEBNFS_SPECCHAR_START
) {
1681 switch ((unsigned char)*fromcp
) {
1682 case WEBNFS_NATIVE_CHAR
:
1684 * 'Native' path for us is the same
1685 * as a path according to the NFS spec,
1686 * just skip the escape char.
1691 * More may be added in the future, range 0x80-0xff
1695 FREE_ZONE(cp
, MAXPATHLEN
, M_NAMEI
);
1700 * Translate the '%' escapes, URL-style.
1702 while (*fromcp
!= '\0') {
1703 if (*fromcp
== WEBNFS_ESC_CHAR
) {
1704 if (fromcp
[1] != '\0' && fromcp
[2] != '\0') {
1706 *tocp
++ = HEXSTRTOI(fromcp
);
1711 FREE_ZONE(cp
, MAXPATHLEN
, M_NAMEI
);
1715 *tocp
++ = *fromcp
++;
1719 tmppn
= cnp
->cn_pnbuf
;
1720 long len
= cnp
->cn_pnlen
;
1722 cnp
->cn_pnlen
= MAXPATHLEN
;
1723 FREE_ZONE(tmppn
, len
, M_NAMEI
);
1728 ndp
->ni_pathlen
= (tocp
- cnp
->cn_pnbuf
) + 1;
1729 ndp
->ni_segflg
= UIO_SYSSPACE
;
1731 /* XXX CSM 12/4/97 Revisit when enabling WebNFS */
1734 ndp
->ni_rootdir
= rootvnode
;
1735 ndp
->ni_loopcnt
= 0;
1736 if (cnp
->cn_pnbuf
[0] == '/')
1739 cnp
->cn_flags
|= NOCROSSMOUNT
;
1742 cnp
->cn_flags
|= NOCROSSMOUNT
;
1749 cnp
->cn_nameptr
= cnp
->cn_pnbuf
;
1750 ndp
->ni_startdir
= dp
;
1752 * And call lookup() to do the real work
1754 error
= lookup(ndp
);
1758 * Check for encountering a symbolic link
1760 if ((cnp
->cn_flags
& ISSYMLINK
) == 0) {
1761 nfsrv_object_create(ndp
->ni_vp
);
1762 if (cnp
->cn_flags
& (SAVENAME
| SAVESTART
)) {
1763 cnp
->cn_flags
|= HASBUF
;
1768 if ((cnp
->cn_flags
& LOCKPARENT
) && ndp
->ni_pathlen
== 1)
1769 VOP_UNLOCK(ndp
->ni_dvp
, 0, p
);
1770 /* XXX CSM 12/4/97 Revisit when enabling WebNFS */
1779 /* XXX CSM 12/4/97 Revisit when enabling WebNFS */
1783 if (ndp
->ni_loopcnt
++ >= MAXSYMLINKS
) {
1787 /* XXX assert(olen <= MAXPATHLEN - 1); */
1788 if (ndp
->ni_pathlen
> 1)
1789 MALLOC_ZONE(cp
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1793 aiov
.iov_len
= MAXPATHLEN
;
1794 auio
.uio_iov
= &aiov
;
1795 auio
.uio_iovcnt
= 1;
1796 auio
.uio_offset
= 0;
1797 auio
.uio_rw
= UIO_READ
;
1798 auio
.uio_segflg
= UIO_SYSSPACE
;
1799 auio
.uio_procp
= (struct proc
*)0;
1800 auio
.uio_resid
= MAXPATHLEN
;
1801 error
= VOP_READLINK(ndp
->ni_vp
, &auio
, cnp
->cn_cred
);
1804 if (ndp
->ni_pathlen
> 1)
1805 FREE_ZONE(cp
, MAXPATHLEN
, M_NAMEI
);
1808 linklen
= MAXPATHLEN
- auio
.uio_resid
;
1813 if (linklen
+ ndp
->ni_pathlen
>= MAXPATHLEN
) {
1814 error
= ENAMETOOLONG
;
1817 if (ndp
->ni_pathlen
> 1) {
1818 long len
= cnp
->cn_pnlen
;
1819 tmppn
= cnp
->cn_pnbuf
;
1821 cnp
->cn_pnlen
= olen
+ 1;
1822 bcopy(ndp
->ni_next
, cp
+ linklen
, ndp
->ni_pathlen
);
1823 FREE_ZONE(tmppn
, len
, M_NAMEI
);
1825 cnp
->cn_pnbuf
[linklen
] = '\0';
1826 ndp
->ni_pathlen
+= linklen
;
1830 * Check if root directory should replace current directory.
1832 if (cnp
->cn_pnbuf
[0] == '/') {
1834 dp
= ndp
->ni_rootdir
;
1841 tmppn
= cnp
->cn_pnbuf
;
1842 cnp
->cn_pnbuf
= NULL
;
1843 cnp
->cn_flags
&= ~HASBUF
;
1844 FREE_ZONE(tmppn
, cnp
->cn_pnlen
, M_NAMEI
);
1850 * A fiddled version of m_adj() that ensures null fill to a long
1851 * boundary and only trims off the back end
1854 nfsm_adj(mp
, len
, nul
)
1859 register struct mbuf
*m
;
1860 register int count
, i
;
1864 * Trim from tail. Scan the mbuf chain,
1865 * calculating its length and finding the last mbuf.
1866 * If the adjustment only affects this mbuf, then just
1867 * adjust and return. Otherwise, rescan and truncate
1868 * after the remaining size.
1874 if (m
->m_next
== (struct mbuf
*)0)
1878 if (m
->m_len
> len
) {
1881 cp
= mtod(m
, caddr_t
)+m
->m_len
-nul
;
1882 for (i
= 0; i
< nul
; i
++)
1891 * Correct length for chain is "count".
1892 * Find the mbuf with last data, adjust its length,
1893 * and toss data from remaining mbufs on chain.
1895 for (m
= mp
; m
; m
= m
->m_next
) {
1896 if (m
->m_len
>= count
) {
1899 cp
= mtod(m
, caddr_t
)+m
->m_len
-nul
;
1900 for (i
= 0; i
< nul
; i
++)
1907 for (m
= m
->m_next
;m
;m
= m
->m_next
)
1912 * Make these functions instead of macros, so that the kernel text size
1913 * doesn't get too big...
1916 nfsm_srvwcc(nfsd
, before_ret
, before_vap
, after_ret
, after_vap
, mbp
, bposp
)
1917 struct nfsrv_descript
*nfsd
;
1919 register struct vattr
*before_vap
;
1921 struct vattr
*after_vap
;
1925 register struct mbuf
*mb
= *mbp
, *mb2
;
1926 register char *bpos
= *bposp
;
1927 register u_long
*tl
;
1930 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1933 nfsm_build(tl
, u_long
*, 7 * NFSX_UNSIGNED
);
1935 txdr_hyper(&(before_vap
->va_size
), tl
);
1937 txdr_nfsv3time(&(before_vap
->va_mtime
), tl
);
1939 txdr_nfsv3time(&(before_vap
->va_ctime
), tl
);
1943 nfsm_srvpostopattr(nfsd
, after_ret
, after_vap
, mbp
, bposp
);
1947 nfsm_srvpostopattr(nfsd
, after_ret
, after_vap
, mbp
, bposp
)
1948 struct nfsrv_descript
*nfsd
;
1950 struct vattr
*after_vap
;
1954 register struct mbuf
*mb
= *mbp
, *mb2
;
1955 register char *bpos
= *bposp
;
1956 register u_long
*tl
;
1957 register struct nfs_fattr
*fp
;
1960 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1963 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
+ NFSX_V3FATTR
);
1965 fp
= (struct nfs_fattr
*)tl
;
1966 nfsm_srvfattr(nfsd
, after_vap
, fp
);
1973 nfsm_srvfattr(nfsd
, vap
, fp
)
1974 register struct nfsrv_descript
*nfsd
;
1975 register struct vattr
*vap
;
1976 register struct nfs_fattr
*fp
;
1979 fp
->fa_nlink
= txdr_unsigned(vap
->va_nlink
);
1980 fp
->fa_uid
= txdr_unsigned(vap
->va_uid
);
1981 fp
->fa_gid
= txdr_unsigned(vap
->va_gid
);
1982 if (nfsd
->nd_flag
& ND_NFSV3
) {
1983 fp
->fa_type
= vtonfsv3_type(vap
->va_type
);
1984 fp
->fa_mode
= vtonfsv3_mode(vap
->va_mode
);
1985 txdr_hyper(&vap
->va_size
, &fp
->fa3_size
);
1986 txdr_hyper(&vap
->va_bytes
, &fp
->fa3_used
);
1987 fp
->fa3_rdev
.specdata1
= txdr_unsigned(major(vap
->va_rdev
));
1988 fp
->fa3_rdev
.specdata2
= txdr_unsigned(minor(vap
->va_rdev
));
1989 fp
->fa3_fsid
.nfsuquad
[0] = 0;
1990 fp
->fa3_fsid
.nfsuquad
[1] = txdr_unsigned(vap
->va_fsid
);
1991 fp
->fa3_fileid
.nfsuquad
[0] = 0;
1992 fp
->fa3_fileid
.nfsuquad
[1] = txdr_unsigned(vap
->va_fileid
);
1993 txdr_nfsv3time(&vap
->va_atime
, &fp
->fa3_atime
);
1994 txdr_nfsv3time(&vap
->va_mtime
, &fp
->fa3_mtime
);
1995 txdr_nfsv3time(&vap
->va_ctime
, &fp
->fa3_ctime
);
1997 fp
->fa_type
= vtonfsv2_type(vap
->va_type
);
1998 fp
->fa_mode
= vtonfsv2_mode(vap
->va_type
, vap
->va_mode
);
1999 fp
->fa2_size
= txdr_unsigned(vap
->va_size
);
2000 fp
->fa2_blocksize
= txdr_unsigned(vap
->va_blocksize
);
2001 if (vap
->va_type
== VFIFO
)
2002 fp
->fa2_rdev
= 0xffffffff;
2004 fp
->fa2_rdev
= txdr_unsigned(vap
->va_rdev
);
2005 fp
->fa2_blocks
= txdr_unsigned(vap
->va_bytes
/ NFS_FABLKSIZE
);
2006 fp
->fa2_fsid
= txdr_unsigned(vap
->va_fsid
);
2007 fp
->fa2_fileid
= txdr_unsigned(vap
->va_fileid
);
2008 txdr_nfsv2time(&vap
->va_atime
, &fp
->fa2_atime
);
2009 txdr_nfsv2time(&vap
->va_mtime
, &fp
->fa2_mtime
);
2010 txdr_nfsv2time(&vap
->va_ctime
, &fp
->fa2_ctime
);
2015 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
2016 * - look up fsid in mount list (if not found ret error)
2017 * - get vp and export rights by calling VFS_FHTOVP()
2018 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
2019 * - if not lockflag unlock it with VOP_UNLOCK()
2022 nfsrv_fhtovp(fhp
, lockflag
, vpp
, cred
, slp
, nam
, rdonlyp
, kerbflag
, pubflag
)
2027 struct nfssvc_sock
*slp
;
2033 struct proc
*p
= current_proc(); /* XXX */
2034 register struct mount
*mp
;
2036 struct ucred
*credanon
;
2039 *vpp
= (struct vnode
*)0;
2041 /* XXX CSM 12/4/97 Revisit when enabling WebNFS */
2043 if (nfs_ispublicfh(fhp
)) {
2044 if (!pubflag
|| !nfs_pub
.np_valid
)
2046 fhp
= &nfs_pub
.np_handle
;
2050 mp
= vfs_getvfs(&fhp
->fh_fsid
);
2053 error
= VFS_FHTOVP(mp
, &fhp
->fh_fid
, nam
, vpp
, &exflags
, &credanon
);
2056 /* vnode pointer should be good at this point or ... */
2060 * Check/setup credentials.
2062 if (exflags
& MNT_EXKERB
) {
2065 return (NFSERR_AUTHERR
| AUTH_TOOWEAK
);
2067 } else if (kerbflag
) {
2069 return (NFSERR_AUTHERR
| AUTH_TOOWEAK
);
2070 } else if (cred
->cr_uid
== 0 || (exflags
& MNT_EXPORTANON
)) {
2071 cred
->cr_uid
= credanon
->cr_uid
;
2072 for (i
= 0; i
< credanon
->cr_ngroups
&& i
< NGROUPS
; i
++)
2073 cred
->cr_groups
[i
] = credanon
->cr_groups
[i
];
2074 cred
->cr_ngroups
= i
;
2076 if (exflags
& MNT_EXRDONLY
)
2081 nfsrv_object_create(*vpp
);
2084 VOP_UNLOCK(*vpp
, 0, p
);
2090 * WebNFS: check if a filehandle is a public filehandle. For v3, this
2091 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
2092 * transformed this to all zeroes in both cases, so check for it.
2098 char *cp
= (char *)fhp
;
2101 for (i
= 0; i
< NFSX_V3FH
; i
++)
2107 #endif /* NFS_NOSERVER */
2109 * This function compares two net addresses by family and returns TRUE
2110 * if they are the same host.
2111 * If there is any doubt, return FALSE.
2112 * The AF_INET family is handled as a special case so that address mbufs
2113 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
2116 netaddr_match(family
, haddr
, nam
)
2118 union nethostaddr
*haddr
;
2121 register struct sockaddr_in
*inetaddr
;
2125 inetaddr
= mtod(nam
, struct sockaddr_in
*);
2126 if (inetaddr
->sin_family
== AF_INET
&&
2127 inetaddr
->sin_addr
.s_addr
== haddr
->had_inetaddr
)
2133 register struct sockaddr_iso
*isoaddr1
, *isoaddr2
;
2135 isoaddr1
= mtod(nam
, struct sockaddr_iso
*);
2136 isoaddr2
= mtod(haddr
->had_nam
, struct sockaddr_iso
*);
2137 if (isoaddr1
->siso_family
== AF_ISO
&&
2138 isoaddr1
->siso_nlen
> 0 &&
2139 isoaddr1
->siso_nlen
== isoaddr2
->siso_nlen
&&
2140 SAME_ISOADDR(isoaddr1
, isoaddr2
))
2151 static nfsuint64 nfs_nullcookie
= { 0, 0 };
2153 * This function finds the directory cookie that corresponds to the
2154 * logical byte offset given.
2157 nfs_getcookie(np
, off
, add
)
2158 register struct nfsnode
*np
;
2162 register struct nfsdmap
*dp
, *dp2
;
2165 pos
= off
/ NFS_DIRBLKSIZ
;
2169 panic("nfs getcookie add at 0");
2171 return (&nfs_nullcookie
);
2174 dp
= np
->n_cookies
.lh_first
;
2177 MALLOC_ZONE(dp
, struct nfsdmap
*,
2178 sizeof (struct nfsdmap
),
2179 M_NFSDIROFF
, M_WAITOK
);
2180 dp
->ndm_eocookie
= 0;
2181 LIST_INSERT_HEAD(&np
->n_cookies
, dp
, ndm_list
);
2183 return ((nfsuint64
*)0);
2185 while (pos
>= NFSNUMCOOKIES
) {
2186 pos
-= NFSNUMCOOKIES
;
2187 if (dp
->ndm_list
.le_next
) {
2188 if (!add
&& dp
->ndm_eocookie
< NFSNUMCOOKIES
&&
2189 pos
>= dp
->ndm_eocookie
)
2190 return ((nfsuint64
*)0);
2191 dp
= dp
->ndm_list
.le_next
;
2193 MALLOC_ZONE(dp2
, struct nfsdmap
*,
2194 sizeof (struct nfsdmap
),
2195 M_NFSDIROFF
, M_WAITOK
);
2196 dp2
->ndm_eocookie
= 0;
2197 LIST_INSERT_AFTER(dp
, dp2
, ndm_list
);
2200 return ((nfsuint64
*)0);
2202 if (pos
>= dp
->ndm_eocookie
) {
2204 dp
->ndm_eocookie
= pos
+ 1;
2206 return ((nfsuint64
*)0);
2208 return (&dp
->ndm_cookies
[pos
]);
2212 * Invalidate cached directory information, except for the actual directory
2213 * blocks (which are invalidated separately).
2214 * Done mainly to avoid the use of stale offset cookies.
2218 register struct vnode
*vp
;
2220 register struct nfsnode
*np
= VTONFS(vp
);
2223 if (vp
->v_type
!= VDIR
)
2224 panic("nfs: invaldir not dir");
2226 np
->n_direofoffset
= 0;
2227 np
->n_cookieverf
.nfsuquad
[0] = 0;
2228 np
->n_cookieverf
.nfsuquad
[1] = 0;
2229 if (np
->n_cookies
.lh_first
)
2230 np
->n_cookies
.lh_first
->ndm_eocookie
= 0;
2234 * The write verifier has changed (probably due to a server reboot), so all
2235 * NB_NEEDCOMMIT blocks will have to be written again. Since they are on the
2236 * dirty block list as NB_DELWRI, all this takes is clearing the NB_NEEDCOMMIT
2237 * flag. Once done the new write verifier can be set for the mount point.
2243 register struct vnode
*vp
, *nvp
;
2244 register struct nfsbuf
*bp
, *nbp
;
2250 for (vp
= mp
->mnt_vnodelist
.lh_first
; vp
; vp
= nvp
) {
2251 if (vp
->v_mount
!= mp
) /* Paranoia */
2253 nvp
= vp
->v_mntvnodes
.le_next
;
2255 for (bp
= np
->n_dirtyblkhd
.lh_first
; bp
; bp
= nbp
) {
2256 nbp
= bp
->nb_vnbufs
.le_next
;
2257 if ((bp
->nb_flags
& (NB_BUSY
| NB_DELWRI
| NB_NEEDCOMMIT
))
2258 == (NB_DELWRI
| NB_NEEDCOMMIT
)) {
2259 bp
->nb_flags
&= ~NB_NEEDCOMMIT
;
2260 np
->n_needcommitcnt
--;
2261 CHECK_NEEDCOMMITCNT(np
);
2268 #ifndef NFS_NOSERVER
2270 * Map errnos to NFS error numbers. For Version 3 also filter out error
2271 * numbers not specified for the associated procedure.
2274 nfsrv_errmap(nd
, err
)
2275 struct nfsrv_descript
*nd
;
2278 register short *defaulterrp
, *errp
;
2280 if (nd
->nd_flag
& ND_NFSV3
) {
2281 if (nd
->nd_procnum
<= NFSPROC_COMMIT
) {
2282 errp
= defaulterrp
= nfsrv_v3errmap
[nd
->nd_procnum
];
2286 else if (*errp
> err
)
2289 return ((int)*defaulterrp
);
2291 return (err
& 0xffff);
2294 return ((int)nfsrv_v2errmap
[err
- 1]);
2298 /* XXX CSM 11/25/97 Revisit when Ramesh merges vm with buffer cache */
2299 #define vfs_object_create(v, p, c, l) (0)
2302 nfsrv_object_create(struct vnode
*vp
) {
2303 struct proc
*curproc
= current_proc();
2305 if ((vp
== NULL
) || (vp
->v_type
!= VREG
))
2307 return vfs_object_create(vp
, curproc
, curproc
?curproc
->p_ucred
:NULL
, 1);
2309 #endif /* NFS_NOSERVER */