2 * Copyright (c) 2009 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * 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
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * Copyright (c) 1989, 1993
36 * The Regents of the University of California. All rights reserved.
38 * This code is derived from software contributed to Berkeley by
39 * Rick Macklem at The University of Guelph.
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 3. All advertising materials mentioning features or use of this software
50 * must display the following acknowledgement:
51 * This product includes software developed by the University of
52 * California, Berkeley and its contributors.
53 * 4. Neither the name of the University nor the names of its contributors
54 * may be used to endorse or promote products derived from this software
55 * without specific prior written permission.
57 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
71 * These functions support the macros and help fiddle mbuf chains for
72 * the nfs op functions. They do things like create the rpc header and
73 * copy data between mbuf chains and uio lists.
75 #include <sys/param.h>
76 #include <sys/systm.h>
77 #include <sys/kernel.h>
80 #include <sys/mount.h>
81 #include <sys/vnode.h>
82 #include <sys/nlookup.h>
83 #include <sys/namei.h>
85 #include <sys/socket.h>
87 #include <sys/malloc.h>
88 #include <sys/sysent.h>
89 #include <sys/syscall.h>
91 #include <sys/objcache.h>
94 #include <vm/vm_object.h>
95 #include <vm/vm_extern.h>
96 #include <vm/vm_zone.h>
101 #include "nfsproto.h"
103 #include "nfsmount.h"
105 #include "xdr_subs.h"
106 #include "nfsm_subs.h"
109 #include <netinet/in.h>
111 static u_int32_t nfs_xid
= 0;
114 * Create the header for an rpc request packet
115 * The hsiz is the size of the rest of the nfs request header.
116 * (just used to decide if a cluster is a good idea)
119 nfsm_reqhead(nfsm_info_t info
, struct vnode
*vp
, u_long procid
, int hsiz
)
121 info
->mb
= m_getl(hsiz
, MB_WAIT
, MT_DATA
, 0, NULL
);
123 info
->mreq
= info
->mb
;
124 info
->bpos
= mtod(info
->mb
, caddr_t
);
128 * Build the RPC header and fill in the authorization info.
129 * The authorization string argument is only used when the credentials
130 * come from outside of the kernel.
131 * Returns the head of the mbuf list.
134 nfsm_rpchead(struct ucred
*cr
, int nmflag
, int procid
, int auth_type
,
135 int auth_len
, char *auth_str
, int verf_len
, char *verf_str
,
136 struct mbuf
*mrest
, int mrest_len
, struct mbuf
**mbp
,
139 struct nfsm_info info
;
142 int siz
, grpsiz
, authsiz
, dsiz
;
145 authsiz
= nfsm_rndup(auth_len
);
146 dsiz
= authsiz
+ 10 * NFSX_UNSIGNED
;
147 info
.mb
= m_getl(dsiz
, MB_WAIT
, MT_DATA
, M_PKTHDR
, NULL
);
148 if (dsiz
< MINCLSIZE
) {
150 MH_ALIGN(info
.mb
, dsiz
);
152 MH_ALIGN(info
.mb
, 8 * NFSX_UNSIGNED
);
154 info
.mb
->m_len
= info
.mb
->m_pkthdr
.len
= 0;
156 info
.bpos
= mtod(info
.mb
, caddr_t
);
159 * First the RPC header.
161 tl
= nfsm_build(&info
, 8 * NFSX_UNSIGNED
);
163 /* Get a pretty random xid to start with */
167 * Skip zero xid if it should ever happen.
172 *tl
++ = *xidp
= txdr_unsigned(nfs_xid
);
175 *tl
++ = txdr_unsigned(NFS_PROG
);
176 if (nmflag
& NFSMNT_NFSV3
)
177 *tl
++ = txdr_unsigned(NFS_VER3
);
179 *tl
++ = txdr_unsigned(NFS_VER2
);
180 if (nmflag
& NFSMNT_NFSV3
)
181 *tl
++ = txdr_unsigned(procid
);
183 *tl
++ = txdr_unsigned(nfsv2_procid
[procid
]);
186 * And then the authorization cred.
188 *tl
++ = txdr_unsigned(auth_type
);
189 *tl
= txdr_unsigned(authsiz
);
192 tl
= nfsm_build(&info
, auth_len
);
193 *tl
++ = 0; /* stamp ?? */
194 *tl
++ = 0; /* NULL hostname */
195 *tl
++ = txdr_unsigned(cr
->cr_uid
);
196 *tl
++ = txdr_unsigned(cr
->cr_groups
[0]);
197 grpsiz
= (auth_len
>> 2) - 5;
198 *tl
++ = txdr_unsigned(grpsiz
);
199 for (i
= 1; i
<= grpsiz
; i
++)
200 *tl
++ = txdr_unsigned(cr
->cr_groups
[i
]);
205 if (M_TRAILINGSPACE(info
.mb
) == 0) {
206 mb2
= m_getl(siz
, MB_WAIT
, MT_DATA
, 0, NULL
);
208 info
.mb
->m_next
= mb2
;
210 info
.bpos
= mtod(info
.mb
, caddr_t
);
212 i
= min(siz
, M_TRAILINGSPACE(info
.mb
));
213 bcopy(auth_str
, info
.bpos
, i
);
219 if ((siz
= (nfsm_rndup(auth_len
) - auth_len
)) > 0) {
220 for (i
= 0; i
< siz
; i
++)
222 info
.mb
->m_len
+= siz
;
228 * And the verifier...
230 tl
= nfsm_build(&info
, 2 * NFSX_UNSIGNED
);
232 *tl
++ = txdr_unsigned(RPCAUTH_KERB4
);
233 *tl
= txdr_unsigned(verf_len
);
236 if (M_TRAILINGSPACE(info
.mb
) == 0) {
237 mb2
= m_getl(siz
, MB_WAIT
, MT_DATA
,
240 info
.mb
->m_next
= mb2
;
242 info
.bpos
= mtod(info
.mb
, caddr_t
);
244 i
= min(siz
, M_TRAILINGSPACE(info
.mb
));
245 bcopy(verf_str
, info
.bpos
, i
);
251 if ((siz
= (nfsm_rndup(verf_len
) - verf_len
)) > 0) {
252 for (i
= 0; i
< siz
; i
++)
254 info
.mb
->m_len
+= siz
;
257 *tl
++ = txdr_unsigned(RPCAUTH_NULL
);
260 info
.mb
->m_next
= mrest
;
261 info
.mreq
->m_pkthdr
.len
= authsiz
+ 10 * NFSX_UNSIGNED
+ mrest_len
;
262 info
.mreq
->m_pkthdr
.rcvif
= NULL
;
268 nfsm_build(nfsm_info_t info
, int bytes
)
273 if (bytes
> M_TRAILINGSPACE(info
->mb
)) {
274 MGET(mb2
, MB_WAIT
, MT_DATA
);
276 panic("build > MLEN");
277 info
->mb
->m_next
= mb2
;
280 info
->bpos
= mtod(info
->mb
, caddr_t
);
283 info
->mb
->m_len
+= bytes
;
290 * If NULL returned caller is expected to abort with an EBADRPC error.
291 * Caller will usually use the NULLOUT macro.
294 nfsm_dissect(nfsm_info_t info
, int bytes
)
301 n
= mtod(info
->md
, caddr_t
) + info
->md
->m_len
- info
->dpos
;
306 error
= nfsm_disct(&info
->md
, &info
->dpos
, bytes
, n
, &cp2
);
320 * Caller is expected to abort if non-zero error is returned.
323 nfsm_fhtom(nfsm_info_t info
, struct vnode
*vp
)
331 n
= nfsm_rndup(VTONFS(vp
)->n_fhsize
) + NFSX_UNSIGNED
;
332 if (n
<= M_TRAILINGSPACE(info
->mb
)) {
333 tl
= nfsm_build(info
, n
);
334 *tl
++ = txdr_unsigned(VTONFS(vp
)->n_fhsize
);
335 *(tl
+ ((n
>> 2) - 2)) = 0;
336 bcopy((caddr_t
)VTONFS(vp
)->n_fhp
,(caddr_t
)tl
,
337 VTONFS(vp
)->n_fhsize
);
339 } else if ((error
= nfsm_strtmbuf(&info
->mb
, &info
->bpos
,
340 (caddr_t
)VTONFS(vp
)->n_fhp
,
341 VTONFS(vp
)->n_fhsize
)) != 0) {
346 cp
= nfsm_build(info
, NFSX_V2FH
);
347 bcopy(VTONFS(vp
)->n_fhp
, cp
, NFSX_V2FH
);
354 nfsm_srvfhtom(nfsm_info_t info
, fhandle_t
*fhp
)
359 tl
= nfsm_build(info
, NFSX_UNSIGNED
+ NFSX_V3FH
);
360 *tl
++ = txdr_unsigned(NFSX_V3FH
);
361 bcopy(fhp
, tl
, NFSX_V3FH
);
363 tl
= nfsm_build(info
, NFSX_V2FH
);
364 bcopy(fhp
, tl
, NFSX_V2FH
);
369 nfsm_srvpostop_fh(nfsm_info_t info
, fhandle_t
*fhp
)
373 tl
= nfsm_build(info
, 2 * NFSX_UNSIGNED
+ NFSX_V3FH
);
375 *tl
++ = txdr_unsigned(NFSX_V3FH
);
376 bcopy(fhp
, tl
, NFSX_V3FH
);
380 * Caller is expected to abort if non-zero error is returned.
382 * NOTE: (*vpp) may be loaded with a valid vnode even if (*gotvpp)
383 * winds up 0. The caller is responsible for dealing with (*vpp).
386 nfsm_mtofh(nfsm_info_t info
, struct vnode
*dvp
, struct vnode
**vpp
, int *gotvpp
)
388 struct nfsnode
*ttnp
;
395 tl
= nfsm_dissect(info
, NFSX_UNSIGNED
);
398 *gotvpp
= fxdr_unsigned(int, *tl
);
403 NEGATIVEOUT(ttfhsize
= nfsm_getfh(info
, &ttfhp
));
404 error
= nfs_nget(dvp
->v_mount
, ttfhp
, ttfhsize
, &ttnp
);
413 tl
= nfsm_dissect(info
, NFSX_UNSIGNED
);
417 *gotvpp
= fxdr_unsigned(int, *tl
);
418 } else if (fxdr_unsigned(int, *tl
)) {
419 error
= nfsm_adv(info
, NFSX_V3FATTR
);
425 error
= nfsm_loadattr(info
, *vpp
, NULL
);
432 * Caller is expected to abort with EBADRPC if a negative length is returned.
435 nfsm_getfh(nfsm_info_t info
, nfsfh_t
**fhpp
)
442 tl
= nfsm_dissect(info
, NFSX_UNSIGNED
);
445 if ((n
= fxdr_unsigned(int, *tl
)) <= 0 || n
> NFSX_V3FHMAX
) {
453 *fhpp
= nfsm_dissect(info
, nfsm_rndup(n
));
460 * Caller is expected to abort if a non-zero error is returned.
463 nfsm_loadattr(nfsm_info_t info
, struct vnode
*vp
, struct vattr
*vap
)
467 error
= nfs_loadattrcache(vp
, &info
->md
, &info
->dpos
, vap
, 0);
477 * Caller is expected to abort if a non-zero error is returned.
480 nfsm_postop_attr(nfsm_info_t info
, struct vnode
*vp
, int *attrp
, int lflags
)
485 tl
= nfsm_dissect(info
, NFSX_UNSIGNED
);
488 *attrp
= fxdr_unsigned(int, *tl
);
490 error
= nfs_loadattrcache(vp
, &info
->md
, &info
->dpos
,
503 * Caller is expected to abort if a non-zero error is returned.
506 nfsm_wcc_data(nfsm_info_t info
, struct vnode
*vp
, int *attrp
)
513 tl
= nfsm_dissect(info
, NFSX_UNSIGNED
);
516 if (*tl
== nfs_true
) {
517 tl
= nfsm_dissect(info
, 6 * NFSX_UNSIGNED
);
521 ttretf
= (VTONFS(vp
)->n_mtime
==
522 fxdr_unsigned(u_int32_t
, *(tl
+ 2)));
524 VTONFS(vp
)->n_flag
|= NRMODIFIED
;
526 error
= nfsm_postop_attr(info
, vp
, &ttattrf
,
527 NFS_LATTR_NOSHRINK
|NFS_LATTR_NOMTIMECHECK
);
531 error
= nfsm_postop_attr(info
, vp
, &ttattrf
,
544 * This function updates the attribute cache based on data returned in the
545 * NFS reply for NFS RPCs that modify the target file. If the RPC succeeds
546 * a 'before' and 'after' mtime is returned that allows us to determine if
547 * the new mtime attribute represents our modification or someone else's
550 * The flag argument returns non-0 if the original times matched, zero if
551 * they did not match. NRMODIFIED is automatically set if the before time
552 * does not match the original n_mtime, and n_mtime is automatically updated
553 * to the new after time (by nfsm_postop_attr()).
555 * If full is true, set all fields, otherwise just set mode and time fields
558 nfsm_v3attrbuild(nfsm_info_t info
, struct vattr
*vap
, int full
)
562 if (vap
->va_mode
!= (mode_t
)VNOVAL
) {
563 tl
= nfsm_build(info
, 2 * NFSX_UNSIGNED
);
565 *tl
= txdr_unsigned(vap
->va_mode
);
567 tl
= nfsm_build(info
, NFSX_UNSIGNED
);
570 if (full
&& vap
->va_uid
!= (uid_t
)VNOVAL
) {
571 tl
= nfsm_build(info
, 2 * NFSX_UNSIGNED
);
573 *tl
= txdr_unsigned(vap
->va_uid
);
575 tl
= nfsm_build(info
, NFSX_UNSIGNED
);
578 if (full
&& vap
->va_gid
!= (gid_t
)VNOVAL
) {
579 tl
= nfsm_build(info
, 2 * NFSX_UNSIGNED
);
581 *tl
= txdr_unsigned(vap
->va_gid
);
583 tl
= nfsm_build(info
, NFSX_UNSIGNED
);
586 if (full
&& vap
->va_size
!= VNOVAL
) {
587 tl
= nfsm_build(info
, 3 * NFSX_UNSIGNED
);
589 txdr_hyper(vap
->va_size
, tl
);
591 tl
= nfsm_build(info
, NFSX_UNSIGNED
);
594 if (vap
->va_atime
.tv_sec
!= VNOVAL
) {
595 if (vap
->va_atime
.tv_sec
!= time_second
) {
596 tl
= nfsm_build(info
, 3 * NFSX_UNSIGNED
);
597 *tl
++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT
);
598 txdr_nfsv3time(&vap
->va_atime
, tl
);
600 tl
= nfsm_build(info
, NFSX_UNSIGNED
);
601 *tl
= txdr_unsigned(NFSV3SATTRTIME_TOSERVER
);
604 tl
= nfsm_build(info
, NFSX_UNSIGNED
);
605 *tl
= txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE
);
607 if (vap
->va_mtime
.tv_sec
!= VNOVAL
) {
608 if (vap
->va_mtime
.tv_sec
!= time_second
) {
609 tl
= nfsm_build(info
, 3 * NFSX_UNSIGNED
);
610 *tl
++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT
);
611 txdr_nfsv3time(&vap
->va_mtime
, tl
);
613 tl
= nfsm_build(info
, NFSX_UNSIGNED
);
614 *tl
= txdr_unsigned(NFSV3SATTRTIME_TOSERVER
);
617 tl
= nfsm_build(info
, NFSX_UNSIGNED
);
618 *tl
= txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE
);
623 * Caller is expected to abort with EBADRPC if a negative length is returned.
626 nfsm_strsiz(nfsm_info_t info
, int maxlen
)
631 tl
= nfsm_dissect(info
, NFSX_UNSIGNED
);
634 len
= fxdr_unsigned(int32_t, *tl
);
635 if (len
< 0 || len
> maxlen
)
641 * Caller is expected to abort if a negative length is returned, but also
642 * call nfsm_reply(0) if -2 is returned.
644 * This function sets *errorp. Caller should not modify the error code.
647 nfsm_srvstrsiz(nfsm_info_t info
, int maxlen
, int *errorp
)
652 tl
= nfsm_dissect(info
, NFSX_UNSIGNED
);
657 len
= fxdr_unsigned(int32_t,*tl
);
658 if (len
> maxlen
|| len
<= 0) {
666 * Caller is expected to abort if a negative length is returned, but also
667 * call nfsm_reply(0) if -2 is returned.
669 * This function sets *errorp. Caller should not modify the error code.
672 nfsm_srvnamesiz(nfsm_info_t info
, int *errorp
)
677 tl
= nfsm_dissect(info
, NFSX_UNSIGNED
);
684 * In this case if *errorp is not EBADRPC and we are NFSv3,
685 * nfsm_reply() will not return a negative number. But all
686 * call cases assume len is valid so we really do want
689 len
= fxdr_unsigned(int32_t,*tl
);
690 if (len
> NFS_MAXNAMLEN
)
691 *errorp
= NFSERR_NAMETOL
;
700 * Caller is expected to abort if a non-zero error is returned.
703 nfsm_mtouio(nfsm_info_t info
, struct uio
*uiop
, int len
)
708 (error
= nfsm_mbuftouio(&info
->md
, uiop
, len
, &info
->dpos
)) != 0) {
717 * Caller is expected to abort if a non-zero error is returned.
720 nfsm_mtobio(nfsm_info_t info
, struct bio
*bio
, int len
)
725 (error
= nfsm_mbuftobio(&info
->md
, bio
, len
, &info
->dpos
)) != 0) {
734 * Caller is expected to abort if a non-zero error is returned.
737 nfsm_uiotom(nfsm_info_t info
, struct uio
*uiop
, int len
)
741 error
= nfsm_uiotombuf(uiop
, &info
->mb
, len
, &info
->bpos
);
751 nfsm_biotom(nfsm_info_t info
, struct bio
*bio
, int off
, int len
)
755 error
= nfsm_biotombuf(bio
, &info
->mb
, off
, len
, &info
->bpos
);
765 * Caller is expected to abort if a negative value is returned. This
766 * function sets *errorp. Caller should not modify the error code.
768 * We load up the remaining info fields and run the request state
769 * machine until it is done.
771 * This call runs the entire state machine and does not return until
772 * the command is complete.
775 nfsm_request(nfsm_info_t info
, struct vnode
*vp
, int procnum
,
776 thread_t td
, struct ucred
*cred
, int *errorp
)
778 info
->state
= NFSM_STATE_SETUP
;
779 info
->procnum
= procnum
;
784 info
->nmp
= VFSTONFS(vp
->v_mount
);
786 *errorp
= nfs_request(info
, NFSM_STATE_SETUP
, NFSM_STATE_DONE
);
788 if ((*errorp
& NFSERR_RETERR
) == 0)
790 *errorp
&= ~NFSERR_RETERR
;
796 * This call starts the state machine through the initial transmission.
797 * Completion is via the bio. The info structure must have installed
800 * If we are unable to do the initial tx we generate the bio completion
804 nfsm_request_bio(nfsm_info_t info
, struct vnode
*vp
, int procnum
,
805 thread_t td
, struct ucred
*cred
)
810 info
->state
= NFSM_STATE_SETUP
;
811 info
->procnum
= procnum
;
815 info
->nmp
= VFSTONFS(vp
->v_mount
);
817 error
= nfs_request(info
, NFSM_STATE_SETUP
, NFSM_STATE_WAITREPLY
);
818 if (error
!= EINPROGRESS
) {
819 kprintf("nfsm_request_bio: early abort %d\n", error
);
820 bp
= info
->bio
->bio_buf
;
822 bp
->b_flags
|= B_ERROR
;
829 * Caller is expected to abort if a non-zero error is returned.
832 nfsm_strtom(nfsm_info_t info
, const void *data
, int len
, int maxlen
)
841 return(ENAMETOOLONG
);
843 n
= nfsm_rndup(len
) + NFSX_UNSIGNED
;
844 if (n
<= M_TRAILINGSPACE(info
->mb
)) {
845 tl
= nfsm_build(info
, n
);
846 *tl
++ = txdr_unsigned(len
);
847 *(tl
+ ((n
>> 2) - 2)) = 0;
848 bcopy(data
, tl
, len
);
851 error
= nfsm_strtmbuf(&info
->mb
, &info
->bpos
, data
, len
);
861 * Caller is expected to abort if a negative value is returned. This
862 * function sets *errorp. Caller should not modify the error code.
865 nfsm_reply(nfsm_info_t info
,
866 struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
867 int siz
, int *errorp
)
869 nfsd
->nd_repstat
= *errorp
;
870 if (*errorp
&& !(nfsd
->nd_flag
& ND_NFSV3
))
872 nfs_rephead(siz
, nfsd
, slp
, *errorp
, &info
->mreq
,
873 &info
->mb
, &info
->bpos
);
874 if (info
->mrep
!= NULL
) {
878 if (*errorp
&& (!(nfsd
->nd_flag
& ND_NFSV3
) || *errorp
== EBADRPC
)) {
886 nfsm_writereply(nfsm_info_t info
,
887 struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
890 nfsd
->nd_repstat
= error
;
891 if (error
&& !(info
->v3
))
893 nfs_rephead(siz
, nfsd
, slp
, error
, &info
->mreq
, &info
->mb
, &info
->bpos
);
897 * Caller is expected to abort if a non-zero error is returned.
900 nfsm_adv(nfsm_info_t info
, int len
)
905 n
= mtod(info
->md
, caddr_t
) + info
->md
->m_len
- info
->dpos
;
909 } else if ((error
= nfs_adv(&info
->md
, &info
->dpos
, len
, n
)) != 0) {
917 * Caller is expected to abort if a negative length is returned, but also
918 * call nfsm_reply(0) if -2 is returned.
920 * This function sets *errorp. Caller should not modify the error code.
923 nfsm_srvmtofh(nfsm_info_t info
, struct nfsrv_descript
*nfsd
,
924 fhandle_t
*fhp
, int *errorp
)
929 if (nfsd
->nd_flag
& ND_NFSV3
) {
930 tl
= nfsm_dissect(info
, NFSX_UNSIGNED
);
935 fhlen
= fxdr_unsigned(int, *tl
);
936 if (fhlen
!= 0 && fhlen
!= NFSX_V3FH
) {
944 tl
= nfsm_dissect(info
, fhlen
);
949 bcopy(tl
, fhp
, fhlen
);
951 bzero(fhp
, NFSX_V3FH
);
957 _nfsm_clget(nfsm_info_t info
, struct mbuf
**mp1
, struct mbuf
**mp2
,
958 char **bp
, char **be
)
961 if (*mp1
== info
->mb
)
962 (*mp1
)->m_len
+= *bp
- info
->bpos
;
963 *mp1
= m_getcl(MB_WAIT
, MT_DATA
, 0);
964 (*mp1
)->m_len
= MCLBYTES
;
965 (*mp2
)->m_next
= *mp1
;
967 *bp
= mtod(*mp1
, caddr_t
);
968 *be
= *bp
+ (*mp1
)->m_len
;
974 nfsm_srvsattr(nfsm_info_t info
, struct vattr
*vap
)
979 NULLOUT(tl
= nfsm_dissect(info
, NFSX_UNSIGNED
));
980 if (*tl
== nfs_true
) {
981 NULLOUT(tl
= nfsm_dissect(info
, NFSX_UNSIGNED
));
982 vap
->va_mode
= nfstov_mode(*tl
);
984 NULLOUT(tl
= nfsm_dissect(info
, NFSX_UNSIGNED
));
985 if (*tl
== nfs_true
) {
986 NULLOUT(tl
= nfsm_dissect(info
, NFSX_UNSIGNED
));
987 vap
->va_uid
= fxdr_unsigned(uid_t
, *tl
);
989 NULLOUT(tl
= nfsm_dissect(info
, NFSX_UNSIGNED
));
990 if (*tl
== nfs_true
) {
991 NULLOUT(tl
= nfsm_dissect(info
, NFSX_UNSIGNED
));
992 vap
->va_gid
= fxdr_unsigned(gid_t
, *tl
);
994 NULLOUT(tl
= nfsm_dissect(info
, NFSX_UNSIGNED
));
995 if (*tl
== nfs_true
) {
996 NULLOUT(tl
= nfsm_dissect(info
, 2 * NFSX_UNSIGNED
));
997 vap
->va_size
= fxdr_hyper(tl
);
999 NULLOUT(tl
= nfsm_dissect(info
, NFSX_UNSIGNED
));
1000 switch (fxdr_unsigned(int, *tl
)) {
1001 case NFSV3SATTRTIME_TOCLIENT
:
1002 NULLOUT(tl
= nfsm_dissect(info
, 2 * NFSX_UNSIGNED
));
1003 fxdr_nfsv3time(tl
, &vap
->va_atime
);
1005 case NFSV3SATTRTIME_TOSERVER
:
1006 getnanotime(&vap
->va_atime
);
1009 NULLOUT(tl
= nfsm_dissect(info
, NFSX_UNSIGNED
));
1010 switch (fxdr_unsigned(int, *tl
)) {
1011 case NFSV3SATTRTIME_TOCLIENT
:
1012 NULLOUT(tl
= nfsm_dissect(info
, 2 * NFSX_UNSIGNED
));
1013 fxdr_nfsv3time(tl
, &vap
->va_mtime
);
1015 case NFSV3SATTRTIME_TOSERVER
:
1016 getnanotime(&vap
->va_mtime
);
1024 * copies mbuf chain to the uio scatter/gather list
1027 nfsm_mbuftouio(struct mbuf
**mrep
, struct uio
*uiop
, int siz
, caddr_t
*dpos
)
1029 char *mbufcp
, *uiocp
;
1030 int xfer
, left
, len
;
1037 len
= mtod(mp
, caddr_t
)+mp
->m_len
-mbufcp
;
1038 rem
= nfsm_rndup(siz
)-siz
;
1040 if (uiop
->uio_iovcnt
<= 0 || uiop
->uio_iov
== NULL
)
1042 left
= uiop
->uio_iov
->iov_len
;
1043 uiocp
= uiop
->uio_iov
->iov_base
;
1052 mbufcp
= mtod(mp
, caddr_t
);
1055 xfer
= (left
> len
) ? len
: left
;
1058 if (uiop
->uio_iov
->iov_op
!= NULL
)
1059 (*(uiop
->uio_iov
->iov_op
))
1060 (mbufcp
, uiocp
, xfer
);
1063 if (uiop
->uio_segflg
== UIO_SYSSPACE
)
1064 bcopy(mbufcp
, uiocp
, xfer
);
1066 copyout(mbufcp
, uiocp
, xfer
);
1071 uiop
->uio_offset
+= xfer
;
1072 uiop
->uio_resid
-= xfer
;
1074 if (uiop
->uio_iov
->iov_len
<= siz
) {
1078 uiop
->uio_iov
->iov_base
= (char *)uiop
->uio_iov
->iov_base
+ uiosiz
;
1079 uiop
->uio_iov
->iov_len
-= uiosiz
;
1087 error
= nfs_adv(mrep
, dpos
, rem
, len
);
1095 * copies mbuf chain to the bio buffer
1098 nfsm_mbuftobio(struct mbuf
**mrep
, struct bio
*bio
, int size
, caddr_t
*dpos
)
1100 struct buf
*bp
= bio
->bio_buf
;
1111 len
= mtod(mp
, caddr_t
) + mp
->m_len
- mbufcp
;
1112 rem
= nfsm_rndup(size
) - size
;
1114 bio_left
= bp
->b_bcount
;
1115 bio_cp
= bp
->b_data
;
1122 mbufcp
= mtod(mp
, caddr_t
);
1125 if ((xfer
= len
) > size
)
1128 if (xfer
> bio_left
)
1130 bcopy(mbufcp
, bio_cp
, xfer
);
1133 * Not enough buffer space in the bio.
1147 error
= nfs_adv(mrep
, dpos
, rem
, len
);
1155 * copies a uio scatter/gather list to an mbuf chain.
1156 * NOTE: can ony handle iovcnt == 1
1159 nfsm_uiotombuf(struct uio
*uiop
, struct mbuf
**mq
, int siz
, caddr_t
*bpos
)
1162 struct mbuf
*mp
, *mp2
;
1163 int xfer
, left
, mlen
;
1165 boolean_t getcluster
;
1169 if (uiop
->uio_iovcnt
!= 1)
1170 panic("nfsm_uiotombuf: iovcnt != 1");
1173 if (siz
>= MINCLSIZE
)
1177 rem
= nfsm_rndup(siz
) - siz
;
1180 left
= uiop
->uio_iov
->iov_len
;
1181 uiocp
= uiop
->uio_iov
->iov_base
;
1186 mlen
= M_TRAILINGSPACE(mp
);
1189 mp
= m_getcl(MB_WAIT
, MT_DATA
, 0);
1191 mp
= m_get(MB_WAIT
, MT_DATA
);
1195 mlen
= M_TRAILINGSPACE(mp
);
1197 xfer
= (left
> mlen
) ? mlen
: left
;
1200 if (uiop
->uio_iov
->iov_op
!= NULL
)
1201 (*(uiop
->uio_iov
->iov_op
))
1202 (uiocp
, mtod(mp
, caddr_t
)+mp
->m_len
, xfer
);
1205 if (uiop
->uio_segflg
== UIO_SYSSPACE
)
1206 bcopy(uiocp
, mtod(mp
, caddr_t
)+mp
->m_len
, xfer
);
1208 copyin(uiocp
, mtod(mp
, caddr_t
)+mp
->m_len
, xfer
);
1212 uiop
->uio_offset
+= xfer
;
1213 uiop
->uio_resid
-= xfer
;
1215 uiop
->uio_iov
->iov_base
= (char *)uiop
->uio_iov
->iov_base
+ uiosiz
;
1216 uiop
->uio_iov
->iov_len
-= uiosiz
;
1220 if (rem
> M_TRAILINGSPACE(mp
)) {
1221 MGET(mp
, MB_WAIT
, MT_DATA
);
1225 cp
= mtod(mp
, caddr_t
)+mp
->m_len
;
1226 for (left
= 0; left
< rem
; left
++)
1231 *bpos
= mtod(mp
, caddr_t
)+mp
->m_len
;
1237 nfsm_biotombuf(struct bio
*bio
, struct mbuf
**mq
, int off
,
1238 int siz
, caddr_t
*bpos
)
1240 struct buf
*bp
= bio
->bio_buf
;
1241 struct mbuf
*mp
, *mp2
;
1246 boolean_t getcluster
;
1249 if (siz
>= MINCLSIZE
)
1253 rem
= nfsm_rndup(siz
) - siz
;
1256 bio_cp
= bp
->b_data
+ off
;
1260 mlen
= M_TRAILINGSPACE(mp
);
1263 mp
= m_getcl(MB_WAIT
, MT_DATA
, 0);
1265 mp
= m_get(MB_WAIT
, MT_DATA
);
1269 mlen
= M_TRAILINGSPACE(mp
);
1271 xfer
= (bio_left
< mlen
) ? bio_left
: mlen
;
1272 bcopy(bio_cp
, mtod(mp
, caddr_t
) + mp
->m_len
, xfer
);
1278 if (rem
> M_TRAILINGSPACE(mp
)) {
1279 MGET(mp
, MB_WAIT
, MT_DATA
);
1283 cp
= mtod(mp
, caddr_t
) + mp
->m_len
;
1284 for (mlen
= 0; mlen
< rem
; mlen
++)
1289 *bpos
= mtod(mp
, caddr_t
) + mp
->m_len
;
1296 * Help break down an mbuf chain by setting the first siz bytes contiguous
1297 * pointed to by returned val.
1298 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
1299 * cases. (The macros use the vars. dpos and dpos2)
1302 nfsm_disct(struct mbuf
**mdp
, caddr_t
*dposp
, int siz
, int left
, caddr_t
*cp2
)
1304 struct mbuf
*mp
, *mp2
;
1310 *mdp
= mp
= mp
->m_next
;
1314 *dposp
= mtod(mp
, caddr_t
);
1319 } else if (mp
->m_next
== NULL
) {
1321 } else if (siz
> MHLEN
) {
1322 panic("nfs S too big");
1324 MGET(mp2
, MB_WAIT
, MT_DATA
);
1325 mp2
->m_next
= mp
->m_next
;
1329 *cp2
= p
= mtod(mp
, caddr_t
);
1330 bcopy(*dposp
, p
, left
); /* Copy what was left */
1334 /* Loop around copying up the siz2 bytes */
1338 xfer
= (siz2
> mp2
->m_len
) ? mp2
->m_len
: siz2
;
1340 bcopy(mtod(mp2
, caddr_t
), p
, xfer
);
1342 mp2
->m_data
+= xfer
;
1351 *dposp
= mtod(mp2
, caddr_t
);
1357 * Advance the position in the mbuf chain.
1360 nfs_adv(struct mbuf
**mdp
, caddr_t
*dposp
, int offs
, int left
)
1375 *dposp
= mtod(m
, caddr_t
)+offs
;
1380 * Copy a string into mbufs for the hard cases...
1383 nfsm_strtmbuf(struct mbuf
**mb
, char **bpos
, const char *cp
, long siz
)
1385 struct mbuf
*m1
= NULL
, *m2
;
1386 long left
, xfer
, len
, tlen
;
1392 left
= M_TRAILINGSPACE(m2
);
1394 tl
= ((u_int32_t
*)(*bpos
));
1395 *tl
++ = txdr_unsigned(siz
);
1397 left
-= NFSX_UNSIGNED
;
1398 m2
->m_len
+= NFSX_UNSIGNED
;
1400 bcopy(cp
, (caddr_t
) tl
, left
);
1407 /* Loop around adding mbufs */
1411 m1
= m_getl(siz
, MB_WAIT
, MT_DATA
, 0, &msize
);
1415 tl
= mtod(m1
, u_int32_t
*);
1418 *tl
++ = txdr_unsigned(siz
);
1419 m1
->m_len
-= NFSX_UNSIGNED
;
1420 tlen
= NFSX_UNSIGNED
;
1423 if (siz
< m1
->m_len
) {
1424 len
= nfsm_rndup(siz
);
1427 *(tl
+(xfer
>>2)) = 0;
1429 xfer
= len
= m1
->m_len
;
1431 bcopy(cp
, (caddr_t
) tl
, xfer
);
1432 m1
->m_len
= len
+tlen
;
1437 *bpos
= mtod(m1
, caddr_t
)+m1
->m_len
;
1442 * A fiddled version of m_adj() that ensures null fill to a long
1443 * boundary and only trims off the back end
1446 nfsm_adj(struct mbuf
*mp
, int len
, int nul
)
1453 * Trim from tail. Scan the mbuf chain,
1454 * calculating its length and finding the last mbuf.
1455 * If the adjustment only affects this mbuf, then just
1456 * adjust and return. Otherwise, rescan and truncate
1457 * after the remaining size.
1463 if (m
->m_next
== NULL
)
1467 if (m
->m_len
> len
) {
1470 cp
= mtod(m
, caddr_t
)+m
->m_len
-nul
;
1471 for (i
= 0; i
< nul
; i
++)
1480 * Correct length for chain is "count".
1481 * Find the mbuf with last data, adjust its length,
1482 * and toss data from remaining mbufs on chain.
1484 for (m
= mp
; m
; m
= m
->m_next
) {
1485 if (m
->m_len
>= count
) {
1488 cp
= mtod(m
, caddr_t
)+m
->m_len
-nul
;
1489 for (i
= 0; i
< nul
; i
++)
1496 for (m
= m
->m_next
;m
;m
= m
->m_next
)
1501 * Make these functions instead of macros, so that the kernel text size
1502 * doesn't get too big...
1505 nfsm_srvwcc_data(nfsm_info_t info
, struct nfsrv_descript
*nfsd
,
1506 int before_ret
, struct vattr
*before_vap
,
1507 int after_ret
, struct vattr
*after_vap
)
1512 * before_ret is 0 if before_vap is valid, non-zero if it isn't.
1515 tl
= nfsm_build(info
, NFSX_UNSIGNED
);
1518 tl
= nfsm_build(info
, 7 * NFSX_UNSIGNED
);
1520 txdr_hyper(before_vap
->va_size
, tl
);
1522 txdr_nfsv3time(&(before_vap
->va_mtime
), tl
);
1524 txdr_nfsv3time(&(before_vap
->va_ctime
), tl
);
1526 nfsm_srvpostop_attr(info
, nfsd
, after_ret
, after_vap
);
1530 nfsm_srvpostop_attr(nfsm_info_t info
, struct nfsrv_descript
*nfsd
,
1531 int after_ret
, struct vattr
*after_vap
)
1533 struct nfs_fattr
*fp
;
1537 tl
= nfsm_build(info
, NFSX_UNSIGNED
);
1540 tl
= nfsm_build(info
, NFSX_UNSIGNED
+ NFSX_V3FATTR
);
1542 fp
= (struct nfs_fattr
*)tl
;
1543 nfsm_srvfattr(nfsd
, after_vap
, fp
);
1548 nfsm_srvfattr(struct nfsrv_descript
*nfsd
, struct vattr
*vap
,
1549 struct nfs_fattr
*fp
)
1552 * NFS seems to truncate nlink to 16 bits, don't let it overflow.
1554 if (vap
->va_nlink
> 65535)
1555 fp
->fa_nlink
= 65535;
1557 fp
->fa_nlink
= txdr_unsigned(vap
->va_nlink
);
1558 fp
->fa_uid
= txdr_unsigned(vap
->va_uid
);
1559 fp
->fa_gid
= txdr_unsigned(vap
->va_gid
);
1560 if (nfsd
->nd_flag
& ND_NFSV3
) {
1561 fp
->fa_type
= vtonfsv3_type(vap
->va_type
);
1562 fp
->fa_mode
= vtonfsv3_mode(vap
->va_mode
);
1563 txdr_hyper(vap
->va_size
, &fp
->fa3_size
);
1564 txdr_hyper(vap
->va_bytes
, &fp
->fa3_used
);
1565 fp
->fa3_rdev
.specdata1
= txdr_unsigned(vap
->va_rmajor
);
1566 fp
->fa3_rdev
.specdata2
= txdr_unsigned(vap
->va_rminor
);
1567 fp
->fa3_fsid
.nfsuquad
[0] = 0;
1568 fp
->fa3_fsid
.nfsuquad
[1] = txdr_unsigned(vap
->va_fsid
);
1569 txdr_hyper(vap
->va_fileid
, &fp
->fa3_fileid
);
1570 txdr_nfsv3time(&vap
->va_atime
, &fp
->fa3_atime
);
1571 txdr_nfsv3time(&vap
->va_mtime
, &fp
->fa3_mtime
);
1572 txdr_nfsv3time(&vap
->va_ctime
, &fp
->fa3_ctime
);
1574 fp
->fa_type
= vtonfsv2_type(vap
->va_type
);
1575 fp
->fa_mode
= vtonfsv2_mode(vap
->va_type
, vap
->va_mode
);
1576 fp
->fa2_size
= txdr_unsigned(vap
->va_size
);
1577 fp
->fa2_blocksize
= txdr_unsigned(vap
->va_blocksize
);
1578 if (vap
->va_type
== VFIFO
)
1579 fp
->fa2_rdev
= 0xffffffff;
1581 fp
->fa2_rdev
= txdr_unsigned(makeudev(vap
->va_rmajor
, vap
->va_rminor
));
1582 fp
->fa2_blocks
= txdr_unsigned(vap
->va_bytes
/ NFS_FABLKSIZE
);
1583 fp
->fa2_fsid
= txdr_unsigned(vap
->va_fsid
);
1584 fp
->fa2_fileid
= txdr_unsigned(vap
->va_fileid
);
1585 txdr_nfsv2time(&vap
->va_atime
, &fp
->fa2_atime
);
1586 txdr_nfsv2time(&vap
->va_mtime
, &fp
->fa2_mtime
);
1587 txdr_nfsv2time(&vap
->va_ctime
, &fp
->fa2_ctime
);