nrelease - fix/improve livecd
[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/mbuf.h>
79 #include <sys/socket.h>
80 #include <sys/stat.h>
81 #include <sys/malloc.h>
82 #include <sys/sysent.h>
83 #include <sys/syscall.h>
84 #include <sys/conf.h>
85 #include <sys/objcache.h>
86
87 #include <vm/vm.h>
88 #include <vm/vm_object.h>
89 #include <vm/vm_extern.h>
90
91 #include <sys/buf2.h>
92
93 #include "rpcv2.h"
94 #include "nfsproto.h"
95 #include "nfs.h"
96 #include "nfsmount.h"
97 #include "nfsnode.h"
98 #include "xdr_subs.h"
99 #include "nfsm_subs.h"
100 #include "nfsrtt.h"
101
102 #include <netinet/in.h>
103
104 static u_int32_t nfs_xid = 0;
105
106 /*
107  * Create the header for an rpc request packet
108  * The hsiz is the size of the rest of the nfs request header.
109  * (just used to decide if a cluster is a good idea)
110  */
111 void
112 nfsm_reqhead(nfsm_info_t info, struct vnode *vp, u_long procid, int hsiz)
113 {
114         info->mb = m_getl(hsiz, M_WAITOK, MT_DATA, 0, NULL);
115         info->mb->m_len = 0;
116         info->mreq = info->mb;
117         info->bpos = mtod(info->mb, caddr_t);
118 }
119
120 /*
121  * Build the RPC header and fill in the authorization info.
122  * The authorization string argument is only used when the credentials
123  * come from outside of the kernel.
124  * Returns the head of the mbuf list.
125  */
126 struct mbuf *
127 nfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type,
128              int auth_len, char *auth_str, int verf_len, char *verf_str,
129              struct mbuf *mrest, int mrest_len, struct mbuf **mbp,
130              u_int32_t *xidp)
131 {
132         struct nfsm_info info;
133         struct mbuf *mb2;
134         u_int32_t *tl;
135         u_int32_t xid;
136         int siz, grpsiz, authsiz, dsiz;
137         int i;
138
139         authsiz = nfsm_rndup(auth_len);
140         dsiz = authsiz + 10 * NFSX_UNSIGNED;
141         info.mb = m_getl(dsiz, M_WAITOK, MT_DATA, M_PKTHDR, NULL);
142         if (dsiz < MINCLSIZE) {
143                 if (dsiz < MHLEN)
144                         MH_ALIGN(info.mb, dsiz);
145                 else
146                         MH_ALIGN(info.mb, 8 * NFSX_UNSIGNED);
147         }
148         info.mb->m_len = info.mb->m_pkthdr.len = 0;
149         info.mreq = info.mb;
150         info.bpos = mtod(info.mb, caddr_t);
151
152         /*
153          * First the RPC header.
154          */
155         tl = nfsm_build(&info, 8 * NFSX_UNSIGNED);
156
157         /* Get a pretty random xid to start with */
158         if (!nfs_xid)
159                 nfs_xid = krandom();
160
161         do {
162                 xid = atomic_fetchadd_int(&nfs_xid, 1);
163         } while (xid == 0);
164
165         *tl++ = *xidp = txdr_unsigned(xid);
166         *tl++ = rpc_call;
167         *tl++ = rpc_vers;
168         *tl++ = txdr_unsigned(NFS_PROG);
169         if (nmflag & NFSMNT_NFSV3)
170                 *tl++ = txdr_unsigned(NFS_VER3);
171         else
172                 *tl++ = txdr_unsigned(NFS_VER2);
173         if (nmflag & NFSMNT_NFSV3)
174                 *tl++ = txdr_unsigned(procid);
175         else
176                 *tl++ = txdr_unsigned(nfsv2_procid[procid]);
177
178         /*
179          * And then the authorization cred.
180          */
181         *tl++ = txdr_unsigned(auth_type);
182         *tl = txdr_unsigned(authsiz);
183         switch (auth_type) {
184         case RPCAUTH_UNIX:
185                 tl = nfsm_build(&info, auth_len);
186                 *tl++ = 0;              /* stamp ?? */
187                 *tl++ = 0;              /* NULL hostname */
188                 *tl++ = txdr_unsigned(cr->cr_uid);
189                 *tl++ = txdr_unsigned(cr->cr_groups[0]);
190                 grpsiz = (auth_len >> 2) - 5;
191                 *tl++ = txdr_unsigned(grpsiz);
192                 for (i = 1; i <= grpsiz; i++)
193                         *tl++ = txdr_unsigned(cr->cr_groups[i]);
194                 break;
195         case RPCAUTH_KERB4:
196                 siz = auth_len;
197                 while (siz > 0) {
198                         if (M_TRAILINGSPACE(info.mb) == 0) {
199                                 mb2 = m_getl(siz, M_WAITOK, MT_DATA, 0, NULL);
200                                 mb2->m_len = 0;
201                                 info.mb->m_next = mb2;
202                                 info.mb = mb2;
203                                 info.bpos = mtod(info.mb, caddr_t);
204                         }
205                         i = min(siz, M_TRAILINGSPACE(info.mb));
206                         bcopy(auth_str, info.bpos, i);
207                         info.mb->m_len += i;
208                         auth_str += i;
209                         info.bpos += i;
210                         siz -= i;
211                 }
212                 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
213                         for (i = 0; i < siz; i++)
214                                 *info.bpos++ = '\0';
215                         info.mb->m_len += siz;
216                 }
217                 break;
218         }
219
220         /*
221          * And the verifier...
222          */
223         tl = nfsm_build(&info, 2 * NFSX_UNSIGNED);
224         if (verf_str) {
225                 *tl++ = txdr_unsigned(RPCAUTH_KERB4);
226                 *tl = txdr_unsigned(verf_len);
227                 siz = verf_len;
228                 while (siz > 0) {
229                         if (M_TRAILINGSPACE(info.mb) == 0) {
230                                 mb2 = m_getl(siz, M_WAITOK, MT_DATA,
231                                                   0, NULL);
232                                 mb2->m_len = 0;
233                                 info.mb->m_next = mb2;
234                                 info.mb = mb2;
235                                 info.bpos = mtod(info.mb, caddr_t);
236                         }
237                         i = min(siz, M_TRAILINGSPACE(info.mb));
238                         bcopy(verf_str, info.bpos, i);
239                         info.mb->m_len += i;
240                         verf_str += i;
241                         info.bpos += i;
242                         siz -= i;
243                 }
244                 if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
245                         for (i = 0; i < siz; i++)
246                                 *info.bpos++ = '\0';
247                         info.mb->m_len += siz;
248                 }
249         } else {
250                 *tl++ = txdr_unsigned(RPCAUTH_NULL);
251                 *tl = 0;
252         }
253         info.mb->m_next = mrest;
254         info.mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
255         info.mreq->m_pkthdr.rcvif = NULL;
256         *mbp = info.mb;
257         return (info.mreq);
258 }
259
260 void *
261 nfsm_build(nfsm_info_t info, int bytes)
262 {
263         struct mbuf *mb2;
264         void *ptr;
265
266         if (bytes > M_TRAILINGSPACE(info->mb)) {
267                 MGET(mb2, M_WAITOK, MT_DATA);
268                 if (bytes > MLEN)
269                         panic("build > MLEN");
270                 info->mb->m_next = mb2;
271                 info->mb = mb2;
272                 info->mb->m_len = 0;
273                 info->bpos = mtod(info->mb, caddr_t);
274         }
275         ptr = info->bpos;
276         info->mb->m_len += bytes;
277         info->bpos += bytes;
278         return (ptr);
279 }
280
281 /*
282  *
283  * If NULL returned caller is expected to abort with an EBADRPC error.
284  * Caller will usually use the NULLOUT macro.
285  */
286 void *
287 nfsm_dissect(nfsm_info_t info, int bytes)
288 {
289         caddr_t cp2;
290         void *ptr;
291         int error;
292         int n;
293
294         /*
295          * Check for missing reply packet.  This typically occurs if there
296          * is a soft termination w/too many retries.
297          */
298         if (info->md == NULL) {
299                 if (info->mrep) {
300                         m_freem(info->mrep);
301                         info->mrep = NULL;
302                 }
303                 return NULL;
304         }
305
306         /*
307          * Otherwise any error will be due to the packet format
308          */
309         n = mtod(info->md, caddr_t) + info->md->m_len - info->dpos;
310         if (bytes <= n) {
311                 ptr = info->dpos;
312                 info->dpos += bytes;
313         } else {
314                 error = nfsm_disct(&info->md, &info->dpos, bytes, n, &cp2);
315                 if (error) {
316                         m_freem(info->mrep);
317                         info->mrep = NULL;
318                         ptr = NULL;
319                 } else {
320                         ptr = cp2;
321                 }
322         }
323         return (ptr);
324 }
325
326 /*
327  *
328  * Caller is expected to abort if non-zero error is returned.
329  */
330 int
331 nfsm_fhtom(nfsm_info_t info, struct vnode *vp)
332 {
333         u_int32_t *tl;
334         caddr_t cp;
335         int error;
336         int n;
337
338         if (info->v3) {
339                 n = nfsm_rndup(VTONFS(vp)->n_fhsize) + NFSX_UNSIGNED;
340                 if (n <= M_TRAILINGSPACE(info->mb)) {
341                         tl = nfsm_build(info, n);
342                         *tl++ = txdr_unsigned(VTONFS(vp)->n_fhsize);
343                         *(tl + ((n >> 2) - 2)) = 0;
344                         bcopy((caddr_t)VTONFS(vp)->n_fhp,(caddr_t)tl,
345                                 VTONFS(vp)->n_fhsize);
346                         error = 0;
347                 } else if ((error = nfsm_strtmbuf(&info->mb, &info->bpos,
348                                                 (caddr_t)VTONFS(vp)->n_fhp,
349                                                 VTONFS(vp)->n_fhsize)) != 0) {
350                         m_freem(info->mreq);
351                         info->mreq = NULL;
352                 }
353         } else {
354                 cp = nfsm_build(info, NFSX_V2FH);
355                 bcopy(VTONFS(vp)->n_fhp, cp, NFSX_V2FH);
356                 error = 0;
357         }
358         return (error);
359 }
360
361 void
362 nfsm_srvfhtom(nfsm_info_t info, fhandle_t *fhp)
363 {
364         u_int32_t *tl;
365
366         if (info->v3) {
367                 tl = nfsm_build(info, NFSX_UNSIGNED + NFSX_V3FH);
368                 *tl++ = txdr_unsigned(NFSX_V3FH);
369                 bcopy(fhp, tl, NFSX_V3FH);
370         } else {
371                 tl = nfsm_build(info, NFSX_V2FH);
372                 bcopy(fhp, tl, NFSX_V2FH);
373         }
374 }
375
376 void
377 nfsm_srvpostop_fh(nfsm_info_t info, fhandle_t *fhp)
378 {
379         u_int32_t *tl;
380
381         tl = nfsm_build(info, 2 * NFSX_UNSIGNED + NFSX_V3FH);
382         *tl++ = nfs_true;
383         *tl++ = txdr_unsigned(NFSX_V3FH);
384         bcopy(fhp, tl, NFSX_V3FH);
385 }
386
387 /*
388  * Caller is expected to abort if non-zero error is returned.
389  *
390  * NOTE: (*vpp) may be loaded with a valid vnode even if (*gotvpp)
391  *       winds up 0.  The caller is responsible for dealing with (*vpp).
392  */
393 int
394 nfsm_mtofh(nfsm_info_t info, struct vnode *dvp, struct vnode **vpp, int *gotvpp)
395 {
396         struct nfsnode *ttnp;
397         nfsfh_t *ttfhp;
398         u_int32_t *tl;
399         int ttfhsize;
400         int error = 0;
401
402         if (info->v3) {
403                 tl = nfsm_dissect(info, NFSX_UNSIGNED);
404                 if (tl == NULL)
405                         return(EBADRPC);
406                 *gotvpp = fxdr_unsigned(int, *tl);
407         } else {
408                 *gotvpp = 1;
409         }
410         if (*gotvpp) {
411                 NEGATIVEOUT(ttfhsize = nfsm_getfh(info, &ttfhp));
412                 error = nfs_nget(dvp->v_mount, ttfhp, ttfhsize, &ttnp, NULL);
413                 if (error) {
414                         m_freem(info->mrep);
415                         info->mrep = NULL;
416                         return (error);
417                 }
418                 *vpp = NFSTOV(ttnp);
419         }
420         if (info->v3) {
421                 tl = nfsm_dissect(info, NFSX_UNSIGNED);
422                 if (tl == NULL)
423                         return (EBADRPC);
424                 if (*gotvpp) {
425                         *gotvpp = fxdr_unsigned(int, *tl);
426                 } else if (fxdr_unsigned(int, *tl)) {
427                         error = nfsm_adv(info, NFSX_V3FATTR);
428                         if (error)
429                                 return (error);
430                 }
431         }
432         if (*gotvpp)
433                 error = nfsm_loadattr(info, *vpp, NULL);
434 nfsmout:
435         return (error);
436 }
437
438 /*
439  *
440  * Caller is expected to abort with EBADRPC if a negative length is returned.
441  */
442 int
443 nfsm_getfh(nfsm_info_t info, nfsfh_t **fhpp)
444 {
445         u_int32_t *tl;
446         int n;
447
448         *fhpp = NULL;
449         if (info->v3) {
450                 tl = nfsm_dissect(info, NFSX_UNSIGNED);
451                 if (tl == NULL)
452                         return(-1);
453                 if ((n = fxdr_unsigned(int, *tl)) <= 0 || n > NFSX_V3FHMAX) {
454                         m_freem(info->mrep);
455                         info->mrep = NULL;
456                         return(-1);
457                 }
458         } else {
459                 n = NFSX_V2FH;
460         }
461         *fhpp = nfsm_dissect(info, nfsm_rndup(n));
462         if (*fhpp == NULL)
463                 return(-1);
464         return(n);
465 }
466
467 /*
468  * Caller is expected to abort if a non-zero error is returned.
469  */
470 int
471 nfsm_loadattr(nfsm_info_t info, struct vnode *vp, struct vattr *vap)
472 {
473         int error;
474
475         error = nfs_loadattrcache(vp, &info->md, &info->dpos, vap, 0);
476         if (error) {
477                 m_freem(info->mrep);
478                 info->mrep = NULL;
479                 return (error);
480         }
481         return (0);
482 }
483
484 /*
485  * Caller is expected to abort if a non-zero error is returned.
486  */
487 int
488 nfsm_postop_attr(nfsm_info_t info, struct vnode *vp, int *attrp, int lflags)
489 {
490         u_int32_t *tl;
491         int error;
492
493         tl = nfsm_dissect(info, NFSX_UNSIGNED);
494         if (tl == NULL)
495                 return(EBADRPC);
496         *attrp = fxdr_unsigned(int, *tl);
497         if (*attrp) {
498                 error = nfs_loadattrcache(vp, &info->md, &info->dpos,
499                                           NULL, lflags);
500                 if (error) {
501                         *attrp = 0;
502                         m_freem(info->mrep);
503                         info->mrep = NULL;
504                         return (error);
505                 }
506         }
507         return (0);
508 }
509
510 /*
511  * Caller is expected to abort if a non-zero error is returned.
512  */
513 int
514 nfsm_wcc_data(nfsm_info_t info, struct vnode *vp, int *attrp)
515 {
516         u_int32_t *tl;
517         int error;
518         int ttattrf;
519         int ttretf = 0;
520
521         tl = nfsm_dissect(info, NFSX_UNSIGNED);
522         if (tl == NULL)
523                 return (EBADRPC);
524         if (*tl == nfs_true) {
525                 tl = nfsm_dissect(info, 6 * NFSX_UNSIGNED);
526                 if (tl == NULL)
527                         return (EBADRPC);
528                 if (*attrp) {
529                         ttretf = (VTONFS(vp)->n_mtime ==
530                                 fxdr_unsigned(u_int32_t, *(tl + 2)));
531                         if (ttretf == 0)
532                                 VTONFS(vp)->n_flag |= NRMODIFIED;
533                 }
534                 error = nfsm_postop_attr(info, vp, &ttattrf,
535                                  NFS_LATTR_NOSHRINK|NFS_LATTR_NOMTIMECHECK);
536                 if (error)
537                         return(error);
538         } else {
539                 error = nfsm_postop_attr(info, vp, &ttattrf,
540                                          NFS_LATTR_NOSHRINK);
541                 if (error)
542                         return(error);
543         }
544         if (*attrp)
545                 *attrp = ttretf;
546         else
547                 *attrp = ttattrf;
548         return(0);
549 }
550
551 /*
552  * This function updates the attribute cache based on data returned in the
553  * NFS reply for NFS RPCs that modify the target file.  If the RPC succeeds
554  * a 'before' and 'after' mtime is returned that allows us to determine if
555  * the new mtime attribute represents our modification or someone else's
556  * modification.
557  *
558  * The flag argument returns non-0 if the original times matched, zero if
559  * they did not match.  NRMODIFIED is automatically set if the before time
560  * does not match the original n_mtime, and n_mtime is automatically updated
561  * to the new after time (by nfsm_postop_attr()).
562  *
563  * If full is true, set all fields, otherwise just set mode and time fields
564  */
565 void
566 nfsm_v3attrbuild(nfsm_info_t info, struct vattr *vap, int full)
567 {
568         u_int32_t *tl;
569
570         if (vap->va_mode != (mode_t)VNOVAL) {
571                 tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
572                 *tl++ = nfs_true;
573                 *tl = txdr_unsigned(vap->va_mode);
574         } else {
575                 tl = nfsm_build(info, NFSX_UNSIGNED);
576                 *tl = nfs_false;
577         }
578         if (full && vap->va_uid != (uid_t)VNOVAL) {
579                 tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
580                 *tl++ = nfs_true;
581                 *tl = txdr_unsigned(vap->va_uid);
582         } else {
583                 tl = nfsm_build(info, NFSX_UNSIGNED);
584                 *tl = nfs_false;
585         }
586         if (full && vap->va_gid != (gid_t)VNOVAL) {
587                 tl = nfsm_build(info, 2 * NFSX_UNSIGNED);
588                 *tl++ = nfs_true;
589                 *tl = txdr_unsigned(vap->va_gid);
590         } else {
591                 tl = nfsm_build(info, NFSX_UNSIGNED);
592                 *tl = nfs_false;
593         }
594         if (full && vap->va_size != VNOVAL) {
595                 tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
596                 *tl++ = nfs_true;
597                 txdr_hyper(vap->va_size, tl);
598         } else {
599                 tl = nfsm_build(info, NFSX_UNSIGNED);
600                 *tl = nfs_false;
601         }
602         if (vap->va_atime.tv_sec != VNOVAL) {
603                 if (vap->va_atime.tv_sec != time_second) {
604                         tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
605                         *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
606                         txdr_nfsv3time(&vap->va_atime, tl);
607                 } else {
608                         tl = nfsm_build(info, NFSX_UNSIGNED);
609                         *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
610                 }
611         } else {
612                 tl = nfsm_build(info, NFSX_UNSIGNED);
613                 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
614         }
615         if (vap->va_mtime.tv_sec != VNOVAL) {
616                 if (vap->va_mtime.tv_sec != time_second) {
617                         tl = nfsm_build(info, 3 * NFSX_UNSIGNED);
618                         *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
619                         txdr_nfsv3time(&vap->va_mtime, tl);
620                 } else {
621                         tl = nfsm_build(info, NFSX_UNSIGNED);
622                         *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
623                 }
624         } else {
625                 tl = nfsm_build(info, NFSX_UNSIGNED);
626                 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
627         }
628 }
629
630 /*
631  * Caller is expected to abort with EBADRPC if a negative length is returned.
632  */
633 int
634 nfsm_strsiz(nfsm_info_t info, int maxlen)
635 {
636         u_int32_t *tl;
637         int len;
638
639         tl = nfsm_dissect(info, NFSX_UNSIGNED);
640         if (tl == NULL)
641                 return(-1);
642         len = fxdr_unsigned(int32_t, *tl);
643         if (len < 0 || len > maxlen)
644                 return(-1);
645         return (len);
646 }
647
648 /*
649  * Caller is expected to abort if a negative length is returned, but also
650  * call nfsm_reply(0) if -2 is returned.
651  *
652  * This function sets *errorp.  Caller should not modify the error code.
653  */
654 int
655 nfsm_srvstrsiz(nfsm_info_t info, int maxlen, int *errorp)
656 {
657         u_int32_t *tl;
658         int len;
659
660         tl = nfsm_dissect(info, NFSX_UNSIGNED);
661         if (tl == NULL) {
662                 *errorp = EBADRPC;
663                 return(-1);
664         }
665         len = fxdr_unsigned(int32_t,*tl);
666         if (len > maxlen || len <= 0) {
667                 *errorp = EBADRPC;
668                 return(-2);
669         }
670         return(len);
671 }
672
673 /*
674  * Caller is expected to abort if a negative length is returned, but also
675  * call nfsm_reply(0) if -2 is returned.
676  *
677  * This function sets *errorp.  Caller should not modify the error code.
678  */
679 int
680 nfsm_srvnamesiz(nfsm_info_t info, int *errorp)
681 {
682         u_int32_t *tl;
683         int len;
684
685         tl = nfsm_dissect(info, NFSX_UNSIGNED);
686         if (tl == NULL) {
687                 *errorp = EBADRPC;
688                 return(-1);
689         }
690
691         /*
692          * In this case if *errorp is not EBADRPC and we are NFSv3,
693          * nfsm_reply() will not return a negative number.  But all
694          * call cases assume len is valid so we really do want
695          * to return -1.
696          */
697         len = fxdr_unsigned(int32_t,*tl);
698         if (len > NFS_MAXNAMLEN)
699                 *errorp = NFSERR_NAMETOL;
700         if (len <= 0)
701                 *errorp = EBADRPC;
702         if (*errorp)
703                 return(-2);
704         return (len);
705 }
706
707 /*
708  * Caller is expected to abort if a non-zero error is returned.
709  */
710 int
711 nfsm_mtouio(nfsm_info_t info, struct uio *uiop, int len)
712 {
713         int error;
714
715         if (len > 0 &&
716            (error = nfsm_mbuftouio(&info->md, uiop, len, &info->dpos)) != 0) {
717                 m_freem(info->mrep);
718                 info->mrep = NULL;
719                 return(error);
720         }
721         return(0);
722 }
723
724 /*
725  * Caller is expected to abort if a non-zero error is returned.
726  */
727 int
728 nfsm_mtobio(nfsm_info_t info, struct bio *bio, int len)
729 {
730         int error;
731
732         if (len > 0 &&
733            (error = nfsm_mbuftobio(&info->md, bio, len, &info->dpos)) != 0) {
734                 m_freem(info->mrep);
735                 info->mrep = NULL;
736                 return(error);
737        }
738        return (0);
739 }
740
741 /*
742  * Caller is expected to abort if a non-zero error is returned.
743  */
744 int
745 nfsm_uiotom(nfsm_info_t info, struct uio *uiop, int len)
746 {
747         int error;
748
749         error = nfsm_uiotombuf(uiop, &info->mb, len, &info->bpos);
750         if (error) {
751                 m_freem(info->mreq);
752                 info->mreq = NULL;
753                 return (error);
754         }
755         return(0);
756 }
757
758 int
759 nfsm_biotom(nfsm_info_t info, struct bio *bio, int off, int len)
760 {
761         int error;
762
763         error = nfsm_biotombuf(bio, &info->mb, off, len, &info->bpos);
764         if (error) {
765                 m_freem(info->mreq);
766                 info->mreq = NULL;
767                 return (error);
768         }
769         return(0);
770 }
771
772 /*
773  * Caller is expected to abort if a negative value is returned.  This
774  * function sets *errorp.  Caller should not modify the error code.
775  *
776  * We load up the remaining info fields and run the request state
777  * machine until it is done.
778  *
779  * This call runs the entire state machine and does not return until
780  * the command is complete.
781  */
782 int
783 nfsm_request(nfsm_info_t info, struct vnode *vp, int procnum,
784              thread_t td, struct ucred *cred, int *errorp)
785 {
786         info->state = NFSM_STATE_SETUP;
787         info->procnum = procnum;
788         info->vp = vp;
789         info->td = td;
790         info->cred = cred;
791         info->bio = NULL;
792         info->nmp = VFSTONFS(vp->v_mount);
793
794         *errorp = nfs_request(info, NFSM_STATE_SETUP, NFSM_STATE_DONE);
795         if (*errorp) {
796                 if ((*errorp & NFSERR_RETERR) == 0)
797                         return(-1);
798                 *errorp &= ~NFSERR_RETERR;
799         }
800         return(0);
801 }
802
803 /*
804  * This call starts the state machine through the initial transmission.
805  * Completion is via the bio.  The info structure must have installed
806  * a 'done' callback.
807  *
808  * If we are unable to do the initial tx we generate the bio completion
809  * ourselves.
810  */
811 void
812 nfsm_request_bio(nfsm_info_t info, struct vnode *vp, int procnum,
813              thread_t td, struct ucred *cred)
814 {
815         struct buf *bp;
816         int error;
817
818         info->state = NFSM_STATE_SETUP;
819         info->procnum = procnum;
820         info->vp = vp;
821         info->td = td;
822         info->cred = cred;
823         info->nmp = VFSTONFS(vp->v_mount);
824
825         error = nfs_request(info, NFSM_STATE_SETUP, NFSM_STATE_WAITREPLY);
826         if (error != EINPROGRESS) {
827                 kprintf("nfsm_request_bio: early abort %d\n", error);
828                 bp = info->bio->bio_buf;
829                 if (error) {
830                         bp->b_flags |= B_ERROR;
831                         if (error == EIO)               /* unrecoverable */
832                                 bp->b_flags |= B_INVAL;
833                 }
834                 bp->b_error = error;
835                 biodone(info->bio);
836         }
837 }
838
839 /*
840  * Caller is expected to abort if a non-zero error is returned.
841  */
842 int
843 nfsm_strtom(nfsm_info_t info, const void *data, int len, int maxlen)
844 {
845         u_int32_t *tl;
846         int error;
847         int n;
848
849         if (len > maxlen) {
850                 m_freem(info->mreq);
851                 info->mreq = NULL;
852                 return(ENAMETOOLONG);
853         }
854         n = nfsm_rndup(len) + NFSX_UNSIGNED;
855         if (n <= M_TRAILINGSPACE(info->mb)) {
856                 tl = nfsm_build(info, n);
857                 *tl++ = txdr_unsigned(len);
858                 *(tl + ((n >> 2) - 2)) = 0;
859                 bcopy(data, tl, len);
860                 error = 0;
861         } else {
862                 error = nfsm_strtmbuf(&info->mb, &info->bpos, data, len);
863                 if (error) {
864                         m_freem(info->mreq);
865                         info->mreq = NULL;
866                 }
867         }
868         return (error);
869 }
870
871 /*
872  * Caller is expected to abort if a negative value is returned.  This
873  * function sets *errorp.  Caller should not modify the error code.
874  */
875 int
876 nfsm_reply(nfsm_info_t info,
877            struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
878            int siz, int *errorp)
879 {
880         nfsd->nd_repstat = *errorp;
881         if (*errorp && !(nfsd->nd_flag & ND_NFSV3))
882                 siz = 0;
883         nfs_rephead(siz, nfsd, slp, *errorp, &info->mreq,
884                     &info->mb, &info->bpos);
885         if (info->mrep != NULL) {
886                 m_freem(info->mrep);
887                 info->mrep = NULL;
888         }
889         if (*errorp && (!(nfsd->nd_flag & ND_NFSV3) || *errorp == EBADRPC)) {
890                 *errorp = 0;
891                 return(-1);
892         }
893         return(0);
894 }
895
896 void
897 nfsm_writereply(nfsm_info_t info,
898                 struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
899                 int error, int siz)
900 {
901         nfsd->nd_repstat = error;
902         if (error && !(info->v3))
903                 siz = 0;
904         nfs_rephead(siz, nfsd, slp, error, &info->mreq, &info->mb, &info->bpos);
905 }
906
907 /*
908  * Caller is expected to abort if a non-zero error is returned.
909  */
910 int
911 nfsm_adv(nfsm_info_t info, int len)
912 {
913         int error;
914         int n;
915
916         n = mtod(info->md, caddr_t) + info->md->m_len - info->dpos;
917         if (n >= len) {
918                 info->dpos += len;
919                 error = 0;
920         } else if ((error = nfs_adv(&info->md, &info->dpos, len, n)) != 0) {
921                 m_freem(info->mrep);
922                 info->mrep = NULL;
923         }
924         return (error);
925 }
926
927 /*
928  * Caller is expected to abort if a negative length is returned, but also
929  * call nfsm_reply(0) if -2 is returned.
930  *
931  * This function sets *errorp.  Caller should not modify the error code.
932  */
933 int
934 nfsm_srvmtofh(nfsm_info_t info, struct nfsrv_descript *nfsd,
935               fhandle_t *fhp, int *errorp)
936 {
937         u_int32_t *tl;
938         int fhlen;
939
940         if (nfsd->nd_flag & ND_NFSV3) {
941                 tl = nfsm_dissect(info, NFSX_UNSIGNED);
942                 if (tl == NULL) {
943                         *errorp = EBADRPC;
944                         return(-1);
945                 }
946                 fhlen = fxdr_unsigned(int, *tl);
947                 if (fhlen != 0 && fhlen != NFSX_V3FH) {
948                         *errorp = EBADRPC;
949                         return(-2);
950                 }
951         } else {
952                 fhlen = NFSX_V2FH;
953         }
954         if (fhlen != 0) {
955                 tl = nfsm_dissect(info, fhlen);
956                 if (tl == NULL) {
957                         *errorp = EBADRPC;
958                         return(-1);
959                 }
960                 bcopy(tl, fhp, fhlen);
961         } else {
962                 bzero(fhp, NFSX_V3FH);
963         }
964         return(0);
965 }
966
967 void *
968 _nfsm_clget(nfsm_info_t info, struct mbuf **mp1, struct mbuf **mp2,
969             char **bp, char **be)
970 {
971         if (*bp >= *be) {
972                 if (*mp1 == info->mb)
973                         (*mp1)->m_len += *bp - info->bpos;
974                 *mp1 = m_getcl(M_WAITOK, MT_DATA, 0);
975                 (*mp1)->m_len = MCLBYTES;
976                 (*mp2)->m_next = *mp1;
977                 *mp2 = *mp1;
978                 *bp = mtod(*mp1, caddr_t);
979                 *be = *bp + (*mp1)->m_len;
980         }
981         return(*bp);
982 }
983
984 int
985 nfsm_srvsattr(nfsm_info_t info, struct vattr *vap)
986 {
987         u_int32_t *tl;
988         int error = 0;
989
990         NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
991         if (*tl == nfs_true) {
992                 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
993                 vap->va_mode = nfstov_mode(*tl);
994         }
995         NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
996         if (*tl == nfs_true) {
997                 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
998                 vap->va_uid = fxdr_unsigned(uid_t, *tl);
999         }
1000         NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1001         if (*tl == nfs_true) {
1002                 NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1003                 vap->va_gid = fxdr_unsigned(gid_t, *tl);
1004         }
1005         NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1006         if (*tl == nfs_true) {
1007                 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
1008                 vap->va_size = fxdr_hyper(tl);
1009         }
1010         NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1011         switch (fxdr_unsigned(int, *tl)) {
1012         case NFSV3SATTRTIME_TOCLIENT:
1013                 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
1014                 fxdr_nfsv3time(tl, &vap->va_atime);
1015                 break;
1016         case NFSV3SATTRTIME_TOSERVER:
1017                 getnanotime(&vap->va_atime);
1018                 break;
1019         }
1020         NULLOUT(tl = nfsm_dissect(info, NFSX_UNSIGNED));
1021         switch (fxdr_unsigned(int, *tl)) {
1022         case NFSV3SATTRTIME_TOCLIENT:
1023                 NULLOUT(tl = nfsm_dissect(info, 2 * NFSX_UNSIGNED));
1024                 fxdr_nfsv3time(tl, &vap->va_mtime);
1025                 break;
1026         case NFSV3SATTRTIME_TOSERVER:
1027                 getnanotime(&vap->va_mtime);
1028                 break;
1029         }
1030 nfsmout:
1031         return (error);
1032 }
1033
1034 /*
1035  * copies mbuf chain to the uio scatter/gather list
1036  */
1037 int
1038 nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos)
1039 {
1040         char *mbufcp, *uiocp;
1041         int xfer, left, len;
1042         struct mbuf *mp;
1043         long uiosiz, rem;
1044         int error = 0;
1045
1046         mp = *mrep;
1047         mbufcp = *dpos;
1048         len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
1049         rem = nfsm_rndup(siz)-siz;
1050         while (siz > 0) {
1051                 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
1052                         return (EFBIG);
1053                 left = uiop->uio_iov->iov_len;
1054                 uiocp = uiop->uio_iov->iov_base;
1055                 if (left > siz)
1056                         left = siz;
1057                 uiosiz = left;
1058                 while (left > 0) {
1059                         while (len == 0) {
1060                                 mp = mp->m_next;
1061                                 if (mp == NULL)
1062                                         return (EBADRPC);
1063                                 mbufcp = mtod(mp, caddr_t);
1064                                 len = mp->m_len;
1065                         }
1066                         xfer = (left > len) ? len : left;
1067 #ifdef notdef
1068                         /* Not Yet.. */
1069                         if (uiop->uio_iov->iov_op != NULL)
1070                                 (*(uiop->uio_iov->iov_op))
1071                                 (mbufcp, uiocp, xfer);
1072                         else
1073 #endif
1074                         if (uiop->uio_segflg == UIO_SYSSPACE)
1075                                 bcopy(mbufcp, uiocp, xfer);
1076                         else
1077                                 copyout(mbufcp, uiocp, xfer);
1078                         left -= xfer;
1079                         len -= xfer;
1080                         mbufcp += xfer;
1081                         uiocp += xfer;
1082                         uiop->uio_offset += xfer;
1083                         uiop->uio_resid -= xfer;
1084                 }
1085                 if (uiop->uio_iov->iov_len <= siz) {
1086                         uiop->uio_iovcnt--;
1087                         uiop->uio_iov++;
1088                 } else {
1089                         uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
1090                         uiop->uio_iov->iov_len -= uiosiz;
1091                 }
1092                 siz -= uiosiz;
1093         }
1094         *dpos = mbufcp;
1095         *mrep = mp;
1096         if (rem > 0) {
1097                 if (len < rem)
1098                         error = nfs_adv(mrep, dpos, rem, len);
1099                 else
1100                         *dpos += rem;
1101         }
1102         return (error);
1103 }
1104
1105 /*
1106  * copies mbuf chain to the bio buffer
1107  */
1108 int
1109 nfsm_mbuftobio(struct mbuf **mrep, struct bio *bio, int size, caddr_t *dpos)
1110 {
1111         struct buf *bp = bio->bio_buf;
1112         char *mbufcp;
1113         char *bio_cp;
1114         int xfer, len;
1115         struct mbuf *mp;
1116         long rem;
1117         int error = 0;
1118         int bio_left;
1119
1120         mp = *mrep;
1121         mbufcp = *dpos;
1122         len = mtod(mp, caddr_t) + mp->m_len - mbufcp;
1123         rem = nfsm_rndup(size) - size;
1124
1125         bio_left = bp->b_bcount;
1126         bio_cp = bp->b_data;
1127
1128         while (size > 0) {
1129                 while (len == 0) {
1130                         mp = mp->m_next;
1131                         if (mp == NULL)
1132                                 return (EBADRPC);
1133                         mbufcp = mtod(mp, caddr_t);
1134                         len = mp->m_len;
1135                 }
1136                 if ((xfer = len) > size)
1137                         xfer = size;
1138                 if (bio_left) {
1139                         if (xfer > bio_left)
1140                                 xfer = bio_left;
1141                         bcopy(mbufcp, bio_cp, xfer);
1142                 } else {
1143                         /*
1144                          * Not enough buffer space in the bio.
1145                          */
1146                         return(EFBIG);
1147                 }
1148                 size -= xfer;
1149                 bio_left -= xfer;
1150                 bio_cp += xfer;
1151                 len -= xfer;
1152                 mbufcp += xfer;
1153         }
1154         *dpos = mbufcp;
1155         *mrep = mp;
1156         if (rem > 0) {
1157                 if (len < rem)
1158                         error = nfs_adv(mrep, dpos, rem, len);
1159                 else
1160                         *dpos += rem;
1161         }
1162         return (error);
1163 }
1164
1165 /*
1166  * copies a uio scatter/gather list to an mbuf chain.
1167  * NOTE: can ony handle iovcnt == 1
1168  */
1169 int
1170 nfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos)
1171 {
1172         char *uiocp;
1173         struct mbuf *mp, *mp2;
1174         int xfer, left, mlen;
1175         int uiosiz, rem;
1176         boolean_t getcluster;
1177         char *cp;
1178
1179 #ifdef DIAGNOSTIC
1180         if (uiop->uio_iovcnt != 1)
1181                 panic("nfsm_uiotombuf: iovcnt != 1");
1182 #endif
1183
1184         if (siz >= MINCLSIZE)
1185                 getcluster = TRUE;
1186         else
1187                 getcluster = FALSE;
1188         rem = nfsm_rndup(siz) - siz;
1189         mp = mp2 = *mq;
1190         while (siz > 0) {
1191                 left = uiop->uio_iov->iov_len;
1192                 uiocp = uiop->uio_iov->iov_base;
1193                 if (left > siz)
1194                         left = siz;
1195                 uiosiz = left;
1196                 while (left > 0) {
1197                         mlen = M_TRAILINGSPACE(mp);
1198                         if (mlen == 0) {
1199                                 if (getcluster)
1200                                         mp = m_getcl(M_WAITOK, MT_DATA, 0);
1201                                 else
1202                                         mp = m_get(M_WAITOK, MT_DATA);
1203                                 mp->m_len = 0;
1204                                 mp2->m_next = mp;
1205                                 mp2 = mp;
1206                                 mlen = M_TRAILINGSPACE(mp);
1207                         }
1208                         xfer = (left > mlen) ? mlen : left;
1209 #ifdef notdef
1210                         /* Not Yet.. */
1211                         if (uiop->uio_iov->iov_op != NULL)
1212                                 (*(uiop->uio_iov->iov_op))
1213                                 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1214                         else
1215 #endif
1216                         if (uiop->uio_segflg == UIO_SYSSPACE)
1217                                 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1218                         else
1219                                 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
1220                         mp->m_len += xfer;
1221                         left -= xfer;
1222                         uiocp += xfer;
1223                         uiop->uio_offset += xfer;
1224                         uiop->uio_resid -= xfer;
1225                 }
1226                 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
1227                 uiop->uio_iov->iov_len -= uiosiz;
1228                 siz -= uiosiz;
1229         }
1230         if (rem > 0) {
1231                 if (rem > M_TRAILINGSPACE(mp)) {
1232                         MGET(mp, M_WAITOK, MT_DATA);
1233                         mp->m_len = 0;
1234                         mp2->m_next = mp;
1235                 }
1236                 cp = mtod(mp, caddr_t)+mp->m_len;
1237                 for (left = 0; left < rem; left++)
1238                         *cp++ = '\0';
1239                 mp->m_len += rem;
1240                 *bpos = cp;
1241         } else
1242                 *bpos = mtod(mp, caddr_t)+mp->m_len;
1243         *mq = mp;
1244         return (0);
1245 }
1246
1247 int
1248 nfsm_biotombuf(struct bio *bio, struct mbuf **mq, int off,
1249                int siz, caddr_t *bpos)
1250 {
1251         struct buf *bp = bio->bio_buf;
1252         struct mbuf *mp, *mp2;
1253         char *bio_cp;
1254         int bio_left;
1255         int xfer, mlen;
1256         int rem;
1257         boolean_t getcluster;
1258         char *cp;
1259
1260         if (siz >= MINCLSIZE)
1261                 getcluster = TRUE;
1262         else
1263                 getcluster = FALSE;
1264         rem = nfsm_rndup(siz) - siz;
1265         mp = mp2 = *mq;
1266
1267         bio_cp = bp->b_data + off;
1268         bio_left = siz;
1269
1270         while (bio_left) {
1271                 mlen = M_TRAILINGSPACE(mp);
1272                 if (mlen == 0) {
1273                         if (getcluster)
1274                                 mp = m_getcl(M_WAITOK, MT_DATA, 0);
1275                         else
1276                                 mp = m_get(M_WAITOK, MT_DATA);
1277                         mp->m_len = 0;
1278                         mp2->m_next = mp;
1279                         mp2 = mp;
1280                         mlen = M_TRAILINGSPACE(mp);
1281                 }
1282                 xfer = (bio_left < mlen) ? bio_left : mlen;
1283                 bcopy(bio_cp, mtod(mp, caddr_t) + mp->m_len, xfer);
1284                 mp->m_len += xfer;
1285                 bio_left -= xfer;
1286                 bio_cp += xfer;
1287         }
1288         if (rem > 0) {
1289                 if (rem > M_TRAILINGSPACE(mp)) {
1290                         MGET(mp, M_WAITOK, MT_DATA);
1291                         mp->m_len = 0;
1292                         mp2->m_next = mp;
1293                 }
1294                 cp = mtod(mp, caddr_t) + mp->m_len;
1295                 for (mlen = 0; mlen < rem; mlen++)
1296                         *cp++ = '\0';
1297                 mp->m_len += rem;
1298                 *bpos = cp;
1299         } else {
1300                 *bpos = mtod(mp, caddr_t) + mp->m_len;
1301         }
1302         *mq = mp;
1303         return(0);
1304 }
1305
1306 /*
1307  * Help break down an mbuf chain by setting the first siz bytes contiguous
1308  * pointed to by returned val.
1309  * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
1310  * cases. (The macros use the vars. dpos and dpos2)
1311  */
1312 int
1313 nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, caddr_t *cp2)
1314 {
1315         struct mbuf *mp, *mp2;
1316         int siz2, xfer;
1317         caddr_t p;
1318
1319         mp = *mdp;
1320         while (left == 0) {
1321                 *mdp = mp = mp->m_next;
1322                 if (mp == NULL)
1323                         return (EBADRPC);
1324                 left = mp->m_len;
1325                 *dposp = mtod(mp, caddr_t);
1326         }
1327         if (left >= siz) {
1328                 *cp2 = *dposp;
1329                 *dposp += siz;
1330         } else if (mp->m_next == NULL) {
1331                 return (EBADRPC);
1332         } else if (siz > MHLEN) {
1333                 panic("nfs S too big");
1334         } else {
1335                 MGET(mp2, M_WAITOK, MT_DATA);
1336                 mp2->m_next = mp->m_next;
1337                 mp->m_next = mp2;
1338                 mp->m_len -= left;
1339                 mp = mp2;
1340                 *cp2 = p = mtod(mp, caddr_t);
1341                 bcopy(*dposp, p, left);         /* Copy what was left */
1342                 siz2 = siz-left;
1343                 p += left;
1344                 mp2 = mp->m_next;
1345                 /* Loop around copying up the siz2 bytes */
1346                 while (siz2 > 0) {
1347                         if (mp2 == NULL)
1348                                 return (EBADRPC);
1349                         xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
1350                         if (xfer > 0) {
1351                                 bcopy(mtod(mp2, caddr_t), p, xfer);
1352                                 mp2->m_len -= xfer;
1353                                 mp2->m_data += xfer;
1354                                 p += xfer;
1355                                 siz2 -= xfer;
1356                         }
1357                         if (siz2 > 0)
1358                                 mp2 = mp2->m_next;
1359                 }
1360                 mp->m_len = siz;
1361                 *mdp = mp2;
1362                 *dposp = mtod(mp2, caddr_t);
1363         }
1364         return (0);
1365 }
1366
1367 /*
1368  * Advance the position in the mbuf chain.
1369  */
1370 int
1371 nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left)
1372 {
1373         struct mbuf *m;
1374         int s;
1375
1376         m = *mdp;
1377         s = left;
1378         while (s < offs) {
1379                 offs -= s;
1380                 m = m->m_next;
1381                 if (m == NULL)
1382                         return (EBADRPC);
1383                 s = m->m_len;
1384         }
1385         *mdp = m;
1386         *dposp = mtod(m, caddr_t)+offs;
1387         return (0);
1388 }
1389
1390 /*
1391  * Copy a string into mbufs for the hard cases...
1392  */
1393 int
1394 nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz)
1395 {
1396         struct mbuf *m1 = NULL, *m2;
1397         long left, xfer, len, tlen;
1398         u_int32_t *tl;
1399         int putsize;
1400
1401         putsize = 1;
1402         m2 = *mb;
1403         left = M_TRAILINGSPACE(m2);
1404         if (left > 0) {
1405                 tl = ((u_int32_t *)(*bpos));
1406                 *tl++ = txdr_unsigned(siz);
1407                 putsize = 0;
1408                 left -= NFSX_UNSIGNED;
1409                 m2->m_len += NFSX_UNSIGNED;
1410                 if (left > 0) {
1411                         bcopy(cp, (caddr_t) tl, left);
1412                         siz -= left;
1413                         cp += left;
1414                         m2->m_len += left;
1415                         left = 0;
1416                 }
1417         }
1418         /* Loop around adding mbufs */
1419         while (siz > 0) {
1420                 int msize;
1421
1422                 m1 = m_getl(siz, M_WAITOK, MT_DATA, 0, &msize);
1423                 m1->m_len = msize;
1424                 m2->m_next = m1;
1425                 m2 = m1;
1426                 tl = mtod(m1, u_int32_t *);
1427                 tlen = 0;
1428                 if (putsize) {
1429                         *tl++ = txdr_unsigned(siz);
1430                         m1->m_len -= NFSX_UNSIGNED;
1431                         tlen = NFSX_UNSIGNED;
1432                         putsize = 0;
1433                 }
1434                 if (siz < m1->m_len) {
1435                         len = nfsm_rndup(siz);
1436                         xfer = siz;
1437                         if (xfer < len)
1438                                 *(tl+(xfer>>2)) = 0;
1439                 } else {
1440                         xfer = len = m1->m_len;
1441                 }
1442                 bcopy(cp, (caddr_t) tl, xfer);
1443                 m1->m_len = len+tlen;
1444                 siz -= xfer;
1445                 cp += xfer;
1446         }
1447         *mb = m1;
1448         *bpos = mtod(m1, caddr_t)+m1->m_len;
1449         return (0);
1450 }
1451
1452 /*
1453  * A fiddled version of m_adj() that ensures null fill to a long
1454  * boundary and only trims off the back end
1455  */
1456 void
1457 nfsm_adj(struct mbuf *mp, int len, int nul)
1458 {
1459         struct mbuf *m;
1460         int count, i;
1461         char *cp;
1462
1463         /*
1464          * Trim from tail.  Scan the mbuf chain,
1465          * calculating its length and finding the last mbuf.
1466          * If the adjustment only affects this mbuf, then just
1467          * adjust and return.  Otherwise, rescan and truncate
1468          * after the remaining size.
1469          */
1470         count = 0;
1471         m = mp;
1472         for (;;) {
1473                 count += m->m_len;
1474                 if (m->m_next == NULL)
1475                         break;
1476                 m = m->m_next;
1477         }
1478         if (m->m_len > len) {
1479                 m->m_len -= len;
1480                 if (nul > 0) {
1481                         cp = mtod(m, caddr_t)+m->m_len-nul;
1482                         for (i = 0; i < nul; i++)
1483                                 *cp++ = '\0';
1484                 }
1485                 return;
1486         }
1487         count -= len;
1488         if (count < 0)
1489                 count = 0;
1490         /*
1491          * Correct length for chain is "count".
1492          * Find the mbuf with last data, adjust its length,
1493          * and toss data from remaining mbufs on chain.
1494          */
1495         for (m = mp; m; m = m->m_next) {
1496                 if (m->m_len >= count) {
1497                         m->m_len = count;
1498                         if (nul > 0) {
1499                                 cp = mtod(m, caddr_t)+m->m_len-nul;
1500                                 for (i = 0; i < nul; i++)
1501                                         *cp++ = '\0';
1502                         }
1503                         break;
1504                 }
1505                 count -= m->m_len;
1506         }
1507         for (m = m->m_next;m;m = m->m_next)
1508                 m->m_len = 0;
1509 }
1510
1511 /*
1512  * Make these functions instead of macros, so that the kernel text size
1513  * doesn't get too big...
1514  */
1515 void
1516 nfsm_srvwcc_data(nfsm_info_t info, struct nfsrv_descript *nfsd,
1517                  int before_ret, struct vattr *before_vap,
1518                  int after_ret, struct vattr *after_vap)
1519 {
1520         u_int32_t *tl;
1521
1522         /*
1523          * before_ret is 0 if before_vap is valid, non-zero if it isn't.
1524          */
1525         if (before_ret) {
1526                 tl = nfsm_build(info, NFSX_UNSIGNED);
1527                 *tl = nfs_false;
1528         } else {
1529                 tl = nfsm_build(info, 7 * NFSX_UNSIGNED);
1530                 *tl++ = nfs_true;
1531                 txdr_hyper(before_vap->va_size, tl);
1532                 tl += 2;
1533                 txdr_nfsv3time(&(before_vap->va_mtime), tl);
1534                 tl += 2;
1535                 txdr_nfsv3time(&(before_vap->va_ctime), tl);
1536         }
1537         nfsm_srvpostop_attr(info, nfsd, after_ret, after_vap);
1538 }
1539
1540 void
1541 nfsm_srvpostop_attr(nfsm_info_t info, struct nfsrv_descript *nfsd,
1542                    int after_ret, struct vattr *after_vap)
1543 {
1544         struct nfs_fattr *fp;
1545         u_int32_t *tl;
1546
1547         if (after_ret) {
1548                 tl = nfsm_build(info, NFSX_UNSIGNED);
1549                 *tl = nfs_false;
1550         } else {
1551                 tl = nfsm_build(info, NFSX_UNSIGNED + NFSX_V3FATTR);
1552                 *tl++ = nfs_true;
1553                 fp = (struct nfs_fattr *)tl;
1554                 nfsm_srvfattr(nfsd, after_vap, fp);
1555         }
1556 }
1557
1558 void
1559 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
1560               struct nfs_fattr *fp)
1561 {
1562         /*
1563          * NFS seems to truncate nlink to 16 bits, don't let it overflow.
1564          */
1565         if (vap->va_nlink > 65535)
1566                 fp->fa_nlink = 65535;
1567         else
1568                 fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1569         fp->fa_uid = txdr_unsigned(vap->va_uid);
1570         fp->fa_gid = txdr_unsigned(vap->va_gid);
1571         if (nfsd->nd_flag & ND_NFSV3) {
1572                 fp->fa_type = vtonfsv3_type(vap->va_type);
1573                 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1574                 txdr_hyper(vap->va_size, &fp->fa3_size);
1575                 txdr_hyper(vap->va_bytes, &fp->fa3_used);
1576                 fp->fa3_rdev.specdata1 = txdr_unsigned(vap->va_rmajor);
1577                 fp->fa3_rdev.specdata2 = txdr_unsigned(vap->va_rminor);
1578                 fp->fa3_fsid.nfsuquad[0] = 0;
1579                 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1580                 txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
1581                 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1582                 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1583                 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1584         } else {
1585                 fp->fa_type = vtonfsv2_type(vap->va_type);
1586                 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1587                 fp->fa2_size = txdr_unsigned(vap->va_size);
1588                 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1589                 if (vap->va_type == VFIFO)
1590                         fp->fa2_rdev = 0xffffffff;
1591                 else
1592                         fp->fa2_rdev = txdr_unsigned(makeudev(vap->va_rmajor, vap->va_rminor));
1593                 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1594                 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1595                 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1596                 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1597                 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1598                 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1599         }
1600 }