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