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. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67 * These functions support the macros and help fiddle mbuf chains for
68 * the nfs op functions. They do things like create the rpc header and
69 * copy data between mbuf chains and uio lists.
71 #include <sys/param.h>
72 #include <sys/systm.h>
73 #include <sys/kernel.h>
76 #include <sys/mount.h>
77 #include <sys/vnode.h>
78 #include <sys/nlookup.h>
79 #include <sys/namei.h>
81 #include <sys/socket.h>
83 #include <sys/malloc.h>
84 #include <sys/sysent.h>
85 #include <sys/syscall.h>
87 #include <sys/objcache.h>
90 #include <vm/vm_object.h>
91 #include <vm/vm_extern.h>
100 #include "xdr_subs.h"
101 #include "nfsm_subs.h"
104 #include <netinet/in.h>
106 static u_int32_t nfs_xid
= 0;
109 * Create the header for an rpc request packet
110 * The hsiz is the size of the rest of the nfs request header.
111 * (just used to decide if a cluster is a good idea)
114 nfsm_reqhead(nfsm_info_t info
, struct vnode
*vp
, u_long procid
, int hsiz
)
116 info
->mb
= m_getl(hsiz
, M_WAITOK
, MT_DATA
, 0, NULL
);
118 info
->mreq
= info
->mb
;
119 info
->bpos
= mtod(info
->mb
, caddr_t
);
123 * Build the RPC header and fill in the authorization info.
124 * The authorization string argument is only used when the credentials
125 * come from outside of the kernel.
126 * Returns the head of the mbuf list.
129 nfsm_rpchead(struct ucred
*cr
, int nmflag
, int procid
, int auth_type
,
130 int auth_len
, char *auth_str
, int verf_len
, char *verf_str
,
131 struct mbuf
*mrest
, int mrest_len
, struct mbuf
**mbp
,
134 struct nfsm_info info
;
138 int siz
, grpsiz
, authsiz
, dsiz
;
141 authsiz
= nfsm_rndup(auth_len
);
142 dsiz
= authsiz
+ 10 * NFSX_UNSIGNED
;
143 info
.mb
= m_getl(dsiz
, M_WAITOK
, MT_DATA
, M_PKTHDR
, NULL
);
144 if (dsiz
< MINCLSIZE
) {
146 MH_ALIGN(info
.mb
, dsiz
);
148 MH_ALIGN(info
.mb
, 8 * NFSX_UNSIGNED
);
150 info
.mb
->m_len
= info
.mb
->m_pkthdr
.len
= 0;
152 info
.bpos
= mtod(info
.mb
, caddr_t
);
155 * First the RPC header.
157 tl
= nfsm_build(&info
, 8 * NFSX_UNSIGNED
);
159 /* Get a pretty random xid to start with */
164 xid
= atomic_fetchadd_int(&nfs_xid
, 1);
167 *tl
++ = *xidp
= txdr_unsigned(xid
);
170 *tl
++ = txdr_unsigned(NFS_PROG
);
171 if (nmflag
& NFSMNT_NFSV3
)
172 *tl
++ = txdr_unsigned(NFS_VER3
);
174 *tl
++ = txdr_unsigned(NFS_VER2
);
175 if (nmflag
& NFSMNT_NFSV3
)
176 *tl
++ = txdr_unsigned(procid
);
178 *tl
++ = txdr_unsigned(nfsv2_procid
[procid
]);
181 * And then the authorization cred.
183 *tl
++ = txdr_unsigned(auth_type
);
184 *tl
= txdr_unsigned(authsiz
);
187 tl
= nfsm_build(&info
, auth_len
);
188 *tl
++ = 0; /* stamp ?? */
189 *tl
++ = 0; /* NULL hostname */
190 *tl
++ = txdr_unsigned(cr
->cr_uid
);
191 *tl
++ = txdr_unsigned(cr
->cr_groups
[0]);
192 grpsiz
= (auth_len
>> 2) - 5;
193 *tl
++ = txdr_unsigned(grpsiz
);
194 for (i
= 1; i
<= grpsiz
; i
++)
195 *tl
++ = txdr_unsigned(cr
->cr_groups
[i
]);
200 if (M_TRAILINGSPACE(info
.mb
) == 0) {
201 mb2
= m_getl(siz
, M_WAITOK
, MT_DATA
, 0, NULL
);
203 info
.mb
->m_next
= mb2
;
205 info
.bpos
= mtod(info
.mb
, caddr_t
);
207 i
= min(siz
, M_TRAILINGSPACE(info
.mb
));
208 bcopy(auth_str
, info
.bpos
, i
);
214 if ((siz
= (nfsm_rndup(auth_len
) - auth_len
)) > 0) {
215 for (i
= 0; i
< siz
; i
++)
217 info
.mb
->m_len
+= siz
;
223 * And the verifier...
225 tl
= nfsm_build(&info
, 2 * NFSX_UNSIGNED
);
227 *tl
++ = txdr_unsigned(RPCAUTH_KERB4
);
228 *tl
= txdr_unsigned(verf_len
);
231 if (M_TRAILINGSPACE(info
.mb
) == 0) {
232 mb2
= m_getl(siz
, M_WAITOK
, MT_DATA
,
235 info
.mb
->m_next
= mb2
;
237 info
.bpos
= mtod(info
.mb
, caddr_t
);
239 i
= min(siz
, M_TRAILINGSPACE(info
.mb
));
240 bcopy(verf_str
, info
.bpos
, i
);
246 if ((siz
= (nfsm_rndup(verf_len
) - verf_len
)) > 0) {
247 for (i
= 0; i
< siz
; i
++)
249 info
.mb
->m_len
+= siz
;
252 *tl
++ = txdr_unsigned(RPCAUTH_NULL
);
255 info
.mb
->m_next
= mrest
;
256 info
.mreq
->m_pkthdr
.len
= authsiz
+ 10 * NFSX_UNSIGNED
+ mrest_len
;
257 info
.mreq
->m_pkthdr
.rcvif
= NULL
;
263 nfsm_build(nfsm_info_t info
, int bytes
)
268 if (bytes
> M_TRAILINGSPACE(info
->mb
)) {
269 MGET(mb2
, M_WAITOK
, MT_DATA
);
271 panic("build > MLEN");
272 info
->mb
->m_next
= mb2
;
275 info
->bpos
= mtod(info
->mb
, caddr_t
);
278 info
->mb
->m_len
+= bytes
;
285 * If NULL returned caller is expected to abort with an EBADRPC error.
286 * Caller will usually use the NULLOUT macro.
289 nfsm_dissect(nfsm_info_t info
, int bytes
)
297 * Check for missing reply packet. This typically occurs if there
298 * is a soft termination w/too many retries.
300 if (info
->md
== NULL
) {
309 * Otherwise any error will be due to the packet format
311 n
= mtod(info
->md
, caddr_t
) + info
->md
->m_len
- info
->dpos
;
316 error
= nfsm_disct(&info
->md
, &info
->dpos
, bytes
, n
, &cp2
);
330 * Caller is expected to abort if non-zero error is returned.
333 nfsm_fhtom(nfsm_info_t info
, struct vnode
*vp
)
341 n
= nfsm_rndup(VTONFS(vp
)->n_fhsize
) + NFSX_UNSIGNED
;
342 if (n
<= M_TRAILINGSPACE(info
->mb
)) {
343 tl
= nfsm_build(info
, n
);
344 *tl
++ = txdr_unsigned(VTONFS(vp
)->n_fhsize
);
345 *(tl
+ ((n
>> 2) - 2)) = 0;
346 bcopy((caddr_t
)VTONFS(vp
)->n_fhp
,(caddr_t
)tl
,
347 VTONFS(vp
)->n_fhsize
);
349 } else if ((error
= nfsm_strtmbuf(&info
->mb
, &info
->bpos
,
350 (caddr_t
)VTONFS(vp
)->n_fhp
,
351 VTONFS(vp
)->n_fhsize
)) != 0) {
356 cp
= nfsm_build(info
, NFSX_V2FH
);
357 bcopy(VTONFS(vp
)->n_fhp
, cp
, NFSX_V2FH
);
364 nfsm_srvfhtom(nfsm_info_t info
, fhandle_t
*fhp
)
369 tl
= nfsm_build(info
, NFSX_UNSIGNED
+ NFSX_V3FH
);
370 *tl
++ = txdr_unsigned(NFSX_V3FH
);
371 bcopy(fhp
, tl
, NFSX_V3FH
);
373 tl
= nfsm_build(info
, NFSX_V2FH
);
374 bcopy(fhp
, tl
, NFSX_V2FH
);
379 nfsm_srvpostop_fh(nfsm_info_t info
, fhandle_t
*fhp
)
383 tl
= nfsm_build(info
, 2 * NFSX_UNSIGNED
+ NFSX_V3FH
);
385 *tl
++ = txdr_unsigned(NFSX_V3FH
);
386 bcopy(fhp
, tl
, NFSX_V3FH
);
390 * Caller is expected to abort if non-zero error is returned.
392 * NOTE: (*vpp) may be loaded with a valid vnode even if (*gotvpp)
393 * winds up 0. The caller is responsible for dealing with (*vpp).
396 nfsm_mtofh(nfsm_info_t info
, struct vnode
*dvp
, struct vnode
**vpp
, int *gotvpp
)
398 struct nfsnode
*ttnp
;
405 tl
= nfsm_dissect(info
, NFSX_UNSIGNED
);
408 *gotvpp
= fxdr_unsigned(int, *tl
);
413 NEGATIVEOUT(ttfhsize
= nfsm_getfh(info
, &ttfhp
));
414 error
= nfs_nget(dvp
->v_mount
, ttfhp
, ttfhsize
, &ttnp
, NULL
);
423 tl
= nfsm_dissect(info
, NFSX_UNSIGNED
);
427 *gotvpp
= fxdr_unsigned(int, *tl
);
428 } else if (fxdr_unsigned(int, *tl
)) {
429 error
= nfsm_adv(info
, NFSX_V3FATTR
);
435 error
= nfsm_loadattr(info
, *vpp
, NULL
);
442 * Caller is expected to abort with EBADRPC if a negative length is returned.
445 nfsm_getfh(nfsm_info_t info
, nfsfh_t
**fhpp
)
452 tl
= nfsm_dissect(info
, NFSX_UNSIGNED
);
455 if ((n
= fxdr_unsigned(int, *tl
)) <= 0 || n
> NFSX_V3FHMAX
) {
463 *fhpp
= nfsm_dissect(info
, nfsm_rndup(n
));
470 * Caller is expected to abort if a non-zero error is returned.
473 nfsm_loadattr(nfsm_info_t info
, struct vnode
*vp
, struct vattr
*vap
)
477 error
= nfs_loadattrcache(vp
, &info
->md
, &info
->dpos
, vap
, 0);
487 * Caller is expected to abort if a non-zero error is returned.
490 nfsm_postop_attr(nfsm_info_t info
, struct vnode
*vp
, int *attrp
, int lflags
)
495 tl
= nfsm_dissect(info
, NFSX_UNSIGNED
);
498 *attrp
= fxdr_unsigned(int, *tl
);
500 error
= nfs_loadattrcache(vp
, &info
->md
, &info
->dpos
,
513 * Caller is expected to abort if a non-zero error is returned.
516 nfsm_wcc_data(nfsm_info_t info
, struct vnode
*vp
, int *attrp
)
523 tl
= nfsm_dissect(info
, NFSX_UNSIGNED
);
526 if (*tl
== nfs_true
) {
527 tl
= nfsm_dissect(info
, 6 * NFSX_UNSIGNED
);
531 ttretf
= (VTONFS(vp
)->n_mtime
==
532 fxdr_unsigned(u_int32_t
, *(tl
+ 2)));
534 VTONFS(vp
)->n_flag
|= NRMODIFIED
;
536 error
= nfsm_postop_attr(info
, vp
, &ttattrf
,
537 NFS_LATTR_NOSHRINK
|NFS_LATTR_NOMTIMECHECK
);
541 error
= nfsm_postop_attr(info
, vp
, &ttattrf
,
554 * This function updates the attribute cache based on data returned in the
555 * NFS reply for NFS RPCs that modify the target file. If the RPC succeeds
556 * a 'before' and 'after' mtime is returned that allows us to determine if
557 * the new mtime attribute represents our modification or someone else's
560 * The flag argument returns non-0 if the original times matched, zero if
561 * they did not match. NRMODIFIED is automatically set if the before time
562 * does not match the original n_mtime, and n_mtime is automatically updated
563 * to the new after time (by nfsm_postop_attr()).
565 * If full is true, set all fields, otherwise just set mode and time fields
568 nfsm_v3attrbuild(nfsm_info_t info
, struct vattr
*vap
, int full
)
572 if (vap
->va_mode
!= (mode_t
)VNOVAL
) {
573 tl
= nfsm_build(info
, 2 * NFSX_UNSIGNED
);
575 *tl
= txdr_unsigned(vap
->va_mode
);
577 tl
= nfsm_build(info
, NFSX_UNSIGNED
);
580 if (full
&& vap
->va_uid
!= (uid_t
)VNOVAL
) {
581 tl
= nfsm_build(info
, 2 * NFSX_UNSIGNED
);
583 *tl
= txdr_unsigned(vap
->va_uid
);
585 tl
= nfsm_build(info
, NFSX_UNSIGNED
);
588 if (full
&& vap
->va_gid
!= (gid_t
)VNOVAL
) {
589 tl
= nfsm_build(info
, 2 * NFSX_UNSIGNED
);
591 *tl
= txdr_unsigned(vap
->va_gid
);
593 tl
= nfsm_build(info
, NFSX_UNSIGNED
);
596 if (full
&& vap
->va_size
!= VNOVAL
) {
597 tl
= nfsm_build(info
, 3 * NFSX_UNSIGNED
);
599 txdr_hyper(vap
->va_size
, tl
);
601 tl
= nfsm_build(info
, NFSX_UNSIGNED
);
604 if (vap
->va_atime
.tv_sec
!= VNOVAL
) {
605 if (vap
->va_atime
.tv_sec
!= time_second
) {
606 tl
= nfsm_build(info
, 3 * NFSX_UNSIGNED
);
607 *tl
++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT
);
608 txdr_nfsv3time(&vap
->va_atime
, tl
);
610 tl
= nfsm_build(info
, NFSX_UNSIGNED
);
611 *tl
= txdr_unsigned(NFSV3SATTRTIME_TOSERVER
);
614 tl
= nfsm_build(info
, NFSX_UNSIGNED
);
615 *tl
= txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE
);
617 if (vap
->va_mtime
.tv_sec
!= VNOVAL
) {
618 if (vap
->va_mtime
.tv_sec
!= time_second
) {
619 tl
= nfsm_build(info
, 3 * NFSX_UNSIGNED
);
620 *tl
++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT
);
621 txdr_nfsv3time(&vap
->va_mtime
, tl
);
623 tl
= nfsm_build(info
, NFSX_UNSIGNED
);
624 *tl
= txdr_unsigned(NFSV3SATTRTIME_TOSERVER
);
627 tl
= nfsm_build(info
, NFSX_UNSIGNED
);
628 *tl
= txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE
);
633 * Caller is expected to abort with EBADRPC if a negative length is returned.
636 nfsm_strsiz(nfsm_info_t info
, int maxlen
)
641 tl
= nfsm_dissect(info
, NFSX_UNSIGNED
);
644 len
= fxdr_unsigned(int32_t, *tl
);
645 if (len
< 0 || len
> maxlen
)
651 * Caller is expected to abort if a negative length is returned, but also
652 * call nfsm_reply(0) if -2 is returned.
654 * This function sets *errorp. Caller should not modify the error code.
657 nfsm_srvstrsiz(nfsm_info_t info
, int maxlen
, int *errorp
)
662 tl
= nfsm_dissect(info
, NFSX_UNSIGNED
);
667 len
= fxdr_unsigned(int32_t,*tl
);
668 if (len
> maxlen
|| len
<= 0) {
676 * Caller is expected to abort if a negative length is returned, but also
677 * call nfsm_reply(0) if -2 is returned.
679 * This function sets *errorp. Caller should not modify the error code.
682 nfsm_srvnamesiz(nfsm_info_t info
, int *errorp
)
687 tl
= nfsm_dissect(info
, NFSX_UNSIGNED
);
694 * In this case if *errorp is not EBADRPC and we are NFSv3,
695 * nfsm_reply() will not return a negative number. But all
696 * call cases assume len is valid so we really do want
699 len
= fxdr_unsigned(int32_t,*tl
);
700 if (len
> NFS_MAXNAMLEN
)
701 *errorp
= NFSERR_NAMETOL
;
710 * Caller is expected to abort if a non-zero error is returned.
713 nfsm_mtouio(nfsm_info_t info
, struct uio
*uiop
, int len
)
718 (error
= nfsm_mbuftouio(&info
->md
, uiop
, len
, &info
->dpos
)) != 0) {
727 * Caller is expected to abort if a non-zero error is returned.
730 nfsm_mtobio(nfsm_info_t info
, struct bio
*bio
, int len
)
735 (error
= nfsm_mbuftobio(&info
->md
, bio
, len
, &info
->dpos
)) != 0) {
744 * Caller is expected to abort if a non-zero error is returned.
747 nfsm_uiotom(nfsm_info_t info
, struct uio
*uiop
, int len
)
751 error
= nfsm_uiotombuf(uiop
, &info
->mb
, len
, &info
->bpos
);
761 nfsm_biotom(nfsm_info_t info
, struct bio
*bio
, int off
, int len
)
765 error
= nfsm_biotombuf(bio
, &info
->mb
, off
, len
, &info
->bpos
);
775 * Caller is expected to abort if a negative value is returned. This
776 * function sets *errorp. Caller should not modify the error code.
778 * We load up the remaining info fields and run the request state
779 * machine until it is done.
781 * This call runs the entire state machine and does not return until
782 * the command is complete.
785 nfsm_request(nfsm_info_t info
, struct vnode
*vp
, int procnum
,
786 thread_t td
, struct ucred
*cred
, int *errorp
)
788 info
->state
= NFSM_STATE_SETUP
;
789 info
->procnum
= procnum
;
794 info
->nmp
= VFSTONFS(vp
->v_mount
);
796 *errorp
= nfs_request(info
, NFSM_STATE_SETUP
, NFSM_STATE_DONE
);
798 if ((*errorp
& NFSERR_RETERR
) == 0)
800 *errorp
&= ~NFSERR_RETERR
;
806 * This call starts the state machine through the initial transmission.
807 * Completion is via the bio. The info structure must have installed
810 * If we are unable to do the initial tx we generate the bio completion
814 nfsm_request_bio(nfsm_info_t info
, struct vnode
*vp
, int procnum
,
815 thread_t td
, struct ucred
*cred
)
820 info
->state
= NFSM_STATE_SETUP
;
821 info
->procnum
= procnum
;
825 info
->nmp
= VFSTONFS(vp
->v_mount
);
827 error
= nfs_request(info
, NFSM_STATE_SETUP
, NFSM_STATE_WAITREPLY
);
828 if (error
!= EINPROGRESS
) {
829 kprintf("nfsm_request_bio: early abort %d\n", error
);
830 bp
= info
->bio
->bio_buf
;
832 bp
->b_flags
|= B_ERROR
;
833 if (error
== EIO
) /* unrecoverable */
834 bp
->b_flags
|= B_INVAL
;
842 * Caller is expected to abort if a non-zero error is returned.
845 nfsm_strtom(nfsm_info_t info
, const void *data
, int len
, int maxlen
)
854 return(ENAMETOOLONG
);
856 n
= nfsm_rndup(len
) + NFSX_UNSIGNED
;
857 if (n
<= M_TRAILINGSPACE(info
->mb
)) {
858 tl
= nfsm_build(info
, n
);
859 *tl
++ = txdr_unsigned(len
);
860 *(tl
+ ((n
>> 2) - 2)) = 0;
861 bcopy(data
, tl
, len
);
864 error
= nfsm_strtmbuf(&info
->mb
, &info
->bpos
, data
, len
);
874 * Caller is expected to abort if a negative value is returned. This
875 * function sets *errorp. Caller should not modify the error code.
878 nfsm_reply(nfsm_info_t info
,
879 struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
880 int siz
, int *errorp
)
882 nfsd
->nd_repstat
= *errorp
;
883 if (*errorp
&& !(nfsd
->nd_flag
& ND_NFSV3
))
885 nfs_rephead(siz
, nfsd
, slp
, *errorp
, &info
->mreq
,
886 &info
->mb
, &info
->bpos
);
887 if (info
->mrep
!= NULL
) {
891 if (*errorp
&& (!(nfsd
->nd_flag
& ND_NFSV3
) || *errorp
== EBADRPC
)) {
899 nfsm_writereply(nfsm_info_t info
,
900 struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
903 nfsd
->nd_repstat
= error
;
904 if (error
&& !(info
->v3
))
906 nfs_rephead(siz
, nfsd
, slp
, error
, &info
->mreq
, &info
->mb
, &info
->bpos
);
910 * Caller is expected to abort if a non-zero error is returned.
913 nfsm_adv(nfsm_info_t info
, int len
)
918 n
= mtod(info
->md
, caddr_t
) + info
->md
->m_len
- info
->dpos
;
922 } else if ((error
= nfs_adv(&info
->md
, &info
->dpos
, len
, n
)) != 0) {
930 * Caller is expected to abort if a negative length is returned, but also
931 * call nfsm_reply(0) if -2 is returned.
933 * This function sets *errorp. Caller should not modify the error code.
936 nfsm_srvmtofh(nfsm_info_t info
, struct nfsrv_descript
*nfsd
,
937 fhandle_t
*fhp
, int *errorp
)
942 if (nfsd
->nd_flag
& ND_NFSV3
) {
943 tl
= nfsm_dissect(info
, NFSX_UNSIGNED
);
948 fhlen
= fxdr_unsigned(int, *tl
);
949 if (fhlen
!= 0 && fhlen
!= NFSX_V3FH
) {
957 tl
= nfsm_dissect(info
, fhlen
);
962 bcopy(tl
, fhp
, fhlen
);
964 bzero(fhp
, NFSX_V3FH
);
970 _nfsm_clget(nfsm_info_t info
, struct mbuf
**mp1
, struct mbuf
**mp2
,
971 char **bp
, char **be
)
974 if (*mp1
== info
->mb
)
975 (*mp1
)->m_len
+= *bp
- info
->bpos
;
976 *mp1
= m_getcl(M_WAITOK
, MT_DATA
, 0);
977 (*mp1
)->m_len
= MCLBYTES
;
978 (*mp2
)->m_next
= *mp1
;
980 *bp
= mtod(*mp1
, caddr_t
);
981 *be
= *bp
+ (*mp1
)->m_len
;
987 nfsm_srvsattr(nfsm_info_t info
, struct vattr
*vap
)
992 NULLOUT(tl
= nfsm_dissect(info
, NFSX_UNSIGNED
));
993 if (*tl
== nfs_true
) {
994 NULLOUT(tl
= nfsm_dissect(info
, NFSX_UNSIGNED
));
995 vap
->va_mode
= nfstov_mode(*tl
);
997 NULLOUT(tl
= nfsm_dissect(info
, NFSX_UNSIGNED
));
998 if (*tl
== nfs_true
) {
999 NULLOUT(tl
= nfsm_dissect(info
, NFSX_UNSIGNED
));
1000 vap
->va_uid
= fxdr_unsigned(uid_t
, *tl
);
1002 NULLOUT(tl
= nfsm_dissect(info
, NFSX_UNSIGNED
));
1003 if (*tl
== nfs_true
) {
1004 NULLOUT(tl
= nfsm_dissect(info
, NFSX_UNSIGNED
));
1005 vap
->va_gid
= fxdr_unsigned(gid_t
, *tl
);
1007 NULLOUT(tl
= nfsm_dissect(info
, NFSX_UNSIGNED
));
1008 if (*tl
== nfs_true
) {
1009 NULLOUT(tl
= nfsm_dissect(info
, 2 * NFSX_UNSIGNED
));
1010 vap
->va_size
= fxdr_hyper(tl
);
1012 NULLOUT(tl
= nfsm_dissect(info
, NFSX_UNSIGNED
));
1013 switch (fxdr_unsigned(int, *tl
)) {
1014 case NFSV3SATTRTIME_TOCLIENT
:
1015 NULLOUT(tl
= nfsm_dissect(info
, 2 * NFSX_UNSIGNED
));
1016 fxdr_nfsv3time(tl
, &vap
->va_atime
);
1018 case NFSV3SATTRTIME_TOSERVER
:
1019 getnanotime(&vap
->va_atime
);
1022 NULLOUT(tl
= nfsm_dissect(info
, NFSX_UNSIGNED
));
1023 switch (fxdr_unsigned(int, *tl
)) {
1024 case NFSV3SATTRTIME_TOCLIENT
:
1025 NULLOUT(tl
= nfsm_dissect(info
, 2 * NFSX_UNSIGNED
));
1026 fxdr_nfsv3time(tl
, &vap
->va_mtime
);
1028 case NFSV3SATTRTIME_TOSERVER
:
1029 getnanotime(&vap
->va_mtime
);
1037 * copies mbuf chain to the uio scatter/gather list
1040 nfsm_mbuftouio(struct mbuf
**mrep
, struct uio
*uiop
, int siz
, caddr_t
*dpos
)
1042 char *mbufcp
, *uiocp
;
1043 int xfer
, left
, len
;
1050 len
= mtod(mp
, caddr_t
)+mp
->m_len
-mbufcp
;
1051 rem
= nfsm_rndup(siz
)-siz
;
1053 if (uiop
->uio_iovcnt
<= 0 || uiop
->uio_iov
== NULL
)
1055 left
= uiop
->uio_iov
->iov_len
;
1056 uiocp
= uiop
->uio_iov
->iov_base
;
1065 mbufcp
= mtod(mp
, caddr_t
);
1068 xfer
= (left
> len
) ? len
: left
;
1071 if (uiop
->uio_iov
->iov_op
!= NULL
)
1072 (*(uiop
->uio_iov
->iov_op
))
1073 (mbufcp
, uiocp
, xfer
);
1076 if (uiop
->uio_segflg
== UIO_SYSSPACE
)
1077 bcopy(mbufcp
, uiocp
, xfer
);
1079 copyout(mbufcp
, uiocp
, xfer
);
1084 uiop
->uio_offset
+= xfer
;
1085 uiop
->uio_resid
-= xfer
;
1087 if (uiop
->uio_iov
->iov_len
<= siz
) {
1091 uiop
->uio_iov
->iov_base
= (char *)uiop
->uio_iov
->iov_base
+ uiosiz
;
1092 uiop
->uio_iov
->iov_len
-= uiosiz
;
1100 error
= nfs_adv(mrep
, dpos
, rem
, len
);
1108 * copies mbuf chain to the bio buffer
1111 nfsm_mbuftobio(struct mbuf
**mrep
, struct bio
*bio
, int size
, caddr_t
*dpos
)
1113 struct buf
*bp
= bio
->bio_buf
;
1124 len
= mtod(mp
, caddr_t
) + mp
->m_len
- mbufcp
;
1125 rem
= nfsm_rndup(size
) - size
;
1127 bio_left
= bp
->b_bcount
;
1128 bio_cp
= bp
->b_data
;
1135 mbufcp
= mtod(mp
, caddr_t
);
1138 if ((xfer
= len
) > size
)
1141 if (xfer
> bio_left
)
1143 bcopy(mbufcp
, bio_cp
, xfer
);
1146 * Not enough buffer space in the bio.
1160 error
= nfs_adv(mrep
, dpos
, rem
, len
);
1168 * copies a uio scatter/gather list to an mbuf chain.
1169 * NOTE: can ony handle iovcnt == 1
1172 nfsm_uiotombuf(struct uio
*uiop
, struct mbuf
**mq
, int siz
, caddr_t
*bpos
)
1175 struct mbuf
*mp
, *mp2
;
1176 int xfer
, left
, mlen
;
1178 boolean_t getcluster
;
1182 if (uiop
->uio_iovcnt
!= 1)
1183 panic("nfsm_uiotombuf: iovcnt != 1");
1186 if (siz
>= MINCLSIZE
)
1190 rem
= nfsm_rndup(siz
) - siz
;
1193 left
= uiop
->uio_iov
->iov_len
;
1194 uiocp
= uiop
->uio_iov
->iov_base
;
1199 mlen
= M_TRAILINGSPACE(mp
);
1202 mp
= m_getcl(M_WAITOK
, MT_DATA
, 0);
1204 mp
= m_get(M_WAITOK
, MT_DATA
);
1208 mlen
= M_TRAILINGSPACE(mp
);
1210 xfer
= (left
> mlen
) ? mlen
: left
;
1213 if (uiop
->uio_iov
->iov_op
!= NULL
)
1214 (*(uiop
->uio_iov
->iov_op
))
1215 (uiocp
, mtod(mp
, caddr_t
)+mp
->m_len
, xfer
);
1218 if (uiop
->uio_segflg
== UIO_SYSSPACE
)
1219 bcopy(uiocp
, mtod(mp
, caddr_t
)+mp
->m_len
, xfer
);
1221 copyin(uiocp
, mtod(mp
, caddr_t
)+mp
->m_len
, xfer
);
1225 uiop
->uio_offset
+= xfer
;
1226 uiop
->uio_resid
-= xfer
;
1228 uiop
->uio_iov
->iov_base
= (char *)uiop
->uio_iov
->iov_base
+ uiosiz
;
1229 uiop
->uio_iov
->iov_len
-= uiosiz
;
1233 if (rem
> M_TRAILINGSPACE(mp
)) {
1234 MGET(mp
, M_WAITOK
, MT_DATA
);
1238 cp
= mtod(mp
, caddr_t
)+mp
->m_len
;
1239 for (left
= 0; left
< rem
; left
++)
1244 *bpos
= mtod(mp
, caddr_t
)+mp
->m_len
;
1250 nfsm_biotombuf(struct bio
*bio
, struct mbuf
**mq
, int off
,
1251 int siz
, caddr_t
*bpos
)
1253 struct buf
*bp
= bio
->bio_buf
;
1254 struct mbuf
*mp
, *mp2
;
1259 boolean_t getcluster
;
1262 if (siz
>= MINCLSIZE
)
1266 rem
= nfsm_rndup(siz
) - siz
;
1269 bio_cp
= bp
->b_data
+ off
;
1273 mlen
= M_TRAILINGSPACE(mp
);
1276 mp
= m_getcl(M_WAITOK
, MT_DATA
, 0);
1278 mp
= m_get(M_WAITOK
, MT_DATA
);
1282 mlen
= M_TRAILINGSPACE(mp
);
1284 xfer
= (bio_left
< mlen
) ? bio_left
: mlen
;
1285 bcopy(bio_cp
, mtod(mp
, caddr_t
) + mp
->m_len
, xfer
);
1291 if (rem
> M_TRAILINGSPACE(mp
)) {
1292 MGET(mp
, M_WAITOK
, MT_DATA
);
1296 cp
= mtod(mp
, caddr_t
) + mp
->m_len
;
1297 for (mlen
= 0; mlen
< rem
; mlen
++)
1302 *bpos
= mtod(mp
, caddr_t
) + mp
->m_len
;
1309 * Help break down an mbuf chain by setting the first siz bytes contiguous
1310 * pointed to by returned val.
1311 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
1312 * cases. (The macros use the vars. dpos and dpos2)
1315 nfsm_disct(struct mbuf
**mdp
, caddr_t
*dposp
, int siz
, int left
, caddr_t
*cp2
)
1317 struct mbuf
*mp
, *mp2
;
1323 *mdp
= mp
= mp
->m_next
;
1327 *dposp
= mtod(mp
, caddr_t
);
1332 } else if (mp
->m_next
== NULL
) {
1334 } else if (siz
> MHLEN
) {
1335 panic("nfs S too big");
1337 MGET(mp2
, M_WAITOK
, MT_DATA
);
1338 mp2
->m_next
= mp
->m_next
;
1342 *cp2
= p
= mtod(mp
, caddr_t
);
1343 bcopy(*dposp
, p
, left
); /* Copy what was left */
1347 /* Loop around copying up the siz2 bytes */
1351 xfer
= (siz2
> mp2
->m_len
) ? mp2
->m_len
: siz2
;
1353 bcopy(mtod(mp2
, caddr_t
), p
, xfer
);
1355 mp2
->m_data
+= xfer
;
1364 *dposp
= mtod(mp2
, caddr_t
);
1370 * Advance the position in the mbuf chain.
1373 nfs_adv(struct mbuf
**mdp
, caddr_t
*dposp
, int offs
, int left
)
1388 *dposp
= mtod(m
, caddr_t
)+offs
;
1393 * Copy a string into mbufs for the hard cases...
1396 nfsm_strtmbuf(struct mbuf
**mb
, char **bpos
, const char *cp
, long siz
)
1398 struct mbuf
*m1
= NULL
, *m2
;
1399 long left
, xfer
, len
, tlen
;
1405 left
= M_TRAILINGSPACE(m2
);
1407 tl
= ((u_int32_t
*)(*bpos
));
1408 *tl
++ = txdr_unsigned(siz
);
1410 left
-= NFSX_UNSIGNED
;
1411 m2
->m_len
+= NFSX_UNSIGNED
;
1413 bcopy(cp
, (caddr_t
) tl
, left
);
1420 /* Loop around adding mbufs */
1424 m1
= m_getl(siz
, M_WAITOK
, MT_DATA
, 0, &msize
);
1428 tl
= mtod(m1
, u_int32_t
*);
1431 *tl
++ = txdr_unsigned(siz
);
1432 m1
->m_len
-= NFSX_UNSIGNED
;
1433 tlen
= NFSX_UNSIGNED
;
1436 if (siz
< m1
->m_len
) {
1437 len
= nfsm_rndup(siz
);
1440 *(tl
+(xfer
>>2)) = 0;
1442 xfer
= len
= m1
->m_len
;
1444 bcopy(cp
, (caddr_t
) tl
, xfer
);
1445 m1
->m_len
= len
+tlen
;
1450 *bpos
= mtod(m1
, caddr_t
)+m1
->m_len
;
1455 * A fiddled version of m_adj() that ensures null fill to a long
1456 * boundary and only trims off the back end
1459 nfsm_adj(struct mbuf
*mp
, int len
, int nul
)
1466 * Trim from tail. Scan the mbuf chain,
1467 * calculating its length and finding the last mbuf.
1468 * If the adjustment only affects this mbuf, then just
1469 * adjust and return. Otherwise, rescan and truncate
1470 * after the remaining size.
1476 if (m
->m_next
== NULL
)
1480 if (m
->m_len
> len
) {
1483 cp
= mtod(m
, caddr_t
)+m
->m_len
-nul
;
1484 for (i
= 0; i
< nul
; i
++)
1493 * Correct length for chain is "count".
1494 * Find the mbuf with last data, adjust its length,
1495 * and toss data from remaining mbufs on chain.
1497 for (m
= mp
; m
; m
= m
->m_next
) {
1498 if (m
->m_len
>= count
) {
1501 cp
= mtod(m
, caddr_t
)+m
->m_len
-nul
;
1502 for (i
= 0; i
< nul
; i
++)
1509 for (m
= m
->m_next
;m
;m
= m
->m_next
)
1514 * Make these functions instead of macros, so that the kernel text size
1515 * doesn't get too big...
1518 nfsm_srvwcc_data(nfsm_info_t info
, struct nfsrv_descript
*nfsd
,
1519 int before_ret
, struct vattr
*before_vap
,
1520 int after_ret
, struct vattr
*after_vap
)
1525 * before_ret is 0 if before_vap is valid, non-zero if it isn't.
1528 tl
= nfsm_build(info
, NFSX_UNSIGNED
);
1531 tl
= nfsm_build(info
, 7 * NFSX_UNSIGNED
);
1533 txdr_hyper(before_vap
->va_size
, tl
);
1535 txdr_nfsv3time(&(before_vap
->va_mtime
), tl
);
1537 txdr_nfsv3time(&(before_vap
->va_ctime
), tl
);
1539 nfsm_srvpostop_attr(info
, nfsd
, after_ret
, after_vap
);
1543 nfsm_srvpostop_attr(nfsm_info_t info
, struct nfsrv_descript
*nfsd
,
1544 int after_ret
, struct vattr
*after_vap
)
1546 struct nfs_fattr
*fp
;
1550 tl
= nfsm_build(info
, NFSX_UNSIGNED
);
1553 tl
= nfsm_build(info
, NFSX_UNSIGNED
+ NFSX_V3FATTR
);
1555 fp
= (struct nfs_fattr
*)tl
;
1556 nfsm_srvfattr(nfsd
, after_vap
, fp
);
1561 nfsm_srvfattr(struct nfsrv_descript
*nfsd
, struct vattr
*vap
,
1562 struct nfs_fattr
*fp
)
1565 * NFS seems to truncate nlink to 16 bits, don't let it overflow.
1567 if (vap
->va_nlink
> 65535)
1568 fp
->fa_nlink
= 65535;
1570 fp
->fa_nlink
= txdr_unsigned(vap
->va_nlink
);
1571 fp
->fa_uid
= txdr_unsigned(vap
->va_uid
);
1572 fp
->fa_gid
= txdr_unsigned(vap
->va_gid
);
1573 if (nfsd
->nd_flag
& ND_NFSV3
) {
1574 fp
->fa_type
= vtonfsv3_type(vap
->va_type
);
1575 fp
->fa_mode
= vtonfsv3_mode(vap
->va_mode
);
1576 txdr_hyper(vap
->va_size
, &fp
->fa3_size
);
1577 txdr_hyper(vap
->va_bytes
, &fp
->fa3_used
);
1578 fp
->fa3_rdev
.specdata1
= txdr_unsigned(vap
->va_rmajor
);
1579 fp
->fa3_rdev
.specdata2
= txdr_unsigned(vap
->va_rminor
);
1580 fp
->fa3_fsid
.nfsuquad
[0] = 0;
1581 fp
->fa3_fsid
.nfsuquad
[1] = txdr_unsigned(vap
->va_fsid
);
1582 txdr_hyper(vap
->va_fileid
, &fp
->fa3_fileid
);
1583 txdr_nfsv3time(&vap
->va_atime
, &fp
->fa3_atime
);
1584 txdr_nfsv3time(&vap
->va_mtime
, &fp
->fa3_mtime
);
1585 txdr_nfsv3time(&vap
->va_ctime
, &fp
->fa3_ctime
);
1587 fp
->fa_type
= vtonfsv2_type(vap
->va_type
);
1588 fp
->fa_mode
= vtonfsv2_mode(vap
->va_type
, vap
->va_mode
);
1589 fp
->fa2_size
= txdr_unsigned(vap
->va_size
);
1590 fp
->fa2_blocksize
= txdr_unsigned(vap
->va_blocksize
);
1591 if (vap
->va_type
== VFIFO
)
1592 fp
->fa2_rdev
= 0xffffffff;
1594 fp
->fa2_rdev
= txdr_unsigned(makeudev(vap
->va_rmajor
, vap
->va_rminor
));
1595 fp
->fa2_blocks
= txdr_unsigned(vap
->va_bytes
/ NFS_FABLKSIZE
);
1596 fp
->fa2_fsid
= txdr_unsigned(vap
->va_fsid
);
1597 fp
->fa2_fileid
= txdr_unsigned(vap
->va_fileid
);
1598 txdr_nfsv2time(&vap
->va_atime
, &fp
->fa2_atime
);
1599 txdr_nfsv2time(&vap
->va_mtime
, &fp
->fa2_mtime
);
1600 txdr_nfsv2time(&vap
->va_ctime
, &fp
->fa2_ctime
);