2 * linux/fs/nfs/nfs2xdr.c
4 * XDR functions to encode/decode NFS RPC arguments and results.
6 * Copyright (C) 1992, 1993, 1994 Rick Sladkey
7 * Copyright (C) 1996 Olaf Kirch
8 * 04 Aug 1998 Ion Badulescu <ionut@cs.columbia.edu>
9 * FIFO's need special handling in NFSv2
12 #include <linux/param.h>
13 #include <linux/sched.h>
15 #include <linux/malloc.h>
16 #include <linux/utsname.h>
17 #include <linux/errno.h>
18 #include <linux/string.h>
20 #include <linux/pagemap.h>
21 #include <linux/proc_fs.h>
22 #include <linux/sunrpc/clnt.h>
23 #include <linux/nfs.h>
24 #include <linux/nfs2.h>
25 #include <linux/nfs_fs.h>
27 /* Uncomment this to support servers requiring longword lengths */
28 #define NFS_PAD_WRITES 1
30 #define NFSDBG_FACILITY NFSDBG_XDR
31 /* #define NFS_PARANOIA 1 */
33 extern int nfs_stat_to_errno(int stat
);
35 /* Mapping from NFS error code to "errno" error code. */
36 #define errno_NFSERR_IO EIO
39 * Declare the space requirements for NFS arguments and replies as
40 * number of 32bit-words
42 #define NFS_fhandle_sz 8
43 #define NFS_sattr_sz 8
44 #define NFS_filename_sz 1+(NFS2_MAXNAMLEN>>2)
45 #define NFS_path_sz 1+(NFS2_MAXPATHLEN>>2)
46 #define NFS_fattr_sz 17
48 #define NFS_entry_sz NFS_filename_sz+3
50 #define NFS_enc_void_sz 0
51 #define NFS_diropargs_sz NFS_fhandle_sz+NFS_filename_sz
52 #define NFS_sattrargs_sz NFS_fhandle_sz+NFS_sattr_sz
53 #define NFS_readlinkargs_sz NFS_fhandle_sz
54 #define NFS_readargs_sz NFS_fhandle_sz+3
55 #define NFS_writeargs_sz NFS_fhandle_sz+4
56 #define NFS_createargs_sz NFS_diropargs_sz+NFS_sattr_sz
57 #define NFS_renameargs_sz NFS_diropargs_sz+NFS_diropargs_sz
58 #define NFS_linkargs_sz NFS_fhandle_sz+NFS_diropargs_sz
59 #define NFS_symlinkargs_sz NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz
60 #define NFS_readdirargs_sz NFS_fhandle_sz+2
62 #define NFS_dec_void_sz 0
63 #define NFS_attrstat_sz 1+NFS_fattr_sz
64 #define NFS_diropres_sz 1+NFS_fhandle_sz+NFS_fattr_sz
65 #define NFS_readlinkres_sz 1
66 #define NFS_readres_sz 1+NFS_fattr_sz+1
67 #define NFS_writeres_sz NFS_attrstat_sz
69 #define NFS_readdirres_sz 1
70 #define NFS_statfsres_sz 1+NFS_info_sz
73 * Common NFS XDR functions as inlines
76 xdr_encode_fhandle(u32
*p
, struct nfs_fh
*fhandle
)
78 memcpy(p
, fhandle
->data
, NFS2_FHSIZE
);
79 return p
+ XDR_QUADLEN(NFS2_FHSIZE
);
83 xdr_decode_fhandle(u32
*p
, struct nfs_fh
*fhandle
)
85 /* Zero handle first to allow comparisons */
86 memset(fhandle
, 0, sizeof(*fhandle
));
87 /* NFSv2 handles have a fixed length */
88 fhandle
->size
= NFS2_FHSIZE
;
89 memcpy(fhandle
->data
, p
, NFS2_FHSIZE
);
90 return p
+ XDR_QUADLEN(NFS2_FHSIZE
);
94 xdr_decode_string2(u32
*p
, char **string
, unsigned int *len
,
100 *string
= (char *) p
;
101 return p
+ XDR_QUADLEN(*len
);
105 xdr_decode_time(u32
*p
, u64
*timep
)
107 u64 tmp
= (u64
)ntohl(*p
++) << 32;
108 *timep
= tmp
+ (u64
)ntohl(*p
++);
113 xdr_decode_fattr(u32
*p
, struct nfs_fattr
*fattr
)
115 fattr
->type
= (enum nfs_ftype
) ntohl(*p
++);
116 fattr
->mode
= ntohl(*p
++);
117 fattr
->nlink
= ntohl(*p
++);
118 fattr
->uid
= ntohl(*p
++);
119 fattr
->gid
= ntohl(*p
++);
120 fattr
->size
= ntohl(*p
++);
121 fattr
->du
.nfs2
.blocksize
= ntohl(*p
++);
122 fattr
->rdev
= ntohl(*p
++);
123 fattr
->du
.nfs2
.blocks
= ntohl(*p
++);
124 fattr
->fsid
= ntohl(*p
++);
125 fattr
->fileid
= ntohl(*p
++);
126 p
= xdr_decode_time(p
, &fattr
->atime
);
127 p
= xdr_decode_time(p
, &fattr
->mtime
);
128 p
= xdr_decode_time(p
, &fattr
->ctime
);
129 fattr
->valid
|= NFS_ATTR_FATTR
;
130 if (fattr
->type
== NFCHR
&& fattr
->rdev
== NFS2_FIFO_DEV
) {
131 fattr
->type
= NFFIFO
;
132 fattr
->mode
= (fattr
->mode
& ~S_IFMT
) | S_IFIFO
;
138 #define SATTR(p, attr, flag, field) \
139 *p++ = (attr->ia_valid & flag) ? htonl(attr->field) : ~(u32) 0
141 xdr_encode_sattr(u32
*p
, struct iattr
*attr
)
143 SATTR(p
, attr
, ATTR_MODE
, ia_mode
);
144 SATTR(p
, attr
, ATTR_UID
, ia_uid
);
145 SATTR(p
, attr
, ATTR_GID
, ia_gid
);
146 SATTR(p
, attr
, ATTR_SIZE
, ia_size
);
148 if (attr
->ia_valid
& (ATTR_ATIME
|ATTR_ATIME_SET
)) {
149 *p
++ = htonl(attr
->ia_atime
);
156 if (attr
->ia_valid
& (ATTR_MTIME
|ATTR_MTIME_SET
)) {
157 *p
++ = htonl(attr
->ia_mtime
);
168 * NFS encode functions
171 * Encode void argument
174 nfs_xdr_enc_void(struct rpc_rqst
*req
, u32
*p
, void *dummy
)
176 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
181 * Encode file handle argument
182 * GETATTR, READLINK, STATFS
185 nfs_xdr_fhandle(struct rpc_rqst
*req
, u32
*p
, struct nfs_fh
*fh
)
187 p
= xdr_encode_fhandle(p
, fh
);
188 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
193 * Encode SETATTR arguments
196 nfs_xdr_sattrargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_sattrargs
*args
)
198 p
= xdr_encode_fhandle(p
, args
->fh
);
199 p
= xdr_encode_sattr(p
, args
->sattr
);
200 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
205 * Encode directory ops argument
206 * LOOKUP, REMOVE, RMDIR
209 nfs_xdr_diropargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_diropargs
*args
)
211 p
= xdr_encode_fhandle(p
, args
->fh
);
212 p
= xdr_encode_array(p
, args
->name
, args
->len
);
213 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
218 * Arguments to a READ call. Since we read data directly into the page
219 * cache, we also set up the reply iovec here so that iov[1] points
220 * exactly to the page we want to fetch.
223 nfs_xdr_readargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_readargs
*args
)
225 struct rpc_auth
*auth
= req
->rq_task
->tk_auth
;
229 p
= xdr_encode_fhandle(p
, args
->fh
);
230 *p
++ = htonl(args
->offset
);
231 *p
++ = htonl(args
->count
);
232 *p
++ = htonl(args
->count
);
233 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
235 /* Get the number of buffers in the receive iovec */
238 if (nr
+2 > MAX_IOVEC
) {
239 printk(KERN_ERR
"NFS: Bad number of iov's in xdr_readargs\n");
243 /* set up reply iovec */
244 replen
= (RPC_REPHDRSIZE
+ auth
->au_rslack
+ NFS_readres_sz
) << 2;
245 buflen
= req
->rq_rvec
[0].iov_len
;
246 req
->rq_rvec
[0].iov_len
= replen
;
248 memcpy(req
->rq_rvec
+ 1, args
->iov
, nr
* sizeof(struct iovec
));
250 req
->rq_rvec
[nr
+1].iov_base
= (u8
*) req
->rq_rvec
[0].iov_base
+ replen
;
251 req
->rq_rvec
[nr
+1].iov_len
= buflen
- replen
;
252 req
->rq_rlen
= args
->count
+ buflen
;
262 nfs_xdr_readres(struct rpc_rqst
*req
, u32
*p
, struct nfs_readres
*res
)
264 struct iovec
*iov
= req
->rq_rvec
;
265 int status
, count
, recvd
, hdrlen
;
267 if ((status
= ntohl(*p
++)))
268 return -nfs_stat_to_errno(status
);
269 p
= xdr_decode_fattr(p
, res
->fattr
);
272 hdrlen
= (u8
*) p
- (u8
*) iov
->iov_base
;
273 recvd
= req
->rq_rlen
- hdrlen
;
274 if (p
!= iov
[req
->rq_rnr
-1].iov_base
) {
275 /* Unexpected reply header size. Punt.
276 * XXX: Move iovec contents to align data on page
277 * boundary and adjust RPC header size guess */
278 printk(KERN_WARNING
"NFS: Odd RPC header size in read reply: %d\n", hdrlen
);
279 return -errno_NFSERR_IO
;
282 printk(KERN_WARNING
"NFS: server cheating in read reply: "
283 "count %d > recvd %d\n", count
, recvd
);
287 dprintk("RPC: readres OK count %d\n", count
);
288 if (count
< res
->count
) {
289 xdr_zero_iovec(iov
+1, req
->rq_rnr
-2, res
->count
- count
);
291 res
->eof
= 1; /* Silly NFSv3ism which can't be helped */
300 * Write arguments. Splice the buffer to be written into the iovec.
303 nfs_xdr_writeargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_writeargs
*args
)
306 u32 count
= args
->count
;
308 p
= xdr_encode_fhandle(p
, args
->fh
);
309 *p
++ = htonl(args
->offset
);
310 *p
++ = htonl(args
->offset
);
313 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
315 /* Get the number of buffers in the send iovec */
318 if (nr
+2 > MAX_IOVEC
) {
319 printk(KERN_ERR
"NFS: Bad number of iov's in xdr_writeargs "
320 "(nr %d max %d)\n", nr
, MAX_IOVEC
);
325 memcpy(req
->rq_svec
+ 1, args
->iov
, nr
* sizeof(struct iovec
));
327 #ifdef NFS_PAD_WRITES
329 * Some old servers require that the message length
330 * be a multiple of 4, so we pad it here if needed.
333 struct iovec
*iov
= req
->rq_svec
+ nr
+ 1;
334 int pad
= 4 - (count
& 3);
336 iov
->iov_base
= (void *) "\0\0\0";
342 req
->rq_slen
+= count
;
349 * Encode create arguments
353 nfs_xdr_createargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_createargs
*args
)
355 p
= xdr_encode_fhandle(p
, args
->fh
);
356 p
= xdr_encode_array(p
, args
->name
, args
->len
);
357 p
= xdr_encode_sattr(p
, args
->sattr
);
358 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
363 * Encode RENAME arguments
366 nfs_xdr_renameargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_renameargs
*args
)
368 p
= xdr_encode_fhandle(p
, args
->fromfh
);
369 p
= xdr_encode_array(p
, args
->fromname
, args
->fromlen
);
370 p
= xdr_encode_fhandle(p
, args
->tofh
);
371 p
= xdr_encode_array(p
, args
->toname
, args
->tolen
);
372 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
377 * Encode LINK arguments
380 nfs_xdr_linkargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_linkargs
*args
)
382 p
= xdr_encode_fhandle(p
, args
->fromfh
);
383 p
= xdr_encode_fhandle(p
, args
->tofh
);
384 p
= xdr_encode_array(p
, args
->toname
, args
->tolen
);
385 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
390 * Encode SYMLINK arguments
393 nfs_xdr_symlinkargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_symlinkargs
*args
)
395 p
= xdr_encode_fhandle(p
, args
->fromfh
);
396 p
= xdr_encode_array(p
, args
->fromname
, args
->fromlen
);
397 p
= xdr_encode_array(p
, args
->topath
, args
->tolen
);
398 p
= xdr_encode_sattr(p
, args
->sattr
);
399 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
404 * Encode arguments to readdir call
407 nfs_xdr_readdirargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_readdirargs
*args
)
409 struct rpc_task
*task
= req
->rq_task
;
410 struct rpc_auth
*auth
= task
->tk_auth
;
411 u32 bufsiz
= args
->bufsiz
;
415 * Some servers (e.g. HP OS 9.5) seem to expect the buffer size
416 * to be in longwords ... check whether to convert the size.
418 if (task
->tk_client
->cl_flags
& NFS_CLNTF_BUFSIZE
)
419 bufsiz
= bufsiz
>> 2;
421 p
= xdr_encode_fhandle(p
, args
->fh
);
422 *p
++ = htonl(args
->cookie
);
423 *p
++ = htonl(bufsiz
); /* see above */
424 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
426 /* set up reply iovec */
427 replen
= (RPC_REPHDRSIZE
+ auth
->au_rslack
+ NFS_readdirres_sz
) << 2;
428 buflen
= req
->rq_rvec
[0].iov_len
;
429 req
->rq_rvec
[0].iov_len
= replen
;
430 req
->rq_rvec
[1].iov_base
= args
->buffer
;
431 req
->rq_rvec
[1].iov_len
= args
->bufsiz
;
432 req
->rq_rvec
[2].iov_base
= (u8
*) req
->rq_rvec
[0].iov_base
+ replen
;
433 req
->rq_rvec
[2].iov_len
= buflen
- replen
;
434 req
->rq_rlen
= buflen
+ args
->bufsiz
;
441 * Decode the result of a readdir call.
442 * We're not really decoding anymore, we just leave the buffer untouched
443 * and only check that it is syntactically correct.
444 * The real decoding happens in nfs_decode_entry below, called directly
445 * from nfs_readdir for each entry.
448 nfs_xdr_readdirres(struct rpc_rqst
*req
, u32
*p
, struct nfs_readdirres
*res
)
450 struct iovec
*iov
= req
->rq_rvec
;
452 u32
*end
, *entry
, len
;
454 if ((status
= ntohl(*p
++)))
455 return -nfs_stat_to_errno(status
);
456 if ((void *) p
!= ((u8
*) iov
->iov_base
+iov
->iov_len
)) {
457 /* Unexpected reply header size. Punt. */
458 printk(KERN_WARNING
"NFS: Odd RPC header size in readdirres reply\n");
459 return -errno_NFSERR_IO
;
462 /* Get start and end address of XDR data */
463 p
= (u32
*) iov
[1].iov_base
;
464 end
= (u32
*) ((u8
*) p
+ iov
[1].iov_len
);
466 /* Get start and end of dirent buffer */
467 if (res
->buffer
!= p
) {
468 printk(KERN_ERR
"NFS: Bad result buffer in readdir\n");
469 return -errno_NFSERR_IO
;
472 for (nr
= 0; *p
++; nr
++) {
476 p
+= XDR_QUADLEN(len
) + 1; /* name plus cookie */
477 if (len
> NFS2_MAXNAMLEN
) {
478 printk(KERN_WARNING
"NFS: giant filename in readdir (len 0x%x)!\n",
480 return -errno_NFSERR_IO
;
484 "NFS: short packet in readdir reply!\n");
485 entry
[0] = entry
[1] = 0;
493 nfs_decode_dirent(u32
*p
, struct nfs_entry
*entry
, int plus
)
497 return ERR_PTR(-EAGAIN
);
499 return ERR_PTR(-EBADCOOKIE
);
502 entry
->ino
= ntohl(*p
++);
503 entry
->len
= ntohl(*p
++);
504 entry
->name
= (const char *) p
;
505 p
+= XDR_QUADLEN(entry
->len
);
506 entry
->prev_cookie
= entry
->cookie
;
507 entry
->cookie
= ntohl(*p
++);
508 entry
->eof
= !p
[0] && p
[1];
514 * NFS XDR decode functions
520 nfs_xdr_dec_void(struct rpc_rqst
*req
, u32
*p
, void *dummy
)
526 * Decode simple status reply
529 nfs_xdr_stat(struct rpc_rqst
*req
, u32
*p
, void *dummy
)
533 if ((status
= ntohl(*p
++)) != 0)
534 status
= -nfs_stat_to_errno(status
);
539 * Decode attrstat reply
540 * GETATTR, SETATTR, WRITE
543 nfs_xdr_attrstat(struct rpc_rqst
*req
, u32
*p
, struct nfs_fattr
*fattr
)
547 if ((status
= ntohl(*p
++)))
548 return -nfs_stat_to_errno(status
);
549 xdr_decode_fattr(p
, fattr
);
554 * Decode diropres reply
555 * LOOKUP, CREATE, MKDIR
558 nfs_xdr_diropres(struct rpc_rqst
*req
, u32
*p
, struct nfs_diropok
*res
)
562 if ((status
= ntohl(*p
++)))
563 return -nfs_stat_to_errno(status
);
564 p
= xdr_decode_fhandle(p
, res
->fh
);
565 xdr_decode_fattr(p
, res
->fattr
);
570 * Encode READLINK args
573 nfs_xdr_readlinkargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_readlinkargs
*args
)
575 struct rpc_task
*task
= req
->rq_task
;
576 struct rpc_auth
*auth
= task
->tk_auth
;
579 p
= xdr_encode_fhandle(p
, args
->fh
);
580 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
581 replen
= (RPC_REPHDRSIZE
+ auth
->au_rslack
+ NFS_readlinkres_sz
) << 2;
582 buflen
= req
->rq_rvec
[0].iov_len
;
583 req
->rq_rvec
[0].iov_len
= replen
;
584 req
->rq_rvec
[1].iov_base
= args
->buffer
;
585 req
->rq_rvec
[1].iov_len
= args
->bufsiz
;
586 req
->rq_rvec
[2].iov_base
= (u8
*) req
->rq_rvec
[0].iov_base
+ replen
;
587 req
->rq_rvec
[2].iov_len
= buflen
- replen
;
588 req
->rq_rlen
= buflen
+ args
->bufsiz
;
594 * Decode READLINK reply
597 nfs_xdr_readlinkres(struct rpc_rqst
*req
, u32
*p
, struct nfs_readlinkres
*res
)
604 if ((status
= ntohl(*p
++)))
605 return -nfs_stat_to_errno(status
);
606 strlen
= (u32
*)res
->buffer
;
607 /* Convert length of symlink */
608 len
= ntohl(*strlen
);
609 if (len
> res
->bufsiz
- 5)
610 len
= res
->bufsiz
- 5;
612 /* NULL terminate the string we got */
613 string
= (char *)(strlen
+ 1);
622 nfs_xdr_writeres(struct rpc_rqst
*req
, u32
*p
, struct nfs_writeres
*res
)
624 res
->verf
->committed
= NFS_FILE_SYNC
;
625 return nfs_xdr_attrstat(req
, p
, res
->fattr
);
629 * Decode STATFS reply
632 nfs_xdr_statfsres(struct rpc_rqst
*req
, u32
*p
, struct nfs_fsinfo
*res
)
637 if ((status
= ntohl(*p
++)))
638 return -nfs_stat_to_errno(status
);
640 /* For NFSv2, we more or less have to guess the preferred
641 * read/write/readdir sizes from the single 'transfer size'
644 xfer_size
= ntohl(*p
++); /* tsize */
645 res
->rtmax
= 8 * 1024;
646 res
->rtpref
= xfer_size
;
647 res
->rtmult
= xfer_size
;
648 res
->wtmax
= 8 * 1024;
649 res
->wtpref
= xfer_size
;
650 res
->wtmult
= xfer_size
;
651 res
->dtpref
= PAGE_CACHE_SIZE
;
652 res
->maxfilesize
= 0x7FFFFFFF; /* just a guess */
653 res
->bsize
= ntohl(*p
++);
655 res
->tbytes
= ntohl(*p
++) * res
->bsize
;
656 res
->fbytes
= ntohl(*p
++) * res
->bsize
;
657 res
->abytes
= ntohl(*p
++) * res
->bsize
;
667 * We need to translate between nfs status return values and
668 * the local errno values which may not be the same.
675 { NFSERR_PERM
, EPERM
},
676 { NFSERR_NOENT
, ENOENT
},
677 { NFSERR_IO
, errno_NFSERR_IO
},
678 { NFSERR_NXIO
, ENXIO
},
679 /* { NFSERR_EAGAIN, EAGAIN }, */
680 { NFSERR_ACCES
, EACCES
},
681 { NFSERR_EXIST
, EEXIST
},
682 { NFSERR_XDEV
, EXDEV
},
683 { NFSERR_NODEV
, ENODEV
},
684 { NFSERR_NOTDIR
, ENOTDIR
},
685 { NFSERR_ISDIR
, EISDIR
},
686 { NFSERR_INVAL
, EINVAL
},
687 { NFSERR_FBIG
, EFBIG
},
688 { NFSERR_NOSPC
, ENOSPC
},
689 { NFSERR_ROFS
, EROFS
},
690 { NFSERR_MLINK
, EMLINK
},
691 { NFSERR_NAMETOOLONG
, ENAMETOOLONG
},
692 { NFSERR_NOTEMPTY
, ENOTEMPTY
},
693 { NFSERR_DQUOT
, EDQUOT
},
694 { NFSERR_STALE
, ESTALE
},
695 { NFSERR_REMOTE
, EREMOTE
},
697 { NFSERR_WFLUSH
, EWFLUSH
},
699 { NFSERR_BADHANDLE
, EBADHANDLE
},
700 { NFSERR_NOT_SYNC
, ENOTSYNC
},
701 { NFSERR_BAD_COOKIE
, EBADCOOKIE
},
702 { NFSERR_NOTSUPP
, ENOTSUPP
},
703 { NFSERR_TOOSMALL
, ETOOSMALL
},
704 { NFSERR_SERVERFAULT
, ESERVERFAULT
},
705 { NFSERR_BADTYPE
, EBADTYPE
},
706 { NFSERR_JUKEBOX
, EJUKEBOX
},
711 * Convert an NFS error code to a local one.
712 * This one is used jointly by NFSv2 and NFSv3.
715 nfs_stat_to_errno(int stat
)
719 for (i
= 0; nfs_errtbl
[i
].stat
!= -1; i
++) {
720 if (nfs_errtbl
[i
].stat
== stat
)
721 return nfs_errtbl
[i
].errno
;
723 printk(KERN_ERR
"nfs_stat_to_errno: bad nfs status return value: %d\n", stat
);
724 return nfs_errtbl
[i
].errno
;
728 # define MAX(a, b) (((a) > (b))? (a) : (b))
731 #define PROC(proc, argtype, restype) \
733 (kxdrproc_t) nfs_xdr_##argtype, \
734 (kxdrproc_t) nfs_xdr_##restype, \
735 MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2, \
739 static struct rpc_procinfo nfs_procedures
[18] = {
740 PROC(null
, enc_void
, dec_void
),
741 PROC(getattr
, fhandle
, attrstat
),
742 PROC(setattr
, sattrargs
, attrstat
),
743 PROC(root
, enc_void
, dec_void
),
744 PROC(lookup
, diropargs
, diropres
),
745 PROC(readlink
, readlinkargs
, readlinkres
),
746 PROC(read
, readargs
, readres
),
747 PROC(writecache
, enc_void
, dec_void
),
748 PROC(write
, writeargs
, writeres
),
749 PROC(create
, createargs
, diropres
),
750 PROC(remove
, diropargs
, stat
),
751 PROC(rename
, renameargs
, stat
),
752 PROC(link
, linkargs
, stat
),
753 PROC(symlink
, symlinkargs
, stat
),
754 PROC(mkdir
, createargs
, diropres
),
755 PROC(rmdir
, diropargs
, stat
),
756 PROC(readdir
, readdirargs
, readdirres
),
757 PROC(statfs
, fhandle
, statfsres
),
760 struct rpc_version nfs_version2
= {
762 sizeof(nfs_procedures
)/sizeof(nfs_procedures
[0]),