]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - 6/sys/nfs4client/nfs4_subs.c
Clone Kip's Xen on stable/6 tree so that I can work on improving FreeBSD/amd64
[FreeBSD/FreeBSD.git] / 6 / 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
135         FA4_SET(FA4_TYPE, __readdir_bm);
136         FA4_SET(FA4_FSID, __readdir_bm);
137         FA4_SET(FA4_FILEID, __readdir_bm);
138         FA4_SET(FA4_RDATTR_ERROR, __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         static char zero_stateid[NFSX_V4STATEID];
425
426         nfsm_buildf_xx(mb, bpos, "uo",
427             NFSV4OP_SETATTR,
428             NFSX_V4STATEID, fcp ? fcp->stateid : zero_stateid);
429         error = nfsm_v4build_attrs_xx(vap, mb, bpos);
430         if (error == 0)
431                 cp->req_nops++;
432
433         return (error);
434 }
435
436 int
437 nfsm_v4build_getfh_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh,
438     struct mbuf **mb, caddr_t *bpos)
439 {
440         nfsm_buildf_xx(mb, bpos, "u", NFSV4OP_GETFH);
441
442         gfh->vp = cp->curvp;
443         cp->req_nops++;
444
445         return (0);
446 }
447
448 int
449 nfsm_v4build_lookup_xx(struct nfs4_compound *cp, struct nfs4_oparg_lookup *l,
450     struct mbuf **mb, caddr_t *bpos)
451 {
452         nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_LOOKUP, l->namelen, l->name);
453
454         cp->curvp = l->vp;
455         cp->req_nops++;
456
457         return (0);
458 }
459
460 int
461 nfsm_v4build_setclientid_xx(struct nfs4_compound *cp,
462     struct nfs4_oparg_setclientid *sci, struct mbuf **mb, caddr_t *bpos)
463 {
464         struct timeval tv;
465
466         microtime(&tv);
467
468         nfsm_buildf_xx(mb, bpos, "uuusussu",
469             NFSV4OP_SETCLIENTID,
470             tv.tv_sec, tv.tv_usec,
471             sci->namelen, sci->name,
472             sci->cb_prog,
473             sci->cb_netidlen, sci->cb_netid,
474             sci->cb_univaddrlen, sci->cb_univaddr,
475             0xCA11BACC);
476
477         cp->req_nops++;
478
479         return (0);
480 }
481
482 int
483 nfsm_v4build_setclientid_confirm_xx(struct nfs4_compound *cp,
484     struct nfs4_oparg_setclientid *sci, struct mbuf **mb, caddr_t *bpos)
485 {
486         nfsm_buildf_xx(mb, bpos, "uho",
487             NFSV4OP_SETCLIENTID_CONFIRM,
488             sci->clientid,
489             sizeof(sci->verf), sci->verf);
490
491         cp->req_nops++;
492
493         return (0);
494 }
495
496 int
497 nfsm_v4build_open_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
498     struct mbuf **mb, caddr_t *bpos)
499 {
500         int error = 0;
501         struct nfs4_lowner *lop = op->fcp->lop;
502
503         nfsm_buildf_xx(mb, bpos, "uuuuhuu",
504             NFSV4OP_OPEN,
505             lop->lo_seqid,
506             op->flags & O_ACCMODE,
507             NFSV4OPENSHARE_DENY_NONE,
508             cp->nmp->nm_clientid,
509             4, lop->lo_id);
510
511         if (op->flags & O_CREAT) {
512                 nfsm_buildf_xx(mb, bpos, "u", OTCREATE);
513                 /* openflag4: mode */
514                 nfsm_buildf_xx(mb, bpos, "u", CMUNCHECKED);
515                 /* openflag4: createattrs... */
516                 if (op->vap != NULL) {
517                         if (op->flags & O_TRUNC)
518                                 op->vap->va_size = 0;
519                         error = nfsm_v4build_attrs_xx(op->vap, mb, bpos);
520                         if (error != 0)
521                                 return (error);
522                 } else
523                         nfsm_buildf_xx(mb, bpos, "uu", 0, 0);
524         } else
525                 nfsm_buildf_xx(mb, bpos, "u", OTNOCREATE);
526
527         nfsm_buildf_xx(mb, bpos, "us", op->ctype,
528             op->cnp->cn_namelen, op->cnp->cn_nameptr);
529
530         cp->seqidused = cp->req_nops++;
531         cp->fcp = op->fcp;
532
533         return (error);
534 }
535
536 /*
537  * XXX
538  * - Wait on recovery
539  */
540 int
541 nfsm_v4build_open_confirm_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
542     struct mbuf **mb, caddr_t *bpos)
543 {
544         nfsm_buildf_xx(mb, bpos, "uou",
545             NFSV4OP_OPEN_CONFIRM,
546             NFSX_V4STATEID, op->fcp->stateid,
547             op->fcp->lop->lo_seqid);
548
549         cp->seqidused = cp->req_nops++;
550         cp->fcp = op->fcp;
551
552         return (0);
553 }
554
555 /*
556  * XXX
557  * - Wait on recovery
558  */
559 int
560 nfsm_v4build_close_xx(struct nfs4_compound *cp, struct nfs4_fctx *fcp,
561     struct mbuf **mb, caddr_t *bpos)
562 {
563         struct nfs4_lowner *lop = fcp->lop;
564
565         nfsm_buildf_xx(mb, bpos, "uuo",
566             NFSV4OP_CLOSE,
567             lop->lo_seqid,
568             NFSX_V4STATEID, fcp->stateid);
569
570         cp->seqidused = cp->req_nops++;
571         cp->fcp = fcp;
572
573         return (0);
574 }
575
576 int
577 nfsm_v4build_access_xx(struct nfs4_compound *cp, struct nfs4_oparg_access *acc,
578     struct mbuf **mb, caddr_t *bpos)
579 {
580         nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_ACCESS, acc->mode);
581         cp->req_nops++;
582
583         return (0);
584 }
585
586 int
587 nfsm_v4build_read_xx(struct nfs4_compound *cp, struct nfs4_oparg_read *r,
588     struct mbuf **mb, caddr_t *bpos)
589 {
590         nfsm_buildf_xx(mb, bpos, "uohu",
591             NFSV4OP_READ,
592             NFSX_V4STATEID, r->fcp->stateid,
593             r->off,
594             r->maxcnt);
595         cp->req_nops++;
596
597         return (0);
598 }
599
600 int
601 nfsm_v4build_write_xx(struct nfs4_compound *cp, struct nfs4_oparg_write *w,
602     struct mbuf **mb, caddr_t *bpos)
603 {
604         nfsm_buildf_xx(mb, bpos, "uohuu",
605             NFSV4OP_WRITE,
606             NFSX_V4STATEID, w->fcp->stateid,
607             w->off,
608             w->stable,
609             w->cnt);
610         cp->req_nops++;
611         return (nfsm_uiotombuf(w->uiop, mb, w->cnt, bpos));
612 }
613
614 int
615 nfsm_v4build_commit_xx(struct nfs4_compound *cp, struct nfs4_oparg_commit *c,
616     struct mbuf **mb, caddr_t *bpos)
617 {
618         nfsm_buildf_xx(mb, bpos, "uhu", NFSV4OP_COMMIT, c->start, c->len);
619         cp->req_nops++;
620
621         return (0);
622 }
623
624 int
625 nfsm_v4build_readdir_xx(struct nfs4_compound *cp, struct nfs4_oparg_readdir *r,
626     struct mbuf **mb, caddr_t *bpos)
627 {
628         int i;
629
630         nfsm_buildf_xx(mb, bpos, "uhouuu",
631             NFSV4OP_READDIR,
632             r->cookie,
633             sizeof(r->verf), r->verf,
634             r->cnt >> 4,        /* meaningless "dircount" field */
635             r->cnt,
636             r->bm->bmlen);
637
638         for (i = 0; i < r->bm->bmlen; i++)
639                 nfsm_buildf_xx(mb, bpos, "u", r->bm->bmval[i]);
640
641         cp->req_nops++;
642
643         return (0);
644 }
645
646 int
647 nfsm_v4build_renew_xx(struct nfs4_compound *cp, uint64_t cid,
648     struct mbuf **mb, caddr_t *bpos)
649 {
650         nfsm_buildf_xx(mb, bpos, "uh", NFSV4OP_RENEW, cid);
651         cp->req_nops++;
652
653         return (0);
654 }
655
656 int
657 nfsm_v4build_create_xx(struct nfs4_compound *cp, struct nfs4_oparg_create *c,
658     struct mbuf **mb, caddr_t *bpos)
659 {
660         uint32_t t1;
661
662         nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_CREATE, c->type);
663
664         if (c->type == NFLNK)
665                 /* XXX strlen */
666                 nfsm_buildf_xx(mb, bpos, "s", strlen(c->linktext), c->linktext);
667         else if (c->type == NFCHR || c->type == NFBLK)
668                 nfsm_buildf_xx(mb, bpos, "uu",
669                     umajor(c->vap->va_rdev), uminor(c->vap->va_rdev));
670
671         /* Name */
672         nfsm_buildf_xx(mb, bpos, "s", c->namelen, c->name);     
673
674         /* Attributes */
675         t1 = nfsm_v4build_attrs_xx(c->vap, mb, bpos);
676         if (t1 != 0)
677                 return (t1);
678
679         cp->req_nops++;
680
681         return (0);
682 }
683
684 int
685 nfsm_v4build_rename_xx(struct nfs4_compound *cp, struct nfs4_oparg_rename *r,
686     struct mbuf **mb, caddr_t *bpos)
687 {
688         nfsm_buildf_xx(mb, bpos, "uss", NFSV4OP_RENAME, r->fnamelen, r->fname,
689             r->tnamelen, r->tname);
690
691         cp->req_nops++;
692
693         return (0);
694 }
695
696 int
697 nfsm_v4build_link_xx(struct nfs4_compound *cp, struct nfs4_oparg_link *l,
698     struct mbuf **mb, caddr_t *bpos)
699 {
700         nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_LINK, l->namelen, l->name);
701
702         cp->req_nops++;
703
704         return (0);
705 }
706
707 int
708 nfsm_v4build_remove_xx(struct nfs4_compound *cp, const char *name, u_int namelen,
709     struct mbuf **mb, caddr_t *bpos)
710 {
711         nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_REMOVE, namelen, name);
712
713         cp->req_nops++;
714
715         return (0);
716 }
717
718 int
719 nfsm_v4build_attrs_xx(struct vattr *vap, struct mbuf **mb, caddr_t *bpos)
720 {
721         uint32_t *tl, *attrlenp, *bmvalp, len;
722         size_t siz;
723
724         tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos);
725
726         *tl++ = txdr_unsigned(2);    /* bitmap length */
727         bmvalp = tl;
728         bzero(bmvalp, 8);
729         tl += 2;
730         attrlenp = tl;
731
732         len = 0;
733         if (vap->va_size != VNOVAL) {
734                 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
735                 FA4_SET(FA4_SIZE, bmvalp);
736                 txdr_hyper(vap->va_size, tl); tl += 2;
737                 len += 2 * NFSX_UNSIGNED;
738         }
739         if (vap->va_mode != (u_short)VNOVAL) {
740                 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
741                 FA4_SET(FA4_MODE, bmvalp);
742                 *tl++ = txdr_unsigned(vap->va_mode);
743                 len += NFSX_UNSIGNED;
744         }
745         if (vap->va_uid != VNOVAL) {
746                 int error;
747                 char *name;
748                 error = idmap_uid_to_name(vap->va_uid, &name, &siz);
749                 if (error || name == NULL || siz == 0) {
750                         /* XXX */
751                         siz = sizeof("nobody") - 1;
752                         tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb, 
753                             bpos);
754                         *tl++ = txdr_unsigned(siz);
755                         bcopy("nobody", tl, siz);
756                         len += NFSX_UNSIGNED + nfsm_rndup(siz);
757                 } else {
758                         tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb,
759                             bpos);
760                         *tl++ = txdr_unsigned(siz);
761                         bcopy(name, tl, siz);
762                         len += NFSX_UNSIGNED + nfsm_rndup(siz);
763                 }
764                 FA4_SET(FA4_OWNER, bmvalp);
765         }
766         if (vap->va_gid != VNOVAL) {
767                 int error;
768                 char *name;
769                 error = idmap_gid_to_name(vap->va_gid, &name, &siz);
770                 if (error || name == NULL || siz == 0) {
771                         /* XXX */
772                         siz = sizeof("nogroup") - 1;
773                         tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb, 
774                             bpos);
775                         *tl++ = txdr_unsigned(siz);
776                         bcopy("nogroup", tl, siz);
777                         len += NFSX_UNSIGNED + nfsm_rndup(siz);
778                 } else {
779                         tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb,
780                             bpos);
781                         *tl++ = txdr_unsigned(siz);
782                         bcopy(name, tl, siz);
783                         len += NFSX_UNSIGNED + nfsm_rndup(siz);
784                 }
785                 FA4_SET(FA4_OWNER_GROUP, bmvalp);
786         }
787         if (vap->va_atime.tv_sec != VNOVAL) {
788                 uint64_t val = vap->va_atime.tv_sec;
789                 tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos);
790                 FA4_SET(FA4_TIME_ACCESS_SET, bmvalp);
791                 *tl++ = txdr_unsigned(THCLIENTTIME);
792                 txdr_hyper(val, tl); tl += 2;
793                 *tl++ = txdr_unsigned(vap->va_atime.tv_nsec);
794                 len += 4 * NFSX_UNSIGNED;
795         }
796         if (vap->va_mtime.tv_sec != VNOVAL) {
797                 uint64_t val = vap->va_mtime.tv_sec;
798                 tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos);
799                 FA4_SET(FA4_TIME_MODIFY_SET, bmvalp);
800                 *tl++ = txdr_unsigned(THCLIENTTIME);
801                 txdr_hyper(val, tl); tl += 2;
802                 *tl++ = txdr_unsigned(vap->va_mtime.tv_nsec);
803                 len += 4 * NFSX_UNSIGNED;
804         }
805
806         bmvalp[0] = txdr_unsigned(bmvalp[0]);
807         bmvalp[1] = txdr_unsigned(bmvalp[1]);
808
809         *attrlenp = txdr_unsigned(len);
810
811         return (0);
812 }
813
814 int
815 nfsm_v4dissect_compound_xx(struct nfs4_compound *cp, struct mbuf **md, caddr_t *dpos)
816 {
817         uint32_t taglen, t1, *tl;
818
819         tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
820         if (tl == NULL)
821                 return (EBADRPC);
822
823         /* Reply status is handled by the RPC code */
824
825         taglen = fxdr_unsigned(uint32_t, *tl++);
826         t1 = nfsm_adv_xx(nfsm_rndup(taglen), md, dpos);
827         if (t1 != 0)
828                 return (EBADRPC);
829
830         tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
831         if (tl == NULL)
832                 return (EBADRPC);
833
834         cp->rep_nops = fxdr_unsigned(uint32_t, *tl++);
835
836         return (0);
837 }
838
839 int
840 nfsm_v4dissect_simple_xx(struct nfs4_compound *cp, uint32_t op,
841     uint32_t skipbytes, struct mbuf **md, caddr_t *dpos)
842 {
843         uint32_t t1, dop, status;
844
845         t1 = nfsm_dissectf_xx(md, dpos, "uu", &dop, &status);
846         if (t1 != 0)
847                 return (t1);
848
849         if (dop != op || status != 0)
850                 return (EBADRPC);
851
852         if (skipbytes > 0)
853                 NFSM_ADV(nfsm_rndup(skipbytes));
854
855         return (0);
856 }
857
858 int
859 nfsm_v4dissect_getattr_xx(struct nfs4_compound *cp, struct nfs4_oparg_getattr *ga,
860     struct mbuf **md, caddr_t *dpos)
861 {
862         uint32_t *tl;
863
864         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
865         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_GETATTR ||
866             *tl++ != 0)
867                 return (EBADRPC);
868
869         return (nfsm_v4dissect_attrs_xx(&ga->fa, md, dpos));
870 }
871
872 int
873 nfsm_v4dissect_setattr_xx(struct nfs4_compound *cp, struct mbuf **md, caddr_t *dpos)
874 {
875         uint32_t t1, op, bmlen, status;
876
877         t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
878         if (t1 != 0)
879                 return (t1);
880
881         if (op != NFSV4OP_SETATTR || status != 0)
882                 return (EBADRPC);
883
884         t1 = nfsm_dissectf_xx(md, dpos, "u", &bmlen);
885         if (t1 != 0)
886                 return (t1);
887
888         return (nfsm_dissectf_xx(md, dpos, "k", bmlen << 2));
889 }
890
891 int
892 nfsm_v4dissect_getfh_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh,
893     struct mbuf **md, caddr_t *dpos)
894 {
895         uint32_t *tl, len, xdrlen;
896
897         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
898         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_GETFH)
899                 return (EBADRPC);
900
901         if (*tl++ != 0)
902                 return (EBADRPC);
903
904         NFSM_DISSECT(NFSX_UNSIGNED);
905         len = fxdr_unsigned(uint32_t, *tl++);
906         if (len > NFSX_V4FH)
907                 return (EBADRPC);
908
909         /* XXX integrate this into nfs_mtofh()? */
910
911         gfh->fh_len = len;
912         xdrlen = nfsm_rndup(len);
913
914         NFSM_DISSECT(xdrlen);
915         bcopy(tl, &gfh->fh_val, xdrlen);
916
917         return (0);
918 }
919
920 int
921 nfsm_v4dissect_setclientid_xx(struct nfs4_compound *cp,
922     struct nfs4_oparg_setclientid *sci, struct mbuf **md, caddr_t *dpos)
923 {
924         uint32_t *tl;
925
926         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
927         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_SETCLIENTID)
928                 return (EBADRPC);
929
930         /* Handle NFS4ERR_CLID_INUSE specially */
931         if (*tl++ != 0)
932                 return (EBADRPC);
933
934         NFSM_DISSECT(2 * NFSX_UNSIGNED);
935         sci->clientid = fxdr_hyper(tl);
936
937         NFSM_DISSECT(nfsm_rndup(NFSX_V4VERF));
938         bcopy(tl, sci->verf, NFSX_V4VERF);
939
940         return (0);
941 }
942
943 int
944 nfsm_v4dissect_close_xx(struct nfs4_compound *cp, struct nfs4_fctx *fcp,
945     struct mbuf **md, caddr_t *dpos)
946 {
947         uint32_t *tl, t1;
948
949         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
950         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_CLOSE ||
951             *tl++ != 0)
952                 return (EBADRPC);
953
954         /* Copy stateid */
955         t1 = nfsm_dissectf_xx(md, dpos, "o", NFSX_V4STATEID, fcp->stateid);
956         if (t1 != 0)
957                 return (t1);
958
959         return (0);
960 }
961
962 int
963 nfsm_v4dissect_access_xx(struct nfs4_compound *cp, struct nfs4_oparg_access *acc,
964     struct mbuf **md, caddr_t *dpos)
965 {
966         uint32_t *tl;
967
968         tl = nfsm_dissect_xx(4 * NFSX_UNSIGNED, md, dpos);
969         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_ACCESS ||
970             *tl++ != 0)
971                 return (EBADRPC);
972
973         acc->supported = fxdr_unsigned(uint32_t, *tl++);
974         acc->rmode = fxdr_unsigned(uint32_t, *tl++);
975
976         return (0);
977 }
978
979 int
980 nfsm_v4dissect_open_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
981     struct mbuf **md, caddr_t *dpos)
982 {
983         uint32_t *tl, t1, bmlen, delegtype = ODNONE;
984         int error = 0;
985         nfsv4changeinfo cinfo;
986         struct nfs4_fctx *fcp = op->fcp;
987
988         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
989         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_OPEN ||
990             *tl++ != 0)
991                 return (EBADRPC);
992
993         t1 = nfsm_dissectf_xx(md, dpos, "o", NFSX_V4STATEID, fcp->stateid);
994         if (t1 != 0)
995                 return (t1);
996
997         error = nfsm_v4dissect_changeinfo_xx(&cinfo, md, dpos);
998         if (error != 0)
999                 goto nfsmout;
1000
1001         NFSM_DISSECT(2 * NFSX_UNSIGNED);
1002
1003         op->rflags = fxdr_unsigned(uint32_t, *tl++);
1004         bmlen = fxdr_unsigned(uint32_t, *tl++);
1005         if (bmlen > 2) {
1006                 error = EBADRPC;
1007                 goto nfsmout;
1008         }
1009
1010         /* Skip */
1011         NFSM_ADV(nfsm_rndup(bmlen << 2));
1012
1013         NFSM_DISSECT(NFSX_UNSIGNED);
1014         delegtype = fxdr_unsigned(uint32_t, *tl++);
1015         switch (delegtype) {
1016         case ODREAD:
1017         case ODWRITE:
1018                 printf("nfs4: client delegation not yet supported\n");
1019                 error = EOPNOTSUPP;
1020                 goto nfsmout;
1021                 break;
1022         case ODNONE:
1023         default:
1024                 break;
1025         }
1026
1027  nfsmout:
1028         return (error);
1029 }
1030
1031 int
1032 nfsm_v4dissect_open_confirm_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
1033     struct mbuf **md, caddr_t *dpos)
1034 {
1035         uint32_t *tl;
1036
1037         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
1038         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_OPEN_CONFIRM ||
1039             *tl++ != 0)
1040                 return (EBADRPC);
1041
1042         return nfsm_dissectf_xx(md, dpos, "o", NFSX_V4STATEID, op->fcp->stateid);
1043 }
1044
1045 int
1046 nfsm_v4dissect_read_xx(struct nfs4_compound *cp, struct nfs4_oparg_read *r,
1047     struct mbuf **md, caddr_t *dpos)
1048 {
1049         uint32_t op, status, t1;
1050
1051         t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1052         if (t1 != 0)
1053                 return (t1);
1054
1055         if (op != NFSV4OP_READ || status != 0)
1056                 return (EBADRPC);
1057
1058         t1 = nfsm_dissectf_xx(md, dpos, "uu", &r->eof, &r->retlen);
1059         if (t1 != 0)
1060                 return (t1);
1061
1062         return (nfsm_mbuftouio(md, r->uiop, r->retlen, dpos));
1063 }
1064
1065 int
1066 nfsm_v4dissect_write_xx(struct nfs4_compound *cp, struct nfs4_oparg_write *w,
1067     struct mbuf **md, caddr_t *dpos)
1068 {
1069         uint32_t op, status, t1;
1070
1071         t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1072         if (t1 != 0)
1073                 return (t1);
1074
1075         if (op != NFSV4OP_WRITE || status != 0)
1076                 return (EBADRPC);
1077
1078         return (nfsm_dissectf_xx(md, dpos, "uuo", &w->retlen, &w->committed,
1079                     NFSX_V4VERF, w->wverf));
1080 }
1081
1082 int
1083 nfsm_v4dissect_commit_xx(struct nfs4_compound *cp, struct nfs4_oparg_commit *c,
1084     struct mbuf **md, caddr_t *dpos)
1085 {
1086         uint32_t t1, op, status;
1087
1088         t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1089         if (t1 != 0)
1090                 return (t1);
1091
1092         if (op != NFSV4OP_COMMIT || status != 0)
1093                 return (EBADRPC);
1094
1095         return (nfsm_dissectf_xx(md, dpos, "o", NFSX_V4VERF, c->verf));
1096 }
1097
1098 int
1099 nfsm_v4dissect_create_xx(struct nfs4_compound *cp, struct nfs4_oparg_create *c,
1100     struct mbuf **md, caddr_t *dpos)
1101 {
1102         uint32_t t1, *tl, op, status, bmlen;
1103         nfsv4changeinfo ci;
1104
1105         t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1106         if (t1 != 0)
1107                 return (t1);
1108
1109         if (op != NFSV4OP_CREATE || status != 0)
1110                 return (EBADRPC);
1111
1112         /* Just throw this away for now */
1113         t1 = nfsm_v4dissect_changeinfo_xx(&ci, md, dpos);
1114         if (t1 != 0)
1115                 return (t1);
1116
1117         /* Throw this away too */
1118         NFSM_DISSECT(NFSX_UNSIGNED);
1119         bmlen = fxdr_unsigned(uint32_t, *tl++);
1120         NFSM_DISSECT(bmlen * NFSX_UNSIGNED);
1121         tl += bmlen;
1122
1123         return 0;
1124 }
1125
1126 int
1127 nfsm_v4dissect_readlink_xx(struct nfs4_compound *cp, struct uio *uiop, 
1128     struct mbuf **md, caddr_t *dpos)
1129 {
1130         uint32_t t1, *tl, op, status, linklen;
1131
1132         t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
1133         if (t1 != 0)
1134                 return (t1);
1135
1136         if (op != NFSV4OP_READLINK || status != 0)
1137                 return (EBADRPC);
1138
1139         /* Do this one manually for careful checking of sizes. */
1140         NFSM_DISSECT(NFSX_UNSIGNED);
1141         linklen = fxdr_unsigned(uint32_t, *tl++);
1142         if (linklen <= 0)
1143                 return (EBADRPC);
1144
1145         return (nfsm_mbuftouio(md, uiop, MIN(linklen, uiop->uio_resid), dpos));
1146 }
1147
1148 int
1149 nfsm_v4dissect_changeinfo_xx(nfsv4changeinfo *ci,
1150     struct mbuf **md, caddr_t *dpos)
1151 {
1152         uint32_t *tl;
1153
1154         NFSM_DISSECT(5 * NFSX_UNSIGNED);
1155
1156         ci->ciatomic = fxdr_unsigned(uint32_t, *tl++);
1157         ci->cibefore = fxdr_hyper(tl); tl += 2;
1158         ci->ciafter = fxdr_hyper(tl); tl += 2;
1159
1160         return (0);
1161 }
1162
1163 int
1164 nfsm_v4dissect_attrs_xx(struct nfsv4_fattr *fa, struct mbuf **md, caddr_t *dpos)
1165 {
1166         uint32_t t1, *tl, bmlen, bmval[2], attrlen, len = 0;
1167
1168         /* Bitmap length + value */
1169         NFSM_DISSECT(NFSX_UNSIGNED);
1170
1171         bmlen = fxdr_unsigned(uint32_t, *tl++);
1172         if (bmlen > 2)
1173                 return (EBADRPC);
1174
1175         if (bmlen == 0)
1176                 return (0);
1177
1178         NFSM_DISSECT(nfsm_rndup(bmlen << 2) + NFSX_UNSIGNED);
1179
1180         bmval[0] = bmlen > 0 ? fxdr_unsigned(uint32_t, *tl++) : 0;
1181         bmval[1] = bmlen > 1 ? fxdr_unsigned(uint32_t, *tl++) : 0;
1182
1183         /* Attribute length */
1184         attrlen = fxdr_unsigned(uint32_t, *tl++);
1185
1186         /*
1187          * XXX check for correct (<=) attributes mask return from
1188          * server.  need to pass this in.
1189          */
1190
1191         if (FA4_ISSET(FA4_TYPE, bmval)) {
1192                 /* overflow check */
1193                 NFSM_DISSECT(NFSX_UNSIGNED);
1194                 fa->fa4_type = fxdr_unsigned(uint32_t, *tl++);
1195                 fa->fa4_valid |= FA4V_TYPE;
1196                 len += NFSX_UNSIGNED;
1197         }
1198         if (FA4_ISSET(FA4_CHANGE, bmval)) {
1199                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1200                 fa->fa4_changeid = fxdr_hyper(tl);
1201                 fa->fa4_valid |= FA4V_CHANGEID;
1202                 len += 2 * NFSX_UNSIGNED;
1203         }
1204         if (FA4_ISSET(FA4_SIZE, bmval)) {
1205                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1206                 fa->fa4_size = fxdr_hyper(tl);
1207                 fa->fa4_valid |= FA4V_SIZE;
1208                 len += 2 * NFSX_UNSIGNED;
1209         }
1210         if (FA4_ISSET(FA4_FSID, bmval)) {
1211                 NFSM_DISSECT(4 * NFSX_UNSIGNED);
1212                 fa->fa4_fsid_major = fxdr_hyper(tl); tl += 2;
1213                 fa->fa4_fsid_minor = fxdr_hyper(tl);
1214                 fa->fa4_valid |= FA4V_SIZE;
1215                 len += 4 * NFSX_UNSIGNED;
1216         }
1217         if (FA4_ISSET(FA4_LEASE_TIME, bmval)) {
1218                 NFSM_DISSECT(NFSX_UNSIGNED);
1219                 fa->fa4_lease_time = fxdr_unsigned(uint32_t, *tl++);
1220                 fa->fa4_valid |= FA4V_LEASE_TIME;
1221                 len += NFSX_UNSIGNED;
1222         }
1223         if (FA4_ISSET(FA4_RDATTR_ERROR, bmval)) {
1224                 /* ignore for now; we only ask for it so the compound won't fail */
1225                 NFSM_DISSECT(NFSX_UNSIGNED);
1226                 tl++;
1227                 len += NFSX_UNSIGNED;
1228         }
1229         if (FA4_ISSET(FA4_FILEID, bmval)) {
1230                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1231                 fa->fa4_fileid = fxdr_hyper(tl);
1232                 fa->fa4_valid |= FA4V_FILEID;
1233                 len += 2 * NFSX_UNSIGNED;
1234         }
1235         if (FA4_ISSET(FA4_FILES_FREE, bmval)) {
1236                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1237                 fa->fa4_ffree = fxdr_hyper(tl);
1238                 fa->fa4_valid |= FA4V_FFREE;
1239                 len += 2 * NFSX_UNSIGNED;
1240         }
1241         if (FA4_ISSET(FA4_FILES_TOTAL, bmval)) {
1242                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1243                 fa->fa4_ftotal = fxdr_hyper(tl);
1244                 fa->fa4_valid |= FA4V_FTOTAL;
1245                 len += 2 * NFSX_UNSIGNED;
1246         }
1247         if (FA4_ISSET(FA4_MAXFILESIZE, bmval)) {
1248                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1249                 fa->fa4_maxfilesize = fxdr_hyper(tl);
1250                 fa->fa4_valid |= FA4V_MAXFILESIZE;
1251                 len += 2 * NFSX_UNSIGNED;
1252         }
1253         if (FA4_ISSET(FA4_MAXNAME, bmval)) {
1254                 NFSM_DISSECT(NFSX_UNSIGNED);
1255                 fa->fa4_maxname = fxdr_unsigned(uint32_t, *tl++);
1256                 fa->fa4_valid |= FA4V_MAXNAME;
1257                 len += NFSX_UNSIGNED;
1258         }
1259         if (FA4_ISSET(FA4_MAXREAD, bmval)) {
1260                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1261                 fa->fa4_maxread = fxdr_hyper(tl);
1262                 fa->fa4_valid |= FA4V_MAXREAD;
1263                 len += 2 * NFSX_UNSIGNED;
1264         }
1265         if (FA4_ISSET(FA4_MAXWRITE, bmval)) {
1266                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1267                 fa->fa4_maxwrite = fxdr_hyper(tl);
1268                 fa->fa4_valid |= FA4V_MAXWRITE;
1269                 len += 2 * NFSX_UNSIGNED;
1270         }
1271
1272         if (FA4_ISSET(FA4_MODE, bmval)) {
1273                 NFSM_DISSECT(NFSX_UNSIGNED);
1274                 fa->fa4_mode = fxdr_unsigned(mode_t, *tl++);
1275                 fa->fa4_valid |= FA4V_MODE;
1276                 len += NFSX_UNSIGNED;
1277         }
1278         if (FA4_ISSET(FA4_NUMLINKS, bmval)) {
1279                 NFSM_DISSECT(NFSX_UNSIGNED);
1280                 fa->fa4_nlink = fxdr_unsigned(nlink_t, *tl++);
1281                 fa->fa4_valid |= FA4V_NLINK;
1282                 len += NFSX_UNSIGNED;
1283         }
1284         if (FA4_ISSET(FA4_OWNER, bmval)) {
1285                 uint32_t ownerlen;
1286                 int error;
1287
1288                 NFSM_DISSECT(NFSX_UNSIGNED);
1289
1290                 ownerlen = fxdr_unsigned(uint32_t, *tl++);
1291                 NFSM_DISSECT(nfsm_rndup(ownerlen));
1292                 error = idmap_name_to_uid((char *)tl, ownerlen, &fa->fa4_uid);
1293                 if (error) 
1294                         fa->fa4_uid = -2;
1295                 fa->fa4_valid |= FA4V_UID;
1296                 len += NFSX_UNSIGNED + nfsm_rndup(ownerlen);
1297         }
1298         if (FA4_ISSET(FA4_OWNER_GROUP, bmval)) {
1299                 uint32_t ownergrouplen;
1300                 int error;
1301
1302                 NFSM_DISSECT(NFSX_UNSIGNED);
1303                 ownergrouplen = fxdr_unsigned(uint32_t, *tl++);
1304                 NFSM_DISSECT(nfsm_rndup(ownergrouplen));
1305                 error = idmap_name_to_gid((char *)tl, ownergrouplen, &fa->fa4_gid);
1306                 if (error) 
1307                         fa->fa4_gid = -2;
1308                 fa->fa4_valid |= FA4V_GID;
1309                 len += NFSX_UNSIGNED + nfsm_rndup(ownergrouplen);
1310         }
1311         if (FA4_ISSET(FA4_RAWDEV, bmval)) {
1312                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1313                 fa->fa4_rdev_major = fxdr_unsigned(uint32_t, *tl++);
1314                 fa->fa4_rdev_minor = fxdr_unsigned(uint32_t, *tl++);
1315                 fa->fa4_valid |= FA4V_RDEV;
1316                 len += 2 * NFSX_UNSIGNED;
1317         }
1318         if (FA4_ISSET(FA4_SPACE_AVAIL, bmval)) {
1319                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1320                 fa->fa4_savail = fxdr_hyper(tl);
1321                 fa->fa4_valid |= FA4V_SAVAIL;
1322                 len += 2 * NFSX_UNSIGNED;
1323         }
1324         if (FA4_ISSET(FA4_SPACE_FREE, bmval)) {
1325                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1326                 fa->fa4_sfree = fxdr_hyper(tl);
1327                 fa->fa4_valid |= FA4V_SFREE;
1328                 len += 2 * NFSX_UNSIGNED;
1329         }
1330         if (FA4_ISSET(FA4_SPACE_TOTAL, bmval)) {
1331                 NFSM_DISSECT(2 * NFSX_UNSIGNED);
1332                 fa->fa4_stotal = fxdr_hyper(tl);
1333                 fa->fa4_valid |= FA4V_STOTAL;
1334                 len += 2 * NFSX_UNSIGNED;
1335         }
1336         if (FA4_ISSET(FA4_SPACE_USED, bmval)) {
1337                 NFSM_ADV(2 * NFSX_UNSIGNED);
1338                 len += 2 * NFSX_UNSIGNED;
1339         }
1340         if (FA4_ISSET(FA4_TIME_ACCESS, bmval)) {
1341                 NFSM_MTOTIME(fa->fa4_atime);
1342                 fa->fa4_valid |= FA4V_ATIME;
1343                 len += 3 * NFSX_UNSIGNED;
1344         }
1345         if (FA4_ISSET(FA4_TIME_CREATE, bmval)) {
1346                 NFSM_MTOTIME(fa->fa4_ctime);
1347                 fa->fa4_valid |= FA4V_CTIME;
1348                 len += 3 * NFSX_UNSIGNED;
1349         }
1350         if (FA4_ISSET(FA4_TIME_MODIFY, bmval)) {
1351                 NFSM_MTOTIME(fa->fa4_mtime);
1352                 fa->fa4_valid |= FA4V_MTIME;
1353                 len += 3 * NFSX_UNSIGNED;
1354         }
1355
1356         if (len != attrlen)
1357                 return (EBADRPC);
1358
1359         return (0);
1360 }