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>
100 #include "nfsproto.h"
102 #include "nfsmount.h"
104 #include "xdr_subs.h"
105 #include "nfsm_subs.h"
108 #include <netinet/in.h>
110 static u_int32_t nfs_xid = 0;
113 * Create the header for an rpc request packet
114 * The hsiz is the size of the rest of the nfs request header.
115 * (just used to decide if a cluster is a good idea)
118 nfsm_reqhead(nfsm_info_t info, struct vnode *vp, u_long procid, int hsiz)
120 info->mb = m_getl(hsiz, MB_WAIT, MT_DATA, 0, NULL);
122 info->mreq = info->mb;
123 info->bpos = mtod(info->mb, caddr_t);
127 * Build the RPC header and fill in the authorization info.
128 * The authorization string argument is only used when the credentials
129 * come from outside of the kernel.
130 * Returns the head of the mbuf list.
133 nfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type,
134 int auth_len, char *auth_str, int verf_len, char *verf_str,
135 struct mbuf *mrest, int mrest_len, struct mbuf **mbp,
138 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 */
168 xid = atomic_fetchadd_int(&nfs_xid, 1);
171 *tl++ = *xidp = txdr_unsigned(xid);
174 *tl++ = txdr_unsigned(NFS_PROG);
175 if (nmflag & NFSMNT_NFSV3)
176 *tl++ = txdr_unsigned(NFS_VER3);
178 *tl++ = txdr_unsigned(NFS_VER2);
179 if (nmflag & NFSMNT_NFSV3)
180 *tl++ = txdr_unsigned(procid);
182 *tl++ = txdr_unsigned(nfsv2_procid[procid]);
185 * And then the authorization cred.
187 *tl++ = txdr_unsigned(auth_type);
188 *tl = txdr_unsigned(authsiz);
191 tl = nfsm_build(&info, auth_len);
192 *tl++ = 0; /* stamp ?? */
193 *tl++ = 0; /* NULL hostname */
194 *tl++ = txdr_unsigned(cr->cr_uid);
195 *tl++ = txdr_unsigned(cr->cr_groups[0]);
196 grpsiz = (auth_len >> 2) - 5;
197 *tl++ = txdr_unsigned(grpsiz);
198 for (i = 1; i <= grpsiz; i++)
199 *tl++ = txdr_unsigned(cr->cr_groups[i]);
204 if (M_TRAILINGSPACE(info.mb) == 0) {
205 mb2 = m_getl(siz, MB_WAIT, MT_DATA, 0, NULL);
207 info.mb->m_next = mb2;
209 info.bpos = mtod(info.mb, caddr_t);
211 i = min(siz, M_TRAILINGSPACE(info.mb));
212 bcopy(auth_str, info.bpos, i);
218 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
219 for (i = 0; i < siz; i++)
221 info.mb->m_len += siz;
227 * And the verifier...
229 tl = nfsm_build(&info, 2 * NFSX_UNSIGNED);
231 *tl++ = txdr_unsigned(RPCAUTH_KERB4);
232 *tl = txdr_unsigned(verf_len);
235 if (M_TRAILINGSPACE(info.mb) == 0) {
236 mb2 = m_getl(siz, MB_WAIT, MT_DATA,
239 info.mb->m_next = mb2;
241 info.bpos = mtod(info.mb, caddr_t);
243 i = min(siz, M_TRAILINGSPACE(info.mb));
244 bcopy(verf_str, info.bpos, i);
250 if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
251 for (i = 0; i < siz; i++)
253 info.mb->m_len += siz;
256 *tl++ = txdr_unsigned(RPCAUTH_NULL);
259 info.mb->m_next = mrest;
260 info.mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
261 info.mreq->m_pkthdr.rcvif = NULL;
267 nfsm_build(nfsm_info_t info, int bytes)
272 if (bytes > M_TRAILINGSPACE(info->mb)) {
273 MGET(mb2, MB_WAIT, MT_DATA);
275 panic("build > MLEN");
276 info->mb->m_next = mb2;
279 info->bpos = mtod(info->mb, caddr_t);
282 info->mb->m_len += bytes;
289 * If NULL returned caller is expected to abort with an EBADRPC error.
290 * Caller will usually use the NULLOUT macro.
293 nfsm_dissect(nfsm_info_t info, int bytes)
300 n = mtod(info->md, caddr_t) + info->md->m_len - info->dpos;
305 error = nfsm_disct(&info->md, &info->dpos, bytes, n, &cp2);
319 * Caller is expected to abort if non-zero error is returned.
322 nfsm_fhtom(nfsm_info_t info, struct vnode *vp)
330 n = nfsm_rndup(VTONFS(vp)->n_fhsize) + NFSX_UNSIGNED;
331 if (n <= M_TRAILINGSPACE(info->mb)) {
332 tl = nfsm_build(info, n);
333 *tl++ = txdr_unsigned(VTONFS(vp)->n_fhsize);
334 *(tl + ((n >> 2) - 2)) = 0;
335 bcopy((caddr_t)VTONFS(vp)->n_fhp,(caddr_t)tl,
336 VTONFS(vp)->n_fhsize);
338 } else if ((error = nfsm_strtmbuf(&info->mb, &info->bpos,
339 (caddr_t)VTONFS(vp)->n_fhp,
340 VTONFS(vp)->n_fhsize)) != 0) {
345 cp = nfsm_build(info, NFSX_V2FH);
346 bcopy(VTONFS(vp)->n_fhp, cp, NFSX_V2FH);
353 nfsm_srvfhtom(nfsm_info_t info, fhandle_t *fhp)
358 tl = nfsm_build(info, NFSX_UNSIGNED + NFSX_V3FH);
359 *tl++ = txdr_unsigned(NFSX_V3FH);
360 bcopy(fhp, tl, NFSX_V3FH);
362 tl = nfsm_build(info, NFSX_V2FH);
363 bcopy(fhp, tl, NFSX_V2FH);
368 nfsm_srvpostop_fh(nfsm_info_t info, fhandle_t *fhp)
372 tl = nfsm_build(info, 2 * NFSX_UNSIGNED + NFSX_V3FH);
374 *tl++ = txdr_unsigned(NFSX_V3FH);
375 bcopy(fhp, tl, NFSX_V3FH);
379 * Caller is expected to abort if non-zero error is returned.
381 * NOTE: (*vpp) may be loaded with a valid vnode even if (*gotvpp)
382 * winds up 0. The caller is responsible for dealing with (*vpp).
385 nfsm_mtofh(nfsm_info_t info, struct vnode *dvp, struct vnode **vpp, int *gotvpp)
387 struct nfsnode *ttnp;
394 tl = nfsm_dissect(info, NFSX_UNSIGNED);
397 *gotvpp = fxdr_unsigned(int, *tl);
402 NEGATIVEOUT(ttfhsize = nfsm_getfh(info, &ttfhp));
403 error = nfs_nget(dvp->v_mount, ttfhp, ttfhsize, &ttnp);
412 tl = nfsm_dissect(info, NFSX_UNSIGNED);
416 *gotvpp = fxdr_unsigned(int, *tl);
417 } else if (fxdr_unsigned(int, *tl)) {
418 error = nfsm_adv(info, NFSX_V3FATTR);
424 error = nfsm_loadattr(info, *vpp, NULL);
431 * Caller is expected to abort with EBADRPC if a negative length is returned.
434 nfsm_getfh(nfsm_info_t info, nfsfh_t **fhpp)
441 tl = nfsm_dissect(info, NFSX_UNSIGNED);
444 if ((n = fxdr_unsigned(int, *tl)) <= 0 || n > NFSX_V3FHMAX) {
452 *fhpp = nfsm_dissect(info, nfsm_rndup(n));
459 * Caller is expected to abort if a non-zero error is returned.
462 nfsm_loadattr(nfsm_info_t info, struct vnode *vp, struct vattr *vap)
466 error = nfs_loadattrcache(vp, &info->md, &info->dpos, vap, 0);
476 * Caller is expected to abort if a non-zero error is returned.
479 nfsm_postop_attr(nfsm_info_t info, struct vnode *vp, int *attrp, int lflags)
484 tl = nfsm_dissect(info, NFSX_UNSIGNED);
487 *attrp = fxdr_unsigned(int, *tl);
489 error = nfs_loadattrcache(vp, &info->md, &info->dpos,
502 * Caller is expected to abort if a non-zero error is returned.
505 nfsm_wcc_data(nfsm_info_t info, struct vnode *vp, int *attrp)
512 tl = nfsm_dissect(info, NFSX_UNSIGNED);
515 if (*tl == nfs_true) {
516 tl = nfsm_dissect(info, 6 * NFSX_UNSIGNED);
520 ttretf = (VTONFS(vp)->n_mtime ==
521 fxdr_unsigned(u_int32_t, *(tl + 2)));
523 VTONFS(vp)->n_flag |= NRMODIFIED;
525 error = nfsm_postop_attr(info, vp, &ttattrf,
526 NFS_LATTR_NOSHRINK|NFS_LATTR_NOMTIMECHECK);
530 error = nfsm_postop_attr(info, vp, &ttattrf,
543 * This function updates the attribute cache based on data returned in the
544 * NFS reply for NFS RPCs that modify the target file. If the RPC succeeds
545 * a 'before' and 'after' mtime is returned that allows us to determine if
546 * the new mtime attribute represents our modification or someone else's
549 * The flag argument returns non-0 if the original times matched, zero if
550 * they did not match. NRMODIFIED is automatically set if the before time
551 * does not match the original n_mtime, and n_mtime is automatically updated
552 * to the new after time (by nfsm_postop_attr()).
554 * If full is true, set all fields, otherwise just set mode and time fields
557 nfsm_v3attrbuild(nfsm_info_t info, struct vattr *vap, int full)
561 if (vap->va_mode != (mode_t)VNOVAL) {
562 tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
564 *tl = txdr_unsigned(vap->va_mode);
566 tl = nfsm_build(info, NFSX_UNSIGNED);
569 if (full && vap->va_uid != (uid_t)VNOVAL) {
570 tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
572 *tl = txdr_unsigned(vap->va_uid);
574 tl = nfsm_build(info, NFSX_UNSIGNED);
577 if (full && vap->va_gid != (gid_t)VNOVAL) {
578 tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
580 *tl = txdr_unsigned(vap->va_gid);
582 tl = nfsm_build(info, NFSX_UNSIGNED);
585 if (full && vap->va_size != VNOVAL) {
586 tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
588 txdr_hyper(vap->va_size, tl);
590 tl = nfsm_build(info, NFSX_UNSIGNED);
593 if (vap->va_atime.tv_sec != VNOVAL) {
594 if (vap->va_atime.tv_sec != time_second) {
595 tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
596 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
597 txdr_nfsv3time(&vap->va_atime, tl);
599 tl = nfsm_build(info, NFSX_UNSIGNED);
600 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
603 tl = nfsm_build(info, NFSX_UNSIGNED);
604 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
606 if (vap->va_mtime.tv_sec != VNOVAL) {
607 if (vap->va_mtime.tv_sec != time_second) {
608 tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
609 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
610 txdr_nfsv3time(&vap->va_mtime, tl);
612 tl = nfsm_build(info, NFSX_UNSIGNED);
613 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
616 tl = nfsm_build(info, NFSX_UNSIGNED);
617 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
622 * Caller is expected to abort with EBADRPC if a negative length is returned.
625 nfsm_strsiz(nfsm_info_t info, int maxlen)
630 tl = nfsm_dissect(info, NFSX_UNSIGNED);
633 len = fxdr_unsigned(int32_t, *tl);
634 if (len < 0 || len > maxlen)
640 * Caller is expected to abort if a negative length is returned, but also
641 * call nfsm_reply(0) if -2 is returned.
643 * This function sets *errorp. Caller should not modify the error code.
646 nfsm_srvstrsiz(nfsm_info_t info, int maxlen, int *errorp)
651 tl = nfsm_dissect(info, NFSX_UNSIGNED);
656 len = fxdr_unsigned(int32_t,*tl);
657 if (len > maxlen || len <= 0) {
665 * Caller is expected to abort if a negative length is returned, but also
666 * call nfsm_reply(0) if -2 is returned.
668 * This function sets *errorp. Caller should not modify the error code.
671 nfsm_srvnamesiz(nfsm_info_t info, int *errorp)
676 tl = nfsm_dissect(info, NFSX_UNSIGNED);
683 * In this case if *errorp is not EBADRPC and we are NFSv3,
684 * nfsm_reply() will not return a negative number. But all
685 * call cases assume len is valid so we really do want
688 len = fxdr_unsigned(int32_t,*tl);
689 if (len > NFS_MAXNAMLEN)
690 *errorp = NFSERR_NAMETOL;
699 * Caller is expected to abort if a non-zero error is returned.
702 nfsm_mtouio(nfsm_info_t info, struct uio *uiop, int len)
707 (error = nfsm_mbuftouio(&info->md, uiop, len, &info->dpos)) != 0) {
716 * Caller is expected to abort if a non-zero error is returned.
719 nfsm_mtobio(nfsm_info_t info, struct bio *bio, int len)
724 (error = nfsm_mbuftobio(&info->md, bio, len, &info->dpos)) != 0) {
733 * Caller is expected to abort if a non-zero error is returned.
736 nfsm_uiotom(nfsm_info_t info, struct uio *uiop, int len)
740 error = nfsm_uiotombuf(uiop, &info->mb, len, &info->bpos);
750 nfsm_biotom(nfsm_info_t info, struct bio *bio, int off, int len)
754 error = nfsm_biotombuf(bio, &info->mb, off, len, &info->bpos);
764 * Caller is expected to abort if a negative value is returned. This
765 * function sets *errorp. Caller should not modify the error code.
767 * We load up the remaining info fields and run the request state
768 * machine until it is done.
770 * This call runs the entire state machine and does not return until
771 * the command is complete.
774 nfsm_request(nfsm_info_t info, struct vnode *vp, int procnum,
775 thread_t td, struct ucred *cred, int *errorp)
777 info->state = NFSM_STATE_SETUP;
778 info->procnum = procnum;
783 info->nmp = VFSTONFS(vp->v_mount);
785 *errorp = nfs_request(info, NFSM_STATE_SETUP, NFSM_STATE_DONE);
787 if ((*errorp & NFSERR_RETERR) == 0)
789 *errorp &= ~NFSERR_RETERR;
795 * This call starts the state machine through the initial transmission.
796 * Completion is via the bio. The info structure must have installed
799 * If we are unable to do the initial tx we generate the bio completion
803 nfsm_request_bio(nfsm_info_t info, struct vnode *vp, int procnum,
804 thread_t td, struct ucred *cred)
809 info->state = NFSM_STATE_SETUP;
810 info->procnum = procnum;
814 info->nmp = VFSTONFS(vp->v_mount);
816 error = nfs_request(info, NFSM_STATE_SETUP, NFSM_STATE_WAITREPLY);
817 if (error != EINPROGRESS) {
818 kprintf("nfsm_request_bio: early abort %d\n", error);
819 bp = info->bio->bio_buf;
821 bp->b_flags |= B_ERROR;
822 if (error == EIO) /* unrecoverable */
823 bp->b_flags |= B_INVAL;
831 * Caller is expected to abort if a non-zero error is returned.
834 nfsm_strtom(nfsm_info_t info, const void *data, int len, int maxlen)
843 return(ENAMETOOLONG);
845 n = nfsm_rndup(len) + NFSX_UNSIGNED;
846 if (n <= M_TRAILINGSPACE(info->mb)) {
847 tl = nfsm_build(info, n);
848 *tl++ = txdr_unsigned(len);
849 *(tl + ((n >> 2) - 2)) = 0;
850 bcopy(data, tl, len);
853 error = nfsm_strtmbuf(&info->mb, &info->bpos, data, len);
863 * Caller is expected to abort if a negative value is returned. This
864 * function sets *errorp. Caller should not modify the error code.
867 nfsm_reply(nfsm_info_t info,
868 struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
869 int siz, int *errorp)
871 nfsd->nd_repstat = *errorp;
872 if (*errorp && !(nfsd->nd_flag & ND_NFSV3))
874 nfs_rephead(siz, nfsd, slp, *errorp, &info->mreq,
875 &info->mb, &info->bpos);
876 if (info->mrep != NULL) {
880 if (*errorp && (!(nfsd->nd_flag & ND_NFSV3) || *errorp == EBADRPC)) {
888 nfsm_writereply(nfsm_info_t info,
889 struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
892 nfsd->nd_repstat = error;
893 if (error && !(info->v3))
895 nfs_rephead(siz, nfsd, slp, error, &info->mreq, &info->mb, &info->bpos);
899 * Caller is expected to abort if a non-zero error is returned.
902 nfsm_adv(nfsm_info_t info, int len)
907 n = mtod(info->md, caddr_t) + info->md->m_len - info->dpos;
911 } else if ((error = nfs_adv(&info->md, &info->dpos, len, n)) != 0) {
919 * Caller is expected to abort if a negative length is returned, but also
920 * call nfsm_reply(0) if -2 is returned.
922 * This function sets *errorp. Caller should not modify the error code.
925 nfsm_srvmtofh(nfsm_info_t info, struct nfsrv_descript *nfsd,
926 fhandle_t *fhp, int *errorp)
931 if (nfsd->nd_flag & ND_NFSV3) {
932 tl = nfsm_dissect(info, NFSX_UNSIGNED);
937 fhlen = fxdr_unsigned(int, *tl);
938 if (fhlen != 0 && fhlen != NFSX_V3FH) {
946 tl = nfsm_dissect(info, fhlen);
951 bcopy(tl, fhp, fhlen);
953 bzero(fhp, NFSX_V3FH);
959 _nfsm_clget(nfsm_info_t info, struct mbuf **mp1, struct mbuf **mp2,
960 char **bp, char **be)
963 if (*mp1 == info->mb)
964 (*mp1)->m_len += *bp - info->bpos;
965 *mp1 = m_getcl(MB_WAIT, MT_DATA, 0);
966 (*mp1)->m_len = MCLBYTES;
967 (*mp2)->m_next = *mp1;
969 *bp = mtod(*mp1, caddr_t);
970 *be = *bp + (*mp1)->m_len;
976 nfsm_srvsattr(nfsm_info_t info, struct vattr *vap)
981 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
982 if (*tl == nfs_true) {
983 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
984 vap->va_mode = nfstov_mode(*tl);
986 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
987 if (*tl == nfs_true) {
988 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
989 vap->va_uid = fxdr_unsigned(uid_t, *tl);
991 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
992 if (*tl == nfs_true) {
993 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
994 vap->va_gid = fxdr_unsigned(gid_t, *tl);
996 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
997 if (*tl == nfs_true) {
998 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
999 vap->va_size = fxdr_hyper(tl);
1001 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1002 switch (fxdr_unsigned(int, *tl)) {
1003 case NFSV3SATTRTIME_TOCLIENT:
1004 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
1005 fxdr_nfsv3time(tl, &vap->va_atime);
1007 case NFSV3SATTRTIME_TOSERVER:
1008 getnanotime(&vap->va_atime);
1011 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1012 switch (fxdr_unsigned(int, *tl)) {
1013 case NFSV3SATTRTIME_TOCLIENT:
1014 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
1015 fxdr_nfsv3time(tl, &vap->va_mtime);
1017 case NFSV3SATTRTIME_TOSERVER:
1018 getnanotime(&vap->va_mtime);
1026 * copies mbuf chain to the uio scatter/gather list
1029 nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos)
1031 char *mbufcp, *uiocp;
1032 int xfer, left, len;
1039 len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
1040 rem = nfsm_rndup(siz)-siz;
1042 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
1044 left = uiop->uio_iov->iov_len;
1045 uiocp = uiop->uio_iov->iov_base;
1054 mbufcp = mtod(mp, caddr_t);
1057 xfer = (left > len) ? len : left;
1060 if (uiop->uio_iov->iov_op != NULL)
1061 (*(uiop->uio_iov->iov_op))
1062 (mbufcp, uiocp, xfer);
1065 if (uiop->uio_segflg == UIO_SYSSPACE)
1066 bcopy(mbufcp, uiocp, xfer);
1068 copyout(mbufcp, uiocp, xfer);
1073 uiop->uio_offset += xfer;
1074 uiop->uio_resid -= xfer;
1076 if (uiop->uio_iov->iov_len <= siz) {
1080 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
1081 uiop->uio_iov->iov_len -= uiosiz;
1089 error = nfs_adv(mrep, dpos, rem, len);
1097 * copies mbuf chain to the bio buffer
1100 nfsm_mbuftobio(struct mbuf **mrep, struct bio *bio, int size, caddr_t *dpos)
1102 struct buf *bp = bio->bio_buf;
1113 len = mtod(mp, caddr_t) + mp->m_len - mbufcp;
1114 rem = nfsm_rndup(size) - size;
1116 bio_left = bp->b_bcount;
1117 bio_cp = bp->b_data;
1124 mbufcp = mtod(mp, caddr_t);
1127 if ((xfer = len) > size)
1130 if (xfer > bio_left)
1132 bcopy(mbufcp, bio_cp, xfer);
1135 * Not enough buffer space in the bio.
1149 error = nfs_adv(mrep, dpos, rem, len);
1157 * copies a uio scatter/gather list to an mbuf chain.
1158 * NOTE: can ony handle iovcnt == 1
1161 nfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos)
1164 struct mbuf *mp, *mp2;
1165 int xfer, left, mlen;
1167 boolean_t getcluster;
1171 if (uiop->uio_iovcnt != 1)
1172 panic("nfsm_uiotombuf: iovcnt != 1");
1175 if (siz >= MINCLSIZE)
1179 rem = nfsm_rndup(siz) - siz;
1182 left = uiop->uio_iov->iov_len;
1183 uiocp = uiop->uio_iov->iov_base;
1188 mlen = M_TRAILINGSPACE(mp);
1191 mp = m_getcl(MB_WAIT, MT_DATA, 0);
1193 mp = m_get(MB_WAIT, MT_DATA);
1197 mlen = M_TRAILINGSPACE(mp);
1199 xfer = (left > mlen) ? mlen : left;
1202 if (uiop->uio_iov->iov_op != NULL)
1203 (*(uiop->uio_iov->iov_op))
1204 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1207 if (uiop->uio_segflg == UIO_SYSSPACE)
1208 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1210 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1214 uiop->uio_offset += xfer;
1215 uiop->uio_resid -= xfer;
1217 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
1218 uiop->uio_iov->iov_len -= uiosiz;
1222 if (rem > M_TRAILINGSPACE(mp)) {
1223 MGET(mp, MB_WAIT, MT_DATA);
1227 cp = mtod(mp, caddr_t)+mp->m_len;
1228 for (left = 0; left < rem; left++)
1233 *bpos = mtod(mp, caddr_t)+mp->m_len;
1239 nfsm_biotombuf(struct bio *bio, struct mbuf **mq, int off,
1240 int siz, caddr_t *bpos)
1242 struct buf *bp = bio->bio_buf;
1243 struct mbuf *mp, *mp2;
1248 boolean_t getcluster;
1251 if (siz >= MINCLSIZE)
1255 rem = nfsm_rndup(siz) - siz;
1258 bio_cp = bp->b_data + off;
1262 mlen = M_TRAILINGSPACE(mp);
1265 mp = m_getcl(MB_WAIT, MT_DATA, 0);
1267 mp = m_get(MB_WAIT, MT_DATA);
1271 mlen = M_TRAILINGSPACE(mp);
1273 xfer = (bio_left < mlen) ? bio_left : mlen;
1274 bcopy(bio_cp, mtod(mp, caddr_t) + mp->m_len, xfer);
1280 if (rem > M_TRAILINGSPACE(mp)) {
1281 MGET(mp, MB_WAIT, MT_DATA);
1285 cp = mtod(mp, caddr_t) + mp->m_len;
1286 for (mlen = 0; mlen < rem; mlen++)
1291 *bpos = mtod(mp, caddr_t) + mp->m_len;
1298 * Help break down an mbuf chain by setting the first siz bytes contiguous
1299 * pointed to by returned val.
1300 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
1301 * cases. (The macros use the vars. dpos and dpos2)
1304 nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, caddr_t *cp2)
1306 struct mbuf *mp, *mp2;
1312 *mdp = mp = mp->m_next;
1316 *dposp = mtod(mp, caddr_t);
1321 } else if (mp->m_next == NULL) {
1323 } else if (siz > MHLEN) {
1324 panic("nfs S too big");
1326 MGET(mp2, MB_WAIT, MT_DATA);
1327 mp2->m_next = mp->m_next;
1331 *cp2 = p = mtod(mp, caddr_t);
1332 bcopy(*dposp, p, left); /* Copy what was left */
1336 /* Loop around copying up the siz2 bytes */
1340 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
1342 bcopy(mtod(mp2, caddr_t), p, xfer);
1344 mp2->m_data += xfer;
1353 *dposp = mtod(mp2, caddr_t);
1359 * Advance the position in the mbuf chain.
1362 nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left)
1377 *dposp = mtod(m, caddr_t)+offs;
1382 * Copy a string into mbufs for the hard cases...
1385 nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz)
1387 struct mbuf *m1 = NULL, *m2;
1388 long left, xfer, len, tlen;
1394 left = M_TRAILINGSPACE(m2);
1396 tl = ((u_int32_t *)(*bpos));
1397 *tl++ = txdr_unsigned(siz);
1399 left -= NFSX_UNSIGNED;
1400 m2->m_len += NFSX_UNSIGNED;
1402 bcopy(cp, (caddr_t) tl, left);
1409 /* Loop around adding mbufs */
1413 m1 = m_getl(siz, MB_WAIT, MT_DATA, 0, &msize);
1417 tl = mtod(m1, u_int32_t *);
1420 *tl++ = txdr_unsigned(siz);
1421 m1->m_len -= NFSX_UNSIGNED;
1422 tlen = NFSX_UNSIGNED;
1425 if (siz < m1->m_len) {
1426 len = nfsm_rndup(siz);
1429 *(tl+(xfer>>2)) = 0;
1431 xfer = len = m1->m_len;
1433 bcopy(cp, (caddr_t) tl, xfer);
1434 m1->m_len = len+tlen;
1439 *bpos = mtod(m1, caddr_t)+m1->m_len;
1444 * A fiddled version of m_adj() that ensures null fill to a long
1445 * boundary and only trims off the back end
1448 nfsm_adj(struct mbuf *mp, int len, int nul)
1455 * Trim from tail. Scan the mbuf chain,
1456 * calculating its length and finding the last mbuf.
1457 * If the adjustment only affects this mbuf, then just
1458 * adjust and return. Otherwise, rescan and truncate
1459 * after the remaining size.
1465 if (m->m_next == NULL)
1469 if (m->m_len > len) {
1472 cp = mtod(m, caddr_t)+m->m_len-nul;
1473 for (i = 0; i < nul; i++)
1482 * Correct length for chain is "count".
1483 * Find the mbuf with last data, adjust its length,
1484 * and toss data from remaining mbufs on chain.
1486 for (m = mp; m; m = m->m_next) {
1487 if (m->m_len >= count) {
1490 cp = mtod(m, caddr_t)+m->m_len-nul;
1491 for (i = 0; i < nul; i++)
1498 for (m = m->m_next;m;m = m->m_next)
1503 * Make these functions instead of macros, so that the kernel text size
1504 * doesn't get too big...
1507 nfsm_srvwcc_data(nfsm_info_t info, struct nfsrv_descript *nfsd,
1508 int before_ret, struct vattr *before_vap,
1509 int after_ret, struct vattr *after_vap)
1514 * before_ret is 0 if before_vap is valid, non-zero if it isn't.
1517 tl = nfsm_build(info, NFSX_UNSIGNED);
1520 tl = nfsm_build(info, 7 * NFSX_UNSIGNED);
1522 txdr_hyper(before_vap->va_size, tl);
1524 txdr_nfsv3time(&(before_vap->va_mtime), tl);
1526 txdr_nfsv3time(&(before_vap->va_ctime), tl);
1528 nfsm_srvpostop_attr(info, nfsd, after_ret, after_vap);
1532 nfsm_srvpostop_attr(nfsm_info_t info, struct nfsrv_descript *nfsd,
1533 int after_ret, struct vattr *after_vap)
1535 struct nfs_fattr *fp;
1539 tl = nfsm_build(info, NFSX_UNSIGNED);
1542 tl = nfsm_build(info, NFSX_UNSIGNED + NFSX_V3FATTR);
1544 fp = (struct nfs_fattr *)tl;
1545 nfsm_srvfattr(nfsd, after_vap, fp);
1550 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
1551 struct nfs_fattr *fp)
1554 * NFS seems to truncate nlink to 16 bits, don't let it overflow.
1556 if (vap->va_nlink > 65535)
1557 fp->fa_nlink = 65535;
1559 fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1560 fp->fa_uid = txdr_unsigned(vap->va_uid);
1561 fp->fa_gid = txdr_unsigned(vap->va_gid);
1562 if (nfsd->nd_flag & ND_NFSV3) {
1563 fp->fa_type = vtonfsv3_type(vap->va_type);
1564 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1565 txdr_hyper(vap->va_size, &fp->fa3_size);
1566 txdr_hyper(vap->va_bytes, &fp->fa3_used);
1567 fp->fa3_rdev.specdata1 = txdr_unsigned(vap->va_rmajor);
1568 fp->fa3_rdev.specdata2 = txdr_unsigned(vap->va_rminor);
1569 fp->fa3_fsid.nfsuquad[0] = 0;
1570 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1571 txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
1572 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1573 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1574 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1576 fp->fa_type = vtonfsv2_type(vap->va_type);
1577 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1578 fp->fa2_size = txdr_unsigned(vap->va_size);
1579 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1580 if (vap->va_type == VFIFO)
1581 fp->fa2_rdev = 0xffffffff;
1583 fp->fa2_rdev = txdr_unsigned(makeudev(vap->va_rmajor, vap->va_rminor));
1584 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1585 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1586 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1587 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1588 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1589 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);