]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/nfs4client/nfs4_subs.c
This commit was generated by cvs2svn to compensate for changes in r124528,
[FreeBSD/FreeBSD.git] / sys / nfs4client / nfs4_subs.c
1 /* $FreeBSD$ */
2 /* $Id: nfs4_subs.c,v 1.52 2003/11/05 14:58:59 rees Exp $ */
3
4 /*
5  * copyright (c) 2003
6  * the regents of the university of michigan
7  * all rights reserved
8  * 
9  * permission is granted to use, copy, create derivative works and redistribute
10  * this software and such derivative works for any purpose, so long as the name
11  * of the university of michigan is not used in any advertising or publicity
12  * pertaining to the use or distribution of this software without specific,
13  * written prior authorization.  if the above copyright notice or any other
14  * identification of the university of michigan is included in any copy of any
15  * portion of this software, then the disclaimer below must also be included.
16  * 
17  * this software is provided as is, without representation from the university
18  * of michigan as to its fitness for any purpose, and without warranty by the
19  * university of michigan of any kind, either express or implied, including
20  * without limitation the implied warranties of merchantability and fitness for
21  * a particular purpose. the regents of the university of michigan shall not be
22  * liable for any damages, including special, indirect, incidental, or
23  * consequential damages, with respect to any claim arising out of or in
24  * connection with the use of the software, even if it has been or is hereafter
25  * advised of the possibility of such damages.
26  */
27
28 #include <sys/cdefs.h>
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/bio.h>
34 #include <sys/buf.h>
35 #include <sys/proc.h>
36 #include <sys/mount.h>
37 #include <sys/vnode.h>
38 #include <sys/namei.h>
39 #include <sys/mbuf.h>
40 #include <sys/socket.h>
41 #include <sys/stat.h>
42 #include <sys/malloc.h>
43 #include <sys/sysent.h>
44 #include <sys/syscall.h>
45 #include <sys/sysproto.h>
46 #include <sys/fcntl.h>
47
48 #include <machine/stdarg.h>
49
50 #include <vm/vm.h>
51 #include <vm/vm_object.h>
52 #include <vm/vm_extern.h>
53 #include <vm/uma.h>
54
55 #include <rpc/rpcclnt.h>
56
57 #include <nfs/rpcv2.h>
58 #include <nfs/nfsproto.h>
59 #include <nfsclient/nfs.h>
60 #include <nfs4client/nfs4.h>
61 #include <nfsclient/nfsnode.h>
62 #include <nfsclient/nfsmount.h>
63 #include <nfs/xdr_subs.h>
64 #include <nfsclient/nfsm_subs.h>
65
66 #include <nfs4client/nfs4_dev.h>
67 #include <nfs4client/nfs4_idmap.h>
68 #include <nfs4client/nfs4m_subs.h>
69
70 #include <netinet/in.h>
71
72 #define NFSM_DISSECT(s) do {                                                    \
73         tl = nfsm_dissect_xx((s), md, dpos);                                    \
74         if (tl == NULL) {                                                       \
75                 printf("NFSM_DISSECT error; allocation (%s/%d) (%s:%d)\n", #s, s, __FILE__, __LINE__);  \
76                 return (EBADRPC);                                               \
77         }                                                                       \
78 } while (0)
79
80 #define NFSM_ADV(s) do {                                                \
81         t1 = nfsm_adv_xx((s), md, dpos);                                \
82         if (t1 != 0) {                                                  \
83                 printf("NFSM_ADV error; allocation (%s/%d) (%s:%d)\n", #s, s, __FILE__, __LINE__);      \
84                 return (EBADRPC);                                       \
85         }                                                               \
86 } while (0)
87
88 #define NFSM_MTOTIME(t) do {                            \
89         NFSM_DISSECT(3 * NFSX_UNSIGNED);                \
90         (t).tv_sec = fxdr_hyper(tl);                    \
91         tl += 2;                                        \
92         (t).tv_nsec = fxdr_unsigned(long, *tl++);       \
93 } while (0)
94
95 static uint32_t __fsinfo_bm[2], __fsattr_bm[2], __getattr_bm[2], __readdir_bm[2];
96
97 nfsv4bitmap nfsv4_fsinfobm = { 2, __fsinfo_bm };
98 nfsv4bitmap nfsv4_fsattrbm = { 2, __fsattr_bm };
99 nfsv4bitmap nfsv4_getattrbm = { 2, __getattr_bm };
100 nfsv4bitmap nfsv4_readdirbm = { 2, __readdir_bm };
101
102 /* Helper routines */
103 int nfsm_v4build_attrs_xx(struct vattr *, struct mbuf **, caddr_t *);
104 int nfsm_v4dissect_changeinfo_xx(nfsv4changeinfo *,  struct mbuf **, caddr_t *);
105
106 void
107 nfsm_v4init(void)
108 {
109
110         /* Set up bitmasks */
111         FA4_SET(FA4_FSID, __fsinfo_bm);
112         FA4_SET(FA4_MAXREAD, __fsinfo_bm);
113         FA4_SET(FA4_MAXWRITE, __fsinfo_bm);
114         FA4_SET(FA4_LEASE_TIME, __fsinfo_bm);
115
116         FA4_SET(FA4_FSID, __fsattr_bm);
117         FA4_SET(FA4_FILES_FREE, __fsattr_bm);
118         FA4_SET(FA4_FILES_TOTAL, __fsattr_bm);
119         FA4_SET(FA4_SPACE_AVAIL, __fsattr_bm);
120         FA4_SET(FA4_SPACE_FREE, __fsattr_bm);
121         FA4_SET(FA4_SPACE_TOTAL, __fsattr_bm);
122
123         FA4_SET(FA4_TYPE, __getattr_bm);
124         FA4_SET(FA4_FSID, __getattr_bm);
125         FA4_SET(FA4_SIZE, __getattr_bm);
126         FA4_SET(FA4_MODE, __getattr_bm);
127         FA4_SET(FA4_RAWDEV, __getattr_bm);
128         FA4_SET(FA4_NUMLINKS, __getattr_bm);
129         FA4_SET(FA4_OWNER, __getattr_bm);
130         FA4_SET(FA4_OWNER_GROUP, __getattr_bm);
131         FA4_SET(FA4_FILEID, __getattr_bm);
132         FA4_SET(FA4_TIME_MODIFY, __getattr_bm);
133         FA4_SET(FA4_TIME_ACCESS, __getattr_bm);
134 /*        FA4_SET(FA4_TIME_CREATE, __getattr_bm);*/
135
136         FA4_SET(FA4_TYPE, __readdir_bm);
137         FA4_SET(FA4_FSID, __readdir_bm);
138         FA4_SET(FA4_FILEID, __readdir_bm);
139 }
140
141 /*
142  * Util
143  */
144
145 uint32_t
146 nfs_v4fileid4_to_fileid(uint64_t fid)
147 {
148         return ((uint32_t)((fid >> 32) | fid));
149 }
150
151 void
152 nfs_v4initcompound(struct nfs4_compound *cp)
153 {
154         bzero(cp, sizeof(*cp));
155 }
156
157 /*
158  * Build/dissect XDR buffer with a format string.
159  *
160  *    u - unsigned
161  *    h - hyper
162  *    s - stringlength, string
163  *    k - skip length (bytes)
164  *    a - arraylength, componentlenght, array
165  *    o - opaque fix length
166  *    O - opaque var length in bytes
167  */
168
169 void
170 nfsm_buildf_xx(struct mbuf **mb, caddr_t *bpos, char *fmt, ...)
171 {
172         uint32_t *tl, t1, len, uval;
173         uint64_t hval;
174         va_list args;
175         char *p, *which;
176
177         va_start(args, fmt);
178         for (which = fmt; *which != '\0'; which++)
179                 switch (*which) {
180                 case 'u':       /* Unsigned */
181                         tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
182                         uval = va_arg(args, uint32_t);
183                         *tl++ = txdr_unsigned(uval);
184                         break;
185                 case 'h':       /* Hyper */
186                         tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
187                         hval = va_arg(args, uint64_t);
188                         txdr_hyper(hval, tl);
189                         break;
190                 case 'o':       /* Fixed-length opaque */
191                         len = va_arg(args, uint32_t);
192                         p = va_arg(args, char *);
193                         tl = nfsm_build_xx(nfsm_rndup(len), mb, bpos);
194                         bcopy(p, tl, len);
195                         break;
196                 case 'O':       /* Variable-length opaque */
197                 case 's':       /* String */
198                         len = va_arg(args, uint32_t);
199                         p = va_arg(args, char *);
200                         t1 = nfsm_strtom_xx(p, len, len, mb, bpos);
201                         break;
202                 case 'k':       /* Skip */
203                         len = va_arg(args, uint32_t);
204                         nfsm_build_xx(nfsm_rndup(len), mb, bpos);
205                         break;
206                 default:
207                         panic("Invalid buildf string %s[%c]", fmt, *which);
208                         break;
209                 }
210         va_end(args);
211 }
212
213 int
214 nfsm_dissectf_xx(struct mbuf **md, caddr_t *dpos, char *fmt, ...)
215 {
216         uint32_t *tl, t1, len, *uval;
217         uint64_t *hval;
218         va_list args;
219         char *p, *which;
220
221         va_start(args, fmt);
222         for (which = fmt; *which != '\0'; which++)
223                 switch (*which) {
224                 case 'u':       /* Unsigned */
225                         tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
226                         if (tl == NULL)
227                                 return (EBADRPC);
228                         uval = va_arg(args, uint32_t *);
229                         *uval = fxdr_unsigned(uint32_t, *tl++);
230                         break;
231                 case 'h':       /* Hyper */
232                         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
233                         if (tl == NULL)
234                                 return (EBADRPC);
235                         hval = va_arg(args, uint64_t *);
236                         *hval = fxdr_hyper(tl);
237                         break;
238                 case 'o':       /* Fixed-length opaque */
239                         len = va_arg(args, uint32_t);
240                         p = va_arg(args, void *);
241                         tl = nfsm_dissect_xx(nfsm_rndup(len), md, dpos);
242                         if (tl == NULL)
243                                 return (EBADRPC);
244                         bcopy(tl, p, len);
245                         break;
246                 case 'O':       /* Variable-length opaque */
247                 case 's':       /* String */
248                         len = va_arg(args, uint32_t);
249                         p = va_arg(args, char *);
250                         tl = nfsm_dissect_xx(nfsm_rndup(len), md, dpos);
251                         if (tl == NULL)
252                                 return (EBADRPC);
253                         bcopy(tl, p, len);
254                         break;
255                 case 'k':       /* Skip bytes */
256                         len = va_arg(args, uint32_t);
257                         t1 = nfsm_adv_xx(nfsm_rndup(len), md, dpos);
258                         break;
259                 default:
260                         panic("Invalid dissectf string %s[%c]", fmt, *which);
261                         break;
262                 }
263         va_end(args);
264
265         return (0);
266 }
267
268 /*
269  * XXX - There are a few problems with the way the postops are places
270  * in the code.  Ideally, they should be taken care of immediately, as
271  * to avoid uneceesary waits for mutexes, but then we would be
272  * introducing even more complexity by having to handle two separate
273  * cases.  Also, since they are placed at the end of the vnops', there
274  * may be operations which sleep in between, further extending this
275  * wait.  It is conceivable that there is a deadlock condition there,
276  * too.
277  *
278  * Also, for vnops that do multiple operations, it's inconvenient
279  * since on error, individual decoding will got nfsmout.
280  */
281
282 int
283 nfs_v4postop(struct nfs4_compound *cp, int status)
284 {
285         struct nfs4_fctx *fcp = cp->fcp;
286
287         /*
288          * XXX does the previous result need to be stores with the
289          * lockowner?  ack, spec is unclear ..
290          */
291
292         if (fcp != NULL)
293                 if (cp->seqidused < cp->rep_nops ||
294                     (cp->seqidused + 1 == cp->rep_nops &&
295                         NFS4_SEQIDMUTATINGERROR(status)))
296                         fcp->lop->lo_seqid++;
297
298         return (status);
299 }
300
301 int
302 nfs_v4handlestatus(int status, struct nfs4_compound *cp)
303 {
304         return (status);
305 }
306
307 /*
308  * Initial setup of compound.
309  */
310
311 int
312 nfsm_v4build_compound_xx(struct nfs4_compound *cp, char *tag,
313     struct mbuf **mb, caddr_t *bpos)
314 {
315         uint32_t t1, *tl, siz;
316
317         /* Tag */
318         siz = strlen(tag);
319         t1 = nfsm_rndup(siz) + NFSX_UNSIGNED;
320         if (t1 <= M_TRAILINGSPACE(*mb)) {
321                 tl = nfsm_build_xx(t1, mb, bpos);
322                 *tl++ = txdr_unsigned(siz);
323                 *(tl + ((t1 >> 2) - 2)) = 0;
324                 bcopy(tag, tl, siz);
325         } else {
326                 t1 = nfsm_strtmbuf(mb, bpos, (const char *)tag, siz);
327                 if (t1 != 0)
328                         return (t1);
329         }
330
331         /* Minor version and argarray*/
332         tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
333         *tl++ = txdr_unsigned(NFS4_MINOR_VERSION);
334         /* Save for backfill */
335         cp->req_nopsp = tl;
336         *tl = txdr_unsigned(0);
337
338         cp->curvp = NULL;
339         cp->savevp = NULL;
340
341         return (0);
342 }
343
344 /*
345  * XXX
346  * - backfill for stateid, and such
347  */
348 int
349 nfsm_v4build_finalize_xx(struct nfs4_compound *cp, struct mbuf **mb, caddr_t *bpos)
350 {
351         *cp->req_nopsp = txdr_unsigned(cp->req_nops);
352
353         return (0);
354 }
355
356 int
357 nfsm_v4build_putfh_xx(struct nfs4_compound *cp, struct vnode *vp,
358     struct mbuf **mb, caddr_t *bpos)
359 {
360         uint32_t t1;
361
362         /* Op */
363         nfsm_buildf_xx(mb, bpos, "u", NFSV4OP_PUTFH);
364
365         /* FH */
366         t1 = nfsm_fhtom_xx(vp, 1, mb, bpos);
367         if (t1 != 0)
368                 return (t1);
369
370         cp->req_nops++;
371         cp->curvp = vp;
372
373         return (0);
374 }
375
376 int
377 nfsm_v4build_putfh_nv_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh,
378     struct mbuf **mb, caddr_t *bpos)
379 {
380         nfsm_buildf_xx(mb, bpos, "uuo",
381             NFSV4OP_PUTFH,
382             gfh->fh_len,
383             gfh->fh_len,
384             &gfh->fh_val);
385
386         cp->req_nops++;
387
388         return (0);
389 }
390
391 int
392 nfsm_v4build_simple_xx(struct nfs4_compound *cp, uint32_t op,
393     struct mbuf **mb, caddr_t *bpos)
394 {
395         nfsm_buildf_xx(mb, bpos, "u", op);
396
397         cp->req_nops++;
398
399         return (0);
400 }
401
402 int
403 nfsm_v4build_getattr_xx(struct nfs4_compound *cp, struct nfs4_oparg_getattr *ga,
404     struct mbuf **mb, caddr_t *bpos)
405 {
406         int i;
407
408         /* Op + bitmap length + bitmap */
409         nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_GETATTR, ga->bm->bmlen);
410         for (i = 0; i < ga->bm->bmlen; i++)
411                 nfsm_buildf_xx(mb, bpos, "u", ga->bm->bmval[i]);
412
413         ga->vp = cp->curvp;
414         cp->req_nops++;          
415
416         return (0);
417 }
418
419 int
420 nfsm_v4build_setattr_xx(struct nfs4_compound *cp, struct vattr *vap,
421     struct nfs4_fctx *fcp, struct mbuf **mb, caddr_t *bpos)
422 {
423         int error;
424
425         nfsm_buildf_xx(mb, bpos, "uo",
426             NFSV4OP_SETATTR,
427             NFSX_V4STATEID, fcp->stateid);
428         error = nfsm_v4build_attrs_xx(vap, mb, bpos);
429         if (error == 0)
430                 cp->req_nops++;
431
432         return (error);
433 }
434
435 int
436 nfsm_v4build_getfh_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh,
437     struct mbuf **mb, caddr_t *bpos)
438 {
439         nfsm_buildf_xx(mb, bpos, "u", NFSV4OP_GETFH);
440
441         gfh->vp = cp->curvp;
442         cp->req_nops++;
443
444         return (0);
445 }
446
447 int
448 nfsm_v4build_lookup_xx(struct nfs4_compound *cp, struct nfs4_oparg_lookup *l,
449     struct mbuf **mb, caddr_t *bpos)
450 {
451         nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_LOOKUP, l->namelen, l->name);
452
453         cp->curvp = l->vp;
454         cp->req_nops++;
455
456         return (0);
457 }
458
459 int
460 nfsm_v4build_setclientid_xx(struct nfs4_compound *cp,
461     struct nfs4_oparg_setclientid *sci, struct mbuf **mb, caddr_t *bpos)
462 {
463         struct timeval tv;
464
465         microtime(&tv);
466
467         nfsm_buildf_xx(mb, bpos, "uuusussu",
468             NFSV4OP_SETCLIENTID,
469             tv.tv_sec, tv.tv_usec,
470             sci->namelen, sci->name,
471             sci->cb_prog,
472             sci->cb_netidlen, sci->cb_netid,
473             sci->cb_univaddrlen, sci->cb_univaddr,
474             0xCA11BACC);
475
476         cp->req_nops++;
477
478         return (0);
479 }
480
481 int
482 nfsm_v4build_setclientid_confirm_xx(struct nfs4_compound *cp,
483     struct nfs4_oparg_setclientid *sci, struct mbuf **mb, caddr_t *bpos)
484 {
485         nfsm_buildf_xx(mb, bpos, "uho",
486             NFSV4OP_SETCLIENTID_CONFIRM,
487             sci->clientid,
488             sizeof(sci->verf), sci->verf);
489
490         cp->req_nops++;
491
492         return (0);
493 }
494
495 int
496 nfsm_v4build_open_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
497     struct mbuf **mb, caddr_t *bpos)
498 {
499         int error = 0;
500         struct nfs4_lowner *lop = op->fcp->lop;
501
502         nfsm_buildf_xx(mb, bpos, "uuuuhuu",
503             NFSV4OP_OPEN,
504             lop->lo_seqid,
505             op->flags & O_ACCMODE,
506             NFSV4OPENSHARE_DENY_NONE,
507             cp->nmp->nm_clientid,
508             4, lop->lo_id);
509
510         if (op->flags & O_CREAT) {
511                 nfsm_buildf_xx(mb, bpos, "u", OTCREATE);
512                 /* openflag4: mode */
513                 nfsm_buildf_xx(mb, bpos, "u", CMUNCHECKED);
514                 /* openflag4: createattrs... */
515                 if (op->vap != NULL) {
516                         if (op->flags & O_TRUNC)
517                                 op->vap->va_size = 0;
518                         error = nfsm_v4build_attrs_xx(op->vap, mb, bpos);
519                         if (error != 0)
520                                 return (error);
521                 } else
522                         nfsm_buildf_xx(mb, bpos, "uu", 0, 0);
523         } else
524                 nfsm_buildf_xx(mb, bpos, "u", OTNOCREATE);
525
526         nfsm_buildf_xx(mb, bpos, "us", op->ctype,
527             op->cnp->cn_namelen, op->cnp->cn_nameptr);
528
529         cp->seqidused = cp->req_nops++;
530         cp->fcp = op->fcp;
531
532         return (error);
533 }
534
535 /*
536  * XXX
537  * - Wait on recovery
538  */
539 int
540 nfsm_v4build_open_confirm_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
541     struct mbuf **mb, caddr_t *bpos)
542 {
543         nfsm_buildf_xx(mb, bpos, "uou",
544             NFSV4OP_OPEN_CONFIRM,
545             NFSX_V4STATEID, op->fcp->stateid,
546             op->fcp->lop->lo_seqid);
547
548         cp->seqidused = cp->req_nops++;
549         cp->fcp = op->fcp;
550
551         return (0);
552 }
553
554 /*
555  * XXX
556  * - Wait on recovery
557  */
558 int
559 nfsm_v4build_close_xx(struct nfs4_compound *cp, struct nfs4_fctx *fcp,
560     struct mbuf **mb, caddr_t *bpos)
561 {
562         struct nfs4_lowner *lop = fcp->lop;
563
564         nfsm_buildf_xx(mb, bpos, "uuo",
565             NFSV4OP_CLOSE,
566             lop->lo_seqid,
567             NFSX_V4STATEID, fcp->stateid);
568
569         cp->seqidused = cp->req_nops++;
570         cp->fcp = fcp;
571
572         return (0);
573 }
574
575 int
576 nfsm_v4build_access_xx(struct nfs4_compound *cp, struct nfs4_oparg_access *acc,
577     struct mbuf **mb, caddr_t *bpos)
578 {
579         nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_ACCESS, acc->mode);
580         cp->req_nops++;
581
582         return (0);
583 }
584
585 int
586 nfsm_v4build_read_xx(struct nfs4_compound *cp, struct nfs4_oparg_read *r,
587     struct mbuf **mb, caddr_t *bpos)
588 {
589         nfsm_buildf_xx(mb, bpos, "uohu",
590             NFSV4OP_READ,
591             NFSX_V4STATEID, r->fcp->stateid,
592             r->off,
593             r->maxcnt);
594         cp->req_nops++;
595
596         return (0);
597 }
598
599 int
600 nfsm_v4build_write_xx(struct nfs4_compound *cp, struct nfs4_oparg_write *w,
601     struct mbuf **mb, caddr_t *bpos)
602 {
603         nfsm_buildf_xx(mb, bpos, "uohuu",
604             NFSV4OP_WRITE,
605             NFSX_V4STATEID, w->fcp->stateid,
606             w->off,
607             w->stable,
608             w->cnt);
609         cp->req_nops++;
610         return (nfsm_uiotombuf(w->uiop, mb, w->cnt, bpos));
611 }
612
613 int
614 nfsm_v4build_commit_xx(struct nfs4_compound *cp, struct nfs4_oparg_commit *c,
615     struct mbuf **mb, caddr_t *bpos)
616 {
617         nfsm_buildf_xx(mb, bpos, "uhu", NFSV4OP_COMMIT, c->start, c->len);
618         cp->req_nops++;
619
620         return (0);
621 }
622
623 int
624 nfsm_v4build_readdir_xx(struct nfs4_compound *cp, struct nfs4_oparg_readdir *r,
625     struct mbuf **mb, caddr_t *bpos)
626 {
627         int i;
628
629         nfsm_buildf_xx(mb, bpos, "uhouuu",
630             NFSV4OP_READDIR,
631             r->cookie,
632             sizeof(r->verf), r->verf,
633             r->cnt >> 4,        /* meaningless "dircount" field */
634             r->cnt,
635             r->bm->bmlen);
636
637         for (i = 0; i < r->bm->bmlen; i++)
638                 nfsm_buildf_xx(mb, bpos, "u", r->bm->bmval[i]);
639
640         cp->req_nops++;
641
642         return (0);
643 }
644
645 int
646 nfsm_v4build_renew_xx(struct nfs4_compound *cp, uint64_t cid,
647     struct mbuf **mb, caddr_t *bpos)
648 {
649         nfsm_buildf_xx(mb, bpos, "uh", NFSV4OP_RENEW, cid);
650         cp->req_nops++;
651
652         return (0);
653 }
654
655 int
656 nfsm_v4build_create_xx(struct nfs4_compound *cp, struct nfs4_oparg_create *c,
657     struct mbuf **mb, caddr_t *bpos)
658 {
659         uint32_t t1;
660
661         nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_CREATE, c->type);
662
663         if (c->type == NFLNK)
664                 /* XXX strlen */
665                 nfsm_buildf_xx(mb, bpos, "s", strlen(c->linktext), c->linktext);
666         else if (c->type == NFCHR || c->type == NFBLK)
667                 nfsm_buildf_xx(mb, bpos, "uu",
668                     umajor(c->vap->va_rdev), uminor(c->vap->va_rdev));
669
670         /* Name */
671         nfsm_buildf_xx(mb, bpos, "s", c->namelen, c->name);     
672
673         /* Attributes */
674         t1 = nfsm_v4build_attrs_xx(c->vap, mb, bpos);
675         if (t1 != 0)
676                 return (t1);
677
678         cp->req_nops++;
679
680         return (0);
681 }
682
683 int
684 nfsm_v4build_rename_xx(struct nfs4_compound *cp, struct nfs4_oparg_rename *r,
685     struct mbuf **mb, caddr_t *bpos)
686 {
687         nfsm_buildf_xx(mb, bpos, "uss", NFSV4OP_RENAME, r->fnamelen, r->fname,
688             r->tnamelen, r->tname);
689
690         cp->req_nops++;
691
692         return (0);
693 }
694
695 int
696 nfsm_v4build_link_xx(struct nfs4_compound *cp, struct nfs4_oparg_link *l,
697     struct mbuf **mb, caddr_t *bpos)
698 {
699         nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_LINK, l->namelen, l->name);
700
701         cp->req_nops++;
702
703         return (0);
704 }
705
706 int
707 nfsm_v4build_remove_xx(struct nfs4_compound *cp, const char *name, u_int namelen,
708     struct mbuf **mb, caddr_t *bpos)
709 {
710         nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_REMOVE, namelen, name);
711
712         cp->req_nops++;
713
714         return (0);
715 }
716
717 int
718 nfsm_v4build_attrs_xx(struct vattr *vap, struct mbuf **mb, caddr_t *bpos)
719 {
720         uint32_t *tl, *attrlenp, *bmvalp, len;
721         size_t siz;
722
723         tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos);
724
725         *tl++ = txdr_unsigned(2);    /* bitmap length */
726         bmvalp = tl;
727         bzero(bmvalp, 8);
728         tl += 2;
729         attrlenp = tl;
730
731         len = 0;
732         if (vap->va_size != VNOVAL) {
733                 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
734                 FA4_SET(FA4_SIZE, bmvalp);
735                 txdr_hyper(vap->va_size, tl); tl += 2;
736                 len += 2 * NFSX_UNSIGNED;
737         }
738         if (vap->va_mode != (u_short)VNOVAL) {
739                 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
740                 FA4_SET(FA4_MODE, bmvalp);
741                 *tl++ = txdr_unsigned(vap->va_mode);
742                 len += NFSX_UNSIGNED;
743         }
744         if (vap->va_uid != VNOVAL) {
745                 int error;
746                 char *name;
747                 error = idmap_uid_to_name(vap->va_uid, &name, &siz);
748                 if (error || name == NULL || siz == 0) {
749                         /* XXX */
750                         siz = sizeof("nobody") - 1;
751                         tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb, 
752                             bpos);
753                         *tl++ = txdr_unsigned(siz);
754                         bcopy("nobody", tl, siz);
755                         len += NFSX_UNSIGNED + nfsm_rndup(siz);
756                 } else {
757                         tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb,
758                             bpos);
759                         *tl++ = txdr_unsigned(siz);
760                         bcopy(name, tl, siz);
761                         len += NFSX_UNSIGNED + nfsm_rndup(siz);
762                 }
763                 FA4_SET(FA4_OWNER, bmvalp);
764         }
765         if (vap->va_gid != VNOVAL) {
766                 int error;
767                 char *name;
768                 error = idmap_gid_to_name(vap->va_gid, &name, &siz);
769                 if (error || name == NULL || siz == 0) {
770                         /* XXX */
771                         siz = sizeof("nogroup") - 1;
772                         tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb, 
773                             bpos);
774                         *tl++ = txdr_unsigned(siz);
775                         bcopy("nogroup", tl, siz);
776                         len += NFSX_UNSIGNED + nfsm_rndup(siz);
777                 } else {
778                         tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb,
779                             bpos);
780                         *tl++ = txdr_unsigned(siz);
781                         bcopy(name, tl, siz);
782                         len += NFSX_UNSIGNED + nfsm_rndup(siz);
783                 }
784                 FA4_SET(FA4_OWNER_GROUP, bmvalp);
785         }
786         if (vap->va_atime.tv_sec != VNOVAL) {
787                 uint64_t val = vap->va_atime.tv_sec;
788                 tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos);
789                 FA4_SET(FA4_TIME_ACCESS_SET, bmvalp);
790                 *tl++ = txdr_unsigned(THCLIENTTIME);
791                 txdr_hyper(val, tl); tl += 2;
792                 *tl++ = txdr_unsigned(vap->va_atime.tv_nsec);
793                 len += 4 * NFSX_UNSIGNED;
794         }
795         if (vap->va_mtime.tv_sec != VNOVAL) {
796                 uint64_t val = vap->va_mtime.tv_sec;
797                 tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos);
798                 FA4_SET(FA4_TIME_MODIFY_SET, bmvalp);
799                 *tl++ = txdr_unsigned(THCLIENTTIME);
800                 txdr_hyper(val, tl); tl += 2;
801                 *tl++ = txdr_unsigned(vap->va_mtime.tv_nsec);
802                 len += 4 * NFSX_UNSIGNED;
803         }
804
805         bmvalp[0] = txdr_unsigned(bmvalp[0]);
806         bmvalp[1] = txdr_unsigned(bmvalp[1]);
807
808         *attrlenp = txdr_unsigned(len);
809
810         return (0);
811 }
812
813 int
814 nfsm_v4dissect_compound_xx(struct nfs4_compound *cp, struct mbuf **md, caddr_t *dpos)
815 {
816         uint32_t taglen, t1, *tl;
817
818         tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
819         if (tl == NULL)
820                 return (EBADRPC);
821
822         /* Reply status is handled by the RPC code */
823
824         taglen = fxdr_unsigned(uint32_t, *tl++);
825         t1 = nfsm_adv_xx(nfsm_rndup(taglen), md, dpos);
826         if (t1 != 0)
827                 return (EBADRPC);
828
829         tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
830         if (tl == NULL)
831                 return (EBADRPC);
832
833         cp->rep_nops = fxdr_unsigned(uint32_t, *tl++);
834
835         return (0);
836 }
837
838 int
839 nfsm_v4dissect_simple_xx(struct nfs4_compound *cp, uint32_t op,
840     uint32_t skipbytes, struct mbuf **md, caddr_t *dpos)
841 {
842         uint32_t t1, dop, status;
843
844         t1 = nfsm_dissectf_xx(md, dpos, "uu", &dop, &status);
845         if (t1 != 0)
846                 return (t1);
847
848         if (dop != op || status != 0)
849                 return (EBADRPC);
850
851         if (skipbytes > 0)
852                 NFSM_ADV(nfsm_rndup(skipbytes));
853
854         return (0);
855 }
856
857 int
858 nfsm_v4dissect_getattr_xx(struct nfs4_compound *cp, struct nfs4_oparg_getattr *ga,
859     struct mbuf **md, caddr_t *dpos)
860 {
861         uint32_t *tl;
862
863         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
864         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_GETATTR ||
865             *tl++ != 0)
866                 return (EBADRPC);
867
868         return (nfsm_v4dissect_attrs_xx(&ga->fa, md, dpos));
869 }
870
871 int
872 nfsm_v4dissect_setattr_xx(struct nfs4_compound *cp, struct mbuf **md, caddr_t *dpos)
873 {
874         uint32_t t1, op, bmlen, status;
875
876         t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
877         if (t1 != 0)
878                 return (t1);
879
880         if (op != NFSV4OP_SETATTR || status != 0)
881                 return (EBADRPC);
882
883         t1 = nfsm_dissectf_xx(md, dpos, "u", &bmlen);
884         if (t1 != 0)
885                 return (t1);
886
887         return (nfsm_dissectf_xx(md, dpos, "k", bmlen << 2));
888 }
889
890 int
891 nfsm_v4dissect_getfh_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh,
892     struct mbuf **md, caddr_t *dpos)
893 {
894         uint32_t *tl, len, xdrlen;
895
896         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
897         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_GETFH)
898                 return (EBADRPC);
899
900         if (*tl++ != 0)
901                 return (EBADRPC);
902
903         NFSM_DISSECT(NFSX_UNSIGNED);
904         len = fxdr_unsigned(uint32_t, *tl++);
905         if (len > NFSX_V4FH)
906                 return (EBADRPC);
907
908         /* XXX integrate this into nfs_mtofh()? */
909
910         gfh->fh_len = len;
911         xdrlen = nfsm_rndup(len);
912
913         NFSM_DISSECT(xdrlen);
914         bcopy(tl, &gfh->fh_val, xdrlen);
915
916         return (0);
917 }
918
919 int
920 nfsm_v4dissect_setclientid_xx(struct nfs4_compound *cp,
921     struct nfs4_oparg_setclientid *sci, struct mbuf **md, caddr_t *dpos)
922 {
923         uint32_t *tl;
924
925         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
926         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_SETCLIENTID)
927                 return (EBADRPC);
928
929         /* Handle NFS4ERR_CLID_INUSE specially */
930         if (*tl++ != 0)
931                 return (EBADRPC);
932
933         NFSM_DISSECT(2 * NFSX_UNSIGNED);
934         sci->clientid = fxdr_hyper(tl);
935
936         NFSM_DISSECT(nfsm_rndup(NFSX_V4VERF));
937         bcopy(tl, sci->verf, NFSX_V4VERF);
938
939         return (0);
940 }
941
942 int
943 nfsm_v4dissect_close_xx(struct nfs4_compound *cp, struct nfs4_fctx *fcp,
944     struct mbuf **md, caddr_t *dpos)
945 {
946         uint32_t *tl, t1;
947
948         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
949         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_CLOSE ||
950             *tl++ != 0)
951                 return (EBADRPC);
952
953         /* Copy stateid */
954         t1 = nfsm_dissectf_xx(md, dpos, "o", NFSX_V4STATEID, fcp->stateid);
955         if (t1 != 0)
956                 return (t1);
957
958         return (0);
959 }
960
961 int
962 nfsm_v4dissect_access_xx(struct nfs4_compound *cp, struct nfs4_oparg_access *acc,
963     struct mbuf **md, caddr_t *dpos)
964 {
965         uint32_t *tl;
966
967         tl = nfsm_dissect_xx(4 * NFSX_UNSIGNED, md, dpos);
968         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_ACCESS ||
969             *tl++ != 0)
970                 return (EBADRPC);
971
972         acc->supported = fxdr_unsigned(uint32_t, *tl++);
973         acc->rmode = fxdr_unsigned(uint32_t, *tl++);
974
975         return (0);
976 }
977
978 int
979 nfsm_v4dissect_open_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
980     struct mbuf **md, caddr_t *dpos)
981 {
982         uint32_t *tl, t1, bmlen, delegtype = ODNONE;
983         int error = 0;
984         nfsv4changeinfo cinfo;
985         struct nfs4_fctx *fcp = op->fcp;
986
987         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
988         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_OPEN ||
989             *tl++ != 0)
990                 return (EBADRPC);
991
992         t1 = nfsm_dissectf_xx(md, dpos, "o", NFSX_V4STATEID, fcp->stateid);
993         if (t1 != 0)
994                 return (t1);
995
996         error = nfsm_v4dissect_changeinfo_xx(&cinfo, md, dpos);
997         if (error != 0)
998                 goto nfsmout;
999
1000         NFSM_DISSECT(2 * NFSX_UNSIGNED);
1001
1002         op->rflags = fxdr_unsigned(uint32_t, *tl++);
1003         bmlen = fxdr_unsigned(uint32_t, *tl++);
1004         if (bmlen > 2) {
1005                 error = EBADRPC;
1006                 goto nfsmout;
1007         }
1008
1009         /* Skip */
1010         NFSM_ADV(nfsm_rndup(bmlen << 2));
1011
1012         NFSM_DISSECT(NFSX_UNSIGNED);
1013         delegtype = fxdr_unsigned(uint32_t, *tl++);
1014         switch (delegtype) {
1015         case ODREAD:
1016         case ODWRITE:
1017                 printf("nfs4: client delegation not yet supported\n");
1018                 error = EOPNOTSUPP;
1019                 goto nfsmout;
1020                 break;
1021         case ODNONE:
1022         default:
1023                 break;
1024         }
1025
1026  nfsmout:
1027         return (error);
1028 }
1029
1030 int
1031 nfsm_v4dissect_open_confirm_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
1032     struct mbuf **md, caddr_t *dpos)
1033 {
1034         uint32_t *tl;
1035
1036         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
1037         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_OPEN_CONFIRM ||
1038             *tl++ != 0)
1039                 return (EBADRPC);
1040
1041         return nfsm_dissectf_xx(md, dpos, "o", NFSX_V4STATEID, op->fcp->stateid);
1042 }
1043
1044 int
1045 nfsm_v4dissect_read_xx(struct nfs4_compound *cp, struct nfs4_oparg_read *r,
1046     struct mbuf **md, caddr_t *dpos)
1047 {
1048         uint32_t op, status, t1;
1049
1050         t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1051         if (t1 != 0)
1052                 return (t1);
1053
1054         if (op != NFSV4OP_READ || status != 0)
1055                 return (EBADRPC);
1056
1057         t1 = nfsm_dissectf_xx(md, dpos, "uu", &r->eof, &r->retlen);
1058         if (t1 != 0)
1059                 return (t1);
1060
1061         return (nfsm_mbuftouio(md, r->uiop, r->retlen, dpos));
1062 }
1063
1064 int
1065 nfsm_v4dissect_write_xx(struct nfs4_compound *cp, struct nfs4_oparg_write *w,
1066     struct mbuf **md, caddr_t *dpos)
1067 {
1068         uint32_t op, status, t1;
1069
1070         t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1071         if (t1 != 0)
1072                 return (t1);
1073
1074         if (op != NFSV4OP_WRITE || status != 0)
1075                 return (EBADRPC);
1076
1077         return (nfsm_dissectf_xx(md, dpos, "uuo", &w->retlen, &w->committed,
1078                     NFSX_V4VERF, w->wverf));
1079 }
1080
1081 int
1082 nfsm_v4dissect_commit_xx(struct nfs4_compound *cp, struct nfs4_oparg_commit *c,
1083     struct mbuf **md, caddr_t *dpos)
1084 {
1085         uint32_t t1, op, status;
1086
1087         t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1088         if (t1 != 0)
1089                 return (t1);
1090
1091         if (op != NFSV4OP_COMMIT || status != 0)
1092                 return (EBADRPC);
1093
1094         return (nfsm_dissectf_xx(md, dpos, "o", NFSX_V4VERF, c->verf));
1095 }
1096
1097 int
1098 nfsm_v4dissect_create_xx(struct nfs4_compound *cp, struct nfs4_oparg_create *c,
1099     struct mbuf **md, caddr_t *dpos)
1100 {
1101         uint32_t t1, *tl, op, status, bmlen;
1102         nfsv4changeinfo ci;
1103
1104         t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1105         if (t1 != 0)
1106                 return (t1);
1107
1108         if (op != NFSV4OP_CREATE || status != 0)
1109                 return (EBADRPC);
1110
1111         /* Just throw this away for now */
1112         t1 = nfsm_v4dissect_changeinfo_xx(&ci, md, dpos);
1113         if (t1 != 0)
1114                 return (t1);
1115
1116         /* Throw this away too */
1117         NFSM_DISSECT(NFSX_UNSIGNED);
1118         bmlen = fxdr_unsigned(uint32_t, *tl++);
1119         NFSM_DISSECT(bmlen * NFSX_UNSIGNED);
1120         tl += bmlen;
1121
1122         return 0;
1123 }
1124
1125 int
1126 nfsm_v4dissect_readlink_xx(struct nfs4_compound *cp, struct uio *uiop, 
1127     struct mbuf **md, caddr_t *dpos)
1128 {
1129         uint32_t t1, *tl, op, status, linklen;
1130
1131         t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1132         if (t1 != 0)
1133                 return (t1);
1134
1135         if (op != NFSV4OP_READLINK || status != 0)
1136                 return (EBADRPC);
1137
1138         /* Do this one manually for careful checking of sizes. */
1139         NFSM_DISSECT(NFSX_UNSIGNED);
1140         linklen = fxdr_unsigned(uint32_t, *tl++);
1141         if (linklen <= 0)
1142                 return (EBADRPC);
1143
1144         return (nfsm_mbuftouio(md, uiop, MIN(linklen, uiop->uio_resid), dpos));
1145 }
1146
1147 int
1148 nfsm_v4dissect_changeinfo_xx(nfsv4changeinfo *ci,
1149     struct mbuf **md, caddr_t *dpos)
1150 {
1151         uint32_t *tl;
1152
1153         NFSM_DISSECT(5 * NFSX_UNSIGNED);
1154
1155         ci->ciatomic = fxdr_unsigned(uint32_t, *tl++);
1156         ci->cibefore = fxdr_hyper(tl); tl += 2;
1157         ci->ciafter = fxdr_hyper(tl); tl += 2;
1158
1159         return (0);
1160 }
1161
1162 int
1163 nfsm_v4dissect_attrs_xx(struct nfsv4_fattr *fa, struct mbuf **md, caddr_t *dpos)
1164 {
1165         uint32_t t1, *tl, bmlen, bmval[2], attrlen, len = 0;
1166
1167         /* Bitmap length + value */
1168         NFSM_DISSECT(NFSX_UNSIGNED);
1169
1170         bmlen = fxdr_unsigned(uint32_t, *tl++);
1171         if (bmlen > 2)
1172                 return (EBADRPC);
1173
1174         if (bmlen == 0)
1175                 return (0);
1176
1177         NFSM_DISSECT(nfsm_rndup(bmlen << 2) + NFSX_UNSIGNED);
1178
1179         bmval[0] = bmlen > 0 ? fxdr_unsigned(uint32_t, *tl++) : 0;
1180         bmval[1] = bmlen > 1 ? fxdr_unsigned(uint32_t, *tl++) : 0;
1181
1182         /* Attribute length */
1183         attrlen = fxdr_unsigned(uint32_t, *tl++);
1184
1185         /*
1186          * XXX check for correct (<=) attributes mask return from
1187          * server.  need to pass this in.
1188          */
1189
1190         if (FA4_ISSET(FA4_TYPE, bmval)) {
1191                 /* overflow check */
1192                 NFSM_DISSECT(NFSX_UNSIGNED);
1193                 fa->fa4_type = fxdr_unsigned(uint32_t, *tl++);
1194                 fa->fa4_valid |= FA4V_TYPE;
1195                 len += NFSX_UNSIGNED;
1196         }
1197         if (FA4_ISSET(FA4_CHANGE, bmval)) {
1198                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1199                 fa->fa4_changeid = fxdr_hyper(tl);
1200                 fa->fa4_valid |= FA4V_CHANGEID;
1201                 len += 2 * NFSX_UNSIGNED;
1202         }
1203         if (FA4_ISSET(FA4_SIZE, bmval)) {
1204                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1205                 fa->fa4_size = fxdr_hyper(tl);
1206                 fa->fa4_valid |= FA4V_SIZE;
1207                 len += 2 * NFSX_UNSIGNED;
1208         }
1209         if (FA4_ISSET(FA4_FSID, bmval)) {
1210                 NFSM_DISSECT(4 * NFSX_UNSIGNED);
1211                 fa->fa4_fsid_major = fxdr_hyper(tl); tl += 2;
1212                 fa->fa4_fsid_minor = fxdr_hyper(tl);
1213                 fa->fa4_valid |= FA4V_SIZE;
1214                 len += 4 * NFSX_UNSIGNED;
1215         }
1216         if (FA4_ISSET(FA4_LEASE_TIME, bmval)) {
1217                 NFSM_DISSECT(NFSX_UNSIGNED);
1218                 fa->fa4_lease_time = fxdr_unsigned(uint32_t, *tl++);
1219                 fa->fa4_valid |= FA4V_LEASE_TIME;
1220                 len += NFSX_UNSIGNED;
1221         }
1222         if (FA4_ISSET(FA4_FILEID, bmval)) {
1223                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1224                 fa->fa4_fileid = fxdr_hyper(tl);
1225                 fa->fa4_valid |= FA4V_FILEID;
1226                 len += 2 * NFSX_UNSIGNED;
1227         }
1228         if (FA4_ISSET(FA4_FILES_FREE, bmval)) {
1229                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1230                 fa->fa4_ffree = fxdr_hyper(tl);
1231                 fa->fa4_valid |= FA4V_FFREE;
1232                 len += 2 * NFSX_UNSIGNED;
1233         }
1234         if (FA4_ISSET(FA4_FILES_TOTAL, bmval)) {
1235                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1236                 fa->fa4_ftotal = fxdr_hyper(tl);
1237                 fa->fa4_valid |= FA4V_FTOTAL;
1238                 len += 2 * NFSX_UNSIGNED;
1239         }
1240         if (FA4_ISSET(FA4_MAXFILESIZE, bmval)) {
1241                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1242                 fa->fa4_maxfilesize = fxdr_hyper(tl);
1243                 fa->fa4_valid |= FA4V_MAXFILESIZE;
1244                 len += 2 * NFSX_UNSIGNED;
1245         }
1246         if (FA4_ISSET(FA4_MAXNAME, bmval)) {
1247                 NFSM_DISSECT(NFSX_UNSIGNED);
1248                 fa->fa4_maxname = fxdr_unsigned(uint32_t, *tl++);
1249                 fa->fa4_valid |= FA4V_MAXNAME;
1250                 len += NFSX_UNSIGNED;
1251         }
1252         if (FA4_ISSET(FA4_MAXREAD, bmval)) {
1253                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1254                 fa->fa4_maxread = fxdr_hyper(tl);
1255                 fa->fa4_valid |= FA4V_MAXREAD;
1256                 len += 2 * NFSX_UNSIGNED;
1257         }
1258         if (FA4_ISSET(FA4_MAXWRITE, bmval)) {
1259                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1260                 fa->fa4_maxwrite = fxdr_hyper(tl);
1261                 fa->fa4_valid |= FA4V_MAXWRITE;
1262                 len += 2 * NFSX_UNSIGNED;
1263         }
1264
1265         if (FA4_ISSET(FA4_MODE, bmval)) {
1266                 NFSM_DISSECT(NFSX_UNSIGNED);
1267                 fa->fa4_mode = fxdr_unsigned(mode_t, *tl++);
1268                 fa->fa4_valid |= FA4V_MODE;
1269                 len += NFSX_UNSIGNED;
1270         }
1271         if (FA4_ISSET(FA4_NUMLINKS, bmval)) {
1272                 NFSM_DISSECT(NFSX_UNSIGNED);
1273                 fa->fa4_nlink = fxdr_unsigned(nlink_t, *tl++);
1274                 fa->fa4_valid |= FA4V_NLINK;
1275                 len += NFSX_UNSIGNED;
1276         }
1277         if (FA4_ISSET(FA4_OWNER, bmval)) {
1278                 uint32_t ownerlen;
1279                 int error;
1280
1281                 NFSM_DISSECT(NFSX_UNSIGNED);
1282
1283                 ownerlen = fxdr_unsigned(uint32_t, *tl++);
1284                 NFSM_DISSECT(nfsm_rndup(ownerlen));
1285                 error = idmap_name_to_uid((char *)tl, ownerlen, &fa->fa4_uid);
1286                 if (error) 
1287                         fa->fa4_uid = -2;
1288                 fa->fa4_valid |= FA4V_UID;
1289                 len += NFSX_UNSIGNED + nfsm_rndup(ownerlen);
1290         }
1291         if (FA4_ISSET(FA4_OWNER_GROUP, bmval)) {
1292                 uint32_t ownergrouplen;
1293                 int error;
1294
1295                 NFSM_DISSECT(NFSX_UNSIGNED);
1296                 ownergrouplen = fxdr_unsigned(uint32_t, *tl++);
1297                 NFSM_DISSECT(nfsm_rndup(ownergrouplen));
1298                 error = idmap_name_to_gid((char *)tl, ownergrouplen, &fa->fa4_gid);
1299                 if (error) 
1300                         fa->fa4_gid = -2;
1301                 fa->fa4_valid |= FA4V_GID;
1302                 len += NFSX_UNSIGNED + nfsm_rndup(ownergrouplen);
1303         }
1304         if (FA4_ISSET(FA4_RAWDEV, bmval)) {
1305                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1306                 fa->fa4_rdev_major = fxdr_unsigned(uint32_t, *tl++);
1307                 fa->fa4_rdev_minor = fxdr_unsigned(uint32_t, *tl++);
1308                 fa->fa4_valid |= FA4V_RDEV;
1309                 len += 2 * NFSX_UNSIGNED;
1310         }
1311         if (FA4_ISSET(FA4_SPACE_AVAIL, bmval)) {
1312                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1313                 fa->fa4_savail = fxdr_hyper(tl);
1314                 fa->fa4_valid |= FA4V_SAVAIL;
1315                 len += 2 * NFSX_UNSIGNED;
1316         }
1317         if (FA4_ISSET(FA4_SPACE_FREE, bmval)) {
1318                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1319                 fa->fa4_sfree = fxdr_hyper(tl);
1320                 fa->fa4_valid |= FA4V_SFREE;
1321                 len += 2 * NFSX_UNSIGNED;
1322         }
1323         if (FA4_ISSET(FA4_SPACE_TOTAL, bmval)) {
1324                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1325                 fa->fa4_stotal = fxdr_hyper(tl);
1326                 fa->fa4_valid |= FA4V_STOTAL;
1327                 len += 2 * NFSX_UNSIGNED;
1328         }
1329         if (FA4_ISSET(FA4_SPACE_USED, bmval)) {
1330                 NFSM_ADV(2 * NFSX_UNSIGNED);
1331                 len += 2 * NFSX_UNSIGNED;
1332         }
1333         if (FA4_ISSET(FA4_TIME_ACCESS, bmval)) {
1334                 NFSM_MTOTIME(fa->fa4_atime);
1335                 fa->fa4_valid |= FA4V_ATIME;
1336                 len += 3 * NFSX_UNSIGNED;
1337         }
1338         if (FA4_ISSET(FA4_TIME_CREATE, bmval)) {
1339                 NFSM_MTOTIME(fa->fa4_ctime);
1340                 fa->fa4_valid |= FA4V_CTIME;
1341                 len += 3 * NFSX_UNSIGNED;
1342         }
1343         if (FA4_ISSET(FA4_TIME_MODIFY, bmval)) {
1344                 NFSM_MTOTIME(fa->fa4_mtime);
1345                 fa->fa4_valid |= FA4V_MTIME;
1346                 len += 3 * NFSX_UNSIGNED;
1347         }
1348
1349         if (len != attrlen)
1350                 return (EBADRPC);
1351
1352         return (0);
1353 }