7e803c3f2bcc3f37c4173ad288b732f13ae30c44
[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 struct mbuf *
119 nfsm_reqh(struct vnode *vp, u_long procid, int hsiz, caddr_t *bposp)
120 {
121         struct mbuf *mb;
122         caddr_t bpos;
123
124         mb = m_getl(hsiz, MB_WAIT, MT_DATA, 0, NULL);
125         mb->m_len = 0;
126         bpos = mtod(mb, caddr_t);
127
128         /* Finally, return values */
129         *bposp = bpos;
130         return (mb);
131 }
132
133 /*
134  * Build the RPC header and fill in the authorization info.
135  * The authorization string argument is only used when the credentials
136  * come from outside of the kernel.
137  * Returns the head of the mbuf list.
138  */
139 struct mbuf *
140 nfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type,
141              int auth_len, char *auth_str, int verf_len, char *verf_str,
142              struct mbuf *mrest, int mrest_len, struct mbuf **mbp,
143              u_int32_t *xidp)
144 {
145         struct mbuf *mb;
146         u_int32_t *tl;
147         caddr_t bpos;
148         int i;
149         struct mbuf *mreq, *mb2;
150         int siz, grpsiz, authsiz, dsiz;
151
152         authsiz = nfsm_rndup(auth_len);
153         dsiz = authsiz + 10 * NFSX_UNSIGNED;
154         mb = m_getl(dsiz, MB_WAIT, MT_DATA, M_PKTHDR, NULL);
155         if (dsiz < MINCLSIZE) {
156                 if (dsiz < MHLEN)
157                         MH_ALIGN(mb, dsiz);
158                 else
159                         MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
160         }
161         mb->m_len = mb->m_pkthdr.len = 0;
162         mreq = mb;
163         bpos = mtod(mb, caddr_t);
164
165         /*
166          * First the RPC header.
167          */
168         nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
169
170         /* Get a pretty random xid to start with */
171         if (!nfs_xid)
172                 nfs_xid = krandom();
173         /*
174          * Skip zero xid if it should ever happen.
175          */
176         if (++nfs_xid == 0)
177                 nfs_xid++;
178
179         *tl++ = *xidp = txdr_unsigned(nfs_xid);
180         *tl++ = rpc_call;
181         *tl++ = rpc_vers;
182         *tl++ = txdr_unsigned(NFS_PROG);
183         if (nmflag & NFSMNT_NFSV3)
184                 *tl++ = txdr_unsigned(NFS_VER3);
185         else
186                 *tl++ = txdr_unsigned(NFS_VER2);
187         if (nmflag & NFSMNT_NFSV3)
188                 *tl++ = txdr_unsigned(procid);
189         else
190                 *tl++ = txdr_unsigned(nfsv2_procid[procid]);
191
192         /*
193          * And then the authorization cred.
194          */
195         *tl++ = txdr_unsigned(auth_type);
196         *tl = txdr_unsigned(authsiz);
197         switch (auth_type) {
198         case RPCAUTH_UNIX:
199                 nfsm_build(tl, u_int32_t *, auth_len);
200                 *tl++ = 0;              /* stamp ?? */
201                 *tl++ = 0;              /* NULL hostname */
202                 *tl++ = txdr_unsigned(cr->cr_uid);
203                 *tl++ = txdr_unsigned(cr->cr_groups[0]);
204                 grpsiz = (auth_len >> 2) - 5;
205                 *tl++ = txdr_unsigned(grpsiz);
206                 for (i = 1; i <= grpsiz; i++)
207                         *tl++ = txdr_unsigned(cr->cr_groups[i]);
208                 break;
209         case RPCAUTH_KERB4:
210                 siz = auth_len;
211                 while (siz > 0) {
212                         if (M_TRAILINGSPACE(mb) == 0) {
213                                 mb2 = m_getl(siz, MB_WAIT, MT_DATA, 0, NULL);
214                                 mb2->m_len = 0;
215                                 mb->m_next = mb2;
216                                 mb = mb2;
217                                 bpos = mtod(mb, caddr_t);
218                         }
219                         i = min(siz, M_TRAILINGSPACE(mb));
220                         bcopy(auth_str, bpos, i);
221                         mb->m_len += i;
222                         auth_str += i;
223                         bpos += i;
224                         siz -= i;
225                 }
226                 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
227                         for (i = 0; i < siz; i++)
228                                 *bpos++ = '\0';
229                         mb->m_len += siz;
230                 }
231                 break;
232         };
233
234         /*
235          * And the verifier...
236          */
237         nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
238         if (verf_str) {
239                 *tl++ = txdr_unsigned(RPCAUTH_KERB4);
240                 *tl = txdr_unsigned(verf_len);
241                 siz = verf_len;
242                 while (siz > 0) {
243                         if (M_TRAILINGSPACE(mb) == 0) {
244                                 mb2 = m_getl(siz, MB_WAIT, MT_DATA, 0, NULL);
245                                 mb2->m_len = 0;
246                                 mb->m_next = mb2;
247                                 mb = mb2;
248                                 bpos = mtod(mb, caddr_t);
249                         }
250                         i = min(siz, M_TRAILINGSPACE(mb));
251                         bcopy(verf_str, bpos, i);
252                         mb->m_len += i;
253                         verf_str += i;
254                         bpos += i;
255                         siz -= i;
256                 }
257                 if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
258                         for (i = 0; i < siz; i++)
259                                 *bpos++ = '\0';
260                         mb->m_len += siz;
261                 }
262         } else {
263                 *tl++ = txdr_unsigned(RPCAUTH_NULL);
264                 *tl = 0;
265         }
266         mb->m_next = mrest;
267         mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
268         mreq->m_pkthdr.rcvif = NULL;
269         *mbp = mb;
270         return (mreq);
271 }
272
273 /*
274  * copies mbuf chain to the uio scatter/gather list
275  */
276 int
277 nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos)
278 {
279         char *mbufcp, *uiocp;
280         int xfer, left, len;
281         struct mbuf *mp;
282         long uiosiz, rem;
283         int error = 0;
284
285         mp = *mrep;
286         mbufcp = *dpos;
287         len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
288         rem = nfsm_rndup(siz)-siz;
289         while (siz > 0) {
290                 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
291                         return (EFBIG);
292                 left = uiop->uio_iov->iov_len;
293                 uiocp = uiop->uio_iov->iov_base;
294                 if (left > siz)
295                         left = siz;
296                 uiosiz = left;
297                 while (left > 0) {
298                         while (len == 0) {
299                                 mp = mp->m_next;
300                                 if (mp == NULL)
301                                         return (EBADRPC);
302                                 mbufcp = mtod(mp, caddr_t);
303                                 len = mp->m_len;
304                         }
305                         xfer = (left > len) ? len : left;
306 #ifdef notdef
307                         /* Not Yet.. */
308                         if (uiop->uio_iov->iov_op != NULL)
309                                 (*(uiop->uio_iov->iov_op))
310                                 (mbufcp, uiocp, xfer);
311                         else
312 #endif
313                         if (uiop->uio_segflg == UIO_SYSSPACE)
314                                 bcopy(mbufcp, uiocp, xfer);
315                         else
316                                 copyout(mbufcp, uiocp, xfer);
317                         left -= xfer;
318                         len -= xfer;
319                         mbufcp += xfer;
320                         uiocp += xfer;
321                         uiop->uio_offset += xfer;
322                         uiop->uio_resid -= xfer;
323                 }
324                 if (uiop->uio_iov->iov_len <= siz) {
325                         uiop->uio_iovcnt--;
326                         uiop->uio_iov++;
327                 } else {
328                         uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
329                         uiop->uio_iov->iov_len -= uiosiz;
330                 }
331                 siz -= uiosiz;
332         }
333         *dpos = mbufcp;
334         *mrep = mp;
335         if (rem > 0) {
336                 if (len < rem)
337                         error = nfs_adv(mrep, dpos, rem, len);
338                 else
339                         *dpos += rem;
340         }
341         return (error);
342 }
343
344 /*
345  * copies a uio scatter/gather list to an mbuf chain.
346  * NOTE: can ony handle iovcnt == 1
347  */
348 int
349 nfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos)
350 {
351         char *uiocp;
352         struct mbuf *mp, *mp2;
353         int xfer, left, mlen;
354         int uiosiz, rem;
355         boolean_t getcluster;
356         char *cp;
357
358 #ifdef DIAGNOSTIC
359         if (uiop->uio_iovcnt != 1)
360                 panic("nfsm_uiotombuf: iovcnt != 1");
361 #endif
362
363         if (siz >= MINCLSIZE)
364                 getcluster = TRUE;
365         else
366                 getcluster = FALSE;
367         rem = nfsm_rndup(siz) - siz;
368         mp = mp2 = *mq;
369         while (siz > 0) {
370                 left = uiop->uio_iov->iov_len;
371                 uiocp = uiop->uio_iov->iov_base;
372                 if (left > siz)
373                         left = siz;
374                 uiosiz = left;
375                 while (left > 0) {
376                         mlen = M_TRAILINGSPACE(mp);
377                         if (mlen == 0) {
378                                 if (getcluster)
379                                         mp = m_getcl(MB_WAIT, MT_DATA, 0);
380                                 else
381                                         mp = m_get(MB_WAIT, MT_DATA);
382                                 mp->m_len = 0;
383                                 mp2->m_next = mp;
384                                 mp2 = mp;
385                                 mlen = M_TRAILINGSPACE(mp);
386                         }
387                         xfer = (left > mlen) ? mlen : left;
388 #ifdef notdef
389                         /* Not Yet.. */
390                         if (uiop->uio_iov->iov_op != NULL)
391                                 (*(uiop->uio_iov->iov_op))
392                                 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
393                         else
394 #endif
395                         if (uiop->uio_segflg == UIO_SYSSPACE)
396                                 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
397                         else
398                                 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
399                         mp->m_len += xfer;
400                         left -= xfer;
401                         uiocp += xfer;
402                         uiop->uio_offset += xfer;
403                         uiop->uio_resid -= xfer;
404                 }
405                 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + uiosiz;
406                 uiop->uio_iov->iov_len -= uiosiz;
407                 siz -= uiosiz;
408         }
409         if (rem > 0) {
410                 if (rem > M_TRAILINGSPACE(mp)) {
411                         MGET(mp, MB_WAIT, MT_DATA);
412                         mp->m_len = 0;
413                         mp2->m_next = mp;
414                 }
415                 cp = mtod(mp, caddr_t)+mp->m_len;
416                 for (left = 0; left < rem; left++)
417                         *cp++ = '\0';
418                 mp->m_len += rem;
419                 *bpos = cp;
420         } else
421                 *bpos = mtod(mp, caddr_t)+mp->m_len;
422         *mq = mp;
423         return (0);
424 }
425
426 /*
427  * Help break down an mbuf chain by setting the first siz bytes contiguous
428  * pointed to by returned val.
429  * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
430  * cases. (The macros use the vars. dpos and dpos2)
431  */
432 int
433 nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, caddr_t *cp2)
434 {
435         struct mbuf *mp, *mp2;
436         int siz2, xfer;
437         caddr_t p;
438
439         mp = *mdp;
440         while (left == 0) {
441                 *mdp = mp = mp->m_next;
442                 if (mp == NULL)
443                         return (EBADRPC);
444                 left = mp->m_len;
445                 *dposp = mtod(mp, caddr_t);
446         }
447         if (left >= siz) {
448                 *cp2 = *dposp;
449                 *dposp += siz;
450         } else if (mp->m_next == NULL) {
451                 return (EBADRPC);
452         } else if (siz > MHLEN) {
453                 panic("nfs S too big");
454         } else {
455                 MGET(mp2, MB_WAIT, MT_DATA);
456                 mp2->m_next = mp->m_next;
457                 mp->m_next = mp2;
458                 mp->m_len -= left;
459                 mp = mp2;
460                 *cp2 = p = mtod(mp, caddr_t);
461                 bcopy(*dposp, p, left);         /* Copy what was left */
462                 siz2 = siz-left;
463                 p += left;
464                 mp2 = mp->m_next;
465                 /* Loop around copying up the siz2 bytes */
466                 while (siz2 > 0) {
467                         if (mp2 == NULL)
468                                 return (EBADRPC);
469                         xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
470                         if (xfer > 0) {
471                                 bcopy(mtod(mp2, caddr_t), p, xfer);
472                                 NFSMADV(mp2, xfer);
473                                 mp2->m_len -= xfer;
474                                 p += xfer;
475                                 siz2 -= xfer;
476                         }
477                         if (siz2 > 0)
478                                 mp2 = mp2->m_next;
479                 }
480                 mp->m_len = siz;
481                 *mdp = mp2;
482                 *dposp = mtod(mp2, caddr_t);
483         }
484         return (0);
485 }
486
487 /*
488  * Advance the position in the mbuf chain.
489  */
490 int
491 nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left)
492 {
493         struct mbuf *m;
494         int s;
495
496         m = *mdp;
497         s = left;
498         while (s < offs) {
499                 offs -= s;
500                 m = m->m_next;
501                 if (m == NULL)
502                         return (EBADRPC);
503                 s = m->m_len;
504         }
505         *mdp = m;
506         *dposp = mtod(m, caddr_t)+offs;
507         return (0);
508 }
509
510 /*
511  * Copy a string into mbufs for the hard cases...
512  */
513 int
514 nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz)
515 {
516         struct mbuf *m1 = NULL, *m2;
517         long left, xfer, len, tlen;
518         u_int32_t *tl;
519         int putsize;
520
521         putsize = 1;
522         m2 = *mb;
523         left = M_TRAILINGSPACE(m2);
524         if (left > 0) {
525                 tl = ((u_int32_t *)(*bpos));
526                 *tl++ = txdr_unsigned(siz);
527                 putsize = 0;
528                 left -= NFSX_UNSIGNED;
529                 m2->m_len += NFSX_UNSIGNED;
530                 if (left > 0) {
531                         bcopy(cp, (caddr_t) tl, left);
532                         siz -= left;
533                         cp += left;
534                         m2->m_len += left;
535                         left = 0;
536                 }
537         }
538         /* Loop around adding mbufs */
539         while (siz > 0) {
540                 int msize;
541
542                 m1 = m_getl(siz, MB_WAIT, MT_DATA, 0, &msize);
543                 m1->m_len = msize;
544                 m2->m_next = m1;
545                 m2 = m1;
546                 tl = mtod(m1, u_int32_t *);
547                 tlen = 0;
548                 if (putsize) {
549                         *tl++ = txdr_unsigned(siz);
550                         m1->m_len -= NFSX_UNSIGNED;
551                         tlen = NFSX_UNSIGNED;
552                         putsize = 0;
553                 }
554                 if (siz < m1->m_len) {
555                         len = nfsm_rndup(siz);
556                         xfer = siz;
557                         if (xfer < len)
558                                 *(tl+(xfer>>2)) = 0;
559                 } else {
560                         xfer = len = m1->m_len;
561                 }
562                 bcopy(cp, (caddr_t) tl, xfer);
563                 m1->m_len = len+tlen;
564                 siz -= xfer;
565                 cp += xfer;
566         }
567         *mb = m1;
568         *bpos = mtod(m1, caddr_t)+m1->m_len;
569         return (0);
570 }
571
572 /*
573  * A fiddled version of m_adj() that ensures null fill to a long
574  * boundary and only trims off the back end
575  */
576 void
577 nfsm_adj(struct mbuf *mp, int len, int nul)
578 {
579         struct mbuf *m;
580         int count, i;
581         char *cp;
582
583         /*
584          * Trim from tail.  Scan the mbuf chain,
585          * calculating its length and finding the last mbuf.
586          * If the adjustment only affects this mbuf, then just
587          * adjust and return.  Otherwise, rescan and truncate
588          * after the remaining size.
589          */
590         count = 0;
591         m = mp;
592         for (;;) {
593                 count += m->m_len;
594                 if (m->m_next == NULL)
595                         break;
596                 m = m->m_next;
597         }
598         if (m->m_len > len) {
599                 m->m_len -= len;
600                 if (nul > 0) {
601                         cp = mtod(m, caddr_t)+m->m_len-nul;
602                         for (i = 0; i < nul; i++)
603                                 *cp++ = '\0';
604                 }
605                 return;
606         }
607         count -= len;
608         if (count < 0)
609                 count = 0;
610         /*
611          * Correct length for chain is "count".
612          * Find the mbuf with last data, adjust its length,
613          * and toss data from remaining mbufs on chain.
614          */
615         for (m = mp; m; m = m->m_next) {
616                 if (m->m_len >= count) {
617                         m->m_len = count;
618                         if (nul > 0) {
619                                 cp = mtod(m, caddr_t)+m->m_len-nul;
620                                 for (i = 0; i < nul; i++)
621                                         *cp++ = '\0';
622                         }
623                         break;
624                 }
625                 count -= m->m_len;
626         }
627         for (m = m->m_next;m;m = m->m_next)
628                 m->m_len = 0;
629 }
630
631 /*
632  * Make these functions instead of macros, so that the kernel text size
633  * doesn't get too big...
634  */
635 void
636 nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
637             struct vattr *before_vap, int after_ret, struct vattr *after_vap,
638             struct mbuf **mbp, char **bposp)
639 {
640         struct mbuf *mb = *mbp, *mb2;
641         char *bpos = *bposp;
642         u_int32_t *tl;
643
644         /*
645          * before_ret is 0 if before_vap is valid, non-zero if it isn't.
646          */
647         if (before_ret) {
648                 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
649                 *tl = nfs_false;
650         } else {
651                 nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
652                 *tl++ = nfs_true;
653                 txdr_hyper(before_vap->va_size, tl);
654                 tl += 2;
655                 txdr_nfsv3time(&(before_vap->va_mtime), tl);
656                 tl += 2;
657                 txdr_nfsv3time(&(before_vap->va_ctime), tl);
658         }
659         *bposp = bpos;
660         *mbp = mb;
661         nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
662 }
663
664 void
665 nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret,
666                    struct vattr *after_vap, struct mbuf **mbp, char **bposp)
667 {
668         struct mbuf *mb = *mbp, *mb2;
669         char *bpos = *bposp;
670         u_int32_t *tl;
671         struct nfs_fattr *fp;
672
673         if (after_ret) {
674                 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
675                 *tl = nfs_false;
676         } else {
677                 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
678                 *tl++ = nfs_true;
679                 fp = (struct nfs_fattr *)tl;
680                 nfsm_srvfattr(nfsd, after_vap, fp);
681         }
682         *mbp = mb;
683         *bposp = bpos;
684 }
685
686 void
687 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
688               struct nfs_fattr *fp)
689 {
690         /*
691          * NFS seems to truncate nlink to 16 bits, don't let it overflow.
692          */
693         if (vap->va_nlink > 65535)
694                 fp->fa_nlink = 65535;
695         else
696                 fp->fa_nlink = txdr_unsigned(vap->va_nlink);
697         fp->fa_uid = txdr_unsigned(vap->va_uid);
698         fp->fa_gid = txdr_unsigned(vap->va_gid);
699         if (nfsd->nd_flag & ND_NFSV3) {
700                 fp->fa_type = vtonfsv3_type(vap->va_type);
701                 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
702                 txdr_hyper(vap->va_size, &fp->fa3_size);
703                 txdr_hyper(vap->va_bytes, &fp->fa3_used);
704                 fp->fa3_rdev.specdata1 = txdr_unsigned(vap->va_rmajor);
705                 fp->fa3_rdev.specdata2 = txdr_unsigned(vap->va_rminor);
706                 fp->fa3_fsid.nfsuquad[0] = 0;
707                 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
708                 txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
709                 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
710                 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
711                 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
712         } else {
713                 fp->fa_type = vtonfsv2_type(vap->va_type);
714                 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
715                 fp->fa2_size = txdr_unsigned(vap->va_size);
716                 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
717                 if (vap->va_type == VFIFO)
718                         fp->fa2_rdev = 0xffffffff;
719                 else
720                         fp->fa2_rdev = txdr_unsigned(makeudev(vap->va_rmajor, vap->va_rminor));
721                 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
722                 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
723                 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
724                 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
725                 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
726                 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
727         }
728 }