kernel: Move us to using M_NOWAIT and M_WAITOK for mbuf functions.
[dragonfly.git] / sys / vfs / nfs / nfsm_subs.c
1 /*
2  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
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.
20  *
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.
33  */
34 /*
35  * Copyright (c) 1989, 1993
36  *      The Regents of the University of California.  All rights reserved.
37  *
38  * This code is derived from software contributed to Berkeley by
39  * Rick Macklem at The University of Guelph.
40  *
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.
52  *
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.
64  */
65
66 /*
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.
70  */
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>
88
89 #include <vm/vm.h>
90 #include <vm/vm_object.h>
91 #include <vm/vm_extern.h>
92
93 #include <sys/buf2.h>
94
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"
103
104 #include <netinet/in.h>
105
106 static u_int32_t nfs_xid = 0;
107
108 /*
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)
112  */
113 void
114 nfsm_reqhead(nfsm_info_t info, struct vnode *vp, u_long procid, int hsiz)
115 {
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);
120 }
121
122 /*
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.
127  */
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)
133 {
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;
140
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);
149         }
150         info.mb->m_len = info.mb->m_pkthdr.len = 0;
151         info.mreq = info.mb;
152         info.bpos = mtod(info.mb, caddr_t);
153
154         /*
155          * First the RPC header.
156          */
157         tl = nfsm_build(&info, 8 * NFSX_UNSIGNED);
158
159         /* Get a pretty random xid to start with */
160         if (!nfs_xid)
161                 nfs_xid = krandom();
162
163         do {
164                 xid = atomic_fetchadd_int(&nfs_xid, 1);
165         } while (xid == 0);
166
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]);
179
180         /*
181          * And then the authorization cred.
182          */
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);
206                         }
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;
213                 }
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;
218                 }
219                 break;
220         }
221
222         /*
223          * And the verifier...
224          */
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);
238                         }
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;
245                 }
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;
250                 }
251         } else {
252                 *tl++ = txdr_unsigned(RPCAUTH_NULL);
253                 *tl = 0;
254         }
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);
260 }
261
262 void *
263 nfsm_build(nfsm_info_t info, int bytes)
264 {
265         struct mbuf *mb2;
266         void *ptr;
267
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);
276         }
277         ptr = info->bpos;
278         info->mb->m_len += bytes;
279         info->bpos += bytes;
280         return (ptr);
281 }
282
283 /*
284  *
285  * If NULL returned caller is expected to abort with an EBADRPC error.
286  * Caller will usually use the NULLOUT macro.
287  */
288 void *
289 nfsm_dissect(nfsm_info_t info, int bytes)
290 {
291         caddr_t cp2;
292         void *ptr;
293         int error;
294         int n;
295
296         /*
297          * Check for missing reply packet.  This typically occurs if there
298          * is a soft termination w/too many retries.
299          */
300         if (info->md == NULL) {
301                 if (info->mrep) {
302                         m_freem(info->mrep);
303                         info->mrep = NULL;
304                 }
305                 return NULL;
306         }
307
308         /*
309          * Otherwise any error will be due to the packet format
310          */
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;
323                 }
324         }
325         return (ptr);
326 }
327
328 /*
329  *
330  * Caller is expected to abort if non-zero error is returned.
331  */
332 int
333 nfsm_fhtom(nfsm_info_t info, struct vnode *vp)
334 {
335         u_int32_t *tl;
336         caddr_t cp;
337         int error;
338         int n;
339
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;
354                 }
355         } else {
356                 cp = nfsm_build(info, NFSX_V2FH);
357                 bcopy(VTONFS(vp)->n_fhp, cp, NFSX_V2FH);
358                 error = 0;
359         }
360         return (error);
361 }
362
363 void
364 nfsm_srvfhtom(nfsm_info_t info, fhandle_t *fhp)
365 {
366         u_int32_t *tl;
367
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);
375         }
376 }
377
378 void
379 nfsm_srvpostop_fh(nfsm_info_t info, fhandle_t *fhp)
380 {
381         u_int32_t *tl;
382
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);
387 }
388
389 /*
390  * Caller is expected to abort if non-zero error is returned.
391  *
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).
394  */
395 int
396 nfsm_mtofh(nfsm_info_t info, struct vnode *dvp, struct vnode **vpp, int *gotvpp)
397 {
398         struct nfsnode *ttnp;
399         nfsfh_t *ttfhp;
400         u_int32_t *tl;
401         int ttfhsize;
402         int error = 0;
403
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;
411         }
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);
419                 }
420                 *vpp = NFSTOV(ttnp);
421         }
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);
432                 }
433         }
434         if (*gotvpp)
435                 error = nfsm_loadattr(info, *vpp, NULL);
436 nfsmout:
437         return (error);
438 }
439
440 /*
441  *
442  * Caller is expected to abort with EBADRPC if a negative length is returned.
443  */
444 int
445 nfsm_getfh(nfsm_info_t info, nfsfh_t **fhpp)
446 {
447         u_int32_t *tl;
448         int n;
449
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);
459                 }
460         } else {
461                 n = NFSX_V2FH;
462         }
463         *fhpp = nfsm_dissect(info, nfsm_rndup(n));
464         if (*fhpp == NULL)
465                 return(-1);
466         return(n);
467 }
468
469 /*
470  * Caller is expected to abort if a non-zero error is returned.
471  */
472 int
473 nfsm_loadattr(nfsm_info_t info, struct vnode *vp, struct vattr *vap)
474 {
475         int error;
476
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);
482         }
483         return (0);
484 }
485
486 /*
487  * Caller is expected to abort if a non-zero error is returned.
488  */
489 int
490 nfsm_postop_attr(nfsm_info_t info, struct vnode *vp, int *attrp, int lflags)
491 {
492         u_int32_t *tl;
493         int error;
494
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);
507                 }
508         }
509         return (0);
510 }
511
512 /*
513  * Caller is expected to abort if a non-zero error is returned.
514  */
515 int
516 nfsm_wcc_data(nfsm_info_t info, struct vnode *vp, int *attrp)
517 {
518         u_int32_t *tl;
519         int error;
520         int ttattrf;
521         int ttretf = 0;
522
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;
535                 }
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);
545         }
546         if (*attrp)
547                 *attrp = ttretf;
548         else
549                 *attrp = ttattrf;
550         return(0);
551 }
552
553 /*
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.
559  *
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()).
564  *
565  * If full is true, set all fields, otherwise just set mode and time fields
566  */
567 void
568 nfsm_v3attrbuild(nfsm_info_t info, struct vattr *vap, int full)
569 {
570         u_int32_t *tl;
571
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;
579         }
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;
587         }
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;
595         }
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;
603         }
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);
612                 }
613         } else {
614                 tl = nfsm_build(info, NFSX_UNSIGNED);
615                 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
616         }
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);
625                 }
626         } else {
627                 tl = nfsm_build(info, NFSX_UNSIGNED);
628                 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
629         }
630 }
631
632 /*
633  * Caller is expected to abort with EBADRPC if a negative length is returned.
634  */
635 int
636 nfsm_strsiz(nfsm_info_t info, int maxlen)
637 {
638         u_int32_t *tl;
639         int len;
640
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);
648 }
649
650 /*
651  * Caller is expected to abort if a negative length is returned, but also
652  * call nfsm_reply(0) if -2 is returned.
653  *
654  * This function sets *errorp.  Caller should not modify the error code.
655  */
656 int
657 nfsm_srvstrsiz(nfsm_info_t info, int maxlen, int *errorp)
658 {
659         u_int32_t *tl;
660         int len;
661
662         tl = nfsm_dissect(info, NFSX_UNSIGNED);
663         if (tl == NULL) {
664                 *errorp = EBADRPC;
665                 return(-1);
666         }
667         len = fxdr_unsigned(int32_t,*tl);
668         if (len > maxlen || len <= 0) {
669                 *errorp = EBADRPC;
670                 return(-2);
671         }
672         return(len);
673 }
674
675 /*
676  * Caller is expected to abort if a negative length is returned, but also
677  * call nfsm_reply(0) if -2 is returned.
678  *
679  * This function sets *errorp.  Caller should not modify the error code.
680  */
681 int
682 nfsm_srvnamesiz(nfsm_info_t info, int *errorp)
683 {
684         u_int32_t *tl;
685         int len;
686
687         tl = nfsm_dissect(info, NFSX_UNSIGNED);
688         if (tl == NULL) {
689                 *errorp = EBADRPC;
690                 return(-1);
691         }
692
693         /*
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.
698          */
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);
707 }
708
709 /*
710  * Caller is expected to abort if a non-zero error is returned.
711  */
712 int
713 nfsm_mtouio(nfsm_info_t info, struct uio *uiop, int len)
714 {
715         int error;
716
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);
722         }
723         return(0);
724 }
725
726 /*
727  * Caller is expected to abort if a non-zero error is returned.
728  */
729 int
730 nfsm_mtobio(nfsm_info_t info, struct bio *bio, int len)
731 {
732         int error;
733
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);
739        }
740        return (0);
741 }
742
743 /*
744  * Caller is expected to abort if a non-zero error is returned.
745  */
746 int
747 nfsm_uiotom(nfsm_info_t info, struct uio *uiop, int len)
748 {
749         int error;
750
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);
756         }
757         return(0);
758 }
759
760 int
761 nfsm_biotom(nfsm_info_t info, struct bio *bio, int off, int len)
762 {
763         int error;
764
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);
770         }
771         return(0);
772 }
773
774 /*
775  * Caller is expected to abort if a negative value is returned.  This
776  * function sets *errorp.  Caller should not modify the error code.
777  *
778  * We load up the remaining info fields and run the request state
779  * machine until it is done.
780  *
781  * This call runs the entire state machine and does not return until
782  * the command is complete.
783  */
784 int
785 nfsm_request(nfsm_info_t info, struct vnode *vp, int procnum,
786              thread_t td, struct ucred *cred, int *errorp)
787 {
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);
795
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;
801         }
802         return(0);
803 }
804
805 /*
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.
809  *
810  * If we are unable to do the initial tx we generate the bio completion
811  * ourselves.
812  */
813 void
814 nfsm_request_bio(nfsm_info_t info, struct vnode *vp, int procnum,
815              thread_t td, struct ucred *cred)
816 {
817         struct buf *bp;
818         int error;
819
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);
826
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;
835                 }
836                 bp->b_error = error;
837                 biodone(info->bio);
838         }
839 }
840
841 /*
842  * Caller is expected to abort if a non-zero error is returned.
843  */
844 int
845 nfsm_strtom(nfsm_info_t info, const void *data, int len, int maxlen)
846 {
847         u_int32_t *tl;
848         int error;
849         int n;
850
851         if (len > maxlen) {
852                 m_freem(info->mreq);
853                 info->mreq = NULL;
854                 return(ENAMETOOLONG);
855         }
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;
868                 }
869         }
870         return (error);
871 }
872
873 /*
874  * Caller is expected to abort if a negative value is returned.  This
875  * function sets *errorp.  Caller should not modify the error code.
876  */
877 int
878 nfsm_reply(nfsm_info_t info,
879            struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
880            int siz, int *errorp)
881 {
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;
890         }
891         if (*errorp && (!(nfsd->nd_flag & ND_NFSV3) || *errorp == EBADRPC)) {
892                 *errorp = 0;
893                 return(-1);
894         }
895         return(0);
896 }
897
898 void
899 nfsm_writereply(nfsm_info_t info,
900                 struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
901                 int error, int siz)
902 {
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);
907 }
908
909 /*
910  * Caller is expected to abort if a non-zero error is returned.
911  */
912 int
913 nfsm_adv(nfsm_info_t info, int len)
914 {
915         int error;
916         int n;
917
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;
925         }
926         return (error);
927 }
928
929 /*
930  * Caller is expected to abort if a negative length is returned, but also
931  * call nfsm_reply(0) if -2 is returned.
932  *
933  * This function sets *errorp.  Caller should not modify the error code.
934  */
935 int
936 nfsm_srvmtofh(nfsm_info_t info, struct nfsrv_descript *nfsd,
937               fhandle_t *fhp, int *errorp)
938 {
939         u_int32_t *tl;
940         int fhlen;
941
942         if (nfsd->nd_flag & ND_NFSV3) {
943                 tl = nfsm_dissect(info, NFSX_UNSIGNED);
944                 if (tl == NULL) {
945                         *errorp = EBADRPC;
946                         return(-1);
947                 }
948                 fhlen = fxdr_unsigned(int, *tl);
949                 if (fhlen != 0 && fhlen != NFSX_V3FH) {
950                         *errorp = EBADRPC;
951                         return(-2);
952                 }
953         } else {
954                 fhlen = NFSX_V2FH;
955         }
956         if (fhlen != 0) {
957                 tl = nfsm_dissect(info, fhlen);
958                 if (tl == NULL) {
959                         *errorp = EBADRPC;
960                         return(-1);
961                 }
962                 bcopy(tl, fhp, fhlen);
963         } else {
964                 bzero(fhp, NFSX_V3FH);
965         }
966         return(0);
967 }
968
969 void *
970 _nfsm_clget(nfsm_info_t info, struct mbuf **mp1, struct mbuf **mp2,
971             char **bp, char **be)
972 {
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;
982         }
983         return(*bp);
984 }
985
986 int
987 nfsm_srvsattr(nfsm_info_t info, struct vattr *vap)
988 {
989         u_int32_t *tl;
990         int error = 0;
991
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);
996         }
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);
1001         }
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);
1006         }
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);
1011         }
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;
1021         }
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;
1031         }
1032 nfsmout:
1033         return (error);
1034 }
1035
1036 /*
1037  * copies mbuf chain to the uio scatter/gather list
1038  */
1039 int
1040 nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos)
1041 {
1042         char *mbufcp, *uiocp;
1043         int xfer, left, len;
1044         struct mbuf *mp;
1045         long uiosiz, rem;
1046         int error = 0;
1047
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;
1067                         }
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;
1086                 }
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;
1093                 }
1094                 siz -= uiosiz;
1095         }
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;
1103         }
1104         return (error);
1105 }
1106
1107 /*
1108  * copies mbuf chain to the bio buffer
1109  */
1110 int
1111 nfsm_mbuftobio(struct mbuf **mrep, struct bio *bio, int size, caddr_t *dpos)
1112 {
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;
1121
1122         mp = *mrep;
1123         mbufcp = *dpos;
1124         len = mtod(mp, caddr_t) + mp->m_len - mbufcp;
1125         rem = nfsm_rndup(size) - size;
1126
1127         bio_left = bp->b_bcount;
1128         bio_cp = bp->b_data;
1129
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;
1137                 }
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 {
1145                         /*
1146                          * Not enough buffer space in the bio.
1147                          */
1148                         return(EFBIG);
1149                 }
1150                 size -= xfer;
1151                 bio_left -= xfer;
1152                 bio_cp += xfer;
1153                 len -= xfer;
1154                 mbufcp += xfer;
1155         }
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;
1163         }
1164         return (error);
1165 }
1166
1167 /*
1168  * copies a uio scatter/gather list to an mbuf chain.
1169  * NOTE: can ony handle iovcnt == 1
1170  */
1171 int
1172 nfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos)
1173 {
1174         char *uiocp;
1175         struct mbuf *mp, *mp2;
1176         int xfer, left, mlen;
1177         int uiosiz, rem;
1178         boolean_t getcluster;
1179         char *cp;
1180
1181 #ifdef DIAGNOSTIC
1182         if (uiop->uio_iovcnt != 1)
1183                 panic("nfsm_uiotombuf: iovcnt != 1");
1184 #endif
1185
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);
1209                         }
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;
1227                 }
1228                 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
1229                 uiop->uio_iov->iov_len -= uiosiz;
1230                 siz -= uiosiz;
1231         }
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;
1237                 }
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);
1247 }
1248
1249 int
1250 nfsm_biotombuf(struct bio *bio, struct mbuf **mq, int off,
1251                int siz, caddr_t *bpos)
1252 {
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;
1261
1262         if (siz >= MINCLSIZE)
1263                 getcluster = TRUE;
1264         else
1265                 getcluster = FALSE;
1266         rem = nfsm_rndup(siz) - siz;
1267         mp = mp2 = *mq;
1268
1269         bio_cp = bp->b_data + off;
1270         bio_left = siz;
1271
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);
1283                 }
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;
1289         }
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;
1295                 }
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;
1303         }
1304         *mq = mp;
1305         return(0);
1306 }
1307
1308 /*
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)
1313  */
1314 int
1315 nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, caddr_t *cp2)
1316 {
1317         struct mbuf *mp, *mp2;
1318         int siz2, xfer;
1319         caddr_t p;
1320
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);
1328         }
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;
1358                         }
1359                         if (siz2 > 0)
1360                                 mp2 = mp2->m_next;
1361                 }
1362                 mp->m_len = siz;
1363                 *mdp = mp2;
1364                 *dposp = mtod(mp2, caddr_t);
1365         }
1366         return (0);
1367 }
1368
1369 /*
1370  * Advance the position in the mbuf chain.
1371  */
1372 int
1373 nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left)
1374 {
1375         struct mbuf *m;
1376         int s;
1377
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;
1386         }
1387         *mdp = m;
1388         *dposp = mtod(m, caddr_t)+offs;
1389         return (0);
1390 }
1391
1392 /*
1393  * Copy a string into mbufs for the hard cases...
1394  */
1395 int
1396 nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz)
1397 {
1398         struct mbuf *m1 = NULL, *m2;
1399         long left, xfer, len, tlen;
1400         u_int32_t *tl;
1401         int putsize;
1402
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;
1418                 }
1419         }
1420         /* Loop around adding mbufs */
1421         while (siz > 0) {
1422                 int msize;
1423
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;
1435                 }
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;
1443                 }
1444                 bcopy(cp, (caddr_t) tl, xfer);
1445                 m1->m_len = len+tlen;
1446                 siz -= xfer;
1447                 cp += xfer;
1448         }
1449         *mb = m1;
1450         *bpos = mtod(m1, caddr_t)+m1->m_len;
1451         return (0);
1452 }
1453
1454 /*
1455  * A fiddled version of m_adj() that ensures null fill to a long
1456  * boundary and only trims off the back end
1457  */
1458 void
1459 nfsm_adj(struct mbuf *mp, int len, int nul)
1460 {
1461         struct mbuf *m;
1462         int count, i;
1463         char *cp;
1464
1465         /*
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.
1471          */
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;
1479         }
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';
1486                 }
1487                 return;
1488         }
1489         count -= len;
1490         if (count < 0)
1491                 count = 0;
1492         /*
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.
1496          */
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';
1504                         }
1505                         break;
1506                 }
1507                 count -= m->m_len;
1508         }
1509         for (m = m->m_next;m;m = m->m_next)
1510                 m->m_len = 0;
1511 }
1512
1513 /*
1514  * Make these functions instead of macros, so that the kernel text size
1515  * doesn't get too big...
1516  */
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)
1521 {
1522         u_int32_t *tl;
1523
1524         /*
1525          * before_ret is 0 if before_vap is valid, non-zero if it isn't.
1526          */
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);
1538         }
1539         nfsm_srvpostop_attr(info, nfsd, after_ret, after_vap);
1540 }
1541
1542 void
1543 nfsm_srvpostop_attr(nfsm_info_t info, struct nfsrv_descript *nfsd,
1544                    int after_ret, struct vattr *after_vap)
1545 {
1546         struct nfs_fattr *fp;
1547         u_int32_t *tl;
1548
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);
1557         }
1558 }
1559
1560 void
1561 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
1562               struct nfs_fattr *fp)
1563 {
1564         /*
1565          * NFS seems to truncate nlink to 16 bits, don't let it overflow.
1566          */
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);
1601         }
1602 }