2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95
37 * $FreeBSD: /repoman/r/ncvs/src/sys/nfsclient/nfs_subs.c,v 1.128 2004/04/14 23:23:55 peadar Exp $
38 * $DragonFly: src/sys/vfs/nfs/nfs_subs.c,v 1.47.4.1 2008/09/25 02:20:53 dillon Exp $
42 * These functions support the macros and help fiddle mbuf chains for
43 * the nfs op functions. They do things like create the rpc header and
44 * copy data between mbuf chains and uio lists.
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
51 #include <sys/mount.h>
52 #include <sys/vnode.h>
53 #include <sys/nlookup.h>
54 #include <sys/namei.h>
56 #include <sys/socket.h>
58 #include <sys/malloc.h>
59 #include <sys/sysent.h>
60 #include <sys/syscall.h>
62 #include <sys/objcache.h>
65 #include <vm/vm_object.h>
66 #include <vm/vm_extern.h>
67 #include <vm/vm_zone.h>
77 #include "nfsm_subs.h"
80 #include <netinet/in.h>
83 * Data items converted to xdr at startup, since they are constant
84 * This is kinda hokey, but may save a little time doing byte swaps
86 u_int32_t nfs_xdrneg1
;
87 u_int32_t rpc_call
, rpc_vers
, rpc_reply
, rpc_msgdenied
, rpc_autherr
,
88 rpc_mismatch
, rpc_auth_unix
, rpc_msgaccepted
,
90 u_int32_t nfs_prog
, nfs_true
, nfs_false
;
92 /* And other global data */
93 static u_int32_t nfs_xid
= 0;
94 static enum vtype nv2tov_type
[8]= {
95 VNON
, VREG
, VDIR
, VBLK
, VCHR
, VLNK
, VNON
, VNON
97 enum vtype nv3tov_type
[8]= {
98 VNON
, VREG
, VDIR
, VBLK
, VCHR
, VLNK
, VSOCK
, VFIFO
102 int nfs_pbuf_freecnt
= -1; /* start out unlimited */
104 struct nfs_reqq nfs_reqq
;
105 struct nfssvc_sockhead nfssvc_sockhead
;
106 int nfssvc_sockhead_flag
;
107 struct nfsd_head nfsd_head
;
109 struct nfs_bufq nfs_bufq
;
110 struct nqfhhashhead
*nqfhhashtbl
;
113 static int nfs_prev_nfssvc_sy_narg
;
114 static sy_call_t
*nfs_prev_nfssvc_sy_call
;
119 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
121 int nfsv3_procid
[NFS_NPROCS
] = {
150 #endif /* NFS_NOSERVER */
152 * and the reverse mapping from generic to Version 2 procedure numbers
154 int nfsv2_procid
[NFS_NPROCS
] = {
185 * Maps errno values to nfs error numbers.
186 * Use NFSERR_IO as the catch all for ones not specifically defined in
189 static u_char nfsrv_v2errmap
[ELAST
] = {
190 NFSERR_PERM
, NFSERR_NOENT
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
191 NFSERR_NXIO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
192 NFSERR_IO
, NFSERR_IO
, NFSERR_ACCES
, NFSERR_IO
, NFSERR_IO
,
193 NFSERR_IO
, NFSERR_EXIST
, NFSERR_IO
, NFSERR_NODEV
, NFSERR_NOTDIR
,
194 NFSERR_ISDIR
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
195 NFSERR_IO
, NFSERR_FBIG
, NFSERR_NOSPC
, NFSERR_IO
, NFSERR_ROFS
,
196 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
197 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
198 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
199 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
200 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
201 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
202 NFSERR_IO
, NFSERR_IO
, NFSERR_NAMETOL
, NFSERR_IO
, NFSERR_IO
,
203 NFSERR_NOTEMPTY
, NFSERR_IO
, NFSERR_IO
, NFSERR_DQUOT
, NFSERR_STALE
,
204 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
205 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
206 NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
, NFSERR_IO
,
207 NFSERR_IO
/* << Last is 86 */
211 * Maps errno values to nfs error numbers.
212 * Although it is not obvious whether or not NFS clients really care if
213 * a returned error value is in the specified list for the procedure, the
214 * safest thing to do is filter them appropriately. For Version 2, the
215 * X/Open XNFS document is the only specification that defines error values
216 * for each RPC (The RFC simply lists all possible error values for all RPCs),
217 * so I have decided to not do this for Version 2.
218 * The first entry is the default error return and the rest are the valid
219 * errors for that RPC in increasing numeric order.
221 static short nfsv3err_null
[] = {
226 static short nfsv3err_getattr
[] = {
235 static short nfsv3err_setattr
[] = {
251 static short nfsv3err_lookup
[] = {
264 static short nfsv3err_access
[] = {
273 static short nfsv3err_readlink
[] = {
285 static short nfsv3err_read
[] = {
297 static short nfsv3err_write
[] = {
312 static short nfsv3err_create
[] = {
329 static short nfsv3err_mkdir
[] = {
346 static short nfsv3err_symlink
[] = {
363 static short nfsv3err_mknod
[] = {
381 static short nfsv3err_remove
[] = {
395 static short nfsv3err_rmdir
[] = {
413 static short nfsv3err_rename
[] = {
436 static short nfsv3err_link
[] = {
456 static short nfsv3err_readdir
[] = {
469 static short nfsv3err_readdirplus
[] = {
483 static short nfsv3err_fsstat
[] = {
492 static short nfsv3err_fsinfo
[] = {
500 static short nfsv3err_pathconf
[] = {
508 static short nfsv3err_commit
[] = {
517 static short *nfsrv_v3errmap
[] = {
535 nfsv3err_readdirplus
,
542 #endif /* NFS_NOSERVER */
544 extern struct nfsrtt nfsrtt
;
545 extern struct nfsstats nfsstats
;
546 extern nfstype nfsv2_type
[9];
547 extern nfstype nfsv3_type
[9];
548 extern struct nfsnodehashhead
*nfsnodehashtbl
;
549 extern u_long nfsnodehash
;
552 extern int sys_nfssvc(struct proc
*, struct nfssvc_args
*, int *);
554 LIST_HEAD(nfsnodehashhead
, nfsnode
);
557 * This needs to return a monotonically increasing or close to monotonically
558 * increasing result, otherwise the write gathering queues won't work
567 return ((u_quad_t
)tv
.tv_sec
* 1000000 + (u_quad_t
)tv
.tv_usec
);
571 * Create the header for an rpc request packet
572 * The hsiz is the size of the rest of the nfs request header.
573 * (just used to decide if a cluster is a good idea)
576 nfsm_reqh(struct vnode
*vp
, u_long procid
, int hsiz
, caddr_t
*bposp
)
581 mb
= m_getl(hsiz
, MB_WAIT
, MT_DATA
, 0, NULL
);
583 bpos
= mtod(mb
, caddr_t
);
585 /* Finally, return values */
591 * Build the RPC header and fill in the authorization info.
592 * The authorization string argument is only used when the credentials
593 * come from outside of the kernel.
594 * Returns the head of the mbuf list.
597 nfsm_rpchead(struct ucred
*cr
, int nmflag
, int procid
, int auth_type
,
598 int auth_len
, char *auth_str
, int verf_len
, char *verf_str
,
599 struct mbuf
*mrest
, int mrest_len
, struct mbuf
**mbp
,
606 struct mbuf
*mreq
, *mb2
;
607 int siz
, grpsiz
, authsiz
, dsiz
;
609 authsiz
= nfsm_rndup(auth_len
);
610 dsiz
= authsiz
+ 10 * NFSX_UNSIGNED
;
611 mb
= m_getl(dsiz
, MB_WAIT
, MT_DATA
, M_PKTHDR
, NULL
);
612 if (dsiz
< MINCLSIZE
) {
616 MH_ALIGN(mb
, 8 * NFSX_UNSIGNED
);
618 mb
->m_len
= mb
->m_pkthdr
.len
= 0;
620 bpos
= mtod(mb
, caddr_t
);
623 * First the RPC header.
625 nfsm_build(tl
, u_int32_t
*, 8 * NFSX_UNSIGNED
);
627 /* Get a pretty random xid to start with */
631 * Skip zero xid if it should ever happen.
636 *tl
++ = *xidp
= txdr_unsigned(nfs_xid
);
639 *tl
++ = txdr_unsigned(NFS_PROG
);
640 if (nmflag
& NFSMNT_NFSV3
)
641 *tl
++ = txdr_unsigned(NFS_VER3
);
643 *tl
++ = txdr_unsigned(NFS_VER2
);
644 if (nmflag
& NFSMNT_NFSV3
)
645 *tl
++ = txdr_unsigned(procid
);
647 *tl
++ = txdr_unsigned(nfsv2_procid
[procid
]);
650 * And then the authorization cred.
652 *tl
++ = txdr_unsigned(auth_type
);
653 *tl
= txdr_unsigned(authsiz
);
656 nfsm_build(tl
, u_int32_t
*, auth_len
);
657 *tl
++ = 0; /* stamp ?? */
658 *tl
++ = 0; /* NULL hostname */
659 *tl
++ = txdr_unsigned(cr
->cr_uid
);
660 *tl
++ = txdr_unsigned(cr
->cr_groups
[0]);
661 grpsiz
= (auth_len
>> 2) - 5;
662 *tl
++ = txdr_unsigned(grpsiz
);
663 for (i
= 1; i
<= grpsiz
; i
++)
664 *tl
++ = txdr_unsigned(cr
->cr_groups
[i
]);
669 if (M_TRAILINGSPACE(mb
) == 0) {
670 mb2
= m_getl(siz
, MB_WAIT
, MT_DATA
, 0, NULL
);
674 bpos
= mtod(mb
, caddr_t
);
676 i
= min(siz
, M_TRAILINGSPACE(mb
));
677 bcopy(auth_str
, bpos
, i
);
683 if ((siz
= (nfsm_rndup(auth_len
) - auth_len
)) > 0) {
684 for (i
= 0; i
< siz
; i
++)
692 * And the verifier...
694 nfsm_build(tl
, u_int32_t
*, 2 * NFSX_UNSIGNED
);
696 *tl
++ = txdr_unsigned(RPCAUTH_KERB4
);
697 *tl
= txdr_unsigned(verf_len
);
700 if (M_TRAILINGSPACE(mb
) == 0) {
701 mb2
= m_getl(siz
, MB_WAIT
, MT_DATA
, 0, NULL
);
705 bpos
= mtod(mb
, caddr_t
);
707 i
= min(siz
, M_TRAILINGSPACE(mb
));
708 bcopy(verf_str
, bpos
, i
);
714 if ((siz
= (nfsm_rndup(verf_len
) - verf_len
)) > 0) {
715 for (i
= 0; i
< siz
; i
++)
720 *tl
++ = txdr_unsigned(RPCAUTH_NULL
);
724 mreq
->m_pkthdr
.len
= authsiz
+ 10 * NFSX_UNSIGNED
+ mrest_len
;
725 mreq
->m_pkthdr
.rcvif
= (struct ifnet
*)0;
731 * copies mbuf chain to the uio scatter/gather list
734 nfsm_mbuftouio(struct mbuf
**mrep
, struct uio
*uiop
, int siz
, caddr_t
*dpos
)
736 char *mbufcp
, *uiocp
;
744 len
= mtod(mp
, caddr_t
)+mp
->m_len
-mbufcp
;
745 rem
= nfsm_rndup(siz
)-siz
;
747 if (uiop
->uio_iovcnt
<= 0 || uiop
->uio_iov
== NULL
)
749 left
= uiop
->uio_iov
->iov_len
;
750 uiocp
= uiop
->uio_iov
->iov_base
;
759 mbufcp
= mtod(mp
, caddr_t
);
762 xfer
= (left
> len
) ? len
: left
;
765 if (uiop
->uio_iov
->iov_op
!= NULL
)
766 (*(uiop
->uio_iov
->iov_op
))
767 (mbufcp
, uiocp
, xfer
);
770 if (uiop
->uio_segflg
== UIO_SYSSPACE
)
771 bcopy(mbufcp
, uiocp
, xfer
);
773 copyout(mbufcp
, uiocp
, xfer
);
778 uiop
->uio_offset
+= xfer
;
779 uiop
->uio_resid
-= xfer
;
781 if (uiop
->uio_iov
->iov_len
<= siz
) {
785 uiop
->uio_iov
->iov_base
+= uiosiz
;
786 uiop
->uio_iov
->iov_len
-= uiosiz
;
794 error
= nfs_adv(mrep
, dpos
, rem
, len
);
802 * copies a uio scatter/gather list to an mbuf chain.
803 * NOTE: can ony handle iovcnt == 1
806 nfsm_uiotombuf(struct uio
*uiop
, struct mbuf
**mq
, int siz
, caddr_t
*bpos
)
809 struct mbuf
*mp
, *mp2
;
810 int xfer
, left
, mlen
;
812 boolean_t getcluster
;
816 if (uiop
->uio_iovcnt
!= 1)
817 panic("nfsm_uiotombuf: iovcnt != 1");
820 if (siz
>= MINCLSIZE
)
824 rem
= nfsm_rndup(siz
) - siz
;
827 left
= uiop
->uio_iov
->iov_len
;
828 uiocp
= uiop
->uio_iov
->iov_base
;
833 mlen
= M_TRAILINGSPACE(mp
);
836 mp
= m_getcl(MB_WAIT
, MT_DATA
, 0);
838 mp
= m_get(MB_WAIT
, MT_DATA
);
842 mlen
= M_TRAILINGSPACE(mp
);
844 xfer
= (left
> mlen
) ? mlen
: left
;
847 if (uiop
->uio_iov
->iov_op
!= NULL
)
848 (*(uiop
->uio_iov
->iov_op
))
849 (uiocp
, mtod(mp
, caddr_t
)+mp
->m_len
, xfer
);
852 if (uiop
->uio_segflg
== UIO_SYSSPACE
)
853 bcopy(uiocp
, mtod(mp
, caddr_t
)+mp
->m_len
, xfer
);
855 copyin(uiocp
, mtod(mp
, caddr_t
)+mp
->m_len
, xfer
);
859 uiop
->uio_offset
+= xfer
;
860 uiop
->uio_resid
-= xfer
;
862 uiop
->uio_iov
->iov_base
+= uiosiz
;
863 uiop
->uio_iov
->iov_len
-= uiosiz
;
867 if (rem
> M_TRAILINGSPACE(mp
)) {
868 MGET(mp
, MB_WAIT
, MT_DATA
);
872 cp
= mtod(mp
, caddr_t
)+mp
->m_len
;
873 for (left
= 0; left
< rem
; left
++)
878 *bpos
= mtod(mp
, caddr_t
)+mp
->m_len
;
884 * Help break down an mbuf chain by setting the first siz bytes contiguous
885 * pointed to by returned val.
886 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
887 * cases. (The macros use the vars. dpos and dpos2)
890 nfsm_disct(struct mbuf
**mdp
, caddr_t
*dposp
, int siz
, int left
, caddr_t
*cp2
)
892 struct mbuf
*mp
, *mp2
;
898 *mdp
= mp
= mp
->m_next
;
902 *dposp
= mtod(mp
, caddr_t
);
907 } else if (mp
->m_next
== NULL
) {
909 } else if (siz
> MHLEN
) {
910 panic("nfs S too big");
912 MGET(mp2
, MB_WAIT
, MT_DATA
);
913 mp2
->m_next
= mp
->m_next
;
917 *cp2
= p
= mtod(mp
, caddr_t
);
918 bcopy(*dposp
, p
, left
); /* Copy what was left */
922 /* Loop around copying up the siz2 bytes */
926 xfer
= (siz2
> mp2
->m_len
) ? mp2
->m_len
: siz2
;
928 bcopy(mtod(mp2
, caddr_t
), p
, xfer
);
939 *dposp
= mtod(mp2
, caddr_t
);
945 * Advance the position in the mbuf chain.
948 nfs_adv(struct mbuf
**mdp
, caddr_t
*dposp
, int offs
, int left
)
963 *dposp
= mtod(m
, caddr_t
)+offs
;
968 * Copy a string into mbufs for the hard cases...
971 nfsm_strtmbuf(struct mbuf
**mb
, char **bpos
, const char *cp
, long siz
)
973 struct mbuf
*m1
= NULL
, *m2
;
974 long left
, xfer
, len
, tlen
;
980 left
= M_TRAILINGSPACE(m2
);
982 tl
= ((u_int32_t
*)(*bpos
));
983 *tl
++ = txdr_unsigned(siz
);
985 left
-= NFSX_UNSIGNED
;
986 m2
->m_len
+= NFSX_UNSIGNED
;
988 bcopy(cp
, (caddr_t
) tl
, left
);
995 /* Loop around adding mbufs */
999 m1
= m_getl(siz
, MB_WAIT
, MT_DATA
, 0, &msize
);
1003 tl
= mtod(m1
, u_int32_t
*);
1006 *tl
++ = txdr_unsigned(siz
);
1007 m1
->m_len
-= NFSX_UNSIGNED
;
1008 tlen
= NFSX_UNSIGNED
;
1011 if (siz
< m1
->m_len
) {
1012 len
= nfsm_rndup(siz
);
1015 *(tl
+(xfer
>>2)) = 0;
1017 xfer
= len
= m1
->m_len
;
1019 bcopy(cp
, (caddr_t
) tl
, xfer
);
1020 m1
->m_len
= len
+tlen
;
1025 *bpos
= mtod(m1
, caddr_t
)+m1
->m_len
;
1030 * Called once to initialize data structures...
1033 nfs_init(struct vfsconf
*vfsp
)
1037 callout_init(&nfs_timer_handle
);
1038 nfsmount_zone
= zinit("NFSMOUNT", sizeof(struct nfsmount
), 0, 0, 1);
1040 nfs_mount_type
= vfsp
->vfc_typenum
;
1042 rpc_vers
= txdr_unsigned(RPC_VER2
);
1043 rpc_call
= txdr_unsigned(RPC_CALL
);
1044 rpc_reply
= txdr_unsigned(RPC_REPLY
);
1045 rpc_msgdenied
= txdr_unsigned(RPC_MSGDENIED
);
1046 rpc_msgaccepted
= txdr_unsigned(RPC_MSGACCEPTED
);
1047 rpc_mismatch
= txdr_unsigned(RPC_MISMATCH
);
1048 rpc_autherr
= txdr_unsigned(RPC_AUTHERR
);
1049 rpc_auth_unix
= txdr_unsigned(RPCAUTH_UNIX
);
1050 rpc_auth_kerb
= txdr_unsigned(RPCAUTH_KERB4
);
1051 nfs_prog
= txdr_unsigned(NFS_PROG
);
1052 nfs_true
= txdr_unsigned(TRUE
);
1053 nfs_false
= txdr_unsigned(FALSE
);
1054 nfs_xdrneg1
= txdr_unsigned(-1);
1055 nfs_ticks
= (hz
* NFS_TICKINTVL
+ 500) / 1000;
1058 /* Ensure async daemons disabled */
1059 for (i
= 0; i
< NFS_MAXASYNCDAEMON
; i
++) {
1060 nfs_iodwant
[i
] = NULL
;
1061 nfs_iodmount
[i
] = (struct nfsmount
*)0;
1063 nfs_nhinit(); /* Init the nfsnode table */
1064 #ifndef NFS_NOSERVER
1065 nfsrv_init(0); /* Init server data structures */
1066 nfsrv_initcache(); /* Init the server request cache */
1070 * Initialize reply list and start timer
1072 TAILQ_INIT(&nfs_reqq
);
1076 nfs_prev_nfssvc_sy_narg
= sysent
[SYS_nfssvc
].sy_narg
;
1077 sysent
[SYS_nfssvc
].sy_narg
= 2;
1078 nfs_prev_nfssvc_sy_call
= sysent
[SYS_nfssvc
].sy_call
;
1079 sysent
[SYS_nfssvc
].sy_call
= (sy_call_t
*)sys_nfssvc
;
1081 nfs_pbuf_freecnt
= nswbuf
/ 2 + 1;
1087 nfs_uninit(struct vfsconf
*vfsp
)
1089 callout_stop(&nfs_timer_handle
);
1090 nfs_mount_type
= -1;
1091 sysent
[SYS_nfssvc
].sy_narg
= nfs_prev_nfssvc_sy_narg
;
1092 sysent
[SYS_nfssvc
].sy_call
= nfs_prev_nfssvc_sy_call
;
1097 * Attribute cache routines.
1098 * nfs_loadattrcache() - loads or updates the cache contents from attributes
1099 * that are on the mbuf list
1100 * nfs_getattrcache() - returns valid attributes if found in cache, returns
1105 * Load the attribute cache (that lives in the nfsnode entry) with
1106 * the values on the mbuf list. Load *vaper with the attributes. vaper
1109 * As a side effect n_mtime, which we use to determine if the file was
1110 * modified by some other host, is set to the attribute timestamp and
1111 * NRMODIFIED is set if the two values differ.
1113 * WARNING: the mtime loaded into vaper does not necessarily represent
1114 * n_mtime or n_attr.mtime due to NACC and NUPD.
1117 nfs_loadattrcache(struct vnode
**vpp
, struct mbuf
**mdp
, caddr_t
*dposp
,
1118 struct vattr
*vaper
, int lattr_flags
)
1120 struct vnode
*vp
= *vpp
;
1122 struct nfs_fattr
*fp
;
1132 struct timespec mtime
;
1133 int v3
= NFS_ISV3(vp
);
1136 t1
= (mtod(md
, caddr_t
) + md
->m_len
) - *dposp
;
1137 if ((error
= nfsm_disct(mdp
, dposp
, NFSX_FATTR(v3
), t1
, &cp2
)) != 0)
1139 fp
= (struct nfs_fattr
*)cp2
;
1141 vtyp
= nfsv3tov_type(fp
->fa_type
);
1142 vmode
= fxdr_unsigned(u_short
, fp
->fa_mode
);
1143 rmajor
= (int)fxdr_unsigned(int, fp
->fa3_rdev
.specdata1
);
1144 rminor
= (int)fxdr_unsigned(int, fp
->fa3_rdev
.specdata2
);
1145 fxdr_nfsv3time(&fp
->fa3_mtime
, &mtime
);
1147 vtyp
= nfsv2tov_type(fp
->fa_type
);
1148 vmode
= fxdr_unsigned(u_short
, fp
->fa_mode
);
1152 * The duplicate information returned in fa_type and fa_mode
1153 * is an ambiguity in the NFS version 2 protocol.
1155 * VREG should be taken literally as a regular file. If a
1156 * server intents to return some type information differently
1157 * in the upper bits of the mode field (e.g. for sockets, or
1158 * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we
1159 * leave the examination of the mode bits even in the VREG
1160 * case to avoid breakage for bogus servers, but we make sure
1161 * that there are actually type bits set in the upper part of
1162 * fa_mode (and failing that, trust the va_type field).
1164 * NFSv3 cleared the issue, and requires fa_mode to not
1165 * contain any type information (while also introduing sockets
1166 * and FIFOs for fa_type).
1168 if (vtyp
== VNON
|| (vtyp
== VREG
&& (vmode
& S_IFMT
) != 0))
1169 vtyp
= IFTOVT(vmode
);
1170 rdev
= fxdr_unsigned(int32_t, fp
->fa2_rdev
);
1171 rmajor
= umajor(rdev
);
1172 rminor
= uminor(rdev
);
1173 fxdr_nfsv2time(&fp
->fa2_mtime
, &mtime
);
1176 * Really ugly NFSv2 kludge.
1178 if (vtyp
== VCHR
&& rdev
== (udev_t
)0xffffffff)
1183 * If v_type == VNON it is a new node, so fill in the v_type,
1184 * n_mtime fields. Check to see if it represents a special
1185 * device, and if so, check for a possible alias. Once the
1186 * correct vnode has been obtained, fill in the rest of the
1190 if (vp
->v_type
!= vtyp
) {
1191 nfs_setvtype(vp
, vtyp
);
1192 if (vp
->v_type
== VFIFO
) {
1193 vp
->v_ops
= &vp
->v_mount
->mnt_vn_fifo_ops
;
1194 } else if (vp
->v_type
== VCHR
|| vp
->v_type
== VBLK
) {
1195 vp
->v_ops
= &vp
->v_mount
->mnt_vn_spec_ops
;
1196 addaliasu(vp
, rmajor
, rminor
);
1198 vp
->v_ops
= &vp
->v_mount
->mnt_vn_use_ops
;
1200 np
->n_mtime
= mtime
.tv_sec
;
1201 } else if (np
->n_mtime
!= mtime
.tv_sec
) {
1203 * If we haven't modified the file locally and the server
1204 * timestamp does not match, then the server probably
1205 * modified the file. We must flag this condition so
1206 * the proper syncnronization can be done. We do not
1207 * try to synchronize the state here because that
1208 * could lead to an endless recursion.
1210 * XXX loadattrcache can be set during the reply to a write,
1211 * before the write timestamp is properly processed. To
1212 * avoid unconditionally setting the rmodified bit (which
1213 * has the effect of flushing the cache), we only do this
1214 * check if the lmodified bit is not set.
1216 np
->n_mtime
= mtime
.tv_sec
;
1217 if ((lattr_flags
& NFS_LATTR_NOMTIMECHECK
) == 0)
1218 np
->n_flag
|= NRMODIFIED
;
1221 vap
->va_type
= vtyp
;
1222 vap
->va_mode
= (vmode
& 07777);
1223 vap
->va_rmajor
= rmajor
;
1224 vap
->va_rminor
= rminor
;
1225 vap
->va_mtime
= mtime
;
1226 vap
->va_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
.val
[0];
1228 vap
->va_nlink
= fxdr_unsigned(u_short
, fp
->fa_nlink
);
1229 vap
->va_uid
= fxdr_unsigned(uid_t
, fp
->fa_uid
);
1230 vap
->va_gid
= fxdr_unsigned(gid_t
, fp
->fa_gid
);
1231 vap
->va_size
= fxdr_hyper(&fp
->fa3_size
);
1232 vap
->va_blocksize
= NFS_FABLKSIZE
;
1233 vap
->va_bytes
= fxdr_hyper(&fp
->fa3_used
);
1234 vap
->va_fileid
= fxdr_hyper(&fp
->fa3_fileid
);
1235 fxdr_nfsv3time(&fp
->fa3_atime
, &vap
->va_atime
);
1236 fxdr_nfsv3time(&fp
->fa3_ctime
, &vap
->va_ctime
);
1238 vap
->va_filerev
= 0;
1240 vap
->va_nlink
= fxdr_unsigned(u_short
, fp
->fa_nlink
);
1241 vap
->va_uid
= fxdr_unsigned(uid_t
, fp
->fa_uid
);
1242 vap
->va_gid
= fxdr_unsigned(gid_t
, fp
->fa_gid
);
1243 vap
->va_size
= fxdr_unsigned(u_int32_t
, fp
->fa2_size
);
1244 vap
->va_blocksize
= fxdr_unsigned(int32_t, fp
->fa2_blocksize
);
1245 vap
->va_bytes
= (u_quad_t
)fxdr_unsigned(int32_t, fp
->fa2_blocks
)
1247 vap
->va_fileid
= fxdr_unsigned(int32_t, fp
->fa2_fileid
);
1248 fxdr_nfsv2time(&fp
->fa2_atime
, &vap
->va_atime
);
1250 vap
->va_ctime
.tv_sec
= fxdr_unsigned(u_int32_t
,
1251 fp
->fa2_ctime
.nfsv2_sec
);
1252 vap
->va_ctime
.tv_nsec
= 0;
1253 vap
->va_gen
= fxdr_unsigned(u_int32_t
,fp
->fa2_ctime
.nfsv2_usec
);
1254 vap
->va_filerev
= 0;
1256 np
->n_attrstamp
= time_second
;
1257 if (vap
->va_size
!= np
->n_size
) {
1258 if (vap
->va_type
== VREG
) {
1259 if ((lattr_flags
& NFS_LATTR_NOSHRINK
) &&
1260 vap
->va_size
< np
->n_size
) {
1262 * We've been told not to shrink the file;
1263 * zero np->n_attrstamp to indicate that
1264 * the attributes are stale.
1266 * This occurs primarily due to recursive
1267 * NFS ops that are executed during periods
1268 * where we cannot safely reduce the size of
1271 * Additionally, write rpcs are broken down
1272 * into buffers and np->n_size is
1273 * pre-extended. Setting NRMODIFIED here
1274 * can result in n_size getting reset to a
1275 * lower value, which is NOT what we want.
1276 * XXX this needs to be cleaned up a lot
1279 vap
->va_size
= np
->n_size
;
1280 np
->n_attrstamp
= 0;
1281 if ((np
->n_flag
& NLMODIFIED
) == 0)
1282 np
->n_flag
|= NRMODIFIED
;
1283 } else if (np
->n_flag
& NLMODIFIED
) {
1285 * We've modified the file: Use the larger
1286 * of our size, and the server's size. At
1287 * this point the cache coherency is all
1288 * shot to hell. To try to handle multiple
1289 * clients appending to the file at the same
1290 * time mark that the server has changed
1291 * the file if the server's notion of the
1292 * file size is larger then our notion.
1294 * XXX this needs work.
1296 if (vap
->va_size
< np
->n_size
) {
1297 vap
->va_size
= np
->n_size
;
1299 np
->n_size
= vap
->va_size
;
1300 np
->n_flag
|= NRMODIFIED
;
1304 * Someone changed the file's size on the
1305 * server and there are no local changes
1306 * to get in the way, set the size and mark
1309 np
->n_size
= vap
->va_size
;
1310 np
->n_flag
|= NRMODIFIED
;
1312 vnode_pager_setsize(vp
, np
->n_size
);
1314 np
->n_size
= vap
->va_size
;
1317 if (vaper
!= NULL
) {
1318 bcopy((caddr_t
)vap
, (caddr_t
)vaper
, sizeof(*vap
));
1319 if (np
->n_flag
& NCHG
) {
1320 if (np
->n_flag
& NACC
)
1321 vaper
->va_atime
= np
->n_atim
;
1322 if (np
->n_flag
& NUPD
)
1323 vaper
->va_mtime
= np
->n_mtim
;
1330 #include <sys/sysctl.h>
1331 SYSCTL_DECL(_vfs_nfs
);
1332 static int nfs_acdebug
;
1333 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, acdebug
, CTLFLAG_RW
, &nfs_acdebug
, 0, "");
1337 * Check the time stamp
1338 * If the cache is valid, copy contents to *vap and return 0
1339 * otherwise return an error
1342 nfs_getattrcache(struct vnode
*vp
, struct vattr
*vaper
)
1346 struct nfsmount
*nmp
;
1351 nmp
= VFSTONFS(vp
->v_mount
);
1354 * Dynamic timeout based on how recently the file was modified.
1355 * n_mtime is always valid.
1357 timeo
= (get_approximate_time_t() - np
->n_mtime
) / 60;
1361 kprintf("nfs_getattrcache: initial timeo = %d\n", timeo
);
1364 if (vap
->va_type
== VDIR
) {
1365 if ((np
->n_flag
& NLMODIFIED
) || timeo
< nmp
->nm_acdirmin
)
1366 timeo
= nmp
->nm_acdirmin
;
1367 else if (timeo
> nmp
->nm_acdirmax
)
1368 timeo
= nmp
->nm_acdirmax
;
1370 if ((np
->n_flag
& NLMODIFIED
) || timeo
< nmp
->nm_acregmin
)
1371 timeo
= nmp
->nm_acregmin
;
1372 else if (timeo
> nmp
->nm_acregmax
)
1373 timeo
= nmp
->nm_acregmax
;
1377 if (nfs_acdebug
> 2)
1378 kprintf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n",
1379 nmp
->nm_acregmin
, nmp
->nm_acregmax
,
1380 nmp
->nm_acdirmin
, nmp
->nm_acdirmax
);
1383 kprintf("nfs_getattrcache: age = %d; final timeo = %d\n",
1384 (int)(time_second
- np
->n_attrstamp
), timeo
);
1387 if (np
->n_attrstamp
== 0 || (time_second
- np
->n_attrstamp
) >= timeo
) {
1388 nfsstats
.attrcache_misses
++;
1391 nfsstats
.attrcache_hits
++;
1394 * Our attribute cache can be stale due to modifications made on
1395 * this host. XXX this is a bad hack. We need a more deterministic
1396 * means of finding out which np fields are valid verses attr cache
1397 * fields. We really should update the vattr info on the fly when
1398 * making local changes.
1400 if (vap
->va_size
!= np
->n_size
) {
1401 if (vap
->va_type
== VREG
) {
1402 if (np
->n_flag
& NLMODIFIED
) {
1403 if (vap
->va_size
< np
->n_size
)
1404 vap
->va_size
= np
->n_size
;
1406 np
->n_size
= vap
->va_size
;
1408 np
->n_size
= vap
->va_size
;
1410 vnode_pager_setsize(vp
, np
->n_size
);
1412 np
->n_size
= vap
->va_size
;
1415 bcopy((caddr_t
)vap
, (caddr_t
)vaper
, sizeof(struct vattr
));
1416 if (np
->n_flag
& NCHG
) {
1417 if (np
->n_flag
& NACC
)
1418 vaper
->va_atime
= np
->n_atim
;
1419 if (np
->n_flag
& NUPD
)
1420 vaper
->va_mtime
= np
->n_mtim
;
1425 #ifndef NFS_NOSERVER
1428 * Set up nameidata for a lookup() call and do it.
1430 * If pubflag is set, this call is done for a lookup operation on the
1431 * public filehandle. In that case we allow crossing mountpoints and
1432 * absolute pathnames. However, the caller is expected to check that
1433 * the lookup result is within the public fs, and deny access if
1436 * dirp may be set whether an error is returned or not, and must be
1437 * released by the caller.
1439 * On return nd->nl_nch usually points to the target ncp, which may represent
1442 * NOTE: the caller must call nlookup_done(nd) unconditionally on return
1446 nfs_namei(struct nlookupdata
*nd
, struct ucred
*cred
, int nameiop
,
1447 struct vnode
**dvpp
, struct vnode
**vpp
,
1448 fhandle_t
*fhp
, int len
,
1449 struct nfssvc_sock
*slp
, struct sockaddr
*nam
, struct mbuf
**mdp
,
1450 caddr_t
*dposp
, struct vnode
**dirpp
, struct thread
*td
,
1451 int kerbflag
, int pubflag
)
1456 char *fromcp
, *tocp
, *cp
;
1458 struct nchandle nch
;
1463 namebuf
= objcache_get(namei_oc
, M_WAITOK
);
1468 * Copy the name from the mbuf list to namebuf.
1473 rem
= mtod(md
, caddr_t
) + md
->m_len
- fromcp
;
1474 for (i
= 0; i
< len
; i
++) {
1481 fromcp
= mtod(md
, caddr_t
);
1484 if (*fromcp
== '\0' || (!pubflag
&& *fromcp
== '/')) {
1488 *tocp
++ = *fromcp
++;
1494 len
= nfsm_rndup(len
)-len
;
1498 else if ((error
= nfs_adv(mdp
, dposp
, len
, rem
)) != 0)
1503 * Extract and set starting directory. The returned dp is refd
1506 error
= nfsrv_fhtovp(fhp
, FALSE
, &mp
, &dp
, cred
, slp
,
1507 nam
, &rdonly
, kerbflag
, pubflag
);
1510 if (dp
->v_type
!= VDIR
) {
1517 * Set return directory. Reference to dp is implicitly transfered
1518 * to the returned pointer. This must be set before we potentially
1525 * Oh joy. For WebNFS, handle those pesky '%' escapes,
1526 * and the 'native path' indicator.
1528 cp
= objcache_get(namei_oc
, M_WAITOK
);
1531 if ((unsigned char)*fromcp
>= WEBNFS_SPECCHAR_START
) {
1532 switch ((unsigned char)*fromcp
) {
1533 case WEBNFS_NATIVE_CHAR
:
1535 * 'Native' path for us is the same
1536 * as a path according to the NFS spec,
1537 * just skip the escape char.
1542 * More may be added in the future, range 0x80-0xff
1546 objcache_put(namei_oc
, cp
);
1551 * Translate the '%' escapes, URL-style.
1553 while (*fromcp
!= '\0') {
1554 if (*fromcp
== WEBNFS_ESC_CHAR
) {
1555 if (fromcp
[1] != '\0' && fromcp
[2] != '\0') {
1557 *tocp
++ = HEXSTRTOI(fromcp
);
1562 objcache_put(namei_oc
, cp
);
1566 *tocp
++ = *fromcp
++;
1569 objcache_put(namei_oc
, namebuf
);
1574 * Setup for search. We need to get a start directory from dp. Note
1575 * that dp is ref'd, but we no longer 'own' the ref (*dirpp owns it).
1578 flags
|= NLC_NFS_NOSOFTLINKTRAV
;
1579 flags
|= NLC_NOCROSSMOUNT
;
1582 flags
|= NLC_NFS_RDONLY
;
1583 if (nameiop
== NAMEI_CREATE
|| nameiop
== NAMEI_RENAME
)
1584 flags
|= NLC_CREATE
;
1587 * We need a starting ncp from the directory vnode dp. dp must not
1588 * be locked. The returned ncp will be refd but not locked.
1590 * If no suitable ncp is found we instruct cache_fromdvp() to create
1591 * one. If this fails the directory has probably been removed while
1592 * the target was chdir'd into it and any further lookup will fail.
1594 if ((error
= cache_fromdvp(dp
, cred
, 1, &nch
)) != 0)
1596 nlookup_init_raw(nd
, namebuf
, UIO_SYSSPACE
, flags
, cred
, &nch
);
1600 * Ok, do the lookup.
1602 error
= nlookup(nd
);
1605 * If no error occured return the requested dvpp and vpp. If
1606 * NLC_CREATE was specified nd->nl_nch may represent a negative
1607 * cache hit in which case we do not attempt to obtain the vp.
1611 if (nd
->nl_nch
.ncp
->nc_parent
) {
1613 nch
.ncp
= nch
.ncp
->nc_parent
;
1614 error
= cache_vget(&nch
, nd
->nl_cred
,
1615 LK_EXCLUSIVE
, dvpp
);
1620 if (vpp
&& nd
->nl_nch
.ncp
->nc_vp
) {
1621 error
= cache_vget(&nd
->nl_nch
, nd
->nl_cred
, LK_EXCLUSIVE
, vpp
);
1624 if (dvpp
&& *dvpp
) {
1639 objcache_put(namei_oc
, namebuf
);
1644 * A fiddled version of m_adj() that ensures null fill to a long
1645 * boundary and only trims off the back end
1648 nfsm_adj(struct mbuf
*mp
, int len
, int nul
)
1655 * Trim from tail. Scan the mbuf chain,
1656 * calculating its length and finding the last mbuf.
1657 * If the adjustment only affects this mbuf, then just
1658 * adjust and return. Otherwise, rescan and truncate
1659 * after the remaining size.
1665 if (m
->m_next
== (struct mbuf
*)0)
1669 if (m
->m_len
> len
) {
1672 cp
= mtod(m
, caddr_t
)+m
->m_len
-nul
;
1673 for (i
= 0; i
< nul
; i
++)
1682 * Correct length for chain is "count".
1683 * Find the mbuf with last data, adjust its length,
1684 * and toss data from remaining mbufs on chain.
1686 for (m
= mp
; m
; m
= m
->m_next
) {
1687 if (m
->m_len
>= count
) {
1690 cp
= mtod(m
, caddr_t
)+m
->m_len
-nul
;
1691 for (i
= 0; i
< nul
; i
++)
1698 for (m
= m
->m_next
;m
;m
= m
->m_next
)
1703 * Make these functions instead of macros, so that the kernel text size
1704 * doesn't get too big...
1707 nfsm_srvwcc(struct nfsrv_descript
*nfsd
, int before_ret
,
1708 struct vattr
*before_vap
, int after_ret
, struct vattr
*after_vap
,
1709 struct mbuf
**mbp
, char **bposp
)
1711 struct mbuf
*mb
= *mbp
, *mb2
;
1712 char *bpos
= *bposp
;
1716 * before_ret is 0 if before_vap is valid, non-zero if it isn't.
1719 nfsm_build(tl
, u_int32_t
*, NFSX_UNSIGNED
);
1722 nfsm_build(tl
, u_int32_t
*, 7 * NFSX_UNSIGNED
);
1724 txdr_hyper(before_vap
->va_size
, tl
);
1726 txdr_nfsv3time(&(before_vap
->va_mtime
), tl
);
1728 txdr_nfsv3time(&(before_vap
->va_ctime
), tl
);
1732 nfsm_srvpostopattr(nfsd
, after_ret
, after_vap
, mbp
, bposp
);
1736 nfsm_srvpostopattr(struct nfsrv_descript
*nfsd
, int after_ret
,
1737 struct vattr
*after_vap
, struct mbuf
**mbp
, char **bposp
)
1739 struct mbuf
*mb
= *mbp
, *mb2
;
1740 char *bpos
= *bposp
;
1742 struct nfs_fattr
*fp
;
1745 nfsm_build(tl
, u_int32_t
*, NFSX_UNSIGNED
);
1748 nfsm_build(tl
, u_int32_t
*, NFSX_UNSIGNED
+ NFSX_V3FATTR
);
1750 fp
= (struct nfs_fattr
*)tl
;
1751 nfsm_srvfattr(nfsd
, after_vap
, fp
);
1758 nfsm_srvfattr(struct nfsrv_descript
*nfsd
, struct vattr
*vap
,
1759 struct nfs_fattr
*fp
)
1762 * NFS seems to truncate nlink to 16 bits, don't let it overflow.
1764 if (vap
->va_nlink
> 65535)
1765 fp
->fa_nlink
= 65535;
1767 fp
->fa_nlink
= txdr_unsigned(vap
->va_nlink
);
1768 fp
->fa_uid
= txdr_unsigned(vap
->va_uid
);
1769 fp
->fa_gid
= txdr_unsigned(vap
->va_gid
);
1770 if (nfsd
->nd_flag
& ND_NFSV3
) {
1771 fp
->fa_type
= vtonfsv3_type(vap
->va_type
);
1772 fp
->fa_mode
= vtonfsv3_mode(vap
->va_mode
);
1773 txdr_hyper(vap
->va_size
, &fp
->fa3_size
);
1774 txdr_hyper(vap
->va_bytes
, &fp
->fa3_used
);
1775 fp
->fa3_rdev
.specdata1
= txdr_unsigned(vap
->va_rmajor
);
1776 fp
->fa3_rdev
.specdata2
= txdr_unsigned(vap
->va_rminor
);
1777 fp
->fa3_fsid
.nfsuquad
[0] = 0;
1778 fp
->fa3_fsid
.nfsuquad
[1] = txdr_unsigned(vap
->va_fsid
);
1779 txdr_hyper(vap
->va_fileid
, &fp
->fa3_fileid
);
1780 txdr_nfsv3time(&vap
->va_atime
, &fp
->fa3_atime
);
1781 txdr_nfsv3time(&vap
->va_mtime
, &fp
->fa3_mtime
);
1782 txdr_nfsv3time(&vap
->va_ctime
, &fp
->fa3_ctime
);
1784 fp
->fa_type
= vtonfsv2_type(vap
->va_type
);
1785 fp
->fa_mode
= vtonfsv2_mode(vap
->va_type
, vap
->va_mode
);
1786 fp
->fa2_size
= txdr_unsigned(vap
->va_size
);
1787 fp
->fa2_blocksize
= txdr_unsigned(vap
->va_blocksize
);
1788 if (vap
->va_type
== VFIFO
)
1789 fp
->fa2_rdev
= 0xffffffff;
1791 fp
->fa2_rdev
= txdr_unsigned(makeudev(vap
->va_rmajor
, vap
->va_rminor
));
1792 fp
->fa2_blocks
= txdr_unsigned(vap
->va_bytes
/ NFS_FABLKSIZE
);
1793 fp
->fa2_fsid
= txdr_unsigned(vap
->va_fsid
);
1794 fp
->fa2_fileid
= txdr_unsigned(vap
->va_fileid
);
1795 txdr_nfsv2time(&vap
->va_atime
, &fp
->fa2_atime
);
1796 txdr_nfsv2time(&vap
->va_mtime
, &fp
->fa2_mtime
);
1797 txdr_nfsv2time(&vap
->va_ctime
, &fp
->fa2_ctime
);
1802 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1803 * - look up fsid in mount list (if not found ret error)
1804 * - get vp and export rights by calling VFS_FHTOVP()
1805 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1806 * - if not lockflag unlock it with vn_unlock()
1809 nfsrv_fhtovp(fhandle_t
*fhp
, int lockflag
,
1810 struct mount
**mpp
, struct vnode
**vpp
,
1811 struct ucred
*cred
, struct nfssvc_sock
*slp
, struct sockaddr
*nam
,
1812 int *rdonlyp
, int kerbflag
, int pubflag
)
1816 struct ucred
*credanon
;
1818 #ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */
1819 struct sockaddr_int
*saddr
;
1825 if (nfs_ispublicfh(fhp
)) {
1826 if (!pubflag
|| !nfs_pub
.np_valid
)
1828 fhp
= &nfs_pub
.np_handle
;
1831 mp
= *mpp
= vfs_getvfs(&fhp
->fh_fsid
);
1834 error
= VFS_CHECKEXP(mp
, nam
, &exflags
, &credanon
);
1837 error
= VFS_FHTOVP(mp
, NULL
, &fhp
->fh_fid
, vpp
);
1840 #ifdef MNT_EXNORESPORT
1841 if (!(exflags
& (MNT_EXNORESPORT
|MNT_EXPUBLIC
))) {
1842 saddr
= (struct sockaddr_in
*)nam
;
1843 if (saddr
->sin_family
== AF_INET
&&
1844 ntohs(saddr
->sin_port
) >= IPPORT_RESERVED
) {
1847 return (NFSERR_AUTHERR
| AUTH_TOOWEAK
);
1852 * Check/setup credentials.
1854 if (exflags
& MNT_EXKERB
) {
1858 return (NFSERR_AUTHERR
| AUTH_TOOWEAK
);
1860 } else if (kerbflag
) {
1863 return (NFSERR_AUTHERR
| AUTH_TOOWEAK
);
1864 } else if (cred
->cr_uid
== 0 || (exflags
& MNT_EXPORTANON
)) {
1865 cred
->cr_uid
= credanon
->cr_uid
;
1866 for (i
= 0; i
< credanon
->cr_ngroups
&& i
< NGROUPS
; i
++)
1867 cred
->cr_groups
[i
] = credanon
->cr_groups
[i
];
1868 cred
->cr_ngroups
= i
;
1870 if (exflags
& MNT_EXRDONLY
)
1882 * WebNFS: check if a filehandle is a public filehandle. For v3, this
1883 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
1884 * transformed this to all zeroes in both cases, so check for it.
1887 nfs_ispublicfh(fhandle_t
*fhp
)
1889 char *cp
= (char *)fhp
;
1892 for (i
= 0; i
< NFSX_V3FH
; i
++)
1898 #endif /* NFS_NOSERVER */
1900 * This function compares two net addresses by family and returns TRUE
1901 * if they are the same host.
1902 * If there is any doubt, return FALSE.
1903 * The AF_INET family is handled as a special case so that address mbufs
1904 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1907 netaddr_match(int family
, union nethostaddr
*haddr
, struct sockaddr
*nam
)
1909 struct sockaddr_in
*inetaddr
;
1913 inetaddr
= (struct sockaddr_in
*)nam
;
1914 if (inetaddr
->sin_family
== AF_INET
&&
1915 inetaddr
->sin_addr
.s_addr
== haddr
->had_inetaddr
)
1924 static nfsuint64 nfs_nullcookie
= { { 0, 0 } };
1926 * This function finds the directory cookie that corresponds to the
1927 * logical byte offset given.
1930 nfs_getcookie(struct nfsnode
*np
, off_t off
, int add
)
1932 struct nfsdmap
*dp
, *dp2
;
1935 pos
= (uoff_t
)off
/ NFS_DIRBLKSIZ
;
1936 if (pos
== 0 || off
< 0) {
1939 panic("nfs getcookie add at <= 0");
1941 return (&nfs_nullcookie
);
1944 dp
= np
->n_cookies
.lh_first
;
1947 MALLOC(dp
, struct nfsdmap
*, sizeof (struct nfsdmap
),
1948 M_NFSDIROFF
, M_WAITOK
);
1949 dp
->ndm_eocookie
= 0;
1950 LIST_INSERT_HEAD(&np
->n_cookies
, dp
, ndm_list
);
1952 return ((nfsuint64
*)0);
1954 while (pos
>= NFSNUMCOOKIES
) {
1955 pos
-= NFSNUMCOOKIES
;
1956 if (dp
->ndm_list
.le_next
) {
1957 if (!add
&& dp
->ndm_eocookie
< NFSNUMCOOKIES
&&
1958 pos
>= dp
->ndm_eocookie
)
1959 return ((nfsuint64
*)0);
1960 dp
= dp
->ndm_list
.le_next
;
1962 MALLOC(dp2
, struct nfsdmap
*, sizeof (struct nfsdmap
),
1963 M_NFSDIROFF
, M_WAITOK
);
1964 dp2
->ndm_eocookie
= 0;
1965 LIST_INSERT_AFTER(dp
, dp2
, ndm_list
);
1968 return ((nfsuint64
*)0);
1970 if (pos
>= dp
->ndm_eocookie
) {
1972 dp
->ndm_eocookie
= pos
+ 1;
1974 return ((nfsuint64
*)0);
1976 return (&dp
->ndm_cookies
[pos
]);
1980 * Invalidate cached directory information, except for the actual directory
1981 * blocks (which are invalidated separately).
1982 * Done mainly to avoid the use of stale offset cookies.
1985 nfs_invaldir(struct vnode
*vp
)
1987 struct nfsnode
*np
= VTONFS(vp
);
1990 if (vp
->v_type
!= VDIR
)
1991 panic("nfs: invaldir not dir");
1993 np
->n_direofoffset
= 0;
1994 np
->n_cookieverf
.nfsuquad
[0] = 0;
1995 np
->n_cookieverf
.nfsuquad
[1] = 0;
1996 if (np
->n_cookies
.lh_first
)
1997 np
->n_cookies
.lh_first
->ndm_eocookie
= 0;
2001 * Set the v_type field for an NFS client's vnode and initialize for
2002 * buffer cache operations if necessary.
2005 nfs_setvtype(struct vnode
*vp
, enum vtype vtyp
)
2013 vinitvmio(vp
, 0); /* needs VMIO, size not yet known */
2021 * The write verifier has changed (probably due to a server reboot), so all
2022 * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
2023 * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
2024 * and B_CLUSTEROK flags. Once done the new write verifier can be set for the
2027 * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data
2028 * writes are not clusterable.
2031 static int nfs_clearcommit_bp(struct buf
*bp
, void *data __unused
);
2034 nfs_clearcommit(struct mount
*mp
)
2036 struct vnode
*vp
, *nvp
;
2039 lwkt_gettoken(&ilock
, &mntvnode_token
);
2041 for (vp
= TAILQ_FIRST(&mp
->mnt_nvnodelist
); vp
; vp
= nvp
) {
2042 nvp
= TAILQ_NEXT(vp
, v_nmntvnodes
); /* ZZZ */
2043 RB_SCAN(buf_rb_tree
, &vp
->v_rbdirty_tree
, NULL
,
2044 nfs_clearcommit_bp
, NULL
);
2047 lwkt_reltoken(&ilock
);
2051 nfs_clearcommit_bp(struct buf
*bp
, void *data __unused
)
2053 if (BUF_REFCNT(bp
) == 0 &&
2054 (bp
->b_flags
& (B_DELWRI
| B_NEEDCOMMIT
))
2055 == (B_DELWRI
| B_NEEDCOMMIT
)) {
2056 bp
->b_flags
&= ~(B_NEEDCOMMIT
| B_CLUSTEROK
);
2061 #ifndef NFS_NOSERVER
2063 * Map errnos to NFS error numbers. For Version 3 also filter out error
2064 * numbers not specified for the associated procedure.
2067 nfsrv_errmap(struct nfsrv_descript
*nd
, int err
)
2069 short *defaulterrp
, *errp
;
2071 if (nd
->nd_flag
& ND_NFSV3
) {
2072 if (nd
->nd_procnum
<= NFSPROC_COMMIT
) {
2073 errp
= defaulterrp
= nfsrv_v3errmap
[nd
->nd_procnum
];
2077 else if (*errp
> err
)
2080 return ((int)*defaulterrp
);
2082 return (err
& 0xffff);
2085 return ((int)nfsrv_v2errmap
[err
- 1]);
2090 * Sort the group list in increasing numerical order.
2091 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
2092 * that used to be here.)
2095 nfsrvw_sort(gid_t
*list
, int num
)
2100 /* Insertion sort. */
2101 for (i
= 1; i
< num
; i
++) {
2103 /* find correct slot for value v, moving others up */
2104 for (j
= i
; --j
>= 0 && v
< list
[j
];)
2105 list
[j
+ 1] = list
[j
];
2111 * copy credentials making sure that the result can be compared with bcmp().
2114 nfsrv_setcred(struct ucred
*incred
, struct ucred
*outcred
)
2118 bzero((caddr_t
)outcred
, sizeof (struct ucred
));
2119 outcred
->cr_ref
= 1;
2120 outcred
->cr_uid
= incred
->cr_uid
;
2121 outcred
->cr_ngroups
= incred
->cr_ngroups
;
2122 for (i
= 0; i
< incred
->cr_ngroups
; i
++)
2123 outcred
->cr_groups
[i
] = incred
->cr_groups
[i
];
2124 nfsrvw_sort(outcred
->cr_groups
, outcred
->cr_ngroups
);
2126 #endif /* NFS_NOSERVER */