2 * linux/fs/nfsd/nfs3proc.c
4 * Process version 3 NFS requests.
6 * Copyright (C) 1996, 1997, 1998 Olaf Kirch <okir@monad.swb.de>
9 #include <linux/linkage.h>
10 #include <linux/time.h>
11 #include <linux/errno.h>
13 #include <linux/ext2_fs.h>
14 #include <linux/stat.h>
15 #include <linux/fcntl.h>
16 #include <linux/net.h>
18 #include <linux/unistd.h>
19 #include <linux/slab.h>
20 #include <linux/major.h>
22 #include <linux/sunrpc/svc.h>
23 #include <linux/nfsd/nfsd.h>
24 #include <linux/nfsd/cache.h>
25 #include <linux/nfsd/xdr3.h>
26 #include <linux/nfs3.h>
28 #define NFSDDBG_FACILITY NFSDDBG_PROC
30 #define RETURN_STATUS(st) { resp->status = (st); return (st); }
32 static int nfs3_ftypes
[] = {
39 S_IFSOCK
, /* NF3SOCK */
40 S_IFIFO
, /* NF3FIFO */
47 nfsd3_proc_null(struct svc_rqst
*rqstp
, void *argp
, void *resp
)
53 * Get a file's attributes
56 nfsd3_proc_getattr(struct svc_rqst
*rqstp
, struct nfsd_fhandle
*argp
,
57 struct nfsd3_attrstat
*resp
)
61 dprintk("nfsd: GETATTR(3) %s\n",
62 SVCFH_fmt(&argp
->fh
));
64 fh_copy(&resp
->fh
, &argp
->fh
);
65 nfserr
= fh_verify(rqstp
, &resp
->fh
, 0, MAY_NOP
);
67 RETURN_STATUS(nfserr
);
69 err
= vfs_getattr(resp
->fh
.fh_export
->ex_mnt
,
70 resp
->fh
.fh_dentry
, &resp
->stat
);
71 nfserr
= nfserrno(err
);
73 RETURN_STATUS(nfserr
);
77 * Set a file's attributes
80 nfsd3_proc_setattr(struct svc_rqst
*rqstp
, struct nfsd3_sattrargs
*argp
,
81 struct nfsd3_attrstat
*resp
)
85 dprintk("nfsd: SETATTR(3) %s\n",
86 SVCFH_fmt(&argp
->fh
));
88 fh_copy(&resp
->fh
, &argp
->fh
);
89 nfserr
= nfsd_setattr(rqstp
, &resp
->fh
, &argp
->attrs
,
90 argp
->check_guard
, argp
->guardtime
);
91 RETURN_STATUS(nfserr
);
95 * Look up a path name component
98 nfsd3_proc_lookup(struct svc_rqst
*rqstp
, struct nfsd3_diropargs
*argp
,
99 struct nfsd3_diropres
*resp
)
103 dprintk("nfsd: LOOKUP(3) %s %.*s\n",
104 SVCFH_fmt(&argp
->fh
),
108 fh_copy(&resp
->dirfh
, &argp
->fh
);
109 fh_init(&resp
->fh
, NFS3_FHSIZE
);
111 nfserr
= nfsd_lookup(rqstp
, &resp
->dirfh
,
115 RETURN_STATUS(nfserr
);
122 nfsd3_proc_access(struct svc_rqst
*rqstp
, struct nfsd3_accessargs
*argp
,
123 struct nfsd3_accessres
*resp
)
127 dprintk("nfsd: ACCESS(3) %s 0x%x\n",
128 SVCFH_fmt(&argp
->fh
),
131 fh_copy(&resp
->fh
, &argp
->fh
);
132 resp
->access
= argp
->access
;
133 nfserr
= nfsd_access(rqstp
, &resp
->fh
, &resp
->access
, NULL
);
134 RETURN_STATUS(nfserr
);
141 nfsd3_proc_readlink(struct svc_rqst
*rqstp
, struct nfsd3_readlinkargs
*argp
,
142 struct nfsd3_readlinkres
*resp
)
146 dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp
->fh
));
148 /* Read the symlink. */
149 fh_copy(&resp
->fh
, &argp
->fh
);
150 resp
->len
= NFS3_MAXPATHLEN
;
151 nfserr
= nfsd_readlink(rqstp
, &resp
->fh
, argp
->buffer
, &resp
->len
);
152 RETURN_STATUS(nfserr
);
156 * Read a portion of a file.
159 nfsd3_proc_read(struct svc_rqst
*rqstp
, struct nfsd3_readargs
*argp
,
160 struct nfsd3_readres
*resp
)
164 dprintk("nfsd: READ(3) %s %lu bytes at %lu\n",
165 SVCFH_fmt(&argp
->fh
),
166 (unsigned long) argp
->count
,
167 (unsigned long) argp
->offset
);
169 /* Obtain buffer pointer for payload.
170 * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
171 * + 1 (xdr opaque byte count) = 26
174 resp
->count
= argp
->count
;
175 if (NFSSVC_MAXBLKSIZE
< resp
->count
)
176 resp
->count
= NFSSVC_MAXBLKSIZE
;
178 svc_reserve(rqstp
, ((1 + NFS3_POST_OP_ATTR_WORDS
+ 3)<<2) + resp
->count
+4);
180 fh_copy(&resp
->fh
, &argp
->fh
);
181 nfserr
= nfsd_read(rqstp
, &resp
->fh
, NULL
,
183 argp
->vec
, argp
->vlen
,
186 struct inode
*inode
= resp
->fh
.fh_dentry
->d_inode
;
188 resp
->eof
= (argp
->offset
+ resp
->count
) >= inode
->i_size
;
191 RETURN_STATUS(nfserr
);
195 * Write data to a file
198 nfsd3_proc_write(struct svc_rqst
*rqstp
, struct nfsd3_writeargs
*argp
,
199 struct nfsd3_writeres
*resp
)
203 dprintk("nfsd: WRITE(3) %s %d bytes at %ld%s\n",
204 SVCFH_fmt(&argp
->fh
),
206 (unsigned long) argp
->offset
,
207 argp
->stable
? " stable" : "");
209 fh_copy(&resp
->fh
, &argp
->fh
);
210 resp
->committed
= argp
->stable
;
211 nfserr
= nfsd_write(rqstp
, &resp
->fh
, NULL
,
213 argp
->vec
, argp
->vlen
,
216 resp
->count
= argp
->count
;
217 RETURN_STATUS(nfserr
);
221 * With NFSv3, CREATE processing is a lot easier than with NFSv2.
222 * At least in theory; we'll see how it fares in practice when the
223 * first reports about SunOS compatibility problems start to pour in...
226 nfsd3_proc_create(struct svc_rqst
*rqstp
, struct nfsd3_createargs
*argp
,
227 struct nfsd3_diropres
*resp
)
229 svc_fh
*dirfhp
, *newfhp
= NULL
;
233 dprintk("nfsd: CREATE(3) %s %.*s\n",
234 SVCFH_fmt(&argp
->fh
),
238 dirfhp
= fh_copy(&resp
->dirfh
, &argp
->fh
);
239 newfhp
= fh_init(&resp
->fh
, NFS3_FHSIZE
);
242 /* Get the directory inode */
243 nfserr
= fh_verify(rqstp
, dirfhp
, S_IFDIR
, MAY_CREATE
);
245 RETURN_STATUS(nfserr
);
247 /* Unfudge the mode bits */
248 attr
->ia_mode
&= ~S_IFMT
;
249 if (!(attr
->ia_valid
& ATTR_MODE
)) {
250 attr
->ia_valid
|= ATTR_MODE
;
251 attr
->ia_mode
= S_IFREG
;
253 attr
->ia_mode
= (attr
->ia_mode
& ~S_IFMT
) | S_IFREG
;
256 /* Now create the file and set attributes */
257 nfserr
= nfsd_create_v3(rqstp
, dirfhp
, argp
->name
, argp
->len
,
259 argp
->createmode
, argp
->verf
, NULL
);
261 RETURN_STATUS(nfserr
);
265 * Make directory. This operation is not idempotent.
268 nfsd3_proc_mkdir(struct svc_rqst
*rqstp
, struct nfsd3_createargs
*argp
,
269 struct nfsd3_diropres
*resp
)
273 dprintk("nfsd: MKDIR(3) %s %.*s\n",
274 SVCFH_fmt(&argp
->fh
),
278 argp
->attrs
.ia_valid
&= ~ATTR_SIZE
;
279 fh_copy(&resp
->dirfh
, &argp
->fh
);
280 fh_init(&resp
->fh
, NFS3_FHSIZE
);
281 nfserr
= nfsd_create(rqstp
, &resp
->dirfh
, argp
->name
, argp
->len
,
282 &argp
->attrs
, S_IFDIR
, 0, &resp
->fh
);
284 RETURN_STATUS(nfserr
);
288 nfsd3_proc_symlink(struct svc_rqst
*rqstp
, struct nfsd3_symlinkargs
*argp
,
289 struct nfsd3_diropres
*resp
)
293 dprintk("nfsd: SYMLINK(3) %s %.*s -> %.*s\n",
294 SVCFH_fmt(&argp
->ffh
),
295 argp
->flen
, argp
->fname
,
296 argp
->tlen
, argp
->tname
);
298 fh_copy(&resp
->dirfh
, &argp
->ffh
);
299 fh_init(&resp
->fh
, NFS3_FHSIZE
);
300 nfserr
= nfsd_symlink(rqstp
, &resp
->dirfh
, argp
->fname
, argp
->flen
,
301 argp
->tname
, argp
->tlen
,
302 &resp
->fh
, &argp
->attrs
);
303 RETURN_STATUS(nfserr
);
307 * Make socket/fifo/device.
310 nfsd3_proc_mknod(struct svc_rqst
*rqstp
, struct nfsd3_mknodargs
*argp
,
311 struct nfsd3_diropres
*resp
)
316 dprintk("nfsd: MKNOD(3) %s %.*s\n",
317 SVCFH_fmt(&argp
->fh
),
321 fh_copy(&resp
->dirfh
, &argp
->fh
);
322 fh_init(&resp
->fh
, NFS3_FHSIZE
);
324 if (argp
->ftype
== 0 || argp
->ftype
>= NF3BAD
)
325 RETURN_STATUS(nfserr_inval
);
326 if (argp
->ftype
== NF3CHR
|| argp
->ftype
== NF3BLK
) {
327 rdev
= MKDEV(argp
->major
, argp
->minor
);
328 if (MAJOR(rdev
) != argp
->major
||
329 MINOR(rdev
) != argp
->minor
)
330 RETURN_STATUS(nfserr_inval
);
332 if (argp
->ftype
!= NF3SOCK
&& argp
->ftype
!= NF3FIFO
)
333 RETURN_STATUS(nfserr_inval
);
335 type
= nfs3_ftypes
[argp
->ftype
];
336 nfserr
= nfsd_create(rqstp
, &resp
->dirfh
, argp
->name
, argp
->len
,
337 &argp
->attrs
, type
, rdev
, &resp
->fh
);
339 RETURN_STATUS(nfserr
);
343 * Remove file/fifo/socket etc.
346 nfsd3_proc_remove(struct svc_rqst
*rqstp
, struct nfsd3_diropargs
*argp
,
347 struct nfsd3_attrstat
*resp
)
351 dprintk("nfsd: REMOVE(3) %s %.*s\n",
352 SVCFH_fmt(&argp
->fh
),
356 /* Unlink. -S_IFDIR means file must not be a directory */
357 fh_copy(&resp
->fh
, &argp
->fh
);
358 nfserr
= nfsd_unlink(rqstp
, &resp
->fh
, -S_IFDIR
, argp
->name
, argp
->len
);
359 RETURN_STATUS(nfserr
);
366 nfsd3_proc_rmdir(struct svc_rqst
*rqstp
, struct nfsd3_diropargs
*argp
,
367 struct nfsd3_attrstat
*resp
)
371 dprintk("nfsd: RMDIR(3) %s %.*s\n",
372 SVCFH_fmt(&argp
->fh
),
376 fh_copy(&resp
->fh
, &argp
->fh
);
377 nfserr
= nfsd_unlink(rqstp
, &resp
->fh
, S_IFDIR
, argp
->name
, argp
->len
);
378 RETURN_STATUS(nfserr
);
382 nfsd3_proc_rename(struct svc_rqst
*rqstp
, struct nfsd3_renameargs
*argp
,
383 struct nfsd3_renameres
*resp
)
387 dprintk("nfsd: RENAME(3) %s %.*s ->\n",
388 SVCFH_fmt(&argp
->ffh
),
391 dprintk("nfsd: -> %s %.*s\n",
392 SVCFH_fmt(&argp
->tfh
),
396 fh_copy(&resp
->ffh
, &argp
->ffh
);
397 fh_copy(&resp
->tfh
, &argp
->tfh
);
398 nfserr
= nfsd_rename(rqstp
, &resp
->ffh
, argp
->fname
, argp
->flen
,
399 &resp
->tfh
, argp
->tname
, argp
->tlen
);
400 RETURN_STATUS(nfserr
);
404 nfsd3_proc_link(struct svc_rqst
*rqstp
, struct nfsd3_linkargs
*argp
,
405 struct nfsd3_linkres
*resp
)
409 dprintk("nfsd: LINK(3) %s ->\n",
410 SVCFH_fmt(&argp
->ffh
));
411 dprintk("nfsd: -> %s %.*s\n",
412 SVCFH_fmt(&argp
->tfh
),
416 fh_copy(&resp
->fh
, &argp
->ffh
);
417 fh_copy(&resp
->tfh
, &argp
->tfh
);
418 nfserr
= nfsd_link(rqstp
, &resp
->tfh
, argp
->tname
, argp
->tlen
,
420 RETURN_STATUS(nfserr
);
424 * Read a portion of a directory.
427 nfsd3_proc_readdir(struct svc_rqst
*rqstp
, struct nfsd3_readdirargs
*argp
,
428 struct nfsd3_readdirres
*resp
)
432 dprintk("nfsd: READDIR(3) %s %d bytes at %d\n",
433 SVCFH_fmt(&argp
->fh
),
434 argp
->count
, (u32
) argp
->cookie
);
436 /* Make sure we've room for the NULL ptr & eof flag, and shrink to
437 * client read size */
438 count
= (argp
->count
>> 2) - 2;
440 /* Read directory and encode entries on the fly */
441 fh_copy(&resp
->fh
, &argp
->fh
);
443 resp
->buflen
= count
;
444 resp
->common
.err
= nfs_ok
;
445 resp
->buffer
= argp
->buffer
;
447 nfserr
= nfsd_readdir(rqstp
, &resp
->fh
, (loff_t
*) &argp
->cookie
,
448 &resp
->common
, nfs3svc_encode_entry
);
449 memcpy(resp
->verf
, argp
->verf
, 8);
450 resp
->count
= resp
->buffer
- argp
->buffer
;
452 xdr_encode_hyper(resp
->offset
, argp
->cookie
);
454 RETURN_STATUS(nfserr
);
458 * Read a portion of a directory, including file handles and attrs.
459 * For now, we choose to ignore the dircount parameter.
462 nfsd3_proc_readdirplus(struct svc_rqst
*rqstp
, struct nfsd3_readdirargs
*argp
,
463 struct nfsd3_readdirres
*resp
)
465 int nfserr
, count
= 0;
468 caddr_t page_addr
= NULL
;
470 dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n",
471 SVCFH_fmt(&argp
->fh
),
472 argp
->count
, (u32
) argp
->cookie
);
474 /* Convert byte count to number of words (i.e. >> 2),
475 * and reserve room for the NULL ptr & eof flag (-2 words) */
476 resp
->count
= (argp
->count
>> 2) - 2;
478 /* Read directory and encode entries on the fly */
479 fh_copy(&resp
->fh
, &argp
->fh
);
481 resp
->common
.err
= nfs_ok
;
482 resp
->buffer
= argp
->buffer
;
483 resp
->buflen
= resp
->count
;
485 offset
= argp
->cookie
;
486 nfserr
= nfsd_readdir(rqstp
, &resp
->fh
,
489 nfs3svc_encode_entry_plus
);
490 memcpy(resp
->verf
, argp
->verf
, 8);
491 for (i
=1; i
<rqstp
->rq_resused
; i
++) {
492 page_addr
= page_address(rqstp
->rq_respages
[i
]);
494 if (((caddr_t
)resp
->buffer
>= page_addr
) &&
495 ((caddr_t
)resp
->buffer
< page_addr
+ PAGE_SIZE
)) {
496 count
+= (caddr_t
)resp
->buffer
- page_addr
;
501 resp
->count
= count
>> 2;
503 if (unlikely(resp
->offset1
)) {
504 /* we ended up with offset on a page boundary */
505 *resp
->offset
= htonl(offset
>> 32);
506 *resp
->offset1
= htonl(offset
& 0xffffffff);
507 resp
->offset1
= NULL
;
509 xdr_encode_hyper(resp
->offset
, offset
);
513 RETURN_STATUS(nfserr
);
517 * Get file system stats
520 nfsd3_proc_fsstat(struct svc_rqst
* rqstp
, struct nfsd_fhandle
*argp
,
521 struct nfsd3_fsstatres
*resp
)
525 dprintk("nfsd: FSSTAT(3) %s\n",
526 SVCFH_fmt(&argp
->fh
));
528 nfserr
= nfsd_statfs(rqstp
, &argp
->fh
, &resp
->stats
);
530 RETURN_STATUS(nfserr
);
534 * Get file system info
537 nfsd3_proc_fsinfo(struct svc_rqst
* rqstp
, struct nfsd_fhandle
*argp
,
538 struct nfsd3_fsinfores
*resp
)
542 dprintk("nfsd: FSINFO(3) %s\n",
543 SVCFH_fmt(&argp
->fh
));
545 resp
->f_rtmax
= NFSSVC_MAXBLKSIZE
;
546 resp
->f_rtpref
= NFSSVC_MAXBLKSIZE
;
547 resp
->f_rtmult
= PAGE_SIZE
;
548 resp
->f_wtmax
= NFSSVC_MAXBLKSIZE
;
549 resp
->f_wtpref
= NFSSVC_MAXBLKSIZE
;
550 resp
->f_wtmult
= PAGE_SIZE
;
551 resp
->f_dtpref
= PAGE_SIZE
;
552 resp
->f_maxfilesize
= ~(u32
) 0;
553 resp
->f_properties
= NFS3_FSF_DEFAULT
;
555 nfserr
= fh_verify(rqstp
, &argp
->fh
, 0, MAY_NOP
);
557 /* Check special features of the file system. May request
558 * different read/write sizes for file systems known to have
559 * problems with large blocks */
561 struct super_block
*sb
= argp
->fh
.fh_dentry
->d_inode
->i_sb
;
563 /* Note that we don't care for remote fs's here */
564 if (sb
->s_magic
== 0x4d44 /* MSDOS_SUPER_MAGIC */) {
565 resp
->f_properties
= NFS3_FSF_BILLYBOY
;
567 resp
->f_maxfilesize
= sb
->s_maxbytes
;
571 RETURN_STATUS(nfserr
);
575 * Get pathconf info for the specified file
578 nfsd3_proc_pathconf(struct svc_rqst
* rqstp
, struct nfsd_fhandle
*argp
,
579 struct nfsd3_pathconfres
*resp
)
583 dprintk("nfsd: PATHCONF(3) %s\n",
584 SVCFH_fmt(&argp
->fh
));
586 /* Set default pathconf */
587 resp
->p_link_max
= 255; /* at least */
588 resp
->p_name_max
= 255; /* at least */
589 resp
->p_no_trunc
= 0;
590 resp
->p_chown_restricted
= 1;
591 resp
->p_case_insensitive
= 0;
592 resp
->p_case_preserving
= 1;
594 nfserr
= fh_verify(rqstp
, &argp
->fh
, 0, MAY_NOP
);
597 struct super_block
*sb
= argp
->fh
.fh_dentry
->d_inode
->i_sb
;
599 /* Note that we don't care for remote fs's here */
600 switch (sb
->s_magic
) {
601 case EXT2_SUPER_MAGIC
:
602 resp
->p_link_max
= EXT2_LINK_MAX
;
603 resp
->p_name_max
= EXT2_NAME_LEN
;
605 case 0x4d44: /* MSDOS_SUPER_MAGIC */
606 resp
->p_case_insensitive
= 1;
607 resp
->p_case_preserving
= 0;
613 RETURN_STATUS(nfserr
);
618 * Commit a file (range) to stable storage.
621 nfsd3_proc_commit(struct svc_rqst
* rqstp
, struct nfsd3_commitargs
*argp
,
622 struct nfsd3_commitres
*resp
)
626 dprintk("nfsd: COMMIT(3) %s %u@%Lu\n",
627 SVCFH_fmt(&argp
->fh
),
629 (unsigned long long) argp
->offset
);
631 if (argp
->offset
> NFS_OFFSET_MAX
)
632 RETURN_STATUS(nfserr_inval
);
634 fh_copy(&resp
->fh
, &argp
->fh
);
635 nfserr
= nfsd_commit(rqstp
, &resp
->fh
, argp
->offset
, argp
->count
);
637 RETURN_STATUS(nfserr
);
642 * NFSv3 Server procedures.
643 * Only the results of non-idempotent operations are cached.
645 #define nfs3svc_decode_voidargs NULL
646 #define nfs3svc_release_void NULL
647 #define nfs3svc_decode_fhandleargs nfs3svc_decode_fhandle
648 #define nfs3svc_encode_attrstatres nfs3svc_encode_attrstat
649 #define nfs3svc_encode_wccstatres nfs3svc_encode_wccstat
650 #define nfsd3_mkdirargs nfsd3_createargs
651 #define nfsd3_readdirplusargs nfsd3_readdirargs
652 #define nfsd3_fhandleargs nfsd_fhandle
653 #define nfsd3_fhandleres nfsd3_attrstat
654 #define nfsd3_attrstatres nfsd3_attrstat
655 #define nfsd3_wccstatres nfsd3_attrstat
656 #define nfsd3_createres nfsd3_diropres
657 #define nfsd3_voidres nfsd3_voidargs
658 struct nfsd3_voidargs
{ int dummy
; };
660 #define PROC(name, argt, rest, relt, cache, respsize) \
661 { (svc_procfunc) nfsd3_proc_##name, \
662 (kxdrproc_t) nfs3svc_decode_##argt##args, \
663 (kxdrproc_t) nfs3svc_encode_##rest##res, \
664 (kxdrproc_t) nfs3svc_release_##relt, \
665 sizeof(struct nfsd3_##argt##args), \
666 sizeof(struct nfsd3_##rest##res), \
672 #define ST 1 /* status*/
673 #define FH 17 /* filehandle with length */
674 #define AT 21 /* attributes */
675 #define pAT (1+AT) /* post attributes - conditional */
676 #define WC (7+pAT) /* WCC attributes */
678 static struct svc_procedure nfsd_procedures3
[22] = {
679 PROC(null
, void, void, void, RC_NOCACHE
, ST
),
680 PROC(getattr
, fhandle
, attrstat
, fhandle
, RC_NOCACHE
, ST
+AT
),
681 PROC(setattr
, sattr
, wccstat
, fhandle
, RC_REPLBUFF
, ST
+WC
),
682 PROC(lookup
, dirop
, dirop
, fhandle2
, RC_NOCACHE
, ST
+FH
+pAT
+pAT
),
683 PROC(access
, access
, access
, fhandle
, RC_NOCACHE
, ST
+pAT
+1),
684 PROC(readlink
, readlink
, readlink
, fhandle
, RC_NOCACHE
, ST
+pAT
+1+NFS3_MAXPATHLEN
/4),
685 PROC(read
, read
, read
, fhandle
, RC_NOCACHE
, ST
+pAT
+4+NFSSVC_MAXBLKSIZE
/4),
686 PROC(write
, write
, write
, fhandle
, RC_REPLBUFF
, ST
+WC
+4),
687 PROC(create
, create
, create
, fhandle2
, RC_REPLBUFF
, ST
+(1+FH
+pAT
)+WC
),
688 PROC(mkdir
, mkdir
, create
, fhandle2
, RC_REPLBUFF
, ST
+(1+FH
+pAT
)+WC
),
689 PROC(symlink
, symlink
, create
, fhandle2
, RC_REPLBUFF
, ST
+(1+FH
+pAT
)+WC
),
690 PROC(mknod
, mknod
, create
, fhandle2
, RC_REPLBUFF
, ST
+(1+FH
+pAT
)+WC
),
691 PROC(remove
, dirop
, wccstat
, fhandle
, RC_REPLBUFF
, ST
+WC
),
692 PROC(rmdir
, dirop
, wccstat
, fhandle
, RC_REPLBUFF
, ST
+WC
),
693 PROC(rename
, rename
, rename
, fhandle2
, RC_REPLBUFF
, ST
+WC
+WC
),
694 PROC(link
, link
, link
, fhandle2
, RC_REPLBUFF
, ST
+pAT
+WC
),
695 PROC(readdir
, readdir
, readdir
, fhandle
, RC_NOCACHE
, 0),
696 PROC(readdirplus
,readdirplus
, readdir
, fhandle
, RC_NOCACHE
, 0),
697 PROC(fsstat
, fhandle
, fsstat
, void, RC_NOCACHE
, ST
+pAT
+2*6+1),
698 PROC(fsinfo
, fhandle
, fsinfo
, void, RC_NOCACHE
, ST
+pAT
+12),
699 PROC(pathconf
, fhandle
, pathconf
, void, RC_NOCACHE
, ST
+pAT
+6),
700 PROC(commit
, commit
, commit
, fhandle
, RC_NOCACHE
, ST
+WC
+2),
703 struct svc_version nfsd_version3
= {
706 .vs_proc
= nfsd_procedures3
,
707 .vs_dispatch
= nfsd_dispatch
,
708 .vs_xdrsize
= NFS3_SVC_XDRSIZE
,