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
)
163 u32 max_blocksize
= svc_max_payload(rqstp
);
165 dprintk("nfsd: READ(3) %s %lu bytes at %lu\n",
166 SVCFH_fmt(&argp
->fh
),
167 (unsigned long) argp
->count
,
168 (unsigned long) argp
->offset
);
170 /* Obtain buffer pointer for payload.
171 * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
172 * + 1 (xdr opaque byte count) = 26
175 resp
->count
= argp
->count
;
176 if (max_blocksize
< resp
->count
)
177 resp
->count
= max_blocksize
;
179 svc_reserve(rqstp
, ((1 + NFS3_POST_OP_ATTR_WORDS
+ 3)<<2) + resp
->count
+4);
181 fh_copy(&resp
->fh
, &argp
->fh
);
182 nfserr
= nfsd_read(rqstp
, &resp
->fh
, NULL
,
184 rqstp
->rq_vec
, argp
->vlen
,
187 struct inode
*inode
= resp
->fh
.fh_dentry
->d_inode
;
189 resp
->eof
= (argp
->offset
+ resp
->count
) >= inode
->i_size
;
192 RETURN_STATUS(nfserr
);
196 * Write data to a file
199 nfsd3_proc_write(struct svc_rqst
*rqstp
, struct nfsd3_writeargs
*argp
,
200 struct nfsd3_writeres
*resp
)
204 dprintk("nfsd: WRITE(3) %s %d bytes at %ld%s\n",
205 SVCFH_fmt(&argp
->fh
),
207 (unsigned long) argp
->offset
,
208 argp
->stable
? " stable" : "");
210 fh_copy(&resp
->fh
, &argp
->fh
);
211 resp
->committed
= argp
->stable
;
212 nfserr
= nfsd_write(rqstp
, &resp
->fh
, NULL
,
214 rqstp
->rq_vec
, argp
->vlen
,
217 resp
->count
= argp
->count
;
218 RETURN_STATUS(nfserr
);
222 * With NFSv3, CREATE processing is a lot easier than with NFSv2.
223 * At least in theory; we'll see how it fares in practice when the
224 * first reports about SunOS compatibility problems start to pour in...
227 nfsd3_proc_create(struct svc_rqst
*rqstp
, struct nfsd3_createargs
*argp
,
228 struct nfsd3_diropres
*resp
)
230 svc_fh
*dirfhp
, *newfhp
= NULL
;
234 dprintk("nfsd: CREATE(3) %s %.*s\n",
235 SVCFH_fmt(&argp
->fh
),
239 dirfhp
= fh_copy(&resp
->dirfh
, &argp
->fh
);
240 newfhp
= fh_init(&resp
->fh
, NFS3_FHSIZE
);
243 /* Get the directory inode */
244 nfserr
= fh_verify(rqstp
, dirfhp
, S_IFDIR
, MAY_CREATE
);
246 RETURN_STATUS(nfserr
);
248 /* Unfudge the mode bits */
249 attr
->ia_mode
&= ~S_IFMT
;
250 if (!(attr
->ia_valid
& ATTR_MODE
)) {
251 attr
->ia_valid
|= ATTR_MODE
;
252 attr
->ia_mode
= S_IFREG
;
254 attr
->ia_mode
= (attr
->ia_mode
& ~S_IFMT
) | S_IFREG
;
257 /* Now create the file and set attributes */
258 nfserr
= nfsd_create_v3(rqstp
, dirfhp
, argp
->name
, argp
->len
,
260 argp
->createmode
, argp
->verf
, NULL
);
262 RETURN_STATUS(nfserr
);
266 * Make directory. This operation is not idempotent.
269 nfsd3_proc_mkdir(struct svc_rqst
*rqstp
, struct nfsd3_createargs
*argp
,
270 struct nfsd3_diropres
*resp
)
274 dprintk("nfsd: MKDIR(3) %s %.*s\n",
275 SVCFH_fmt(&argp
->fh
),
279 argp
->attrs
.ia_valid
&= ~ATTR_SIZE
;
280 fh_copy(&resp
->dirfh
, &argp
->fh
);
281 fh_init(&resp
->fh
, NFS3_FHSIZE
);
282 nfserr
= nfsd_create(rqstp
, &resp
->dirfh
, argp
->name
, argp
->len
,
283 &argp
->attrs
, S_IFDIR
, 0, &resp
->fh
);
285 RETURN_STATUS(nfserr
);
289 nfsd3_proc_symlink(struct svc_rqst
*rqstp
, struct nfsd3_symlinkargs
*argp
,
290 struct nfsd3_diropres
*resp
)
294 dprintk("nfsd: SYMLINK(3) %s %.*s -> %.*s\n",
295 SVCFH_fmt(&argp
->ffh
),
296 argp
->flen
, argp
->fname
,
297 argp
->tlen
, argp
->tname
);
299 fh_copy(&resp
->dirfh
, &argp
->ffh
);
300 fh_init(&resp
->fh
, NFS3_FHSIZE
);
301 nfserr
= nfsd_symlink(rqstp
, &resp
->dirfh
, argp
->fname
, argp
->flen
,
302 argp
->tname
, argp
->tlen
,
303 &resp
->fh
, &argp
->attrs
);
304 RETURN_STATUS(nfserr
);
308 * Make socket/fifo/device.
311 nfsd3_proc_mknod(struct svc_rqst
*rqstp
, struct nfsd3_mknodargs
*argp
,
312 struct nfsd3_diropres
*resp
)
317 dprintk("nfsd: MKNOD(3) %s %.*s\n",
318 SVCFH_fmt(&argp
->fh
),
322 fh_copy(&resp
->dirfh
, &argp
->fh
);
323 fh_init(&resp
->fh
, NFS3_FHSIZE
);
325 if (argp
->ftype
== 0 || argp
->ftype
>= NF3BAD
)
326 RETURN_STATUS(nfserr_inval
);
327 if (argp
->ftype
== NF3CHR
|| argp
->ftype
== NF3BLK
) {
328 rdev
= MKDEV(argp
->major
, argp
->minor
);
329 if (MAJOR(rdev
) != argp
->major
||
330 MINOR(rdev
) != argp
->minor
)
331 RETURN_STATUS(nfserr_inval
);
333 if (argp
->ftype
!= NF3SOCK
&& argp
->ftype
!= NF3FIFO
)
334 RETURN_STATUS(nfserr_inval
);
336 type
= nfs3_ftypes
[argp
->ftype
];
337 nfserr
= nfsd_create(rqstp
, &resp
->dirfh
, argp
->name
, argp
->len
,
338 &argp
->attrs
, type
, rdev
, &resp
->fh
);
340 RETURN_STATUS(nfserr
);
344 * Remove file/fifo/socket etc.
347 nfsd3_proc_remove(struct svc_rqst
*rqstp
, struct nfsd3_diropargs
*argp
,
348 struct nfsd3_attrstat
*resp
)
352 dprintk("nfsd: REMOVE(3) %s %.*s\n",
353 SVCFH_fmt(&argp
->fh
),
357 /* Unlink. -S_IFDIR means file must not be a directory */
358 fh_copy(&resp
->fh
, &argp
->fh
);
359 nfserr
= nfsd_unlink(rqstp
, &resp
->fh
, -S_IFDIR
, argp
->name
, argp
->len
);
360 RETURN_STATUS(nfserr
);
367 nfsd3_proc_rmdir(struct svc_rqst
*rqstp
, struct nfsd3_diropargs
*argp
,
368 struct nfsd3_attrstat
*resp
)
372 dprintk("nfsd: RMDIR(3) %s %.*s\n",
373 SVCFH_fmt(&argp
->fh
),
377 fh_copy(&resp
->fh
, &argp
->fh
);
378 nfserr
= nfsd_unlink(rqstp
, &resp
->fh
, S_IFDIR
, argp
->name
, argp
->len
);
379 RETURN_STATUS(nfserr
);
383 nfsd3_proc_rename(struct svc_rqst
*rqstp
, struct nfsd3_renameargs
*argp
,
384 struct nfsd3_renameres
*resp
)
388 dprintk("nfsd: RENAME(3) %s %.*s ->\n",
389 SVCFH_fmt(&argp
->ffh
),
392 dprintk("nfsd: -> %s %.*s\n",
393 SVCFH_fmt(&argp
->tfh
),
397 fh_copy(&resp
->ffh
, &argp
->ffh
);
398 fh_copy(&resp
->tfh
, &argp
->tfh
);
399 nfserr
= nfsd_rename(rqstp
, &resp
->ffh
, argp
->fname
, argp
->flen
,
400 &resp
->tfh
, argp
->tname
, argp
->tlen
);
401 RETURN_STATUS(nfserr
);
405 nfsd3_proc_link(struct svc_rqst
*rqstp
, struct nfsd3_linkargs
*argp
,
406 struct nfsd3_linkres
*resp
)
410 dprintk("nfsd: LINK(3) %s ->\n",
411 SVCFH_fmt(&argp
->ffh
));
412 dprintk("nfsd: -> %s %.*s\n",
413 SVCFH_fmt(&argp
->tfh
),
417 fh_copy(&resp
->fh
, &argp
->ffh
);
418 fh_copy(&resp
->tfh
, &argp
->tfh
);
419 nfserr
= nfsd_link(rqstp
, &resp
->tfh
, argp
->tname
, argp
->tlen
,
421 RETURN_STATUS(nfserr
);
425 * Read a portion of a directory.
428 nfsd3_proc_readdir(struct svc_rqst
*rqstp
, struct nfsd3_readdirargs
*argp
,
429 struct nfsd3_readdirres
*resp
)
433 dprintk("nfsd: READDIR(3) %s %d bytes at %d\n",
434 SVCFH_fmt(&argp
->fh
),
435 argp
->count
, (u32
) argp
->cookie
);
437 /* Make sure we've room for the NULL ptr & eof flag, and shrink to
438 * client read size */
439 count
= (argp
->count
>> 2) - 2;
441 /* Read directory and encode entries on the fly */
442 fh_copy(&resp
->fh
, &argp
->fh
);
444 resp
->buflen
= count
;
445 resp
->common
.err
= nfs_ok
;
446 resp
->buffer
= argp
->buffer
;
448 nfserr
= nfsd_readdir(rqstp
, &resp
->fh
, (loff_t
*) &argp
->cookie
,
449 &resp
->common
, nfs3svc_encode_entry
);
450 memcpy(resp
->verf
, argp
->verf
, 8);
451 resp
->count
= resp
->buffer
- argp
->buffer
;
453 xdr_encode_hyper(resp
->offset
, argp
->cookie
);
455 RETURN_STATUS(nfserr
);
459 * Read a portion of a directory, including file handles and attrs.
460 * For now, we choose to ignore the dircount parameter.
463 nfsd3_proc_readdirplus(struct svc_rqst
*rqstp
, struct nfsd3_readdirargs
*argp
,
464 struct nfsd3_readdirres
*resp
)
466 int nfserr
, count
= 0;
469 caddr_t page_addr
= NULL
;
471 dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n",
472 SVCFH_fmt(&argp
->fh
),
473 argp
->count
, (u32
) argp
->cookie
);
475 /* Convert byte count to number of words (i.e. >> 2),
476 * and reserve room for the NULL ptr & eof flag (-2 words) */
477 resp
->count
= (argp
->count
>> 2) - 2;
479 /* Read directory and encode entries on the fly */
480 fh_copy(&resp
->fh
, &argp
->fh
);
482 resp
->common
.err
= nfs_ok
;
483 resp
->buffer
= argp
->buffer
;
484 resp
->buflen
= resp
->count
;
486 offset
= argp
->cookie
;
487 nfserr
= nfsd_readdir(rqstp
, &resp
->fh
,
490 nfs3svc_encode_entry_plus
);
491 memcpy(resp
->verf
, argp
->verf
, 8);
492 for (i
=1; i
<rqstp
->rq_resused
; i
++) {
493 page_addr
= page_address(rqstp
->rq_respages
[i
]);
495 if (((caddr_t
)resp
->buffer
>= page_addr
) &&
496 ((caddr_t
)resp
->buffer
< page_addr
+ PAGE_SIZE
)) {
497 count
+= (caddr_t
)resp
->buffer
- page_addr
;
502 resp
->count
= count
>> 2;
504 if (unlikely(resp
->offset1
)) {
505 /* we ended up with offset on a page boundary */
506 *resp
->offset
= htonl(offset
>> 32);
507 *resp
->offset1
= htonl(offset
& 0xffffffff);
508 resp
->offset1
= NULL
;
510 xdr_encode_hyper(resp
->offset
, offset
);
514 RETURN_STATUS(nfserr
);
518 * Get file system stats
521 nfsd3_proc_fsstat(struct svc_rqst
* rqstp
, struct nfsd_fhandle
*argp
,
522 struct nfsd3_fsstatres
*resp
)
526 dprintk("nfsd: FSSTAT(3) %s\n",
527 SVCFH_fmt(&argp
->fh
));
529 nfserr
= nfsd_statfs(rqstp
, &argp
->fh
, &resp
->stats
);
531 RETURN_STATUS(nfserr
);
535 * Get file system info
538 nfsd3_proc_fsinfo(struct svc_rqst
* rqstp
, struct nfsd_fhandle
*argp
,
539 struct nfsd3_fsinfores
*resp
)
542 u32 max_blocksize
= svc_max_payload(rqstp
);
544 dprintk("nfsd: FSINFO(3) %s\n",
545 SVCFH_fmt(&argp
->fh
));
547 resp
->f_rtmax
= max_blocksize
;
548 resp
->f_rtpref
= max_blocksize
;
549 resp
->f_rtmult
= PAGE_SIZE
;
550 resp
->f_wtmax
= max_blocksize
;
551 resp
->f_wtpref
= max_blocksize
;
552 resp
->f_wtmult
= PAGE_SIZE
;
553 resp
->f_dtpref
= PAGE_SIZE
;
554 resp
->f_maxfilesize
= ~(u32
) 0;
555 resp
->f_properties
= NFS3_FSF_DEFAULT
;
557 nfserr
= fh_verify(rqstp
, &argp
->fh
, 0, MAY_NOP
);
559 /* Check special features of the file system. May request
560 * different read/write sizes for file systems known to have
561 * problems with large blocks */
563 struct super_block
*sb
= argp
->fh
.fh_dentry
->d_inode
->i_sb
;
565 /* Note that we don't care for remote fs's here */
566 if (sb
->s_magic
== 0x4d44 /* MSDOS_SUPER_MAGIC */) {
567 resp
->f_properties
= NFS3_FSF_BILLYBOY
;
569 resp
->f_maxfilesize
= sb
->s_maxbytes
;
573 RETURN_STATUS(nfserr
);
577 * Get pathconf info for the specified file
580 nfsd3_proc_pathconf(struct svc_rqst
* rqstp
, struct nfsd_fhandle
*argp
,
581 struct nfsd3_pathconfres
*resp
)
585 dprintk("nfsd: PATHCONF(3) %s\n",
586 SVCFH_fmt(&argp
->fh
));
588 /* Set default pathconf */
589 resp
->p_link_max
= 255; /* at least */
590 resp
->p_name_max
= 255; /* at least */
591 resp
->p_no_trunc
= 0;
592 resp
->p_chown_restricted
= 1;
593 resp
->p_case_insensitive
= 0;
594 resp
->p_case_preserving
= 1;
596 nfserr
= fh_verify(rqstp
, &argp
->fh
, 0, MAY_NOP
);
599 struct super_block
*sb
= argp
->fh
.fh_dentry
->d_inode
->i_sb
;
601 /* Note that we don't care for remote fs's here */
602 switch (sb
->s_magic
) {
603 case EXT2_SUPER_MAGIC
:
604 resp
->p_link_max
= EXT2_LINK_MAX
;
605 resp
->p_name_max
= EXT2_NAME_LEN
;
607 case 0x4d44: /* MSDOS_SUPER_MAGIC */
608 resp
->p_case_insensitive
= 1;
609 resp
->p_case_preserving
= 0;
615 RETURN_STATUS(nfserr
);
620 * Commit a file (range) to stable storage.
623 nfsd3_proc_commit(struct svc_rqst
* rqstp
, struct nfsd3_commitargs
*argp
,
624 struct nfsd3_commitres
*resp
)
628 dprintk("nfsd: COMMIT(3) %s %u@%Lu\n",
629 SVCFH_fmt(&argp
->fh
),
631 (unsigned long long) argp
->offset
);
633 if (argp
->offset
> NFS_OFFSET_MAX
)
634 RETURN_STATUS(nfserr_inval
);
636 fh_copy(&resp
->fh
, &argp
->fh
);
637 nfserr
= nfsd_commit(rqstp
, &resp
->fh
, argp
->offset
, argp
->count
);
639 RETURN_STATUS(nfserr
);
644 * NFSv3 Server procedures.
645 * Only the results of non-idempotent operations are cached.
647 #define nfs3svc_decode_voidargs NULL
648 #define nfs3svc_release_void NULL
649 #define nfs3svc_decode_fhandleargs nfs3svc_decode_fhandle
650 #define nfs3svc_encode_attrstatres nfs3svc_encode_attrstat
651 #define nfs3svc_encode_wccstatres nfs3svc_encode_wccstat
652 #define nfsd3_mkdirargs nfsd3_createargs
653 #define nfsd3_readdirplusargs nfsd3_readdirargs
654 #define nfsd3_fhandleargs nfsd_fhandle
655 #define nfsd3_fhandleres nfsd3_attrstat
656 #define nfsd3_attrstatres nfsd3_attrstat
657 #define nfsd3_wccstatres nfsd3_attrstat
658 #define nfsd3_createres nfsd3_diropres
659 #define nfsd3_voidres nfsd3_voidargs
660 struct nfsd3_voidargs
{ int dummy
; };
662 #define PROC(name, argt, rest, relt, cache, respsize) \
663 { (svc_procfunc) nfsd3_proc_##name, \
664 (kxdrproc_t) nfs3svc_decode_##argt##args, \
665 (kxdrproc_t) nfs3svc_encode_##rest##res, \
666 (kxdrproc_t) nfs3svc_release_##relt, \
667 sizeof(struct nfsd3_##argt##args), \
668 sizeof(struct nfsd3_##rest##res), \
674 #define ST 1 /* status*/
675 #define FH 17 /* filehandle with length */
676 #define AT 21 /* attributes */
677 #define pAT (1+AT) /* post attributes - conditional */
678 #define WC (7+pAT) /* WCC attributes */
680 static struct svc_procedure nfsd_procedures3
[22] = {
681 PROC(null
, void, void, void, RC_NOCACHE
, ST
),
682 PROC(getattr
, fhandle
, attrstat
, fhandle
, RC_NOCACHE
, ST
+AT
),
683 PROC(setattr
, sattr
, wccstat
, fhandle
, RC_REPLBUFF
, ST
+WC
),
684 PROC(lookup
, dirop
, dirop
, fhandle2
, RC_NOCACHE
, ST
+FH
+pAT
+pAT
),
685 PROC(access
, access
, access
, fhandle
, RC_NOCACHE
, ST
+pAT
+1),
686 PROC(readlink
, readlink
, readlink
, fhandle
, RC_NOCACHE
, ST
+pAT
+1+NFS3_MAXPATHLEN
/4),
687 PROC(read
, read
, read
, fhandle
, RC_NOCACHE
, ST
+pAT
+4+NFSSVC_MAXBLKSIZE
/4),
688 PROC(write
, write
, write
, fhandle
, RC_REPLBUFF
, ST
+WC
+4),
689 PROC(create
, create
, create
, fhandle2
, RC_REPLBUFF
, ST
+(1+FH
+pAT
)+WC
),
690 PROC(mkdir
, mkdir
, create
, fhandle2
, RC_REPLBUFF
, ST
+(1+FH
+pAT
)+WC
),
691 PROC(symlink
, symlink
, create
, fhandle2
, RC_REPLBUFF
, ST
+(1+FH
+pAT
)+WC
),
692 PROC(mknod
, mknod
, create
, fhandle2
, RC_REPLBUFF
, ST
+(1+FH
+pAT
)+WC
),
693 PROC(remove
, dirop
, wccstat
, fhandle
, RC_REPLBUFF
, ST
+WC
),
694 PROC(rmdir
, dirop
, wccstat
, fhandle
, RC_REPLBUFF
, ST
+WC
),
695 PROC(rename
, rename
, rename
, fhandle2
, RC_REPLBUFF
, ST
+WC
+WC
),
696 PROC(link
, link
, link
, fhandle2
, RC_REPLBUFF
, ST
+pAT
+WC
),
697 PROC(readdir
, readdir
, readdir
, fhandle
, RC_NOCACHE
, 0),
698 PROC(readdirplus
,readdirplus
, readdir
, fhandle
, RC_NOCACHE
, 0),
699 PROC(fsstat
, fhandle
, fsstat
, void, RC_NOCACHE
, ST
+pAT
+2*6+1),
700 PROC(fsinfo
, fhandle
, fsinfo
, void, RC_NOCACHE
, ST
+pAT
+12),
701 PROC(pathconf
, fhandle
, pathconf
, void, RC_NOCACHE
, ST
+pAT
+6),
702 PROC(commit
, commit
, commit
, fhandle
, RC_NOCACHE
, ST
+WC
+2),
705 struct svc_version nfsd_version3
= {
708 .vs_proc
= nfsd_procedures3
,
709 .vs_dispatch
= nfsd_dispatch
,
710 .vs_xdrsize
= NFS3_SVC_XDRSIZE
,