acpi: restructure genwakecode.sh
[dragonfly.git] / sys / vfs / nfs / nfsm_subs.c
blob4c19e8744806ddb02ece2a1a8bc0574de69d28e0
1 /*
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
9 * are met:
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
16 * distribution.
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
32 * SUCH DAMAGE.
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
43 * are met:
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
67 * SUCH DAMAGE.
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>
78 #include <sys/buf.h>
79 #include <sys/proc.h>
80 #include <sys/mount.h>
81 #include <sys/vnode.h>
82 #include <sys/nlookup.h>
83 #include <sys/namei.h>
84 #include <sys/mbuf.h>
85 #include <sys/socket.h>
86 #include <sys/stat.h>
87 #include <sys/malloc.h>
88 #include <sys/sysent.h>
89 #include <sys/syscall.h>
90 #include <sys/conf.h>
91 #include <sys/objcache.h>
93 #include <vm/vm.h>
94 #include <vm/vm_object.h>
95 #include <vm/vm_extern.h>
96 #include <vm/vm_zone.h>
98 #include <sys/buf2.h>
100 #include "rpcv2.h"
101 #include "nfsproto.h"
102 #include "nfs.h"
103 #include "nfsmount.h"
104 #include "nfsnode.h"
105 #include "xdr_subs.h"
106 #include "nfsm_subs.h"
107 #include "nfsrtt.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)
118 void
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);
122 info->mb->m_len = 0;
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.
133 struct mbuf *
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,
137 u_int32_t *xidp)
139 struct nfsm_info info;
140 struct mbuf *mb2;
141 u_int32_t *tl;
142 int siz, grpsiz, authsiz, dsiz;
143 int i;
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) {
149 if (dsiz < MHLEN)
150 MH_ALIGN(info.mb, dsiz);
151 else
152 MH_ALIGN(info.mb, 8 * NFSX_UNSIGNED);
154 info.mb->m_len = info.mb->m_pkthdr.len = 0;
155 info.mreq = info.mb;
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 */
164 if (!nfs_xid)
165 nfs_xid = krandom();
167 * Skip zero xid if it should ever happen.
169 if (++nfs_xid == 0)
170 nfs_xid++;
172 *tl++ = *xidp = txdr_unsigned(nfs_xid);
173 *tl++ = rpc_call;
174 *tl++ = rpc_vers;
175 *tl++ = txdr_unsigned(NFS_PROG);
176 if (nmflag & NFSMNT_NFSV3)
177 *tl++ = txdr_unsigned(NFS_VER3);
178 else
179 *tl++ = txdr_unsigned(NFS_VER2);
180 if (nmflag & NFSMNT_NFSV3)
181 *tl++ = txdr_unsigned(procid);
182 else
183 *tl++ = txdr_unsigned(nfsv2_procid[procid]);
186 * And then the authorization cred.
188 *tl++ = txdr_unsigned(auth_type);
189 *tl = txdr_unsigned(authsiz);
190 switch (auth_type) {
191 case RPCAUTH_UNIX:
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]);
201 break;
202 case RPCAUTH_KERB4:
203 siz = auth_len;
204 while (siz > 0) {
205 if (M_TRAILINGSPACE(info.mb) == 0) {
206 mb2 = m_getl(siz, MB_WAIT, MT_DATA, 0, NULL);
207 mb2->m_len = 0;
208 info.mb->m_next = mb2;
209 info.mb = mb2;
210 info.bpos = mtod(info.mb, caddr_t);
212 i = min(siz, M_TRAILINGSPACE(info.mb));
213 bcopy(auth_str, info.bpos, i);
214 info.mb->m_len += i;
215 auth_str += i;
216 info.bpos += i;
217 siz -= i;
219 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
220 for (i = 0; i < siz; i++)
221 *info.bpos++ = '\0';
222 info.mb->m_len += siz;
224 break;
228 * And the verifier...
230 tl = nfsm_build(&info, 2 * NFSX_UNSIGNED);
231 if (verf_str) {
232 *tl++ = txdr_unsigned(RPCAUTH_KERB4);
233 *tl = txdr_unsigned(verf_len);
234 siz = verf_len;
235 while (siz > 0) {
236 if (M_TRAILINGSPACE(info.mb) == 0) {
237 mb2 = m_getl(siz, MB_WAIT, MT_DATA,
238 0, NULL);
239 mb2->m_len = 0;
240 info.mb->m_next = mb2;
241 info.mb = mb2;
242 info.bpos = mtod(info.mb, caddr_t);
244 i = min(siz, M_TRAILINGSPACE(info.mb));
245 bcopy(verf_str, info.bpos, i);
246 info.mb->m_len += i;
247 verf_str += i;
248 info.bpos += i;
249 siz -= i;
251 if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
252 for (i = 0; i < siz; i++)
253 *info.bpos++ = '\0';
254 info.mb->m_len += siz;
256 } else {
257 *tl++ = txdr_unsigned(RPCAUTH_NULL);
258 *tl = 0;
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;
263 *mbp = info.mb;
264 return (info.mreq);
267 void *
268 nfsm_build(nfsm_info_t info, int bytes)
270 struct mbuf *mb2;
271 void *ptr;
273 if (bytes > M_TRAILINGSPACE(info->mb)) {
274 MGET(mb2, MB_WAIT, MT_DATA);
275 if (bytes > MLEN)
276 panic("build > MLEN");
277 info->mb->m_next = mb2;
278 info->mb = mb2;
279 info->mb->m_len = 0;
280 info->bpos = mtod(info->mb, caddr_t);
282 ptr = info->bpos;
283 info->mb->m_len += bytes;
284 info->bpos += bytes;
285 return (ptr);
290 * If NULL returned caller is expected to abort with an EBADRPC error.
291 * Caller will usually use the NULLOUT macro.
293 void *
294 nfsm_dissect(nfsm_info_t info, int bytes)
296 caddr_t cp2;
297 void *ptr;
298 int error;
299 int n;
301 n = mtod(info->md, caddr_t) + info->md->m_len - info->dpos;
302 if (bytes <= n) {
303 ptr = info->dpos;
304 info->dpos += bytes;
305 } else {
306 error = nfsm_disct(&info->md, &info->dpos, bytes, n, &cp2);
307 if (error) {
308 m_freem(info->mrep);
309 info->mrep = NULL;
310 ptr = NULL;
311 } else {
312 ptr = cp2;
315 return (ptr);
320 * Caller is expected to abort if non-zero error is returned.
323 nfsm_fhtom(nfsm_info_t info, struct vnode *vp)
325 u_int32_t *tl;
326 caddr_t cp;
327 int error;
328 int n;
330 if (info->v3) {
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);
338 error = 0;
339 } else if ((error = nfsm_strtmbuf(&info->mb, &info->bpos,
340 (caddr_t)VTONFS(vp)->n_fhp,
341 VTONFS(vp)->n_fhsize)) != 0) {
342 m_freem(info->mreq);
343 info->mreq = NULL;
345 } else {
346 cp = nfsm_build(info, NFSX_V2FH);
347 bcopy(VTONFS(vp)->n_fhp, cp, NFSX_V2FH);
348 error = 0;
350 return (error);
353 void
354 nfsm_srvfhtom(nfsm_info_t info, fhandle_t *fhp)
356 u_int32_t *tl;
358 if (info->v3) {
359 tl = nfsm_build(info, NFSX_UNSIGNED + NFSX_V3FH);
360 *tl++ = txdr_unsigned(NFSX_V3FH);
361 bcopy(fhp, tl, NFSX_V3FH);
362 } else {
363 tl = nfsm_build(info, NFSX_V2FH);
364 bcopy(fhp, tl, NFSX_V2FH);
368 void
369 nfsm_srvpostop_fh(nfsm_info_t info, fhandle_t *fhp)
371 u_int32_t *tl;
373 tl = nfsm_build(info, 2 * NFSX_UNSIGNED + NFSX_V3FH);
374 *tl++ = nfs_true;
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;
389 nfsfh_t *ttfhp;
390 u_int32_t *tl;
391 int ttfhsize;
392 int error = 0;
394 if (info->v3) {
395 tl = nfsm_dissect(info, NFSX_UNSIGNED);
396 if (tl == NULL)
397 return(EBADRPC);
398 *gotvpp = fxdr_unsigned(int, *tl);
399 } else {
400 *gotvpp = 1;
402 if (*gotvpp) {
403 NEGATIVEOUT(ttfhsize = nfsm_getfh(info, &ttfhp));
404 error = nfs_nget(dvp->v_mount, ttfhp, ttfhsize, &ttnp);
405 if (error) {
406 m_freem(info->mrep);
407 info->mrep = NULL;
408 return (error);
410 *vpp = NFSTOV(ttnp);
412 if (info->v3) {
413 tl = nfsm_dissect(info, NFSX_UNSIGNED);
414 if (tl == NULL)
415 return (EBADRPC);
416 if (*gotvpp) {
417 *gotvpp = fxdr_unsigned(int, *tl);
418 } else if (fxdr_unsigned(int, *tl)) {
419 error = nfsm_adv(info, NFSX_V3FATTR);
420 if (error)
421 return (error);
424 if (*gotvpp)
425 error = nfsm_loadattr(info, *vpp, NULL);
426 nfsmout:
427 return (error);
432 * Caller is expected to abort with EBADRPC if a negative length is returned.
435 nfsm_getfh(nfsm_info_t info, nfsfh_t **fhpp)
437 u_int32_t *tl;
438 int n;
440 *fhpp = NULL;
441 if (info->v3) {
442 tl = nfsm_dissect(info, NFSX_UNSIGNED);
443 if (tl == NULL)
444 return(-1);
445 if ((n = fxdr_unsigned(int, *tl)) <= 0 || n > NFSX_V3FHMAX) {
446 m_freem(info->mrep);
447 info->mrep = NULL;
448 return(-1);
450 } else {
451 n = NFSX_V2FH;
453 *fhpp = nfsm_dissect(info, nfsm_rndup(n));
454 if (*fhpp == NULL)
455 return(-1);
456 return(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)
465 int error;
467 error = nfs_loadattrcache(vp, &info->md, &info->dpos, vap, 0);
468 if (error) {
469 m_freem(info->mrep);
470 info->mrep = NULL;
471 return (error);
473 return (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)
482 u_int32_t *tl;
483 int error;
485 tl = nfsm_dissect(info, NFSX_UNSIGNED);
486 if (tl == NULL)
487 return(EBADRPC);
488 *attrp = fxdr_unsigned(int, *tl);
489 if (*attrp) {
490 error = nfs_loadattrcache(vp, &info->md, &info->dpos,
491 NULL, lflags);
492 if (error) {
493 *attrp = 0;
494 m_freem(info->mrep);
495 info->mrep = NULL;
496 return (error);
499 return (0);
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)
508 u_int32_t *tl;
509 int error;
510 int ttattrf;
511 int ttretf = 0;
513 tl = nfsm_dissect(info, NFSX_UNSIGNED);
514 if (tl == NULL)
515 return (EBADRPC);
516 if (*tl == nfs_true) {
517 tl = nfsm_dissect(info, 6 * NFSX_UNSIGNED);
518 if (tl == NULL)
519 return (EBADRPC);
520 if (*attrp) {
521 ttretf = (VTONFS(vp)->n_mtime ==
522 fxdr_unsigned(u_int32_t, *(tl + 2)));
523 if (ttretf == 0)
524 VTONFS(vp)->n_flag |= NRMODIFIED;
526 error = nfsm_postop_attr(info, vp, &ttattrf,
527 NFS_LATTR_NOSHRINK|NFS_LATTR_NOMTIMECHECK);
528 if (error)
529 return(error);
530 } else {
531 error = nfsm_postop_attr(info, vp, &ttattrf,
532 NFS_LATTR_NOSHRINK);
533 if (error)
534 return(error);
536 if (*attrp)
537 *attrp = ttretf;
538 else
539 *attrp = ttattrf;
540 return(0);
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
548 * modification.
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
557 void
558 nfsm_v3attrbuild(nfsm_info_t info, struct vattr *vap, int full)
560 u_int32_t *tl;
562 if (vap->va_mode != (mode_t)VNOVAL) {
563 tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
564 *tl++ = nfs_true;
565 *tl = txdr_unsigned(vap->va_mode);
566 } else {
567 tl = nfsm_build(info, NFSX_UNSIGNED);
568 *tl = nfs_false;
570 if (full && vap->va_uid != (uid_t)VNOVAL) {
571 tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
572 *tl++ = nfs_true;
573 *tl = txdr_unsigned(vap->va_uid);
574 } else {
575 tl = nfsm_build(info, NFSX_UNSIGNED);
576 *tl = nfs_false;
578 if (full && vap->va_gid != (gid_t)VNOVAL) {
579 tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
580 *tl++ = nfs_true;
581 *tl = txdr_unsigned(vap->va_gid);
582 } else {
583 tl = nfsm_build(info, NFSX_UNSIGNED);
584 *tl = nfs_false;
586 if (full && vap->va_size != VNOVAL) {
587 tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
588 *tl++ = nfs_true;
589 txdr_hyper(vap->va_size, tl);
590 } else {
591 tl = nfsm_build(info, NFSX_UNSIGNED);
592 *tl = nfs_false;
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);
599 } else {
600 tl = nfsm_build(info, NFSX_UNSIGNED);
601 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
603 } else {
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);
612 } else {
613 tl = nfsm_build(info, NFSX_UNSIGNED);
614 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
616 } else {
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)
628 u_int32_t *tl;
629 int len;
631 tl = nfsm_dissect(info, NFSX_UNSIGNED);
632 if (tl == NULL)
633 return(-1);
634 len = fxdr_unsigned(int32_t, *tl);
635 if (len < 0 || len > maxlen)
636 return(-1);
637 return (len);
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)
649 u_int32_t *tl;
650 int len;
652 tl = nfsm_dissect(info, NFSX_UNSIGNED);
653 if (tl == NULL) {
654 *errorp = EBADRPC;
655 return(-1);
657 len = fxdr_unsigned(int32_t,*tl);
658 if (len > maxlen || len <= 0) {
659 *errorp = EBADRPC;
660 return(-2);
662 return(len);
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)
674 u_int32_t *tl;
675 int len;
677 tl = nfsm_dissect(info, NFSX_UNSIGNED);
678 if (tl == NULL) {
679 *errorp = EBADRPC;
680 return(-1);
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
687 * to return -1.
689 len = fxdr_unsigned(int32_t,*tl);
690 if (len > NFS_MAXNAMLEN)
691 *errorp = NFSERR_NAMETOL;
692 if (len <= 0)
693 *errorp = EBADRPC;
694 if (*errorp)
695 return(-2);
696 return (len);
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)
705 int error;
707 if (len > 0 &&
708 (error = nfsm_mbuftouio(&info->md, uiop, len, &info->dpos)) != 0) {
709 m_freem(info->mrep);
710 info->mrep = NULL;
711 return(error);
713 return(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)
722 int error;
724 if (len > 0 &&
725 (error = nfsm_mbuftobio(&info->md, bio, len, &info->dpos)) != 0) {
726 m_freem(info->mrep);
727 info->mrep = NULL;
728 return(error);
730 return (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)
739 int error;
741 error = nfsm_uiotombuf(uiop, &info->mb, len, &info->bpos);
742 if (error) {
743 m_freem(info->mreq);
744 info->mreq = NULL;
745 return (error);
747 return(0);
751 nfsm_biotom(nfsm_info_t info, struct bio *bio, int off, int len)
753 int error;
755 error = nfsm_biotombuf(bio, &info->mb, off, len, &info->bpos);
756 if (error) {
757 m_freem(info->mreq);
758 info->mreq = NULL;
759 return (error);
761 return(0);
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;
780 info->vp = vp;
781 info->td = td;
782 info->cred = cred;
783 info->bio = NULL;
784 info->nmp = VFSTONFS(vp->v_mount);
786 *errorp = nfs_request(info, NFSM_STATE_SETUP, NFSM_STATE_DONE);
787 if (*errorp) {
788 if ((*errorp & NFSERR_RETERR) == 0)
789 return(-1);
790 *errorp &= ~NFSERR_RETERR;
792 return(0);
796 * This call starts the state machine through the initial transmission.
797 * Completion is via the bio. The info structure must have installed
798 * a 'done' callback.
800 * If we are unable to do the initial tx we generate the bio completion
801 * ourselves.
803 void
804 nfsm_request_bio(nfsm_info_t info, struct vnode *vp, int procnum,
805 thread_t td, struct ucred *cred)
807 struct buf *bp;
808 int error;
810 info->state = NFSM_STATE_SETUP;
811 info->procnum = procnum;
812 info->vp = vp;
813 info->td = td;
814 info->cred = cred;
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;
821 if (error)
822 bp->b_flags |= B_ERROR;
823 bp->b_error = error;
824 biodone(info->bio);
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)
834 u_int32_t *tl;
835 int error;
836 int n;
838 if (len > maxlen) {
839 m_freem(info->mreq);
840 info->mreq = NULL;
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);
849 error = 0;
850 } else {
851 error = nfsm_strtmbuf(&info->mb, &info->bpos, data, len);
852 if (error) {
853 m_freem(info->mreq);
854 info->mreq = NULL;
857 return (error);
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))
871 siz = 0;
872 nfs_rephead(siz, nfsd, slp, *errorp, &info->mreq,
873 &info->mb, &info->bpos);
874 if (info->mrep != NULL) {
875 m_freem(info->mrep);
876 info->mrep = NULL;
878 if (*errorp && (!(nfsd->nd_flag & ND_NFSV3) || *errorp == EBADRPC)) {
879 *errorp = 0;
880 return(-1);
882 return(0);
885 void
886 nfsm_writereply(nfsm_info_t info,
887 struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
888 int error, int siz)
890 nfsd->nd_repstat = error;
891 if (error && !(info->v3))
892 siz = 0;
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)
902 int error;
903 int n;
905 n = mtod(info->md, caddr_t) + info->md->m_len - info->dpos;
906 if (n >= len) {
907 info->dpos += len;
908 error = 0;
909 } else if ((error = nfs_adv(&info->md, &info->dpos, len, n)) != 0) {
910 m_freem(info->mrep);
911 info->mrep = NULL;
913 return (error);
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)
926 u_int32_t *tl;
927 int fhlen;
929 if (nfsd->nd_flag & ND_NFSV3) {
930 tl = nfsm_dissect(info, NFSX_UNSIGNED);
931 if (tl == NULL) {
932 *errorp = EBADRPC;
933 return(-1);
935 fhlen = fxdr_unsigned(int, *tl);
936 if (fhlen != 0 && fhlen != NFSX_V3FH) {
937 *errorp = EBADRPC;
938 return(-2);
940 } else {
941 fhlen = NFSX_V2FH;
943 if (fhlen != 0) {
944 tl = nfsm_dissect(info, fhlen);
945 if (tl == NULL) {
946 *errorp = EBADRPC;
947 return(-1);
949 bcopy(tl, fhp, fhlen);
950 } else {
951 bzero(fhp, NFSX_V3FH);
953 return(0);
956 void *
957 _nfsm_clget(nfsm_info_t info, struct mbuf **mp1, struct mbuf **mp2,
958 char **bp, char **be)
960 if (*bp >= *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;
966 *mp2 = *mp1;
967 *bp = mtod(*mp1, caddr_t);
968 *be = *bp + (*mp1)->m_len;
970 return(*bp);
974 nfsm_srvsattr(nfsm_info_t info, struct vattr *vap)
976 u_int32_t *tl;
977 int error = 0;
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);
1004 break;
1005 case NFSV3SATTRTIME_TOSERVER:
1006 getnanotime(&vap->va_atime);
1007 break;
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);
1014 break;
1015 case NFSV3SATTRTIME_TOSERVER:
1016 getnanotime(&vap->va_mtime);
1017 break;
1019 nfsmout:
1020 return (error);
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;
1031 struct mbuf *mp;
1032 long uiosiz, rem;
1033 int error = 0;
1035 mp = *mrep;
1036 mbufcp = *dpos;
1037 len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
1038 rem = nfsm_rndup(siz)-siz;
1039 while (siz > 0) {
1040 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
1041 return (EFBIG);
1042 left = uiop->uio_iov->iov_len;
1043 uiocp = uiop->uio_iov->iov_base;
1044 if (left > siz)
1045 left = siz;
1046 uiosiz = left;
1047 while (left > 0) {
1048 while (len == 0) {
1049 mp = mp->m_next;
1050 if (mp == NULL)
1051 return (EBADRPC);
1052 mbufcp = mtod(mp, caddr_t);
1053 len = mp->m_len;
1055 xfer = (left > len) ? len : left;
1056 #ifdef notdef
1057 /* Not Yet.. */
1058 if (uiop->uio_iov->iov_op != NULL)
1059 (*(uiop->uio_iov->iov_op))
1060 (mbufcp, uiocp, xfer);
1061 else
1062 #endif
1063 if (uiop->uio_segflg == UIO_SYSSPACE)
1064 bcopy(mbufcp, uiocp, xfer);
1065 else
1066 copyout(mbufcp, uiocp, xfer);
1067 left -= xfer;
1068 len -= xfer;
1069 mbufcp += xfer;
1070 uiocp += xfer;
1071 uiop->uio_offset += xfer;
1072 uiop->uio_resid -= xfer;
1074 if (uiop->uio_iov->iov_len <= siz) {
1075 uiop->uio_iovcnt--;
1076 uiop->uio_iov++;
1077 } else {
1078 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
1079 uiop->uio_iov->iov_len -= uiosiz;
1081 siz -= uiosiz;
1083 *dpos = mbufcp;
1084 *mrep = mp;
1085 if (rem > 0) {
1086 if (len < rem)
1087 error = nfs_adv(mrep, dpos, rem, len);
1088 else
1089 *dpos += rem;
1091 return (error);
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;
1101 char *mbufcp;
1102 char *bio_cp;
1103 int xfer, len;
1104 struct mbuf *mp;
1105 long rem;
1106 int error = 0;
1107 int bio_left;
1109 mp = *mrep;
1110 mbufcp = *dpos;
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;
1117 while (size > 0) {
1118 while (len == 0) {
1119 mp = mp->m_next;
1120 if (mp == NULL)
1121 return (EBADRPC);
1122 mbufcp = mtod(mp, caddr_t);
1123 len = mp->m_len;
1125 if ((xfer = len) > size)
1126 xfer = size;
1127 if (bio_left) {
1128 if (xfer > bio_left)
1129 xfer = bio_left;
1130 bcopy(mbufcp, bio_cp, xfer);
1131 } else {
1133 * Not enough buffer space in the bio.
1135 return(EFBIG);
1137 size -= xfer;
1138 bio_left -= xfer;
1139 bio_cp += xfer;
1140 len -= xfer;
1141 mbufcp += xfer;
1143 *dpos = mbufcp;
1144 *mrep = mp;
1145 if (rem > 0) {
1146 if (len < rem)
1147 error = nfs_adv(mrep, dpos, rem, len);
1148 else
1149 *dpos += rem;
1151 return (error);
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)
1161 char *uiocp;
1162 struct mbuf *mp, *mp2;
1163 int xfer, left, mlen;
1164 int uiosiz, rem;
1165 boolean_t getcluster;
1166 char *cp;
1168 #ifdef DIAGNOSTIC
1169 if (uiop->uio_iovcnt != 1)
1170 panic("nfsm_uiotombuf: iovcnt != 1");
1171 #endif
1173 if (siz >= MINCLSIZE)
1174 getcluster = TRUE;
1175 else
1176 getcluster = FALSE;
1177 rem = nfsm_rndup(siz) - siz;
1178 mp = mp2 = *mq;
1179 while (siz > 0) {
1180 left = uiop->uio_iov->iov_len;
1181 uiocp = uiop->uio_iov->iov_base;
1182 if (left > siz)
1183 left = siz;
1184 uiosiz = left;
1185 while (left > 0) {
1186 mlen = M_TRAILINGSPACE(mp);
1187 if (mlen == 0) {
1188 if (getcluster)
1189 mp = m_getcl(MB_WAIT, MT_DATA, 0);
1190 else
1191 mp = m_get(MB_WAIT, MT_DATA);
1192 mp->m_len = 0;
1193 mp2->m_next = mp;
1194 mp2 = mp;
1195 mlen = M_TRAILINGSPACE(mp);
1197 xfer = (left > mlen) ? mlen : left;
1198 #ifdef notdef
1199 /* Not Yet.. */
1200 if (uiop->uio_iov->iov_op != NULL)
1201 (*(uiop->uio_iov->iov_op))
1202 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1203 else
1204 #endif
1205 if (uiop->uio_segflg == UIO_SYSSPACE)
1206 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1207 else
1208 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1209 mp->m_len += xfer;
1210 left -= xfer;
1211 uiocp += 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;
1217 siz -= uiosiz;
1219 if (rem > 0) {
1220 if (rem > M_TRAILINGSPACE(mp)) {
1221 MGET(mp, MB_WAIT, MT_DATA);
1222 mp->m_len = 0;
1223 mp2->m_next = mp;
1225 cp = mtod(mp, caddr_t)+mp->m_len;
1226 for (left = 0; left < rem; left++)
1227 *cp++ = '\0';
1228 mp->m_len += rem;
1229 *bpos = cp;
1230 } else
1231 *bpos = mtod(mp, caddr_t)+mp->m_len;
1232 *mq = mp;
1233 return (0);
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;
1242 char *bio_cp;
1243 int bio_left;
1244 int xfer, mlen;
1245 int rem;
1246 boolean_t getcluster;
1247 char *cp;
1249 if (siz >= MINCLSIZE)
1250 getcluster = TRUE;
1251 else
1252 getcluster = FALSE;
1253 rem = nfsm_rndup(siz) - siz;
1254 mp = mp2 = *mq;
1256 bio_cp = bp->b_data + off;
1257 bio_left = siz;
1259 while (bio_left) {
1260 mlen = M_TRAILINGSPACE(mp);
1261 if (mlen == 0) {
1262 if (getcluster)
1263 mp = m_getcl(MB_WAIT, MT_DATA, 0);
1264 else
1265 mp = m_get(MB_WAIT, MT_DATA);
1266 mp->m_len = 0;
1267 mp2->m_next = mp;
1268 mp2 = mp;
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);
1273 mp->m_len += xfer;
1274 bio_left -= xfer;
1275 bio_cp += xfer;
1277 if (rem > 0) {
1278 if (rem > M_TRAILINGSPACE(mp)) {
1279 MGET(mp, MB_WAIT, MT_DATA);
1280 mp->m_len = 0;
1281 mp2->m_next = mp;
1283 cp = mtod(mp, caddr_t) + mp->m_len;
1284 for (mlen = 0; mlen < rem; mlen++)
1285 *cp++ = '\0';
1286 mp->m_len += rem;
1287 *bpos = cp;
1288 } else {
1289 *bpos = mtod(mp, caddr_t) + mp->m_len;
1291 *mq = mp;
1292 return(0);
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;
1305 int siz2, xfer;
1306 caddr_t p;
1308 mp = *mdp;
1309 while (left == 0) {
1310 *mdp = mp = mp->m_next;
1311 if (mp == NULL)
1312 return (EBADRPC);
1313 left = mp->m_len;
1314 *dposp = mtod(mp, caddr_t);
1316 if (left >= siz) {
1317 *cp2 = *dposp;
1318 *dposp += siz;
1319 } else if (mp->m_next == NULL) {
1320 return (EBADRPC);
1321 } else if (siz > MHLEN) {
1322 panic("nfs S too big");
1323 } else {
1324 MGET(mp2, MB_WAIT, MT_DATA);
1325 mp2->m_next = mp->m_next;
1326 mp->m_next = mp2;
1327 mp->m_len -= left;
1328 mp = mp2;
1329 *cp2 = p = mtod(mp, caddr_t);
1330 bcopy(*dposp, p, left); /* Copy what was left */
1331 siz2 = siz-left;
1332 p += left;
1333 mp2 = mp->m_next;
1334 /* Loop around copying up the siz2 bytes */
1335 while (siz2 > 0) {
1336 if (mp2 == NULL)
1337 return (EBADRPC);
1338 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
1339 if (xfer > 0) {
1340 bcopy(mtod(mp2, caddr_t), p, xfer);
1341 mp2->m_len -= xfer;
1342 mp2->m_data += xfer;
1343 p += xfer;
1344 siz2 -= xfer;
1346 if (siz2 > 0)
1347 mp2 = mp2->m_next;
1349 mp->m_len = siz;
1350 *mdp = mp2;
1351 *dposp = mtod(mp2, caddr_t);
1353 return (0);
1357 * Advance the position in the mbuf chain.
1360 nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left)
1362 struct mbuf *m;
1363 int s;
1365 m = *mdp;
1366 s = left;
1367 while (s < offs) {
1368 offs -= s;
1369 m = m->m_next;
1370 if (m == NULL)
1371 return (EBADRPC);
1372 s = m->m_len;
1374 *mdp = m;
1375 *dposp = mtod(m, caddr_t)+offs;
1376 return (0);
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;
1387 u_int32_t *tl;
1388 int putsize;
1390 putsize = 1;
1391 m2 = *mb;
1392 left = M_TRAILINGSPACE(m2);
1393 if (left > 0) {
1394 tl = ((u_int32_t *)(*bpos));
1395 *tl++ = txdr_unsigned(siz);
1396 putsize = 0;
1397 left -= NFSX_UNSIGNED;
1398 m2->m_len += NFSX_UNSIGNED;
1399 if (left > 0) {
1400 bcopy(cp, (caddr_t) tl, left);
1401 siz -= left;
1402 cp += left;
1403 m2->m_len += left;
1404 left = 0;
1407 /* Loop around adding mbufs */
1408 while (siz > 0) {
1409 int msize;
1411 m1 = m_getl(siz, MB_WAIT, MT_DATA, 0, &msize);
1412 m1->m_len = msize;
1413 m2->m_next = m1;
1414 m2 = m1;
1415 tl = mtod(m1, u_int32_t *);
1416 tlen = 0;
1417 if (putsize) {
1418 *tl++ = txdr_unsigned(siz);
1419 m1->m_len -= NFSX_UNSIGNED;
1420 tlen = NFSX_UNSIGNED;
1421 putsize = 0;
1423 if (siz < m1->m_len) {
1424 len = nfsm_rndup(siz);
1425 xfer = siz;
1426 if (xfer < len)
1427 *(tl+(xfer>>2)) = 0;
1428 } else {
1429 xfer = len = m1->m_len;
1431 bcopy(cp, (caddr_t) tl, xfer);
1432 m1->m_len = len+tlen;
1433 siz -= xfer;
1434 cp += xfer;
1436 *mb = m1;
1437 *bpos = mtod(m1, caddr_t)+m1->m_len;
1438 return (0);
1442 * A fiddled version of m_adj() that ensures null fill to a long
1443 * boundary and only trims off the back end
1445 void
1446 nfsm_adj(struct mbuf *mp, int len, int nul)
1448 struct mbuf *m;
1449 int count, i;
1450 char *cp;
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.
1459 count = 0;
1460 m = mp;
1461 for (;;) {
1462 count += m->m_len;
1463 if (m->m_next == NULL)
1464 break;
1465 m = m->m_next;
1467 if (m->m_len > len) {
1468 m->m_len -= len;
1469 if (nul > 0) {
1470 cp = mtod(m, caddr_t)+m->m_len-nul;
1471 for (i = 0; i < nul; i++)
1472 *cp++ = '\0';
1474 return;
1476 count -= len;
1477 if (count < 0)
1478 count = 0;
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) {
1486 m->m_len = count;
1487 if (nul > 0) {
1488 cp = mtod(m, caddr_t)+m->m_len-nul;
1489 for (i = 0; i < nul; i++)
1490 *cp++ = '\0';
1492 break;
1494 count -= m->m_len;
1496 for (m = m->m_next;m;m = m->m_next)
1497 m->m_len = 0;
1501 * Make these functions instead of macros, so that the kernel text size
1502 * doesn't get too big...
1504 void
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)
1509 u_int32_t *tl;
1512 * before_ret is 0 if before_vap is valid, non-zero if it isn't.
1514 if (before_ret) {
1515 tl = nfsm_build(info, NFSX_UNSIGNED);
1516 *tl = nfs_false;
1517 } else {
1518 tl = nfsm_build(info, 7 * NFSX_UNSIGNED);
1519 *tl++ = nfs_true;
1520 txdr_hyper(before_vap->va_size, tl);
1521 tl += 2;
1522 txdr_nfsv3time(&(before_vap->va_mtime), tl);
1523 tl += 2;
1524 txdr_nfsv3time(&(before_vap->va_ctime), tl);
1526 nfsm_srvpostop_attr(info, nfsd, after_ret, after_vap);
1529 void
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;
1534 u_int32_t *tl;
1536 if (after_ret) {
1537 tl = nfsm_build(info, NFSX_UNSIGNED);
1538 *tl = nfs_false;
1539 } else {
1540 tl = nfsm_build(info, NFSX_UNSIGNED + NFSX_V3FATTR);
1541 *tl++ = nfs_true;
1542 fp = (struct nfs_fattr *)tl;
1543 nfsm_srvfattr(nfsd, after_vap, fp);
1547 void
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;
1556 else
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);
1573 } else {
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;
1580 else
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);