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/time.h>
15 #include <linux/slab.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 #define NFSDBG_FACILITY NFSDBG_XDR
28 /* #define NFS_PARANOIA 1 */
30 extern int nfs_stat_to_errno(int stat
);
32 /* Mapping from NFS error code to "errno" error code. */
33 #define errno_NFSERR_IO EIO
36 * Declare the space requirements for NFS arguments and replies as
37 * number of 32bit-words
39 #define NFS_fhandle_sz (8)
40 #define NFS_sattr_sz (8)
41 #define NFS_filename_sz (1+(NFS2_MAXNAMLEN>>2))
42 #define NFS_path_sz (1+(NFS2_MAXPATHLEN>>2))
43 #define NFS_fattr_sz (17)
44 #define NFS_info_sz (5)
45 #define NFS_entry_sz (NFS_filename_sz+3)
47 #define NFS_diropargs_sz (NFS_fhandle_sz+NFS_filename_sz)
48 #define NFS_sattrargs_sz (NFS_fhandle_sz+NFS_sattr_sz)
49 #define NFS_readlinkargs_sz (NFS_fhandle_sz)
50 #define NFS_readargs_sz (NFS_fhandle_sz+3)
51 #define NFS_writeargs_sz (NFS_fhandle_sz+4)
52 #define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz)
53 #define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz)
54 #define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz)
55 #define NFS_symlinkargs_sz (NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz)
56 #define NFS_readdirargs_sz (NFS_fhandle_sz+2)
58 #define NFS_attrstat_sz (1+NFS_fattr_sz)
59 #define NFS_diropres_sz (1+NFS_fhandle_sz+NFS_fattr_sz)
60 #define NFS_readlinkres_sz (2)
61 #define NFS_readres_sz (1+NFS_fattr_sz+1)
62 #define NFS_writeres_sz (NFS_attrstat_sz)
63 #define NFS_stat_sz (1)
64 #define NFS_readdirres_sz (1)
65 #define NFS_statfsres_sz (1+NFS_info_sz)
68 * Common NFS XDR functions as inlines
71 xdr_encode_fhandle(u32
*p
, struct nfs_fh
*fhandle
)
73 memcpy(p
, fhandle
->data
, NFS2_FHSIZE
);
74 return p
+ XDR_QUADLEN(NFS2_FHSIZE
);
78 xdr_decode_fhandle(u32
*p
, struct nfs_fh
*fhandle
)
80 /* NFSv2 handles have a fixed length */
81 fhandle
->size
= NFS2_FHSIZE
;
82 memcpy(fhandle
->data
, p
, NFS2_FHSIZE
);
83 return p
+ XDR_QUADLEN(NFS2_FHSIZE
);
87 xdr_encode_time(u32
*p
, struct timespec
*timep
)
89 *p
++ = htonl(timep
->tv_sec
);
90 /* Convert nanoseconds into microseconds */
91 *p
++ = htonl(timep
->tv_nsec
? timep
->tv_nsec
/ 1000 : 0);
96 xdr_encode_current_server_time(u32
*p
, struct timespec
*timep
)
99 * Passing the invalid value useconds=1000000 is a
100 * Sun convention for "set to current server time".
101 * It's needed to make permissions checks for the
102 * "touch" program across v2 mounts to Solaris and
103 * Irix boxes work correctly. See description of
104 * sattr in section 6.1 of "NFS Illustrated" by
105 * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5
107 *p
++ = htonl(timep
->tv_sec
);
108 *p
++ = htonl(1000000);
113 xdr_decode_time(u32
*p
, struct timespec
*timep
)
115 timep
->tv_sec
= ntohl(*p
++);
116 /* Convert microseconds into nanoseconds */
117 timep
->tv_nsec
= ntohl(*p
++) * 1000;
122 xdr_decode_fattr(u32
*p
, struct nfs_fattr
*fattr
)
125 fattr
->type
= (enum nfs_ftype
) ntohl(*p
++);
126 fattr
->mode
= ntohl(*p
++);
127 fattr
->nlink
= ntohl(*p
++);
128 fattr
->uid
= ntohl(*p
++);
129 fattr
->gid
= ntohl(*p
++);
130 fattr
->size
= ntohl(*p
++);
131 fattr
->du
.nfs2
.blocksize
= ntohl(*p
++);
133 fattr
->du
.nfs2
.blocks
= ntohl(*p
++);
134 fattr
->fsid_u
.nfs3
= ntohl(*p
++);
135 fattr
->fileid
= ntohl(*p
++);
136 p
= xdr_decode_time(p
, &fattr
->atime
);
137 p
= xdr_decode_time(p
, &fattr
->mtime
);
138 p
= xdr_decode_time(p
, &fattr
->ctime
);
139 fattr
->valid
|= NFS_ATTR_FATTR
;
140 fattr
->rdev
= new_decode_dev(rdev
);
141 if (fattr
->type
== NFCHR
&& rdev
== NFS2_FIFO_DEV
) {
142 fattr
->type
= NFFIFO
;
143 fattr
->mode
= (fattr
->mode
& ~S_IFMT
) | S_IFIFO
;
146 fattr
->timestamp
= jiffies
;
150 #define SATTR(p, attr, flag, field) \
151 *p++ = (attr->ia_valid & flag) ? htonl(attr->field) : ~(u32) 0
153 xdr_encode_sattr(u32
*p
, struct iattr
*attr
)
155 SATTR(p
, attr
, ATTR_MODE
, ia_mode
);
156 SATTR(p
, attr
, ATTR_UID
, ia_uid
);
157 SATTR(p
, attr
, ATTR_GID
, ia_gid
);
158 SATTR(p
, attr
, ATTR_SIZE
, ia_size
);
160 if (attr
->ia_valid
& ATTR_ATIME_SET
) {
161 p
= xdr_encode_time(p
, &attr
->ia_atime
);
162 } else if (attr
->ia_valid
& ATTR_ATIME
) {
163 p
= xdr_encode_current_server_time(p
, &attr
->ia_atime
);
169 if (attr
->ia_valid
& ATTR_MTIME_SET
) {
170 p
= xdr_encode_time(p
, &attr
->ia_mtime
);
171 } else if (attr
->ia_valid
& ATTR_MTIME
) {
172 p
= xdr_encode_current_server_time(p
, &attr
->ia_mtime
);
182 * NFS encode functions
185 * Encode file handle argument
186 * GETATTR, READLINK, STATFS
189 nfs_xdr_fhandle(struct rpc_rqst
*req
, u32
*p
, struct nfs_fh
*fh
)
191 p
= xdr_encode_fhandle(p
, fh
);
192 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
197 * Encode SETATTR arguments
200 nfs_xdr_sattrargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_sattrargs
*args
)
202 p
= xdr_encode_fhandle(p
, args
->fh
);
203 p
= xdr_encode_sattr(p
, args
->sattr
);
204 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
209 * Encode directory ops argument
210 * LOOKUP, REMOVE, RMDIR
213 nfs_xdr_diropargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_diropargs
*args
)
215 p
= xdr_encode_fhandle(p
, args
->fh
);
216 p
= xdr_encode_array(p
, args
->name
, args
->len
);
217 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
222 * Arguments to a READ call. Since we read data directly into the page
223 * cache, we also set up the reply iovec here so that iov[1] points
224 * exactly to the page we want to fetch.
227 nfs_xdr_readargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_readargs
*args
)
229 struct rpc_auth
*auth
= req
->rq_task
->tk_auth
;
231 u32 offset
= (u32
)args
->offset
;
232 u32 count
= args
->count
;
234 p
= xdr_encode_fhandle(p
, args
->fh
);
235 *p
++ = htonl(offset
);
238 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
240 /* Inline the page array */
241 replen
= (RPC_REPHDRSIZE
+ auth
->au_rslack
+ NFS_readres_sz
) << 2;
242 xdr_inline_pages(&req
->rq_rcv_buf
, replen
,
243 args
->pages
, args
->pgbase
, count
);
251 nfs_xdr_readres(struct rpc_rqst
*req
, u32
*p
, struct nfs_readres
*res
)
253 struct kvec
*iov
= req
->rq_rcv_buf
.head
;
254 int status
, count
, recvd
, hdrlen
;
256 if ((status
= ntohl(*p
++)))
257 return -nfs_stat_to_errno(status
);
258 p
= xdr_decode_fattr(p
, res
->fattr
);
262 hdrlen
= (u8
*) p
- (u8
*) iov
->iov_base
;
263 if (iov
->iov_len
< hdrlen
) {
264 printk(KERN_WARNING
"NFS: READ reply header overflowed:"
265 "length %d > %Zu\n", hdrlen
, iov
->iov_len
);
266 return -errno_NFSERR_IO
;
267 } else if (iov
->iov_len
!= hdrlen
) {
268 dprintk("NFS: READ header is short. iovec will be shifted.\n");
269 xdr_shift_buf(&req
->rq_rcv_buf
, iov
->iov_len
- hdrlen
);
272 recvd
= req
->rq_rcv_buf
.len
- hdrlen
;
274 printk(KERN_WARNING
"NFS: server cheating in read reply: "
275 "count %d > recvd %d\n", count
, recvd
);
279 dprintk("RPC: readres OK count %d\n", count
);
280 if (count
< res
->count
)
288 * Write arguments. Splice the buffer to be written into the iovec.
291 nfs_xdr_writeargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_writeargs
*args
)
293 struct xdr_buf
*sndbuf
= &req
->rq_snd_buf
;
294 u32 offset
= (u32
)args
->offset
;
295 u32 count
= args
->count
;
297 p
= xdr_encode_fhandle(p
, args
->fh
);
298 *p
++ = htonl(offset
);
299 *p
++ = htonl(offset
);
302 sndbuf
->len
= xdr_adjust_iovec(sndbuf
->head
, p
);
304 /* Copy the page array */
305 xdr_encode_pages(sndbuf
, args
->pages
, args
->pgbase
, count
);
310 * Encode create arguments
314 nfs_xdr_createargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_createargs
*args
)
316 p
= xdr_encode_fhandle(p
, args
->fh
);
317 p
= xdr_encode_array(p
, args
->name
, args
->len
);
318 p
= xdr_encode_sattr(p
, args
->sattr
);
319 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
324 * Encode RENAME arguments
327 nfs_xdr_renameargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_renameargs
*args
)
329 p
= xdr_encode_fhandle(p
, args
->fromfh
);
330 p
= xdr_encode_array(p
, args
->fromname
, args
->fromlen
);
331 p
= xdr_encode_fhandle(p
, args
->tofh
);
332 p
= xdr_encode_array(p
, args
->toname
, args
->tolen
);
333 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
338 * Encode LINK arguments
341 nfs_xdr_linkargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_linkargs
*args
)
343 p
= xdr_encode_fhandle(p
, args
->fromfh
);
344 p
= xdr_encode_fhandle(p
, args
->tofh
);
345 p
= xdr_encode_array(p
, args
->toname
, args
->tolen
);
346 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
351 * Encode SYMLINK arguments
354 nfs_xdr_symlinkargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_symlinkargs
*args
)
356 p
= xdr_encode_fhandle(p
, args
->fromfh
);
357 p
= xdr_encode_array(p
, args
->fromname
, args
->fromlen
);
358 p
= xdr_encode_array(p
, args
->topath
, args
->tolen
);
359 p
= xdr_encode_sattr(p
, args
->sattr
);
360 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
365 * Encode arguments to readdir call
368 nfs_xdr_readdirargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_readdirargs
*args
)
370 struct rpc_task
*task
= req
->rq_task
;
371 struct rpc_auth
*auth
= task
->tk_auth
;
373 u32 count
= args
->count
;
375 p
= xdr_encode_fhandle(p
, args
->fh
);
376 *p
++ = htonl(args
->cookie
);
377 *p
++ = htonl(count
); /* see above */
378 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
380 /* Inline the page array */
381 replen
= (RPC_REPHDRSIZE
+ auth
->au_rslack
+ NFS_readdirres_sz
) << 2;
382 xdr_inline_pages(&req
->rq_rcv_buf
, replen
, args
->pages
, 0, count
);
387 * Decode the result of a readdir call.
388 * We're not really decoding anymore, we just leave the buffer untouched
389 * and only check that it is syntactically correct.
390 * The real decoding happens in nfs_decode_entry below, called directly
391 * from nfs_readdir for each entry.
394 nfs_xdr_readdirres(struct rpc_rqst
*req
, u32
*p
, void *dummy
)
396 struct xdr_buf
*rcvbuf
= &req
->rq_rcv_buf
;
397 struct kvec
*iov
= rcvbuf
->head
;
401 unsigned int len
, pglen
;
402 u32
*end
, *entry
, *kaddr
;
404 if ((status
= ntohl(*p
++)))
405 return -nfs_stat_to_errno(status
);
407 hdrlen
= (u8
*) p
- (u8
*) iov
->iov_base
;
408 if (iov
->iov_len
< hdrlen
) {
409 printk(KERN_WARNING
"NFS: READDIR reply header overflowed:"
410 "length %d > %Zu\n", hdrlen
, iov
->iov_len
);
411 return -errno_NFSERR_IO
;
412 } else if (iov
->iov_len
!= hdrlen
) {
413 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
414 xdr_shift_buf(rcvbuf
, iov
->iov_len
- hdrlen
);
417 pglen
= rcvbuf
->page_len
;
418 recvd
= rcvbuf
->len
- hdrlen
;
421 page
= rcvbuf
->pages
;
422 kaddr
= p
= (u32
*)kmap_atomic(*page
, KM_USER0
);
423 end
= (u32
*)((char *)p
+ pglen
);
425 for (nr
= 0; *p
++; nr
++) {
430 p
+= XDR_QUADLEN(len
) + 1; /* name plus cookie */
431 if (len
> NFS2_MAXNAMLEN
) {
432 printk(KERN_WARNING
"NFS: giant filename in readdir (len 0x%x)!\n",
440 if (!nr
&& (entry
[0] != 0 || entry
[1] == 0))
443 kunmap_atomic(kaddr
, KM_USER0
);
446 entry
[0] = entry
[1] = 0;
447 /* truncate listing ? */
449 printk(KERN_NOTICE
"NFS: readdir reply truncated!\n");
454 nr
= -errno_NFSERR_IO
;
459 nfs_decode_dirent(u32
*p
, struct nfs_entry
*entry
, int plus
)
463 return ERR_PTR(-EAGAIN
);
465 return ERR_PTR(-EBADCOOKIE
);
468 entry
->ino
= ntohl(*p
++);
469 entry
->len
= ntohl(*p
++);
470 entry
->name
= (const char *) p
;
471 p
+= XDR_QUADLEN(entry
->len
);
472 entry
->prev_cookie
= entry
->cookie
;
473 entry
->cookie
= ntohl(*p
++);
474 entry
->eof
= !p
[0] && p
[1];
480 * NFS XDR decode functions
483 * Decode simple status reply
486 nfs_xdr_stat(struct rpc_rqst
*req
, u32
*p
, void *dummy
)
490 if ((status
= ntohl(*p
++)) != 0)
491 status
= -nfs_stat_to_errno(status
);
496 * Decode attrstat reply
497 * GETATTR, SETATTR, WRITE
500 nfs_xdr_attrstat(struct rpc_rqst
*req
, u32
*p
, struct nfs_fattr
*fattr
)
504 if ((status
= ntohl(*p
++)))
505 return -nfs_stat_to_errno(status
);
506 xdr_decode_fattr(p
, fattr
);
511 * Decode diropres reply
512 * LOOKUP, CREATE, MKDIR
515 nfs_xdr_diropres(struct rpc_rqst
*req
, u32
*p
, struct nfs_diropok
*res
)
519 if ((status
= ntohl(*p
++)))
520 return -nfs_stat_to_errno(status
);
521 p
= xdr_decode_fhandle(p
, res
->fh
);
522 xdr_decode_fattr(p
, res
->fattr
);
527 * Encode READLINK args
530 nfs_xdr_readlinkargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_readlinkargs
*args
)
532 struct rpc_auth
*auth
= req
->rq_task
->tk_auth
;
535 p
= xdr_encode_fhandle(p
, args
->fh
);
536 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
538 /* Inline the page array */
539 replen
= (RPC_REPHDRSIZE
+ auth
->au_rslack
+ NFS_readlinkres_sz
) << 2;
540 xdr_inline_pages(&req
->rq_rcv_buf
, replen
, args
->pages
, args
->pgbase
, args
->pglen
);
545 * Decode READLINK reply
548 nfs_xdr_readlinkres(struct rpc_rqst
*req
, u32
*p
, void *dummy
)
550 struct xdr_buf
*rcvbuf
= &req
->rq_rcv_buf
;
551 struct kvec
*iov
= rcvbuf
->head
;
552 int hdrlen
, len
, recvd
;
556 if ((status
= ntohl(*p
++)))
557 return -nfs_stat_to_errno(status
);
558 /* Convert length of symlink */
560 if (len
>= rcvbuf
->page_len
|| len
<= 0) {
561 dprintk(KERN_WARNING
"nfs: server returned giant symlink!\n");
562 return -ENAMETOOLONG
;
564 hdrlen
= (u8
*) p
- (u8
*) iov
->iov_base
;
565 if (iov
->iov_len
< hdrlen
) {
566 printk(KERN_WARNING
"NFS: READLINK reply header overflowed:"
567 "length %d > %Zu\n", hdrlen
, iov
->iov_len
);
568 return -errno_NFSERR_IO
;
569 } else if (iov
->iov_len
!= hdrlen
) {
570 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
571 xdr_shift_buf(rcvbuf
, iov
->iov_len
- hdrlen
);
573 recvd
= req
->rq_rcv_buf
.len
- hdrlen
;
575 printk(KERN_WARNING
"NFS: server cheating in readlink reply: "
576 "count %u > recvd %u\n", len
, recvd
);
580 /* NULL terminate the string we got */
581 kaddr
= (char *)kmap_atomic(rcvbuf
->pages
[0], KM_USER0
);
582 kaddr
[len
+rcvbuf
->page_base
] = '\0';
583 kunmap_atomic(kaddr
, KM_USER0
);
591 nfs_xdr_writeres(struct rpc_rqst
*req
, u32
*p
, struct nfs_writeres
*res
)
593 res
->verf
->committed
= NFS_FILE_SYNC
;
594 return nfs_xdr_attrstat(req
, p
, res
->fattr
);
598 * Decode STATFS reply
601 nfs_xdr_statfsres(struct rpc_rqst
*req
, u32
*p
, struct nfs2_fsstat
*res
)
605 if ((status
= ntohl(*p
++)))
606 return -nfs_stat_to_errno(status
);
608 res
->tsize
= ntohl(*p
++);
609 res
->bsize
= ntohl(*p
++);
610 res
->blocks
= ntohl(*p
++);
611 res
->bfree
= ntohl(*p
++);
612 res
->bavail
= ntohl(*p
++);
617 * We need to translate between nfs status return values and
618 * the local errno values which may not be the same.
625 { NFSERR_PERM
, EPERM
},
626 { NFSERR_NOENT
, ENOENT
},
627 { NFSERR_IO
, errno_NFSERR_IO
},
628 { NFSERR_NXIO
, ENXIO
},
629 /* { NFSERR_EAGAIN, EAGAIN }, */
630 { NFSERR_ACCES
, EACCES
},
631 { NFSERR_EXIST
, EEXIST
},
632 { NFSERR_XDEV
, EXDEV
},
633 { NFSERR_NODEV
, ENODEV
},
634 { NFSERR_NOTDIR
, ENOTDIR
},
635 { NFSERR_ISDIR
, EISDIR
},
636 { NFSERR_INVAL
, EINVAL
},
637 { NFSERR_FBIG
, EFBIG
},
638 { NFSERR_NOSPC
, ENOSPC
},
639 { NFSERR_ROFS
, EROFS
},
640 { NFSERR_MLINK
, EMLINK
},
641 { NFSERR_NAMETOOLONG
, ENAMETOOLONG
},
642 { NFSERR_NOTEMPTY
, ENOTEMPTY
},
643 { NFSERR_DQUOT
, EDQUOT
},
644 { NFSERR_STALE
, ESTALE
},
645 { NFSERR_REMOTE
, EREMOTE
},
647 { NFSERR_WFLUSH
, EWFLUSH
},
649 { NFSERR_BADHANDLE
, EBADHANDLE
},
650 { NFSERR_NOT_SYNC
, ENOTSYNC
},
651 { NFSERR_BAD_COOKIE
, EBADCOOKIE
},
652 { NFSERR_NOTSUPP
, ENOTSUPP
},
653 { NFSERR_TOOSMALL
, ETOOSMALL
},
654 { NFSERR_SERVERFAULT
, ESERVERFAULT
},
655 { NFSERR_BADTYPE
, EBADTYPE
},
656 { NFSERR_JUKEBOX
, EJUKEBOX
},
661 * Convert an NFS error code to a local one.
662 * This one is used jointly by NFSv2 and NFSv3.
665 nfs_stat_to_errno(int stat
)
669 for (i
= 0; nfs_errtbl
[i
].stat
!= -1; i
++) {
670 if (nfs_errtbl
[i
].stat
== stat
)
671 return nfs_errtbl
[i
].errno
;
673 printk(KERN_ERR
"nfs_stat_to_errno: bad nfs status return value: %d\n", stat
);
674 return nfs_errtbl
[i
].errno
;
678 # define MAX(a, b) (((a) > (b))? (a) : (b))
681 #define PROC(proc, argtype, restype, timer) \
682 [NFSPROC_##proc] = { \
683 .p_proc = NFSPROC_##proc, \
684 .p_encode = (kxdrproc_t) nfs_xdr_##argtype, \
685 .p_decode = (kxdrproc_t) nfs_xdr_##restype, \
686 .p_bufsiz = MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2, \
689 struct rpc_procinfo nfs_procedures
[] = {
690 PROC(GETATTR
, fhandle
, attrstat
, 1),
691 PROC(SETATTR
, sattrargs
, attrstat
, 0),
692 PROC(LOOKUP
, diropargs
, diropres
, 2),
693 PROC(READLINK
, readlinkargs
, readlinkres
, 3),
694 PROC(READ
, readargs
, readres
, 3),
695 PROC(WRITE
, writeargs
, writeres
, 4),
696 PROC(CREATE
, createargs
, diropres
, 0),
697 PROC(REMOVE
, diropargs
, stat
, 0),
698 PROC(RENAME
, renameargs
, stat
, 0),
699 PROC(LINK
, linkargs
, stat
, 0),
700 PROC(SYMLINK
, symlinkargs
, stat
, 0),
701 PROC(MKDIR
, createargs
, diropres
, 0),
702 PROC(RMDIR
, diropargs
, stat
, 0),
703 PROC(READDIR
, readdirargs
, readdirres
, 3),
704 PROC(STATFS
, fhandle
, statfsres
, 0),
707 struct rpc_version nfs_version2
= {
709 .nrprocs
= sizeof(nfs_procedures
)/sizeof(nfs_procedures
[0]),
710 .procs
= nfs_procedures