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