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