[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]

FreeBSD/Linux Kernel Cross Reference
sys/nfs4client/nfs4_subs.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD70  -  FREEBSD6  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  1 /* $FreeBSD: src/sys/nfs4client/nfs4_subs.c,v 1.6 2006/11/28 19:33:28 rees Exp $ */
  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_ACCESS, __getattr_bm);
133         FA4_SET(FA4_TIME_CREATE, __getattr_bm);
134         FA4_SET(FA4_TIME_METADATA, __getattr_bm);
135         FA4_SET(FA4_TIME_MODIFY, __getattr_bm);
136 
137         FA4_SET(FA4_TYPE, __readdir_bm);
138         FA4_SET(FA4_FSID, __readdir_bm);
139         FA4_SET(FA4_FILEID, __readdir_bm);
140         FA4_SET(FA4_RDATTR_ERROR, __readdir_bm);
141 }
142 
143 /*
144  * Util
145  */
146 
147 uint32_t
148 nfs_v4fileid4_to_fileid(uint64_t fid)
149 {
150         return ((uint32_t)((fid >> 32) | fid));
151 }
152 
153 void
154 nfs_v4initcompound(struct nfs4_compound *cp)
155 {
156         bzero(cp, sizeof(*cp));
157 }
158 
159 /*
160  * Build/dissect XDR buffer with a format string.
161  *
162  *    u - unsigned
163  *    h - hyper
164  *    s - stringlength, string
165  *    k - skip length (bytes)
166  *    a - arraylength, componentlenght, array
167  *    o - opaque fix length
168  *    O - opaque var length in bytes
169  */
170 
171 void
172 nfsm_buildf_xx(struct mbuf **mb, caddr_t *bpos, char *fmt, ...)
173 {
174         uint32_t *tl, t1, len, uval;
175         uint64_t hval;
176         va_list args;
177         char *p, *which;
178 
179         va_start(args, fmt);
180         for (which = fmt; *which != '\0'; which++)
181                 switch (*which) {
182                 case 'u':       /* Unsigned */
183                         tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
184                         uval = va_arg(args, uint32_t);
185                         *tl++ = txdr_unsigned(uval);
186                         break;
187                 case 'h':       /* Hyper */
188                         tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
189                         hval = va_arg(args, uint64_t);
190                         txdr_hyper(hval, tl);
191                         break;
192                 case 'o':       /* Fixed-length opaque */
193                         len = va_arg(args, uint32_t);
194                         p = va_arg(args, char *);
195                         tl = nfsm_build_xx(nfsm_rndup(len), mb, bpos);
196                         bcopy(p, tl, len);
197                         break;
198                 case 'O':       /* Variable-length opaque */
199                 case 's':       /* String */
200                         len = va_arg(args, uint32_t);
201                         p = va_arg(args, char *);
202                         t1 = nfsm_strtom_xx(p, len, len, mb, bpos);
203                         break;
204                 case 'k':       /* Skip */
205                         len = va_arg(args, uint32_t);
206                         nfsm_build_xx(nfsm_rndup(len), mb, bpos);
207                         break;
208                 default:
209                         panic("Invalid buildf string %s[%c]", fmt, *which);
210                         break;
211                 }
212         va_end(args);
213 }
214 
215 int
216 nfsm_dissectf_xx(struct mbuf **md, caddr_t *dpos, char *fmt, ...)
217 {
218         uint32_t *tl, t1, len, *uval;
219         uint64_t *hval;
220         va_list args;
221         char *p, *which;
222 
223         va_start(args, fmt);
224         for (which = fmt; *which != '\0'; which++)
225                 switch (*which) {
226                 case 'u':       /* Unsigned */
227                         tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
228                         if (tl == NULL)
229                                 return (EBADRPC);
230                         uval = va_arg(args, uint32_t *);
231                         *uval = fxdr_unsigned(uint32_t, *tl++);
232                         break;
233                 case 'h':       /* Hyper */
234                         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
235                         if (tl == NULL)
236                                 return (EBADRPC);
237                         hval = va_arg(args, uint64_t *);
238                         *hval = fxdr_hyper(tl);
239                         break;
240                 case 'o':       /* Fixed-length opaque */
241                         len = va_arg(args, uint32_t);
242                         p = va_arg(args, void *);
243                         tl = nfsm_dissect_xx(nfsm_rndup(len), md, dpos);
244                         if (tl == NULL)
245                                 return (EBADRPC);
246                         bcopy(tl, p, len);
247                         break;
248                 case 'O':       /* Variable-length opaque */
249                 case 's':       /* String */
250                         len = va_arg(args, uint32_t);
251                         p = va_arg(args, char *);
252                         tl = nfsm_dissect_xx(nfsm_rndup(len), md, dpos);
253                         if (tl == NULL)
254                                 return (EBADRPC);
255                         bcopy(tl, p, len);
256                         break;
257                 case 'k':       /* Skip bytes */
258                         len = va_arg(args, uint32_t);
259                         t1 = nfsm_adv_xx(nfsm_rndup(len), md, dpos);
260                         break;
261                 default:
262                         panic("Invalid dissectf string %s[%c]", fmt, *which);
263                         break;
264                 }
265         va_end(args);
266 
267         return (0);
268 }
269 
270 /*
271  * XXX - There are a few problems with the way the postops are places
272  * in the code.  Ideally, they should be taken care of immediately, as
273  * to avoid uneceesary waits for mutexes, but then we would be
274  * introducing even more complexity by having to handle two separate
275  * cases.  Also, since they are placed at the end of the vnops', there
276  * may be operations which sleep in between, further extending this
277  * wait.  It is conceivable that there is a deadlock condition there,
278  * too.
279  *
280  * Also, for vnops that do multiple operations, it's inconvenient
281  * since on error, individual decoding will got nfsmout.
282  */
283 
284 int
285 nfs_v4postop(struct nfs4_compound *cp, int status)
286 {
287         struct nfs4_fctx *fcp = cp->fcp;
288 
289         /*
290          * XXX does the previous result need to be stores with the
291          * lockowner?  ack, spec is unclear ..
292          */
293 
294         if (fcp != NULL)
295                 if (cp->seqidused < cp->rep_nops ||
296                     (cp->seqidused + 1 == cp->rep_nops &&
297                         NFS4_SEQIDMUTATINGERROR(status)))
298                         fcp->lop->lo_seqid++;
299 
300         return (status);
301 }
302 
303 int
304 nfs_v4handlestatus(int status, struct nfs4_compound *cp)
305 {
306         return (status);
307 }
308 
309 /*
310  * Initial setup of compound.
311  */
312 
313 int
314 nfsm_v4build_compound_xx(struct nfs4_compound *cp, char *tag,
315     struct mbuf **mb, caddr_t *bpos)
316 {
317         uint32_t t1, *tl, siz;
318 
319         /* Tag */
320         siz = strlen(tag);
321         t1 = nfsm_rndup(siz) + NFSX_UNSIGNED;
322         if (t1 <= M_TRAILINGSPACE(*mb)) {
323                 tl = nfsm_build_xx(t1, mb, bpos);
324                 *tl++ = txdr_unsigned(siz);
325                 *(tl + ((t1 >> 2) - 2)) = 0;
326                 bcopy(tag, tl, siz);
327         } else {
328                 t1 = nfsm_strtmbuf(mb, bpos, (const char *)tag, siz);
329                 if (t1 != 0)
330                         return (t1);
331         }
332 
333         /* Minor version and argarray*/
334         tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
335         *tl++ = txdr_unsigned(NFS4_MINOR_VERSION);
336         /* Save for backfill */
337         cp->req_nopsp = tl;
338         *tl = txdr_unsigned(0);
339 
340         cp->curvp = NULL;
341         cp->savevp = NULL;
342 
343         return (0);
344 }
345 
346 /*
347  * XXX
348  * - backfill for stateid, and such
349  */
350 int
351 nfsm_v4build_finalize_xx(struct nfs4_compound *cp, struct mbuf **mb, caddr_t *bpos)
352 {
353         *cp->req_nopsp = txdr_unsigned(cp->req_nops);
354 
355         return (0);
356 }
357 
358 int
359 nfsm_v4build_putfh_xx(struct nfs4_compound *cp, struct vnode *vp,
360     struct mbuf **mb, caddr_t *bpos)
361 {
362         uint32_t t1;
363 
364         /* Op */
365         nfsm_buildf_xx(mb, bpos, "u", NFSV4OP_PUTFH);
366 
367         /* FH */
368         t1 = nfsm_fhtom_xx(vp, 1, mb, bpos);
369         if (t1 != 0)
370                 return (t1);
371 
372         cp->req_nops++;
373         cp->curvp = vp;
374 
375         return (0);
376 }
377 
378 int
379 nfsm_v4build_putfh_nv_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh,
380     struct mbuf **mb, caddr_t *bpos)
381 {
382         nfsm_buildf_xx(mb, bpos, "uuo",
383             NFSV4OP_PUTFH,
384             gfh->fh_len,
385             gfh->fh_len,
386             &gfh->fh_val);
387 
388         cp->req_nops++;
389 
390         return (0);
391 }
392 
393 int
394 nfsm_v4build_simple_xx(struct nfs4_compound *cp, uint32_t op,
395     struct mbuf **mb, caddr_t *bpos)
396 {
397         nfsm_buildf_xx(mb, bpos, "u", op);
398 
399         cp->req_nops++;
400 
401         return (0);
402 }
403 
404 int
405 nfsm_v4build_getattr_xx(struct nfs4_compound *cp, struct nfs4_oparg_getattr *ga,
406     struct mbuf **mb, caddr_t *bpos)
407 {
408         int i;
409 
410         /* Op + bitmap length + bitmap */
411         nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_GETATTR, ga->bm->bmlen);
412         for (i = 0; i < ga->bm->bmlen; i++)
413                 nfsm_buildf_xx(mb, bpos, "u", ga->bm->bmval[i]);
414 
415         ga->vp = cp->curvp;
416         cp->req_nops++;          
417 
418         return (0);
419 }
420 
421 int
422 nfsm_v4build_setattr_xx(struct nfs4_compound *cp, struct vattr *vap,
423     struct nfs4_fctx *fcp, struct mbuf **mb, caddr_t *bpos)
424 {
425         int error;
426         static char zero_stateid[NFSX_V4STATEID];
427 
428         nfsm_buildf_xx(mb, bpos, "uo",
429             NFSV4OP_SETATTR,
430             NFSX_V4STATEID, fcp ? fcp->stateid : zero_stateid);
431         error = nfsm_v4build_attrs_xx(vap, mb, bpos);
432         if (error == 0)
433                 cp->req_nops++;
434 
435         return (error);
436 }
437 
438 int
439 nfsm_v4build_getfh_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh,
440     struct mbuf **mb, caddr_t *bpos)
441 {
442         nfsm_buildf_xx(mb, bpos, "u", NFSV4OP_GETFH);
443 
444         gfh->vp = cp->curvp;
445         cp->req_nops++;
446 
447         return (0);
448 }
449 
450 int
451 nfsm_v4build_lookup_xx(struct nfs4_compound *cp, struct nfs4_oparg_lookup *l,
452     struct mbuf **mb, caddr_t *bpos)
453 {
454         nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_LOOKUP, l->namelen, l->name);
455 
456         cp->curvp = l->vp;
457         cp->req_nops++;
458 
459         return (0);
460 }
461 
462 int
463 nfsm_v4build_setclientid_xx(struct nfs4_compound *cp,
464     struct nfs4_oparg_setclientid *sci, struct mbuf **mb, caddr_t *bpos)
465 {
466         struct timeval tv;
467 
468         microtime(&tv);
469 
470         nfsm_buildf_xx(mb, bpos, "uuusussu",
471             NFSV4OP_SETCLIENTID,
472             tv.tv_sec, tv.tv_usec,
473             sci->namelen, sci->name,
474             sci->cb_prog,
475             sci->cb_netidlen, sci->cb_netid,
476             sci->cb_univaddrlen, sci->cb_univaddr,
477             0xCA11BACC);
478 
479         cp->req_nops++;
480 
481         return (0);
482 }
483 
484 int
485 nfsm_v4build_setclientid_confirm_xx(struct nfs4_compound *cp,
486     struct nfs4_oparg_setclientid *sci, struct mbuf **mb, caddr_t *bpos)
487 {
488         nfsm_buildf_xx(mb, bpos, "uho",
489             NFSV4OP_SETCLIENTID_CONFIRM,
490             sci->clientid,
491             sizeof(sci->verf), sci->verf);
492 
493         cp->req_nops++;
494 
495         return (0);
496 }
497 
498 int
499 nfsm_v4build_open_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
500     struct mbuf **mb, caddr_t *bpos)
501 {
502         int error = 0;
503         struct nfs4_lowner *lop = op->fcp->lop;
504 
505         nfsm_buildf_xx(mb, bpos, "uuuuhuu",
506             NFSV4OP_OPEN,
507             lop->lo_seqid,
508             op->flags & O_ACCMODE,
509             NFSV4OPENSHARE_DENY_NONE,
510             cp->nmp->nm_clientid,
511             4, lop->lo_id);
512 
513         if (op->flags & O_CREAT) {
514                 nfsm_buildf_xx(mb, bpos, "u", OTCREATE);
515                 /* openflag4: mode */
516                 nfsm_buildf_xx(mb, bpos, "u", CMUNCHECKED);
517                 /* openflag4: createattrs... */
518                 if (op->vap != NULL) {
519                         if (op->flags & O_TRUNC)
520                                 op->vap->va_size = 0;
521                         error = nfsm_v4build_attrs_xx(op->vap, mb, bpos);
522                         if (error != 0)
523                                 return (error);
524                 } else
525                         nfsm_buildf_xx(mb, bpos, "uu", 0, 0);
526         } else
527                 nfsm_buildf_xx(mb, bpos, "u", OTNOCREATE);
528 
529         nfsm_buildf_xx(mb, bpos, "us", op->ctype,
530             op->cnp->cn_namelen, op->cnp->cn_nameptr);
531 
532         cp->seqidused = cp->req_nops++;
533         cp->fcp = op->fcp;
534 
535         return (error);
536 }
537 
538 /*
539  * XXX
540  * - Wait on recovery
541  */
542 int
543 nfsm_v4build_open_confirm_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op,
544     struct mbuf **mb, caddr_t *bpos)
545 {
546         nfsm_buildf_xx(mb, bpos, "uou",
547             NFSV4OP_OPEN_CONFIRM,
548             NFSX_V4STATEID, op->fcp->stateid,
549             op->fcp->lop->lo_seqid);
550 
551         cp->seqidused = cp->req_nops++;
552         cp->fcp = op->fcp;
553 
554         return (0);
555 }
556 
557 /*
558  * XXX
559  * - Wait on recovery
560  */
561 int
562 nfsm_v4build_close_xx(struct nfs4_compound *cp, struct nfs4_fctx *fcp,
563     struct mbuf **mb, caddr_t *bpos)
564 {
565         struct nfs4_lowner *lop = fcp->lop;
566 
567         nfsm_buildf_xx(mb, bpos, "uuo",
568             NFSV4OP_CLOSE,
569             lop->lo_seqid,
570             NFSX_V4STATEID, fcp->stateid);
571 
572         cp->seqidused = cp->req_nops++;
573         cp->fcp = fcp;
574 
575         return (0);
576 }
577 
578 int
579 nfsm_v4build_access_xx(struct nfs4_compound *cp, struct nfs4_oparg_access *acc,
580     struct mbuf **mb, caddr_t *bpos)
581 {
582         nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_ACCESS, acc->mode);
583         cp->req_nops++;
584 
585         return (0);
586 }
587 
588 int
589 nfsm_v4build_read_xx(struct nfs4_compound *cp, struct nfs4_oparg_read *r,
590     struct mbuf **mb, caddr_t *bpos)
591 {
592         nfsm_buildf_xx(mb, bpos, "uohu",
593             NFSV4OP_READ,
594             NFSX_V4STATEID, r->fcp->stateid,
595             r->off,
596             r->maxcnt);
597         cp->req_nops++;
598 
599         return (0);
600 }
601 
602 int
603 nfsm_v4build_write_xx(struct nfs4_compound *cp, struct nfs4_oparg_write *w,
604     struct mbuf **mb, caddr_t *bpos)
605 {
606         nfsm_buildf_xx(mb, bpos, "uohuu",
607             NFSV4OP_WRITE,
608             NFSX_V4STATEID, w->fcp->stateid,
609             w->off,
610             w->stable,
611             w->cnt);
612         cp->req_nops++;
613         return (nfsm_uiotombuf(w->uiop, mb, w->cnt, bpos));
614 }
615 
616 int
617 nfsm_v4build_commit_xx(struct nfs4_compound *cp, struct nfs4_oparg_commit *c,
618     struct mbuf **mb, caddr_t *bpos)
619 {
620         nfsm_buildf_xx(mb, bpos, "uhu", NFSV4OP_COMMIT, c->start, c->len);
621         cp->req_nops++;
622 
623         return (0);
624 }
625 
626 int
627 nfsm_v4build_readdir_xx(struct nfs4_compound *cp, struct nfs4_oparg_readdir *r,
628     struct mbuf **mb, caddr_t *bpos)
629 {
630         int i;
631 
632         nfsm_buildf_xx(mb, bpos, "uhouuu",
633             NFSV4OP_READDIR,
634             r->cookie,
635             sizeof(r->verf), r->verf,
636             r->cnt >> 4,        /* meaningless "dircount" field */
637             r->cnt,
638             r->bm->bmlen);
639 
640         for (i = 0; i < r->bm->bmlen; i++)
641                 nfsm_buildf_xx(mb, bpos, "u", r->bm->bmval[i]);
642 
643         cp->req_nops++;
644 
645         return (0);
646 }
647 
648 int
649 nfsm_v4build_renew_xx(struct nfs4_compound *cp, uint64_t cid,
650     struct mbuf **mb, caddr_t *bpos)
651 {
652         nfsm_buildf_xx(mb, bpos, "uh", NFSV4OP_RENEW, cid);
653         cp->req_nops++;
654 
655         return (0);
656 }
657 
658 int
659 nfsm_v4build_create_xx(struct nfs4_compound *cp, struct nfs4_oparg_create *c,
660     struct mbuf **mb, caddr_t *bpos)
661 {
662         uint32_t t1;
663 
664         nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_CREATE, c->type);
665 
666         if (c->type == NFLNK)
667                 /* XXX strlen */
668                 nfsm_buildf_xx(mb, bpos, "s", strlen(c->linktext), c->linktext);
669         else if (c->type == NFCHR || c->type == NFBLK)
670                 nfsm_buildf_xx(mb, bpos, "uu",
671                     umajor(c->vap->va_rdev), uminor(c->vap->va_rdev));
672 
673         /* Name */
674         nfsm_buildf_xx(mb, bpos, "s", c->namelen, c->name);     
675 
676         /* Attributes */
677         t1 = nfsm_v4build_attrs_xx(c->vap, mb, bpos);
678         if (t1 != 0)
679                 return (t1);
680 
681         cp->req_nops++;
682 
683         return (0);
684 }
685 
686 int
687 nfsm_v4build_rename_xx(struct nfs4_compound *cp, struct nfs4_oparg_rename *r,
688     struct mbuf **mb, caddr_t *bpos)
689 {
690         nfsm_buildf_xx(mb, bpos, "uss", NFSV4OP_RENAME, r->fnamelen, r->fname,
691             r->tnamelen, r->tname);
692 
693         cp->req_nops++;
694 
695         return (0);
696 }
697 
698 int
699 nfsm_v4build_link_xx(struct nfs4_compound *cp, struct nfs4_oparg_link *l,
700     struct mbuf **mb, caddr_t *bpos)
701 {
702         nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_LINK, l->namelen, l->name);
703 
704         cp->req_nops++;
705 
706         return (0);
707 }
708 
709 int
710 nfsm_v4build_remove_xx(struct nfs4_compound *cp, const char *name, u_int namelen,
711     struct mbuf **mb, caddr_t *bpos)
712 {
713         nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_REMOVE, namelen, name);
714 
715         cp->req_nops++;
716 
717         return (0);
718 }
719 
720 int
721 nfsm_v4build_attrs_xx(struct vattr *vap, struct mbuf **mb, caddr_t *bpos)
722 {
723         uint32_t *tl, *attrlenp, *bmvalp, len;
724         size_t siz;
725 
726         tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos);
727 
728         *tl++ = txdr_unsigned(2);    /* bitmap length */
729         bmvalp = tl;
730         bzero(bmvalp, 8);
731         tl += 2;
732         attrlenp = tl;
733 
734         len = 0;
735         if (vap->va_size != VNOVAL) {
736                 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
737                 FA4_SET(FA4_SIZE, bmvalp);
738                 txdr_hyper(vap->va_size, tl); tl += 2;
739                 len += 2 * NFSX_UNSIGNED;
740         }
741         if (vap->va_mode != (u_short)VNOVAL) {
742                 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
743                 FA4_SET(FA4_MODE, bmvalp);
744                 *tl++ = txdr_unsigned(vap->va_mode);
745                 len += NFSX_UNSIGNED;
746         }
747         if (vap->va_uid != VNOVAL) {
748                 int error;
749                 char *name;
750                 error = idmap_uid_to_name(vap->va_uid, &name, &siz);
751                 if (error || name == NULL || siz == 0) {
752                         /* XXX */
753                         siz = sizeof("nobody") - 1;
754                         tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb, 
755                             bpos);
756                         *tl++ = txdr_unsigned(siz);
757                         bcopy("nobody", tl, siz);
758                         len += NFSX_UNSIGNED + nfsm_rndup(siz);
759                 } else {
760                         tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb,
761                             bpos);
762                         *tl++ = txdr_unsigned(siz);
763                         bcopy(name, tl, siz);
764                         len += NFSX_UNSIGNED + nfsm_rndup(siz);
765                 }
766                 FA4_SET(FA4_OWNER, bmvalp);
767         }
768         if (vap->va_gid != VNOVAL) {
769                 int error;
770                 char *name;
771                 error = idmap_gid_to_name(vap->va_gid, &name, &siz);
772                 if (error || name == NULL || siz == 0) {
773                         /* XXX */
774                         siz = sizeof("nogroup") - 1;
775                         tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb, 
776                             bpos);
777                         *tl++ = txdr_unsigned(siz);
778                         bcopy("nogroup", tl, siz);
779                         len += NFSX_UNSIGNED + nfsm_rndup(siz);
780                 } else {
781                         tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb,
782                             bpos);
783                         *tl++ = txdr_unsigned(siz);
784                         bcopy(name, tl, siz);
785                         len += NFSX_UNSIGNED + nfsm_rndup(siz);
786                 }
787                 FA4_SET(FA4_OWNER_GROUP, bmvalp);
788         }
789         if (vap->va_atime.tv_sec != VNOVAL) {
790                 uint64_t val = vap->va_atime.tv_sec;
791                 tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos);
792                 FA4_SET(FA4_TIME_ACCESS_SET, bmvalp);
793                 *tl++ = txdr_unsigned(THCLIENTTIME);
794                 txdr_hyper(val, tl); tl += 2;
795                 *tl++ = txdr_unsigned(vap->va_atime.tv_nsec);
796                 len += 4 * NFSX_UNSIGNED;
797         }
798         if (vap->va_mtime.tv_sec != VNOVAL) {
799                 uint64_t val = vap->va_mtime.tv_sec;
800                 tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos);
801                 FA4_SET(FA4_TIME_MODIFY_SET, bmvalp);
802                 *tl++ = txdr_unsigned(THCLIENTTIME);
803                 txdr_hyper(val, tl); tl += 2;
804                 *tl++ = txdr_unsigned(vap->va_mtime.tv_nsec);
805                 len += 4 * NFSX_UNSIGNED;
806         }
807 
808         bmvalp[0] = txdr_unsigned(bmvalp[0]);
809         bmvalp[1] = txdr_unsigned(bmvalp[1]);
810 
811         *attrlenp = txdr_unsigned(len);
812 
813         return (0);
814 }
815 
816 int
817 nfsm_v4dissect_compound_xx(struct nfs4_compound *cp, struct mbuf **md, caddr_t *dpos)
818 {
819         uint32_t taglen, t1, *tl;
820 
821         tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
822         if (tl == NULL)
823                 return (EBADRPC);
824 
825         /* Reply status is handled by the RPC code */
826 
827         taglen = fxdr_unsigned(uint32_t, *tl++);
828         t1 = nfsm_adv_xx(nfsm_rndup(taglen), md, dpos);
829         if (t1 != 0)
830                 return (EBADRPC);
831 
832         tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
833         if (tl == NULL)
834                 return (EBADRPC);
835 
836         cp->rep_nops = fxdr_unsigned(uint32_t, *tl++);
837 
838         return (0);
839 }
840 
841 int
842 nfsm_v4dissect_simple_xx(struct nfs4_compound *cp, uint32_t op,
843     uint32_t skipbytes, struct mbuf **md, caddr_t *dpos)
844 {
845         uint32_t t1, dop, status;
846 
847         t1 = nfsm_dissectf_xx(md, dpos, "uu", &dop, &status);
848         if (t1 != 0)
849                 return (t1);
850 
851         if (dop != op || status != 0)
852                 return (EBADRPC);
853 
854         if (skipbytes > 0)
855                 NFSM_ADV(nfsm_rndup(skipbytes));
856 
857         return (0);
858 }
859 
860 int
861 nfsm_v4dissect_getattr_xx(struct nfs4_compound *cp, struct nfs4_oparg_getattr *ga,
862     struct mbuf **md, caddr_t *dpos)
863 {
864         uint32_t *tl;
865 
866         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
867         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_GETATTR ||
868             *tl++ != 0)
869                 return (EBADRPC);
870 
871         return (nfsm_v4dissect_attrs_xx(&ga->fa, md, dpos));
872 }
873 
874 int
875 nfsm_v4dissect_setattr_xx(struct nfs4_compound *cp, struct mbuf **md, caddr_t *dpos)
876 {
877         uint32_t t1, op, bmlen, status;
878 
879         t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status);
880         if (t1 != 0)
881                 return (t1);
882 
883         if (op != NFSV4OP_SETATTR || status != 0)
884                 return (EBADRPC);
885 
886         t1 = nfsm_dissectf_xx(md, dpos, "u", &bmlen);
887         if (t1 != 0)
888                 return (t1);
889 
890         return (nfsm_dissectf_xx(md, dpos, "k", bmlen << 2));
891 }
892 
893 int
894 nfsm_v4dissect_getfh_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh,
895     struct mbuf **md, caddr_t *dpos)
896 {
897         uint32_t *tl, len, xdrlen;
898 
899         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
900         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_GETFH)
901                 return (EBADRPC);
902 
903         if (*tl++ != 0)
904                 return (EBADRPC);
905 
906         NFSM_DISSECT(NFSX_UNSIGNED);
907         len = fxdr_unsigned(uint32_t, *tl++);
908         if (len > NFSX_V4FH)
909                 return (EBADRPC);
910 
911         /* XXX integrate this into nfs_mtofh()? */
912 
913         gfh->fh_len = len;
914         xdrlen = nfsm_rndup(len);
915 
916         NFSM_DISSECT(xdrlen);
917         bcopy(tl, &gfh->fh_val, xdrlen);
918 
919         return (0);
920 }
921 
922 int
923 nfsm_v4dissect_setclientid_xx(struct nfs4_compound *cp,
924     struct nfs4_oparg_setclientid *sci, struct mbuf **md, caddr_t *dpos)
925 {
926         uint32_t *tl;
927 
928         tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
929         if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_SETCLIENTID)
930                 return (EBADRPC);
931 
932         /* Handle NFS4ERR_CLID_INUSE specially */
933         if (*tl++ != 0)
934                 return (EBADRPC);
935 
936         NFSM_DISSECT(2 * NFSX_UNSIGNED