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;
141 int siz, grpsiz, authsiz, dsiz;
144 authsiz = nfsm_rndup(auth_len);
145 dsiz = authsiz + 10 * NFSX_UNSIGNED;
146 info.mb = m_getl(dsiz, MB_WAIT, MT_DATA, M_PKTHDR, NULL);
147 if (dsiz < MINCLSIZE) {
149 MH_ALIGN(info.mb, dsiz);
151 MH_ALIGN(info.mb, 8 * NFSX_UNSIGNED);
153 info.mb->m_len = info.mb->m_pkthdr.len = 0;
155 info.bpos = mtod(info.mb, caddr_t);
158 * First the RPC header.
160 tl = nfsm_build(&info, 8 * NFSX_UNSIGNED);
162 /* Get a pretty random xid to start with */
166 * Skip zero xid if it should ever happen.
171 *tl++ = *xidp = txdr_unsigned(nfs_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 info.mb2 = m_getl(siz, MB_WAIT, MT_DATA, 0, NULL);
207 info.mb->m_next = info.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 info.mb2 = m_getl(siz, MB_WAIT, MT_DATA,
239 info.mb->m_next = info.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)
271 if (bytes > M_TRAILINGSPACE(info->mb)) {
272 MGET(info->mb2, MB_WAIT, MT_DATA);
274 panic("build > MLEN");
275 info->mb->m_next = info->mb2;
276 info->mb = info->mb2;
278 info->bpos = mtod(info->mb, caddr_t);
281 info->mb->m_len += bytes;
288 * If NULL returned caller is expected to abort with an EBADRPC error.
289 * Caller will usually use the NULLOUT macro.
292 nfsm_dissect(nfsm_info_t info, int bytes)
299 n = mtod(info->md, caddr_t) + info->md->m_len - info->dpos;
304 error = nfsm_disct(&info->md, &info->dpos, bytes, n, &cp2);
318 * Caller is expected to abort if non-zero error is returned.
321 nfsm_fhtom(nfsm_info_t info, struct vnode *vp)
329 n = nfsm_rndup(VTONFS(vp)->n_fhsize) + NFSX_UNSIGNED;
330 if (n <= M_TRAILINGSPACE(info->mb)) {
331 tl = nfsm_build(info, n);
332 *tl++ = txdr_unsigned(VTONFS(vp)->n_fhsize);
333 *(tl + ((n >> 2) - 2)) = 0;
334 bcopy((caddr_t)VTONFS(vp)->n_fhp,(caddr_t)tl,
335 VTONFS(vp)->n_fhsize);
337 } else if ((error = nfsm_strtmbuf(&info->mb, &info->bpos,
338 (caddr_t)VTONFS(vp)->n_fhp,
339 VTONFS(vp)->n_fhsize)) != 0) {
344 cp = nfsm_build(info, NFSX_V2FH);
345 bcopy(VTONFS(vp)->n_fhp, cp, NFSX_V2FH);
352 nfsm_srvfhtom(nfsm_info_t info, fhandle_t *fhp)
357 tl = nfsm_build(info, NFSX_UNSIGNED + NFSX_V3FH);
358 *tl++ = txdr_unsigned(NFSX_V3FH);
359 bcopy(fhp, tl, NFSX_V3FH);
361 tl = nfsm_build(info, NFSX_V2FH);
362 bcopy(fhp, tl, NFSX_V2FH);
367 nfsm_srvpostop_fh(nfsm_info_t info, fhandle_t *fhp)
371 tl = nfsm_build(info, 2 * NFSX_UNSIGNED + NFSX_V3FH);
373 *tl++ = txdr_unsigned(NFSX_V3FH);
374 bcopy(fhp, tl, NFSX_V3FH);
378 * Caller is expected to abort if non-zero error is returned.
380 * NOTE: (*vpp) may be loaded with a valid vnode even if (*gotvpp)
381 * winds up 0. The caller is responsible for dealing with (*vpp).
384 nfsm_mtofh(nfsm_info_t info, struct vnode *dvp, struct vnode **vpp, int *gotvpp)
386 struct nfsnode *ttnp;
393 tl = nfsm_dissect(info, NFSX_UNSIGNED);
396 *gotvpp = fxdr_unsigned(int, *tl);
401 NEGATIVEOUT(ttfhsize = nfsm_getfh(info, &ttfhp));
402 error = nfs_nget(dvp->v_mount, ttfhp, ttfhsize, &ttnp);
411 tl = nfsm_dissect(info, NFSX_UNSIGNED);
415 *gotvpp = fxdr_unsigned(int, *tl);
416 } else if (fxdr_unsigned(int, *tl)) {
417 error = nfsm_adv(info, NFSX_V3FATTR);
423 error = nfsm_loadattr(info, *vpp, NULL);
430 * Caller is expected to abort with EBADRPC if a negative length is returned.
433 nfsm_getfh(nfsm_info_t info, nfsfh_t **fhpp)
440 tl = nfsm_dissect(info, NFSX_UNSIGNED);
443 if ((n = fxdr_unsigned(int, *tl)) <= 0 || n > NFSX_V3FHMAX) {
451 *fhpp = nfsm_dissect(info, nfsm_rndup(n));
458 * Caller is expected to abort if a non-zero error is returned.
461 nfsm_loadattr(nfsm_info_t info, struct vnode *vp, struct vattr *vap)
465 error = nfs_loadattrcache(vp, &info->md, &info->dpos, vap, 0);
475 * Caller is expected to abort if a non-zero error is returned.
478 nfsm_postop_attr(nfsm_info_t info, struct vnode *vp, int *attrp, int lflags)
483 tl = nfsm_dissect(info, NFSX_UNSIGNED);
486 *attrp = fxdr_unsigned(int, *tl);
488 error = nfs_loadattrcache(vp, &info->md, &info->dpos,
501 * Caller is expected to abort if a non-zero error is returned.
504 nfsm_wcc_data(nfsm_info_t info, struct vnode *vp, int *attrp)
511 tl = nfsm_dissect(info, NFSX_UNSIGNED);
514 if (*tl == nfs_true) {
515 tl = nfsm_dissect(info, 6 * NFSX_UNSIGNED);
519 ttretf = (VTONFS(vp)->n_mtime ==
520 fxdr_unsigned(u_int32_t, *(tl + 2)));
522 VTONFS(vp)->n_flag |= NRMODIFIED;
524 error = nfsm_postop_attr(info, vp, &ttattrf,
525 NFS_LATTR_NOSHRINK|NFS_LATTR_NOMTIMECHECK);
529 error = nfsm_postop_attr(info, vp, &ttattrf,
542 * This function updates the attribute cache based on data returned in the
543 * NFS reply for NFS RPCs that modify the target file. If the RPC succeeds
544 * a 'before' and 'after' mtime is returned that allows us to determine if
545 * the new mtime attribute represents our modification or someone else's
548 * The flag argument returns non-0 if the original times matched, zero if
549 * they did not match. NRMODIFIED is automatically set if the before time
550 * does not match the original n_mtime, and n_mtime is automatically updated
551 * to the new after time (by nfsm_postop_attr()).
553 * If full is true, set all fields, otherwise just set mode and time fields
556 nfsm_v3attrbuild(nfsm_info_t info, struct vattr *vap, int full)
560 if (vap->va_mode != (mode_t)VNOVAL) {
561 tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
563 *tl = txdr_unsigned(vap->va_mode);
565 tl = nfsm_build(info, NFSX_UNSIGNED);
568 if (full && vap->va_uid != (uid_t)VNOVAL) {
569 tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
571 *tl = txdr_unsigned(vap->va_uid);
573 tl = nfsm_build(info, NFSX_UNSIGNED);
576 if (full && vap->va_gid != (gid_t)VNOVAL) {
577 tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
579 *tl = txdr_unsigned(vap->va_gid);
581 tl = nfsm_build(info, NFSX_UNSIGNED);
584 if (full && vap->va_size != VNOVAL) {
585 tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
587 txdr_hyper(vap->va_size, tl);
589 tl = nfsm_build(info, NFSX_UNSIGNED);
592 if (vap->va_atime.tv_sec != VNOVAL) {
593 if (vap->va_atime.tv_sec != time_second) {
594 tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
595 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
596 txdr_nfsv3time(&vap->va_atime, tl);
598 tl = nfsm_build(info, NFSX_UNSIGNED);
599 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
602 tl = nfsm_build(info, NFSX_UNSIGNED);
603 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
605 if (vap->va_mtime.tv_sec != VNOVAL) {
606 if (vap->va_mtime.tv_sec != time_second) {
607 tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
608 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
609 txdr_nfsv3time(&vap->va_mtime, tl);
611 tl = nfsm_build(info, NFSX_UNSIGNED);
612 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
615 tl = nfsm_build(info, NFSX_UNSIGNED);
616 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
621 * Caller is expected to abort with EBADRPC if a negative length is returned.
624 nfsm_strsiz(nfsm_info_t info, int maxlen)
629 tl = nfsm_dissect(info, NFSX_UNSIGNED);
632 len = fxdr_unsigned(int32_t, *tl);
633 if (len < 0 || len > maxlen)
639 * Caller is expected to abort if a negative length is returned, but also
640 * call nfsm_reply(0) if -2 is returned.
642 * This function sets *errorp. Caller should not modify the error code.
645 nfsm_srvstrsiz(nfsm_info_t info, int maxlen, int *errorp)
650 tl = nfsm_dissect(info, NFSX_UNSIGNED);
655 len = fxdr_unsigned(int32_t,*tl);
656 if (len > maxlen || len <= 0) {
664 * Caller is expected to abort if a negative length is returned, but also
665 * call nfsm_reply(0) if -2 is returned.
667 * This function sets *errorp. Caller should not modify the error code.
670 nfsm_srvnamesiz(nfsm_info_t info, int *errorp)
675 tl = nfsm_dissect(info, NFSX_UNSIGNED);
682 * In this case if *errorp is not EBADRPC and we are NFSv3,
683 * nfsm_reply() will not return a negative number. But all
684 * call cases assume len is valid so we really do want
687 len = fxdr_unsigned(int32_t,*tl);
688 if (len > NFS_MAXNAMLEN)
689 *errorp = NFSERR_NAMETOL;
698 * Caller is expected to abort if a non-zero error is returned.
701 nfsm_mtouio(nfsm_info_t info, struct uio *uiop, int len)
706 (error = nfsm_mbuftouio(&info->md, uiop, len, &info->dpos)) != 0) {
715 * Caller is expected to abort if a non-zero error is returned.
718 nfsm_uiotom(nfsm_info_t info, struct uio *uiop, int len)
722 if ((error = nfsm_uiotombuf(uiop, &info->mb, len, &info->bpos)) != 0) {
731 * Caller is expected to abort if a negative value is returned. This
732 * function sets *errorp. Caller should not modify the error code.
735 nfsm_request(nfsm_info_t info, struct vnode *vp, int procnum,
736 thread_t td, struct ucred *cred, int *errorp)
738 *errorp = nfs_request(vp, info->mreq, procnum, td, cred,
739 &info->mrep, &info->md, &info->dpos);
741 if ((*errorp & NFSERR_RETERR) == 0)
743 *errorp &= ~NFSERR_RETERR;
749 * Caller is expected to abort if a non-zero error is returned.
752 nfsm_strtom(nfsm_info_t info, const void *data, int len, int maxlen)
761 return(ENAMETOOLONG);
763 n = nfsm_rndup(len) + NFSX_UNSIGNED;
764 if (n <= M_TRAILINGSPACE(info->mb)) {
765 tl = nfsm_build(info, n);
766 *tl++ = txdr_unsigned(len);
767 *(tl + ((n >> 2) - 2)) = 0;
768 bcopy(data, tl, len);
771 error = nfsm_strtmbuf(&info->mb, &info->bpos, data, len);
781 * Caller is expected to abort if a negative value is returned. This
782 * function sets *errorp. Caller should not modify the error code.
785 nfsm_reply(nfsm_info_t info,
786 struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
787 int siz, int *errorp)
789 nfsd->nd_repstat = *errorp;
790 if (*errorp && !(nfsd->nd_flag & ND_NFSV3))
792 nfs_rephead(siz, nfsd, slp, *errorp, &info->mreq,
793 &info->mb, &info->bpos);
794 if (info->mrep != NULL) {
798 if (*errorp && (!(nfsd->nd_flag & ND_NFSV3) || *errorp == EBADRPC)) {
806 nfsm_writereply(nfsm_info_t info,
807 struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
810 nfsd->nd_repstat = error;
811 if (error && !(info->v3))
813 nfs_rephead(siz, nfsd, slp, error, &info->mreq, &info->mb, &info->bpos);
817 * Caller is expected to abort if a non-zero error is returned.
820 nfsm_adv(nfsm_info_t info, int len)
825 n = mtod(info->md, caddr_t) + info->md->m_len - info->dpos;
829 } else if ((error = nfs_adv(&info->md, &info->dpos, len, n)) != 0) {
837 * Caller is expected to abort if a negative length is returned, but also
838 * call nfsm_reply(0) if -2 is returned.
840 * This function sets *errorp. Caller should not modify the error code.
843 nfsm_srvmtofh(nfsm_info_t info, struct nfsrv_descript *nfsd,
844 fhandle_t *fhp, int *errorp)
849 if (nfsd->nd_flag & ND_NFSV3) {
850 tl = nfsm_dissect(info, NFSX_UNSIGNED);
855 fhlen = fxdr_unsigned(int, *tl);
856 if (fhlen != 0 && fhlen != NFSX_V3FH) {
864 tl = nfsm_dissect(info, fhlen);
869 bcopy(tl, fhp, fhlen);
871 bzero(fhp, NFSX_V3FH);
877 _nfsm_clget(nfsm_info_t info, struct mbuf *mp1, struct mbuf *mp2,
884 mp1->m_len += bp - info->bpos;
885 mp1 = m_getcl(MB_WAIT, MT_DATA, 0);
886 mp1->m_len = MCLBYTES;
889 bp = mtod(mp1, caddr_t);
890 be = bp + mp1->m_len;
892 tl = (u_int32_t *)bp;
897 nfsm_srvsattr(nfsm_info_t info, struct vattr *vap)
902 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
903 if (*tl == nfs_true) {
904 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
905 vap->va_mode = nfstov_mode(*tl);
907 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
908 if (*tl == nfs_true) {
909 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
910 vap->va_uid = fxdr_unsigned(uid_t, *tl);
912 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
913 if (*tl == nfs_true) {
914 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
915 vap->va_gid = fxdr_unsigned(gid_t, *tl);
917 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
918 if (*tl == nfs_true) {
919 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
920 vap->va_size = fxdr_hyper(tl);
922 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
923 switch (fxdr_unsigned(int, *tl)) {
924 case NFSV3SATTRTIME_TOCLIENT:
925 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
926 fxdr_nfsv3time(tl, &vap->va_atime);
928 case NFSV3SATTRTIME_TOSERVER:
929 getnanotime(&vap->va_atime);
932 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
933 switch (fxdr_unsigned(int, *tl)) {
934 case NFSV3SATTRTIME_TOCLIENT:
935 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
936 fxdr_nfsv3time(tl, &vap->va_mtime);
938 case NFSV3SATTRTIME_TOSERVER:
939 getnanotime(&vap->va_mtime);
947 * copies mbuf chain to the uio scatter/gather list
950 nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos)
952 char *mbufcp, *uiocp;
960 len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
961 rem = nfsm_rndup(siz)-siz;
963 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
965 left = uiop->uio_iov->iov_len;
966 uiocp = uiop->uio_iov->iov_base;
975 mbufcp = mtod(mp, caddr_t);
978 xfer = (left > len) ? len : left;
981 if (uiop->uio_iov->iov_op != NULL)
982 (*(uiop->uio_iov->iov_op))
983 (mbufcp, uiocp, xfer);
986 if (uiop->uio_segflg == UIO_SYSSPACE)
987 bcopy(mbufcp, uiocp, xfer);
989 copyout(mbufcp, uiocp, xfer);
994 uiop->uio_offset += xfer;
995 uiop->uio_resid -= xfer;
997 if (uiop->uio_iov->iov_len <= siz) {
1001 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
1002 uiop->uio_iov->iov_len -= uiosiz;
1010 error = nfs_adv(mrep, dpos, rem, len);
1018 * copies a uio scatter/gather list to an mbuf chain.
1019 * NOTE: can ony handle iovcnt == 1
1022 nfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos)
1025 struct mbuf *mp, *mp2;
1026 int xfer, left, mlen;
1028 boolean_t getcluster;
1032 if (uiop->uio_iovcnt != 1)
1033 panic("nfsm_uiotombuf: iovcnt != 1");
1036 if (siz >= MINCLSIZE)
1040 rem = nfsm_rndup(siz) - siz;
1043 left = uiop->uio_iov->iov_len;
1044 uiocp = uiop->uio_iov->iov_base;
1049 mlen = M_TRAILINGSPACE(mp);
1052 mp = m_getcl(MB_WAIT, MT_DATA, 0);
1054 mp = m_get(MB_WAIT, MT_DATA);
1058 mlen = M_TRAILINGSPACE(mp);
1060 xfer = (left > mlen) ? mlen : left;
1063 if (uiop->uio_iov->iov_op != NULL)
1064 (*(uiop->uio_iov->iov_op))
1065 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1068 if (uiop->uio_segflg == UIO_SYSSPACE)
1069 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1071 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1075 uiop->uio_offset += xfer;
1076 uiop->uio_resid -= xfer;
1078 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
1079 uiop->uio_iov->iov_len -= uiosiz;
1083 if (rem > M_TRAILINGSPACE(mp)) {
1084 MGET(mp, MB_WAIT, MT_DATA);
1088 cp = mtod(mp, caddr_t)+mp->m_len;
1089 for (left = 0; left < rem; left++)
1094 *bpos = mtod(mp, caddr_t)+mp->m_len;
1100 * Help break down an mbuf chain by setting the first siz bytes contiguous
1101 * pointed to by returned val.
1102 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
1103 * cases. (The macros use the vars. dpos and dpos2)
1106 nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, caddr_t *cp2)
1108 struct mbuf *mp, *mp2;
1114 *mdp = mp = mp->m_next;
1118 *dposp = mtod(mp, caddr_t);
1123 } else if (mp->m_next == NULL) {
1125 } else if (siz > MHLEN) {
1126 panic("nfs S too big");
1128 MGET(mp2, MB_WAIT, MT_DATA);
1129 mp2->m_next = mp->m_next;
1133 *cp2 = p = mtod(mp, caddr_t);
1134 bcopy(*dposp, p, left); /* Copy what was left */
1138 /* Loop around copying up the siz2 bytes */
1142 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
1144 bcopy(mtod(mp2, caddr_t), p, xfer);
1146 mp2->m_data += xfer;
1155 *dposp = mtod(mp2, caddr_t);
1161 * Advance the position in the mbuf chain.
1164 nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left)
1179 *dposp = mtod(m, caddr_t)+offs;
1184 * Copy a string into mbufs for the hard cases...
1187 nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz)
1189 struct mbuf *m1 = NULL, *m2;
1190 long left, xfer, len, tlen;
1196 left = M_TRAILINGSPACE(m2);
1198 tl = ((u_int32_t *)(*bpos));
1199 *tl++ = txdr_unsigned(siz);
1201 left -= NFSX_UNSIGNED;
1202 m2->m_len += NFSX_UNSIGNED;
1204 bcopy(cp, (caddr_t) tl, left);
1211 /* Loop around adding mbufs */
1215 m1 = m_getl(siz, MB_WAIT, MT_DATA, 0, &msize);
1219 tl = mtod(m1, u_int32_t *);
1222 *tl++ = txdr_unsigned(siz);
1223 m1->m_len -= NFSX_UNSIGNED;
1224 tlen = NFSX_UNSIGNED;
1227 if (siz < m1->m_len) {
1228 len = nfsm_rndup(siz);
1231 *(tl+(xfer>>2)) = 0;
1233 xfer = len = m1->m_len;
1235 bcopy(cp, (caddr_t) tl, xfer);
1236 m1->m_len = len+tlen;
1241 *bpos = mtod(m1, caddr_t)+m1->m_len;
1246 * A fiddled version of m_adj() that ensures null fill to a long
1247 * boundary and only trims off the back end
1250 nfsm_adj(struct mbuf *mp, int len, int nul)
1257 * Trim from tail. Scan the mbuf chain,
1258 * calculating its length and finding the last mbuf.
1259 * If the adjustment only affects this mbuf, then just
1260 * adjust and return. Otherwise, rescan and truncate
1261 * after the remaining size.
1267 if (m->m_next == NULL)
1271 if (m->m_len > len) {
1274 cp = mtod(m, caddr_t)+m->m_len-nul;
1275 for (i = 0; i < nul; i++)
1284 * Correct length for chain is "count".
1285 * Find the mbuf with last data, adjust its length,
1286 * and toss data from remaining mbufs on chain.
1288 for (m = mp; m; m = m->m_next) {
1289 if (m->m_len >= count) {
1292 cp = mtod(m, caddr_t)+m->m_len-nul;
1293 for (i = 0; i < nul; i++)
1300 for (m = m->m_next;m;m = m->m_next)
1305 * Make these functions instead of macros, so that the kernel text size
1306 * doesn't get too big...
1309 nfsm_srvwcc_data(nfsm_info_t info, struct nfsrv_descript *nfsd,
1310 int before_ret, struct vattr *before_vap,
1311 int after_ret, struct vattr *after_vap)
1316 * before_ret is 0 if before_vap is valid, non-zero if it isn't.
1319 tl = nfsm_build(info, NFSX_UNSIGNED);
1322 tl = nfsm_build(info, 7 * NFSX_UNSIGNED);
1324 txdr_hyper(before_vap->va_size, tl);
1326 txdr_nfsv3time(&(before_vap->va_mtime), tl);
1328 txdr_nfsv3time(&(before_vap->va_ctime), tl);
1330 nfsm_srvpostop_attr(info, nfsd, after_ret, after_vap);
1334 nfsm_srvpostop_attr(nfsm_info_t info, struct nfsrv_descript *nfsd,
1335 int after_ret, struct vattr *after_vap)
1337 struct nfs_fattr *fp;
1341 tl = nfsm_build(info, NFSX_UNSIGNED);
1344 tl = nfsm_build(info, NFSX_UNSIGNED + NFSX_V3FATTR);
1346 fp = (struct nfs_fattr *)tl;
1347 nfsm_srvfattr(nfsd, after_vap, fp);
1352 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
1353 struct nfs_fattr *fp)
1356 * NFS seems to truncate nlink to 16 bits, don't let it overflow.
1358 if (vap->va_nlink > 65535)
1359 fp->fa_nlink = 65535;
1361 fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1362 fp->fa_uid = txdr_unsigned(vap->va_uid);
1363 fp->fa_gid = txdr_unsigned(vap->va_gid);
1364 if (nfsd->nd_flag & ND_NFSV3) {
1365 fp->fa_type = vtonfsv3_type(vap->va_type);
1366 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1367 txdr_hyper(vap->va_size, &fp->fa3_size);
1368 txdr_hyper(vap->va_bytes, &fp->fa3_used);
1369 fp->fa3_rdev.specdata1 = txdr_unsigned(vap->va_rmajor);
1370 fp->fa3_rdev.specdata2 = txdr_unsigned(vap->va_rminor);
1371 fp->fa3_fsid.nfsuquad[0] = 0;
1372 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1373 txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
1374 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1375 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1376 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1378 fp->fa_type = vtonfsv2_type(vap->va_type);
1379 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1380 fp->fa2_size = txdr_unsigned(vap->va_size);
1381 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1382 if (vap->va_type == VFIFO)
1383 fp->fa2_rdev = 0xffffffff;
1385 fp->fa2_rdev = txdr_unsigned(makeudev(vap->va_rmajor, vap->va_rminor));
1386 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1387 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1388 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1389 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1390 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1391 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);