sched_setaffinity.2: Small markup fix.
[dragonfly.git] / sys / vfs / nfs / nfsm_subs.c
blob2693295954dd0f1da2a62f84e2230a6799c0ef76
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. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
67 * These functions support the macros and help fiddle mbuf chains for
68 * the nfs op functions. They do things like create the rpc header and
69 * copy data between mbuf chains and uio lists.
71 #include <sys/param.h>
72 #include <sys/systm.h>
73 #include <sys/kernel.h>
74 #include <sys/buf.h>
75 #include <sys/proc.h>
76 #include <sys/mount.h>
77 #include <sys/vnode.h>
78 #include <sys/nlookup.h>
79 #include <sys/namei.h>
80 #include <sys/mbuf.h>
81 #include <sys/socket.h>
82 #include <sys/stat.h>
83 #include <sys/malloc.h>
84 #include <sys/sysent.h>
85 #include <sys/syscall.h>
86 #include <sys/conf.h>
87 #include <sys/objcache.h>
89 #include <vm/vm.h>
90 #include <vm/vm_object.h>
91 #include <vm/vm_extern.h>
93 #include <sys/buf2.h>
95 #include "rpcv2.h"
96 #include "nfsproto.h"
97 #include "nfs.h"
98 #include "nfsmount.h"
99 #include "nfsnode.h"
100 #include "xdr_subs.h"
101 #include "nfsm_subs.h"
102 #include "nfsrtt.h"
104 #include <netinet/in.h>
106 static u_int32_t nfs_xid = 0;
109 * Create the header for an rpc request packet
110 * The hsiz is the size of the rest of the nfs request header.
111 * (just used to decide if a cluster is a good idea)
113 void
114 nfsm_reqhead(nfsm_info_t info, struct vnode *vp, u_long procid, int hsiz)
116 info->mb = m_getl(hsiz, M_WAITOK, MT_DATA, 0, NULL);
117 info->mb->m_len = 0;
118 info->mreq = info->mb;
119 info->bpos = mtod(info->mb, caddr_t);
123 * Build the RPC header and fill in the authorization info.
124 * The authorization string argument is only used when the credentials
125 * come from outside of the kernel.
126 * Returns the head of the mbuf list.
128 struct mbuf *
129 nfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type,
130 int auth_len, char *auth_str, int verf_len, char *verf_str,
131 struct mbuf *mrest, int mrest_len, struct mbuf **mbp,
132 u_int32_t *xidp)
134 struct nfsm_info info;
135 struct mbuf *mb2;
136 u_int32_t *tl;
137 u_int32_t xid;
138 int siz, grpsiz, authsiz, dsiz;
139 int i;
141 authsiz = nfsm_rndup(auth_len);
142 dsiz = authsiz + 10 * NFSX_UNSIGNED;
143 info.mb = m_getl(dsiz, M_WAITOK, MT_DATA, M_PKTHDR, NULL);
144 if (dsiz < MINCLSIZE) {
145 if (dsiz < MHLEN)
146 MH_ALIGN(info.mb, dsiz);
147 else
148 MH_ALIGN(info.mb, 8 * NFSX_UNSIGNED);
150 info.mb->m_len = info.mb->m_pkthdr.len = 0;
151 info.mreq = info.mb;
152 info.bpos = mtod(info.mb, caddr_t);
155 * First the RPC header.
157 tl = nfsm_build(&info, 8 * NFSX_UNSIGNED);
159 /* Get a pretty random xid to start with */
160 if (!nfs_xid)
161 nfs_xid = krandom();
163 do {
164 xid = atomic_fetchadd_int(&nfs_xid, 1);
165 } while (xid == 0);
167 *tl++ = *xidp = txdr_unsigned(xid);
168 *tl++ = rpc_call;
169 *tl++ = rpc_vers;
170 *tl++ = txdr_unsigned(NFS_PROG);
171 if (nmflag & NFSMNT_NFSV3)
172 *tl++ = txdr_unsigned(NFS_VER3);
173 else
174 *tl++ = txdr_unsigned(NFS_VER2);
175 if (nmflag & NFSMNT_NFSV3)
176 *tl++ = txdr_unsigned(procid);
177 else
178 *tl++ = txdr_unsigned(nfsv2_procid[procid]);
181 * And then the authorization cred.
183 *tl++ = txdr_unsigned(auth_type);
184 *tl = txdr_unsigned(authsiz);
185 switch (auth_type) {
186 case RPCAUTH_UNIX:
187 tl = nfsm_build(&info, auth_len);
188 *tl++ = 0; /* stamp ?? */
189 *tl++ = 0; /* NULL hostname */
190 *tl++ = txdr_unsigned(cr->cr_uid);
191 *tl++ = txdr_unsigned(cr->cr_groups[0]);
192 grpsiz = (auth_len >> 2) - 5;
193 *tl++ = txdr_unsigned(grpsiz);
194 for (i = 1; i <= grpsiz; i++)
195 *tl++ = txdr_unsigned(cr->cr_groups[i]);
196 break;
197 case RPCAUTH_KERB4:
198 siz = auth_len;
199 while (siz > 0) {
200 if (M_TRAILINGSPACE(info.mb) == 0) {
201 mb2 = m_getl(siz, M_WAITOK, MT_DATA, 0, NULL);
202 mb2->m_len = 0;
203 info.mb->m_next = mb2;
204 info.mb = mb2;
205 info.bpos = mtod(info.mb, caddr_t);
207 i = min(siz, M_TRAILINGSPACE(info.mb));
208 bcopy(auth_str, info.bpos, i);
209 info.mb->m_len += i;
210 auth_str += i;
211 info.bpos += i;
212 siz -= i;
214 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
215 for (i = 0; i < siz; i++)
216 *info.bpos++ = '\0';
217 info.mb->m_len += siz;
219 break;
223 * And the verifier...
225 tl = nfsm_build(&info, 2 * NFSX_UNSIGNED);
226 if (verf_str) {
227 *tl++ = txdr_unsigned(RPCAUTH_KERB4);
228 *tl = txdr_unsigned(verf_len);
229 siz = verf_len;
230 while (siz > 0) {
231 if (M_TRAILINGSPACE(info.mb) == 0) {
232 mb2 = m_getl(siz, M_WAITOK, MT_DATA,
233 0, NULL);
234 mb2->m_len = 0;
235 info.mb->m_next = mb2;
236 info.mb = mb2;
237 info.bpos = mtod(info.mb, caddr_t);
239 i = min(siz, M_TRAILINGSPACE(info.mb));
240 bcopy(verf_str, info.bpos, i);
241 info.mb->m_len += i;
242 verf_str += i;
243 info.bpos += i;
244 siz -= i;
246 if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
247 for (i = 0; i < siz; i++)
248 *info.bpos++ = '\0';
249 info.mb->m_len += siz;
251 } else {
252 *tl++ = txdr_unsigned(RPCAUTH_NULL);
253 *tl = 0;
255 info.mb->m_next = mrest;
256 info.mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
257 info.mreq->m_pkthdr.rcvif = NULL;
258 *mbp = info.mb;
259 return (info.mreq);
262 void *
263 nfsm_build(nfsm_info_t info, int bytes)
265 struct mbuf *mb2;
266 void *ptr;
268 if (bytes > M_TRAILINGSPACE(info->mb)) {
269 MGET(mb2, M_WAITOK, MT_DATA);
270 if (bytes > MLEN)
271 panic("build > MLEN");
272 info->mb->m_next = mb2;
273 info->mb = mb2;
274 info->mb->m_len = 0;
275 info->bpos = mtod(info->mb, caddr_t);
277 ptr = info->bpos;
278 info->mb->m_len += bytes;
279 info->bpos += bytes;
280 return (ptr);
285 * If NULL returned caller is expected to abort with an EBADRPC error.
286 * Caller will usually use the NULLOUT macro.
288 void *
289 nfsm_dissect(nfsm_info_t info, int bytes)
291 caddr_t cp2;
292 void *ptr;
293 int error;
294 int n;
297 * Check for missing reply packet. This typically occurs if there
298 * is a soft termination w/too many retries.
300 if (info->md == NULL) {
301 if (info->mrep) {
302 m_freem(info->mrep);
303 info->mrep = NULL;
305 return NULL;
309 * Otherwise any error will be due to the packet format
311 n = mtod(info->md, caddr_t) + info->md->m_len - info->dpos;
312 if (bytes <= n) {
313 ptr = info->dpos;
314 info->dpos += bytes;
315 } else {
316 error = nfsm_disct(&info->md, &info->dpos, bytes, n, &cp2);
317 if (error) {
318 m_freem(info->mrep);
319 info->mrep = NULL;
320 ptr = NULL;
321 } else {
322 ptr = cp2;
325 return (ptr);
330 * Caller is expected to abort if non-zero error is returned.
333 nfsm_fhtom(nfsm_info_t info, struct vnode *vp)
335 u_int32_t *tl;
336 caddr_t cp;
337 int error;
338 int n;
340 if (info->v3) {
341 n = nfsm_rndup(VTONFS(vp)->n_fhsize) + NFSX_UNSIGNED;
342 if (n <= M_TRAILINGSPACE(info->mb)) {
343 tl = nfsm_build(info, n);
344 *tl++ = txdr_unsigned(VTONFS(vp)->n_fhsize);
345 *(tl + ((n >> 2) - 2)) = 0;
346 bcopy((caddr_t)VTONFS(vp)->n_fhp,(caddr_t)tl,
347 VTONFS(vp)->n_fhsize);
348 error = 0;
349 } else if ((error = nfsm_strtmbuf(&info->mb, &info->bpos,
350 (caddr_t)VTONFS(vp)->n_fhp,
351 VTONFS(vp)->n_fhsize)) != 0) {
352 m_freem(info->mreq);
353 info->mreq = NULL;
355 } else {
356 cp = nfsm_build(info, NFSX_V2FH);
357 bcopy(VTONFS(vp)->n_fhp, cp, NFSX_V2FH);
358 error = 0;
360 return (error);
363 void
364 nfsm_srvfhtom(nfsm_info_t info, fhandle_t *fhp)
366 u_int32_t *tl;
368 if (info->v3) {
369 tl = nfsm_build(info, NFSX_UNSIGNED + NFSX_V3FH);
370 *tl++ = txdr_unsigned(NFSX_V3FH);
371 bcopy(fhp, tl, NFSX_V3FH);
372 } else {
373 tl = nfsm_build(info, NFSX_V2FH);
374 bcopy(fhp, tl, NFSX_V2FH);
378 void
379 nfsm_srvpostop_fh(nfsm_info_t info, fhandle_t *fhp)
381 u_int32_t *tl;
383 tl = nfsm_build(info, 2 * NFSX_UNSIGNED + NFSX_V3FH);
384 *tl++ = nfs_true;
385 *tl++ = txdr_unsigned(NFSX_V3FH);
386 bcopy(fhp, tl, NFSX_V3FH);
390 * Caller is expected to abort if non-zero error is returned.
392 * NOTE: (*vpp) may be loaded with a valid vnode even if (*gotvpp)
393 * winds up 0. The caller is responsible for dealing with (*vpp).
396 nfsm_mtofh(nfsm_info_t info, struct vnode *dvp, struct vnode **vpp, int *gotvpp)
398 struct nfsnode *ttnp;
399 nfsfh_t *ttfhp;
400 u_int32_t *tl;
401 int ttfhsize;
402 int error = 0;
404 if (info->v3) {
405 tl = nfsm_dissect(info, NFSX_UNSIGNED);
406 if (tl == NULL)
407 return(EBADRPC);
408 *gotvpp = fxdr_unsigned(int, *tl);
409 } else {
410 *gotvpp = 1;
412 if (*gotvpp) {
413 NEGATIVEOUT(ttfhsize = nfsm_getfh(info, &ttfhp));
414 error = nfs_nget(dvp->v_mount, ttfhp, ttfhsize, &ttnp, NULL);
415 if (error) {
416 m_freem(info->mrep);
417 info->mrep = NULL;
418 return (error);
420 *vpp = NFSTOV(ttnp);
422 if (info->v3) {
423 tl = nfsm_dissect(info, NFSX_UNSIGNED);
424 if (tl == NULL)
425 return (EBADRPC);
426 if (*gotvpp) {
427 *gotvpp = fxdr_unsigned(int, *tl);
428 } else if (fxdr_unsigned(int, *tl)) {
429 error = nfsm_adv(info, NFSX_V3FATTR);
430 if (error)
431 return (error);
434 if (*gotvpp)
435 error = nfsm_loadattr(info, *vpp, NULL);
436 nfsmout:
437 return (error);
442 * Caller is expected to abort with EBADRPC if a negative length is returned.
445 nfsm_getfh(nfsm_info_t info, nfsfh_t **fhpp)
447 u_int32_t *tl;
448 int n;
450 *fhpp = NULL;
451 if (info->v3) {
452 tl = nfsm_dissect(info, NFSX_UNSIGNED);
453 if (tl == NULL)
454 return(-1);
455 if ((n = fxdr_unsigned(int, *tl)) <= 0 || n > NFSX_V3FHMAX) {
456 m_freem(info->mrep);
457 info->mrep = NULL;
458 return(-1);
460 } else {
461 n = NFSX_V2FH;
463 *fhpp = nfsm_dissect(info, nfsm_rndup(n));
464 if (*fhpp == NULL)
465 return(-1);
466 return(n);
470 * Caller is expected to abort if a non-zero error is returned.
473 nfsm_loadattr(nfsm_info_t info, struct vnode *vp, struct vattr *vap)
475 int error;
477 error = nfs_loadattrcache(vp, &info->md, &info->dpos, vap, 0);
478 if (error) {
479 m_freem(info->mrep);
480 info->mrep = NULL;
481 return (error);
483 return (0);
487 * Caller is expected to abort if a non-zero error is returned.
490 nfsm_postop_attr(nfsm_info_t info, struct vnode *vp, int *attrp, int lflags)
492 u_int32_t *tl;
493 int error;
495 tl = nfsm_dissect(info, NFSX_UNSIGNED);
496 if (tl == NULL)
497 return(EBADRPC);
498 *attrp = fxdr_unsigned(int, *tl);
499 if (*attrp) {
500 error = nfs_loadattrcache(vp, &info->md, &info->dpos,
501 NULL, lflags);
502 if (error) {
503 *attrp = 0;
504 m_freem(info->mrep);
505 info->mrep = NULL;
506 return (error);
509 return (0);
513 * Caller is expected to abort if a non-zero error is returned.
516 nfsm_wcc_data(nfsm_info_t info, struct vnode *vp, int *attrp)
518 u_int32_t *tl;
519 int error;
520 int ttattrf;
521 int ttretf = 0;
523 tl = nfsm_dissect(info, NFSX_UNSIGNED);
524 if (tl == NULL)
525 return (EBADRPC);
526 if (*tl == nfs_true) {
527 tl = nfsm_dissect(info, 6 * NFSX_UNSIGNED);
528 if (tl == NULL)
529 return (EBADRPC);
530 if (*attrp) {
531 ttretf = (VTONFS(vp)->n_mtime ==
532 fxdr_unsigned(u_int32_t, *(tl + 2)));
533 if (ttretf == 0)
534 VTONFS(vp)->n_flag |= NRMODIFIED;
536 error = nfsm_postop_attr(info, vp, &ttattrf,
537 NFS_LATTR_NOSHRINK|NFS_LATTR_NOMTIMECHECK);
538 if (error)
539 return(error);
540 } else {
541 error = nfsm_postop_attr(info, vp, &ttattrf,
542 NFS_LATTR_NOSHRINK);
543 if (error)
544 return(error);
546 if (*attrp)
547 *attrp = ttretf;
548 else
549 *attrp = ttattrf;
550 return(0);
554 * This function updates the attribute cache based on data returned in the
555 * NFS reply for NFS RPCs that modify the target file. If the RPC succeeds
556 * a 'before' and 'after' mtime is returned that allows us to determine if
557 * the new mtime attribute represents our modification or someone else's
558 * modification.
560 * The flag argument returns non-0 if the original times matched, zero if
561 * they did not match. NRMODIFIED is automatically set if the before time
562 * does not match the original n_mtime, and n_mtime is automatically updated
563 * to the new after time (by nfsm_postop_attr()).
565 * If full is true, set all fields, otherwise just set mode and time fields
567 void
568 nfsm_v3attrbuild(nfsm_info_t info, struct vattr *vap, int full)
570 u_int32_t *tl;
572 if (vap->va_mode != (mode_t)VNOVAL) {
573 tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
574 *tl++ = nfs_true;
575 *tl = txdr_unsigned(vap->va_mode);
576 } else {
577 tl = nfsm_build(info, NFSX_UNSIGNED);
578 *tl = nfs_false;
580 if (full && vap->va_uid != (uid_t)VNOVAL) {
581 tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
582 *tl++ = nfs_true;
583 *tl = txdr_unsigned(vap->va_uid);
584 } else {
585 tl = nfsm_build(info, NFSX_UNSIGNED);
586 *tl = nfs_false;
588 if (full && vap->va_gid != (gid_t)VNOVAL) {
589 tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
590 *tl++ = nfs_true;
591 *tl = txdr_unsigned(vap->va_gid);
592 } else {
593 tl = nfsm_build(info, NFSX_UNSIGNED);
594 *tl = nfs_false;
596 if (full && vap->va_size != VNOVAL) {
597 tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
598 *tl++ = nfs_true;
599 txdr_hyper(vap->va_size, tl);
600 } else {
601 tl = nfsm_build(info, NFSX_UNSIGNED);
602 *tl = nfs_false;
604 if (vap->va_atime.tv_sec != VNOVAL) {
605 if (vap->va_atime.tv_sec != time_second) {
606 tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
607 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
608 txdr_nfsv3time(&vap->va_atime, tl);
609 } else {
610 tl = nfsm_build(info, NFSX_UNSIGNED);
611 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
613 } else {
614 tl = nfsm_build(info, NFSX_UNSIGNED);
615 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
617 if (vap->va_mtime.tv_sec != VNOVAL) {
618 if (vap->va_mtime.tv_sec != time_second) {
619 tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
620 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
621 txdr_nfsv3time(&vap->va_mtime, tl);
622 } else {
623 tl = nfsm_build(info, NFSX_UNSIGNED);
624 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
626 } else {
627 tl = nfsm_build(info, NFSX_UNSIGNED);
628 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
633 * Caller is expected to abort with EBADRPC if a negative length is returned.
636 nfsm_strsiz(nfsm_info_t info, int maxlen)
638 u_int32_t *tl;
639 int len;
641 tl = nfsm_dissect(info, NFSX_UNSIGNED);
642 if (tl == NULL)
643 return(-1);
644 len = fxdr_unsigned(int32_t, *tl);
645 if (len < 0 || len > maxlen)
646 return(-1);
647 return (len);
651 * Caller is expected to abort if a negative length is returned, but also
652 * call nfsm_reply(0) if -2 is returned.
654 * This function sets *errorp. Caller should not modify the error code.
657 nfsm_srvstrsiz(nfsm_info_t info, int maxlen, int *errorp)
659 u_int32_t *tl;
660 int len;
662 tl = nfsm_dissect(info, NFSX_UNSIGNED);
663 if (tl == NULL) {
664 *errorp = EBADRPC;
665 return(-1);
667 len = fxdr_unsigned(int32_t,*tl);
668 if (len > maxlen || len <= 0) {
669 *errorp = EBADRPC;
670 return(-2);
672 return(len);
676 * Caller is expected to abort if a negative length is returned, but also
677 * call nfsm_reply(0) if -2 is returned.
679 * This function sets *errorp. Caller should not modify the error code.
682 nfsm_srvnamesiz(nfsm_info_t info, int *errorp)
684 u_int32_t *tl;
685 int len;
687 tl = nfsm_dissect(info, NFSX_UNSIGNED);
688 if (tl == NULL) {
689 *errorp = EBADRPC;
690 return(-1);
694 * In this case if *errorp is not EBADRPC and we are NFSv3,
695 * nfsm_reply() will not return a negative number. But all
696 * call cases assume len is valid so we really do want
697 * to return -1.
699 len = fxdr_unsigned(int32_t,*tl);
700 if (len > NFS_MAXNAMLEN)
701 *errorp = NFSERR_NAMETOL;
702 if (len <= 0)
703 *errorp = EBADRPC;
704 if (*errorp)
705 return(-2);
706 return (len);
710 * Caller is expected to abort if a non-zero error is returned.
713 nfsm_mtouio(nfsm_info_t info, struct uio *uiop, int len)
715 int error;
717 if (len > 0 &&
718 (error = nfsm_mbuftouio(&info->md, uiop, len, &info->dpos)) != 0) {
719 m_freem(info->mrep);
720 info->mrep = NULL;
721 return(error);
723 return(0);
727 * Caller is expected to abort if a non-zero error is returned.
730 nfsm_mtobio(nfsm_info_t info, struct bio *bio, int len)
732 int error;
734 if (len > 0 &&
735 (error = nfsm_mbuftobio(&info->md, bio, len, &info->dpos)) != 0) {
736 m_freem(info->mrep);
737 info->mrep = NULL;
738 return(error);
740 return (0);
744 * Caller is expected to abort if a non-zero error is returned.
747 nfsm_uiotom(nfsm_info_t info, struct uio *uiop, int len)
749 int error;
751 error = nfsm_uiotombuf(uiop, &info->mb, len, &info->bpos);
752 if (error) {
753 m_freem(info->mreq);
754 info->mreq = NULL;
755 return (error);
757 return(0);
761 nfsm_biotom(nfsm_info_t info, struct bio *bio, int off, int len)
763 int error;
765 error = nfsm_biotombuf(bio, &info->mb, off, len, &info->bpos);
766 if (error) {
767 m_freem(info->mreq);
768 info->mreq = NULL;
769 return (error);
771 return(0);
775 * Caller is expected to abort if a negative value is returned. This
776 * function sets *errorp. Caller should not modify the error code.
778 * We load up the remaining info fields and run the request state
779 * machine until it is done.
781 * This call runs the entire state machine and does not return until
782 * the command is complete.
785 nfsm_request(nfsm_info_t info, struct vnode *vp, int procnum,
786 thread_t td, struct ucred *cred, int *errorp)
788 info->state = NFSM_STATE_SETUP;
789 info->procnum = procnum;
790 info->vp = vp;
791 info->td = td;
792 info->cred = cred;
793 info->bio = NULL;
794 info->nmp = VFSTONFS(vp->v_mount);
796 *errorp = nfs_request(info, NFSM_STATE_SETUP, NFSM_STATE_DONE);
797 if (*errorp) {
798 if ((*errorp & NFSERR_RETERR) == 0)
799 return(-1);
800 *errorp &= ~NFSERR_RETERR;
802 return(0);
806 * This call starts the state machine through the initial transmission.
807 * Completion is via the bio. The info structure must have installed
808 * a 'done' callback.
810 * If we are unable to do the initial tx we generate the bio completion
811 * ourselves.
813 void
814 nfsm_request_bio(nfsm_info_t info, struct vnode *vp, int procnum,
815 thread_t td, struct ucred *cred)
817 struct buf *bp;
818 int error;
820 info->state = NFSM_STATE_SETUP;
821 info->procnum = procnum;
822 info->vp = vp;
823 info->td = td;
824 info->cred = cred;
825 info->nmp = VFSTONFS(vp->v_mount);
827 error = nfs_request(info, NFSM_STATE_SETUP, NFSM_STATE_WAITREPLY);
828 if (error != EINPROGRESS) {
829 kprintf("nfsm_request_bio: early abort %d\n", error);
830 bp = info->bio->bio_buf;
831 if (error) {
832 bp->b_flags |= B_ERROR;
833 if (error == EIO) /* unrecoverable */
834 bp->b_flags |= B_INVAL;
836 bp->b_error = error;
837 biodone(info->bio);
842 * Caller is expected to abort if a non-zero error is returned.
845 nfsm_strtom(nfsm_info_t info, const void *data, int len, int maxlen)
847 u_int32_t *tl;
848 int error;
849 int n;
851 if (len > maxlen) {
852 m_freem(info->mreq);
853 info->mreq = NULL;
854 return(ENAMETOOLONG);
856 n = nfsm_rndup(len) + NFSX_UNSIGNED;
857 if (n <= M_TRAILINGSPACE(info->mb)) {
858 tl = nfsm_build(info, n);
859 *tl++ = txdr_unsigned(len);
860 *(tl + ((n >> 2) - 2)) = 0;
861 bcopy(data, tl, len);
862 error = 0;
863 } else {
864 error = nfsm_strtmbuf(&info->mb, &info->bpos, data, len);
865 if (error) {
866 m_freem(info->mreq);
867 info->mreq = NULL;
870 return (error);
874 * Caller is expected to abort if a negative value is returned. This
875 * function sets *errorp. Caller should not modify the error code.
878 nfsm_reply(nfsm_info_t info,
879 struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
880 int siz, int *errorp)
882 nfsd->nd_repstat = *errorp;
883 if (*errorp && !(nfsd->nd_flag & ND_NFSV3))
884 siz = 0;
885 nfs_rephead(siz, nfsd, slp, *errorp, &info->mreq,
886 &info->mb, &info->bpos);
887 if (info->mrep != NULL) {
888 m_freem(info->mrep);
889 info->mrep = NULL;
891 if (*errorp && (!(nfsd->nd_flag & ND_NFSV3) || *errorp == EBADRPC)) {
892 *errorp = 0;
893 return(-1);
895 return(0);
898 void
899 nfsm_writereply(nfsm_info_t info,
900 struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
901 int error, int siz)
903 nfsd->nd_repstat = error;
904 if (error && !(info->v3))
905 siz = 0;
906 nfs_rephead(siz, nfsd, slp, error, &info->mreq, &info->mb, &info->bpos);
910 * Caller is expected to abort if a non-zero error is returned.
913 nfsm_adv(nfsm_info_t info, int len)
915 int error;
916 int n;
918 n = mtod(info->md, caddr_t) + info->md->m_len - info->dpos;
919 if (n >= len) {
920 info->dpos += len;
921 error = 0;
922 } else if ((error = nfs_adv(&info->md, &info->dpos, len, n)) != 0) {
923 m_freem(info->mrep);
924 info->mrep = NULL;
926 return (error);
930 * Caller is expected to abort if a negative length is returned, but also
931 * call nfsm_reply(0) if -2 is returned.
933 * This function sets *errorp. Caller should not modify the error code.
936 nfsm_srvmtofh(nfsm_info_t info, struct nfsrv_descript *nfsd,
937 fhandle_t *fhp, int *errorp)
939 u_int32_t *tl;
940 int fhlen;
942 if (nfsd->nd_flag & ND_NFSV3) {
943 tl = nfsm_dissect(info, NFSX_UNSIGNED);
944 if (tl == NULL) {
945 *errorp = EBADRPC;
946 return(-1);
948 fhlen = fxdr_unsigned(int, *tl);
949 if (fhlen != 0 && fhlen != NFSX_V3FH) {
950 *errorp = EBADRPC;
951 return(-2);
953 } else {
954 fhlen = NFSX_V2FH;
956 if (fhlen != 0) {
957 tl = nfsm_dissect(info, fhlen);
958 if (tl == NULL) {
959 *errorp = EBADRPC;
960 return(-1);
962 bcopy(tl, fhp, fhlen);
963 } else {
964 bzero(fhp, NFSX_V3FH);
966 return(0);
969 void *
970 _nfsm_clget(nfsm_info_t info, struct mbuf **mp1, struct mbuf **mp2,
971 char **bp, char **be)
973 if (*bp >= *be) {
974 if (*mp1 == info->mb)
975 (*mp1)->m_len += *bp - info->bpos;
976 *mp1 = m_getcl(M_WAITOK, MT_DATA, 0);
977 (*mp1)->m_len = MCLBYTES;
978 (*mp2)->m_next = *mp1;
979 *mp2 = *mp1;
980 *bp = mtod(*mp1, caddr_t);
981 *be = *bp + (*mp1)->m_len;
983 return(*bp);
987 nfsm_srvsattr(nfsm_info_t info, struct vattr *vap)
989 u_int32_t *tl;
990 int error = 0;
992 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
993 if (*tl == nfs_true) {
994 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
995 vap->va_mode = nfstov_mode(*tl);
997 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
998 if (*tl == nfs_true) {
999 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1000 vap->va_uid = fxdr_unsigned(uid_t, *tl);
1002 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1003 if (*tl == nfs_true) {
1004 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1005 vap->va_gid = fxdr_unsigned(gid_t, *tl);
1007 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1008 if (*tl == nfs_true) {
1009 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
1010 vap->va_size = fxdr_hyper(tl);
1012 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1013 switch (fxdr_unsigned(int, *tl)) {
1014 case NFSV3SATTRTIME_TOCLIENT:
1015 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
1016 fxdr_nfsv3time(tl, &vap->va_atime);
1017 break;
1018 case NFSV3SATTRTIME_TOSERVER:
1019 getnanotime(&vap->va_atime);
1020 break;
1022 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1023 switch (fxdr_unsigned(int, *tl)) {
1024 case NFSV3SATTRTIME_TOCLIENT:
1025 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
1026 fxdr_nfsv3time(tl, &vap->va_mtime);
1027 break;
1028 case NFSV3SATTRTIME_TOSERVER:
1029 getnanotime(&vap->va_mtime);
1030 break;
1032 nfsmout:
1033 return (error);
1037 * copies mbuf chain to the uio scatter/gather list
1040 nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos)
1042 char *mbufcp, *uiocp;
1043 int xfer, left, len;
1044 struct mbuf *mp;
1045 long uiosiz, rem;
1046 int error = 0;
1048 mp = *mrep;
1049 mbufcp = *dpos;
1050 len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
1051 rem = nfsm_rndup(siz)-siz;
1052 while (siz > 0) {
1053 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
1054 return (EFBIG);
1055 left = uiop->uio_iov->iov_len;
1056 uiocp = uiop->uio_iov->iov_base;
1057 if (left > siz)
1058 left = siz;
1059 uiosiz = left;
1060 while (left > 0) {
1061 while (len == 0) {
1062 mp = mp->m_next;
1063 if (mp == NULL)
1064 return (EBADRPC);
1065 mbufcp = mtod(mp, caddr_t);
1066 len = mp->m_len;
1068 xfer = (left > len) ? len : left;
1069 #ifdef notdef
1070 /* Not Yet.. */
1071 if (uiop->uio_iov->iov_op != NULL)
1072 (*(uiop->uio_iov->iov_op))
1073 (mbufcp, uiocp, xfer);
1074 else
1075 #endif
1076 if (uiop->uio_segflg == UIO_SYSSPACE)
1077 bcopy(mbufcp, uiocp, xfer);
1078 else
1079 copyout(mbufcp, uiocp, xfer);
1080 left -= xfer;
1081 len -= xfer;
1082 mbufcp += xfer;
1083 uiocp += xfer;
1084 uiop->uio_offset += xfer;
1085 uiop->uio_resid -= xfer;
1087 if (uiop->uio_iov->iov_len <= siz) {
1088 uiop->uio_iovcnt--;
1089 uiop->uio_iov++;
1090 } else {
1091 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
1092 uiop->uio_iov->iov_len -= uiosiz;
1094 siz -= uiosiz;
1096 *dpos = mbufcp;
1097 *mrep = mp;
1098 if (rem > 0) {
1099 if (len < rem)
1100 error = nfs_adv(mrep, dpos, rem, len);
1101 else
1102 *dpos += rem;
1104 return (error);
1108 * copies mbuf chain to the bio buffer
1111 nfsm_mbuftobio(struct mbuf **mrep, struct bio *bio, int size, caddr_t *dpos)
1113 struct buf *bp = bio->bio_buf;
1114 char *mbufcp;
1115 char *bio_cp;
1116 int xfer, len;
1117 struct mbuf *mp;
1118 long rem;
1119 int error = 0;
1120 int bio_left;
1122 mp = *mrep;
1123 mbufcp = *dpos;
1124 len = mtod(mp, caddr_t) + mp->m_len - mbufcp;
1125 rem = nfsm_rndup(size) - size;
1127 bio_left = bp->b_bcount;
1128 bio_cp = bp->b_data;
1130 while (size > 0) {
1131 while (len == 0) {
1132 mp = mp->m_next;
1133 if (mp == NULL)
1134 return (EBADRPC);
1135 mbufcp = mtod(mp, caddr_t);
1136 len = mp->m_len;
1138 if ((xfer = len) > size)
1139 xfer = size;
1140 if (bio_left) {
1141 if (xfer > bio_left)
1142 xfer = bio_left;
1143 bcopy(mbufcp, bio_cp, xfer);
1144 } else {
1146 * Not enough buffer space in the bio.
1148 return(EFBIG);
1150 size -= xfer;
1151 bio_left -= xfer;
1152 bio_cp += xfer;
1153 len -= xfer;
1154 mbufcp += xfer;
1156 *dpos = mbufcp;
1157 *mrep = mp;
1158 if (rem > 0) {
1159 if (len < rem)
1160 error = nfs_adv(mrep, dpos, rem, len);
1161 else
1162 *dpos += rem;
1164 return (error);
1168 * copies a uio scatter/gather list to an mbuf chain.
1169 * NOTE: can ony handle iovcnt == 1
1172 nfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos)
1174 char *uiocp;
1175 struct mbuf *mp, *mp2;
1176 int xfer, left, mlen;
1177 int uiosiz, rem;
1178 boolean_t getcluster;
1179 char *cp;
1181 #ifdef DIAGNOSTIC
1182 if (uiop->uio_iovcnt != 1)
1183 panic("nfsm_uiotombuf: iovcnt != 1");
1184 #endif
1186 if (siz >= MINCLSIZE)
1187 getcluster = TRUE;
1188 else
1189 getcluster = FALSE;
1190 rem = nfsm_rndup(siz) - siz;
1191 mp = mp2 = *mq;
1192 while (siz > 0) {
1193 left = uiop->uio_iov->iov_len;
1194 uiocp = uiop->uio_iov->iov_base;
1195 if (left > siz)
1196 left = siz;
1197 uiosiz = left;
1198 while (left > 0) {
1199 mlen = M_TRAILINGSPACE(mp);
1200 if (mlen == 0) {
1201 if (getcluster)
1202 mp = m_getcl(M_WAITOK, MT_DATA, 0);
1203 else
1204 mp = m_get(M_WAITOK, MT_DATA);
1205 mp->m_len = 0;
1206 mp2->m_next = mp;
1207 mp2 = mp;
1208 mlen = M_TRAILINGSPACE(mp);
1210 xfer = (left > mlen) ? mlen : left;
1211 #ifdef notdef
1212 /* Not Yet.. */
1213 if (uiop->uio_iov->iov_op != NULL)
1214 (*(uiop->uio_iov->iov_op))
1215 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1216 else
1217 #endif
1218 if (uiop->uio_segflg == UIO_SYSSPACE)
1219 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1220 else
1221 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1222 mp->m_len += xfer;
1223 left -= xfer;
1224 uiocp += xfer;
1225 uiop->uio_offset += xfer;
1226 uiop->uio_resid -= xfer;
1228 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
1229 uiop->uio_iov->iov_len -= uiosiz;
1230 siz -= uiosiz;
1232 if (rem > 0) {
1233 if (rem > M_TRAILINGSPACE(mp)) {
1234 MGET(mp, M_WAITOK, MT_DATA);
1235 mp->m_len = 0;
1236 mp2->m_next = mp;
1238 cp = mtod(mp, caddr_t)+mp->m_len;
1239 for (left = 0; left < rem; left++)
1240 *cp++ = '\0';
1241 mp->m_len += rem;
1242 *bpos = cp;
1243 } else
1244 *bpos = mtod(mp, caddr_t)+mp->m_len;
1245 *mq = mp;
1246 return (0);
1250 nfsm_biotombuf(struct bio *bio, struct mbuf **mq, int off,
1251 int siz, caddr_t *bpos)
1253 struct buf *bp = bio->bio_buf;
1254 struct mbuf *mp, *mp2;
1255 char *bio_cp;
1256 int bio_left;
1257 int xfer, mlen;
1258 int rem;
1259 boolean_t getcluster;
1260 char *cp;
1262 if (siz >= MINCLSIZE)
1263 getcluster = TRUE;
1264 else
1265 getcluster = FALSE;
1266 rem = nfsm_rndup(siz) - siz;
1267 mp = mp2 = *mq;
1269 bio_cp = bp->b_data + off;
1270 bio_left = siz;
1272 while (bio_left) {
1273 mlen = M_TRAILINGSPACE(mp);
1274 if (mlen == 0) {
1275 if (getcluster)
1276 mp = m_getcl(M_WAITOK, MT_DATA, 0);
1277 else
1278 mp = m_get(M_WAITOK, MT_DATA);
1279 mp->m_len = 0;
1280 mp2->m_next = mp;
1281 mp2 = mp;
1282 mlen = M_TRAILINGSPACE(mp);
1284 xfer = (bio_left < mlen) ? bio_left : mlen;
1285 bcopy(bio_cp, mtod(mp, caddr_t) + mp->m_len, xfer);
1286 mp->m_len += xfer;
1287 bio_left -= xfer;
1288 bio_cp += xfer;
1290 if (rem > 0) {
1291 if (rem > M_TRAILINGSPACE(mp)) {
1292 MGET(mp, M_WAITOK, MT_DATA);
1293 mp->m_len = 0;
1294 mp2->m_next = mp;
1296 cp = mtod(mp, caddr_t) + mp->m_len;
1297 for (mlen = 0; mlen < rem; mlen++)
1298 *cp++ = '\0';
1299 mp->m_len += rem;
1300 *bpos = cp;
1301 } else {
1302 *bpos = mtod(mp, caddr_t) + mp->m_len;
1304 *mq = mp;
1305 return(0);
1309 * Help break down an mbuf chain by setting the first siz bytes contiguous
1310 * pointed to by returned val.
1311 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
1312 * cases. (The macros use the vars. dpos and dpos2)
1315 nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, caddr_t *cp2)
1317 struct mbuf *mp, *mp2;
1318 int siz2, xfer;
1319 caddr_t p;
1321 mp = *mdp;
1322 while (left == 0) {
1323 *mdp = mp = mp->m_next;
1324 if (mp == NULL)
1325 return (EBADRPC);
1326 left = mp->m_len;
1327 *dposp = mtod(mp, caddr_t);
1329 if (left >= siz) {
1330 *cp2 = *dposp;
1331 *dposp += siz;
1332 } else if (mp->m_next == NULL) {
1333 return (EBADRPC);
1334 } else if (siz > MHLEN) {
1335 panic("nfs S too big");
1336 } else {
1337 MGET(mp2, M_WAITOK, MT_DATA);
1338 mp2->m_next = mp->m_next;
1339 mp->m_next = mp2;
1340 mp->m_len -= left;
1341 mp = mp2;
1342 *cp2 = p = mtod(mp, caddr_t);
1343 bcopy(*dposp, p, left); /* Copy what was left */
1344 siz2 = siz-left;
1345 p += left;
1346 mp2 = mp->m_next;
1347 /* Loop around copying up the siz2 bytes */
1348 while (siz2 > 0) {
1349 if (mp2 == NULL)
1350 return (EBADRPC);
1351 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
1352 if (xfer > 0) {
1353 bcopy(mtod(mp2, caddr_t), p, xfer);
1354 mp2->m_len -= xfer;
1355 mp2->m_data += xfer;
1356 p += xfer;
1357 siz2 -= xfer;
1359 if (siz2 > 0)
1360 mp2 = mp2->m_next;
1362 mp->m_len = siz;
1363 *mdp = mp2;
1364 *dposp = mtod(mp2, caddr_t);
1366 return (0);
1370 * Advance the position in the mbuf chain.
1373 nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left)
1375 struct mbuf *m;
1376 int s;
1378 m = *mdp;
1379 s = left;
1380 while (s < offs) {
1381 offs -= s;
1382 m = m->m_next;
1383 if (m == NULL)
1384 return (EBADRPC);
1385 s = m->m_len;
1387 *mdp = m;
1388 *dposp = mtod(m, caddr_t)+offs;
1389 return (0);
1393 * Copy a string into mbufs for the hard cases...
1396 nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz)
1398 struct mbuf *m1 = NULL, *m2;
1399 long left, xfer, len, tlen;
1400 u_int32_t *tl;
1401 int putsize;
1403 putsize = 1;
1404 m2 = *mb;
1405 left = M_TRAILINGSPACE(m2);
1406 if (left > 0) {
1407 tl = ((u_int32_t *)(*bpos));
1408 *tl++ = txdr_unsigned(siz);
1409 putsize = 0;
1410 left -= NFSX_UNSIGNED;
1411 m2->m_len += NFSX_UNSIGNED;
1412 if (left > 0) {
1413 bcopy(cp, (caddr_t) tl, left);
1414 siz -= left;
1415 cp += left;
1416 m2->m_len += left;
1417 left = 0;
1420 /* Loop around adding mbufs */
1421 while (siz > 0) {
1422 int msize;
1424 m1 = m_getl(siz, M_WAITOK, MT_DATA, 0, &msize);
1425 m1->m_len = msize;
1426 m2->m_next = m1;
1427 m2 = m1;
1428 tl = mtod(m1, u_int32_t *);
1429 tlen = 0;
1430 if (putsize) {
1431 *tl++ = txdr_unsigned(siz);
1432 m1->m_len -= NFSX_UNSIGNED;
1433 tlen = NFSX_UNSIGNED;
1434 putsize = 0;
1436 if (siz < m1->m_len) {
1437 len = nfsm_rndup(siz);
1438 xfer = siz;
1439 if (xfer < len)
1440 *(tl+(xfer>>2)) = 0;
1441 } else {
1442 xfer = len = m1->m_len;
1444 bcopy(cp, (caddr_t) tl, xfer);
1445 m1->m_len = len+tlen;
1446 siz -= xfer;
1447 cp += xfer;
1449 *mb = m1;
1450 *bpos = mtod(m1, caddr_t)+m1->m_len;
1451 return (0);
1455 * A fiddled version of m_adj() that ensures null fill to a long
1456 * boundary and only trims off the back end
1458 void
1459 nfsm_adj(struct mbuf *mp, int len, int nul)
1461 struct mbuf *m;
1462 int count, i;
1463 char *cp;
1466 * Trim from tail. Scan the mbuf chain,
1467 * calculating its length and finding the last mbuf.
1468 * If the adjustment only affects this mbuf, then just
1469 * adjust and return. Otherwise, rescan and truncate
1470 * after the remaining size.
1472 count = 0;
1473 m = mp;
1474 for (;;) {
1475 count += m->m_len;
1476 if (m->m_next == NULL)
1477 break;
1478 m = m->m_next;
1480 if (m->m_len > len) {
1481 m->m_len -= len;
1482 if (nul > 0) {
1483 cp = mtod(m, caddr_t)+m->m_len-nul;
1484 for (i = 0; i < nul; i++)
1485 *cp++ = '\0';
1487 return;
1489 count -= len;
1490 if (count < 0)
1491 count = 0;
1493 * Correct length for chain is "count".
1494 * Find the mbuf with last data, adjust its length,
1495 * and toss data from remaining mbufs on chain.
1497 for (m = mp; m; m = m->m_next) {
1498 if (m->m_len >= count) {
1499 m->m_len = count;
1500 if (nul > 0) {
1501 cp = mtod(m, caddr_t)+m->m_len-nul;
1502 for (i = 0; i < nul; i++)
1503 *cp++ = '\0';
1505 break;
1507 count -= m->m_len;
1509 for (m = m->m_next;m;m = m->m_next)
1510 m->m_len = 0;
1514 * Make these functions instead of macros, so that the kernel text size
1515 * doesn't get too big...
1517 void
1518 nfsm_srvwcc_data(nfsm_info_t info, struct nfsrv_descript *nfsd,
1519 int before_ret, struct vattr *before_vap,
1520 int after_ret, struct vattr *after_vap)
1522 u_int32_t *tl;
1525 * before_ret is 0 if before_vap is valid, non-zero if it isn't.
1527 if (before_ret) {
1528 tl = nfsm_build(info, NFSX_UNSIGNED);
1529 *tl = nfs_false;
1530 } else {
1531 tl = nfsm_build(info, 7 * NFSX_UNSIGNED);
1532 *tl++ = nfs_true;
1533 txdr_hyper(before_vap->va_size, tl);
1534 tl += 2;
1535 txdr_nfsv3time(&(before_vap->va_mtime), tl);
1536 tl += 2;
1537 txdr_nfsv3time(&(before_vap->va_ctime), tl);
1539 nfsm_srvpostop_attr(info, nfsd, after_ret, after_vap);
1542 void
1543 nfsm_srvpostop_attr(nfsm_info_t info, struct nfsrv_descript *nfsd,
1544 int after_ret, struct vattr *after_vap)
1546 struct nfs_fattr *fp;
1547 u_int32_t *tl;
1549 if (after_ret) {
1550 tl = nfsm_build(info, NFSX_UNSIGNED);
1551 *tl = nfs_false;
1552 } else {
1553 tl = nfsm_build(info, NFSX_UNSIGNED + NFSX_V3FATTR);
1554 *tl++ = nfs_true;
1555 fp = (struct nfs_fattr *)tl;
1556 nfsm_srvfattr(nfsd, after_vap, fp);
1560 void
1561 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
1562 struct nfs_fattr *fp)
1565 * NFS seems to truncate nlink to 16 bits, don't let it overflow.
1567 if (vap->va_nlink > 65535)
1568 fp->fa_nlink = 65535;
1569 else
1570 fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1571 fp->fa_uid = txdr_unsigned(vap->va_uid);
1572 fp->fa_gid = txdr_unsigned(vap->va_gid);
1573 if (nfsd->nd_flag & ND_NFSV3) {
1574 fp->fa_type = vtonfsv3_type(vap->va_type);
1575 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1576 txdr_hyper(vap->va_size, &fp->fa3_size);
1577 txdr_hyper(vap->va_bytes, &fp->fa3_used);
1578 fp->fa3_rdev.specdata1 = txdr_unsigned(vap->va_rmajor);
1579 fp->fa3_rdev.specdata2 = txdr_unsigned(vap->va_rminor);
1580 fp->fa3_fsid.nfsuquad[0] = 0;
1581 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1582 txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
1583 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1584 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1585 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1586 } else {
1587 fp->fa_type = vtonfsv2_type(vap->va_type);
1588 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1589 fp->fa2_size = txdr_unsigned(vap->va_size);
1590 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1591 if (vap->va_type == VFIFO)
1592 fp->fa2_rdev = 0xffffffff;
1593 else
1594 fp->fa2_rdev = txdr_unsigned(makeudev(vap->va_rmajor, vap->va_rminor));
1595 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1596 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1597 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1598 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1599 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1600 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);