1 // SPDX-License-Identifier: GPL-2.0
3 * Process version 2 NFS requests.
5 * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
8 #include <linux/namei.h>
14 #define NFSDDBG_FACILITY NFSDDBG_PROC
16 static __be32
nfsd_map_status(__be32 status
)
21 case nfserr_nofilehandle
:
22 case nfserr_badhandle
:
23 status
= nfserr_stale
;
27 case nfserr_file_open
:
28 status
= nfserr_acces
;
30 case nfserr_symlink_not_dir
:
31 status
= nfserr_notdir
;
34 case nfserr_wrong_type
:
35 status
= nfserr_inval
;
42 nfsd_proc_null(struct svc_rqst
*rqstp
)
48 * Get a file's attributes
49 * N.B. After this call resp->fh needs an fh_put
52 nfsd_proc_getattr(struct svc_rqst
*rqstp
)
54 struct nfsd_fhandle
*argp
= rqstp
->rq_argp
;
55 struct nfsd_attrstat
*resp
= rqstp
->rq_resp
;
57 dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp
->fh
));
59 fh_copy(&resp
->fh
, &argp
->fh
);
60 resp
->status
= fh_verify(rqstp
, &resp
->fh
, 0,
61 NFSD_MAY_NOP
| NFSD_MAY_BYPASS_GSS_ON_ROOT
);
62 if (resp
->status
!= nfs_ok
)
64 resp
->status
= fh_getattr(&resp
->fh
, &resp
->stat
);
66 resp
->status
= nfsd_map_status(resp
->status
);
71 * Set a file's attributes
72 * N.B. After this call resp->fh needs an fh_put
75 nfsd_proc_setattr(struct svc_rqst
*rqstp
)
77 struct nfsd_sattrargs
*argp
= rqstp
->rq_argp
;
78 struct nfsd_attrstat
*resp
= rqstp
->rq_resp
;
79 struct iattr
*iap
= &argp
->attrs
;
80 struct nfsd_attrs attrs
= {
85 dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n",
87 argp
->attrs
.ia_valid
, (long) argp
->attrs
.ia_size
);
89 fhp
= fh_copy(&resp
->fh
, &argp
->fh
);
92 * NFSv2 does not differentiate between "set-[ac]time-to-now"
93 * which only requires access, and "set-[ac]time-to-X" which
95 * So if it looks like it might be "set both to the same time which
96 * is close to now", and if setattr_prepare fails, then we
97 * convert to "set to now" instead of "set to explicit time"
99 * We only call setattr_prepare as the last test as technically
100 * it is not an interface that we should be using.
102 #define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
103 #define MAX_TOUCH_TIME_ERROR (30*60)
104 if ((iap
->ia_valid
& BOTH_TIME_SET
) == BOTH_TIME_SET
&&
105 iap
->ia_mtime
.tv_sec
== iap
->ia_atime
.tv_sec
) {
109 * Now just make sure time is in the right ballpark.
110 * Solaris, at least, doesn't seem to care what the time
111 * request is. We require it be within 30 minutes of now.
113 time64_t delta
= iap
->ia_atime
.tv_sec
- ktime_get_real_seconds();
115 resp
->status
= fh_verify(rqstp
, fhp
, 0, NFSD_MAY_NOP
);
116 if (resp
->status
!= nfs_ok
)
121 if (delta
< MAX_TOUCH_TIME_ERROR
&&
122 setattr_prepare(&nop_mnt_idmap
, fhp
->fh_dentry
, iap
) != 0) {
124 * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME.
125 * This will cause notify_change to set these times
128 iap
->ia_valid
&= ~BOTH_TIME_SET
;
132 resp
->status
= nfsd_setattr(rqstp
, fhp
, &attrs
, NULL
);
133 if (resp
->status
!= nfs_ok
)
136 resp
->status
= fh_getattr(&resp
->fh
, &resp
->stat
);
138 resp
->status
= nfsd_map_status(resp
->status
);
142 /* Obsolete, replaced by MNTPROC_MNT. */
144 nfsd_proc_root(struct svc_rqst
*rqstp
)
150 * Look up a path name component
151 * Note: the dentry in the resp->fh may be negative if the file
153 * N.B. After this call resp->fh needs an fh_put
156 nfsd_proc_lookup(struct svc_rqst
*rqstp
)
158 struct nfsd_diropargs
*argp
= rqstp
->rq_argp
;
159 struct nfsd_diropres
*resp
= rqstp
->rq_resp
;
161 dprintk("nfsd: LOOKUP %s %.*s\n",
162 SVCFH_fmt(&argp
->fh
), argp
->len
, argp
->name
);
164 fh_init(&resp
->fh
, NFS_FHSIZE
);
165 resp
->status
= nfsd_lookup(rqstp
, &argp
->fh
, argp
->name
, argp
->len
,
168 if (resp
->status
!= nfs_ok
)
171 resp
->status
= fh_getattr(&resp
->fh
, &resp
->stat
);
173 resp
->status
= nfsd_map_status(resp
->status
);
181 nfsd_proc_readlink(struct svc_rqst
*rqstp
)
183 struct nfsd_fhandle
*argp
= rqstp
->rq_argp
;
184 struct nfsd_readlinkres
*resp
= rqstp
->rq_resp
;
186 dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp
->fh
));
188 /* Read the symlink. */
189 resp
->len
= NFS_MAXPATHLEN
;
190 resp
->page
= *(rqstp
->rq_next_page
++);
191 resp
->status
= nfsd_readlink(rqstp
, &argp
->fh
,
192 page_address(resp
->page
), &resp
->len
);
195 resp
->status
= nfsd_map_status(resp
->status
);
200 * Read a portion of a file.
201 * N.B. After this call resp->fh needs an fh_put
204 nfsd_proc_read(struct svc_rqst
*rqstp
)
206 struct nfsd_readargs
*argp
= rqstp
->rq_argp
;
207 struct nfsd_readres
*resp
= rqstp
->rq_resp
;
210 dprintk("nfsd: READ %s %d bytes at %d\n",
211 SVCFH_fmt(&argp
->fh
),
212 argp
->count
, argp
->offset
);
214 argp
->count
= min_t(u32
, argp
->count
, NFSSVC_MAXBLKSIZE_V2
);
215 argp
->count
= min_t(u32
, argp
->count
, rqstp
->rq_res
.buflen
);
217 resp
->pages
= rqstp
->rq_next_page
;
219 /* Obtain buffer pointer for payload. 19 is 1 word for
220 * status, 17 words for fattr, and 1 word for the byte count.
222 svc_reserve_auth(rqstp
, (19<<2) + argp
->count
+ 4);
224 resp
->count
= argp
->count
;
225 fh_copy(&resp
->fh
, &argp
->fh
);
226 resp
->status
= nfsd_read(rqstp
, &resp
->fh
, argp
->offset
,
228 if (resp
->status
== nfs_ok
)
229 resp
->status
= fh_getattr(&resp
->fh
, &resp
->stat
);
230 else if (resp
->status
== nfserr_jukebox
)
231 set_bit(RQ_DROPME
, &rqstp
->rq_flags
);
232 resp
->status
= nfsd_map_status(resp
->status
);
238 nfsd_proc_writecache(struct svc_rqst
*rqstp
)
244 * Write data to a file
245 * N.B. After this call resp->fh needs an fh_put
248 nfsd_proc_write(struct svc_rqst
*rqstp
)
250 struct nfsd_writeargs
*argp
= rqstp
->rq_argp
;
251 struct nfsd_attrstat
*resp
= rqstp
->rq_resp
;
252 unsigned long cnt
= argp
->len
;
255 dprintk("nfsd: WRITE %s %u bytes at %d\n",
256 SVCFH_fmt(&argp
->fh
),
257 argp
->len
, argp
->offset
);
259 nvecs
= svc_fill_write_vector(rqstp
, &argp
->payload
);
261 resp
->status
= nfsd_write(rqstp
, fh_copy(&resp
->fh
, &argp
->fh
),
262 argp
->offset
, rqstp
->rq_vec
, nvecs
,
263 &cnt
, NFS_DATA_SYNC
, NULL
);
264 if (resp
->status
== nfs_ok
)
265 resp
->status
= fh_getattr(&resp
->fh
, &resp
->stat
);
266 else if (resp
->status
== nfserr_jukebox
)
267 set_bit(RQ_DROPME
, &rqstp
->rq_flags
);
268 resp
->status
= nfsd_map_status(resp
->status
);
273 * CREATE processing is complicated. The keyword here is `overloaded.'
274 * The parent directory is kept locked between the check for existence
275 * and the actual create() call in compliance with VFS protocols.
276 * N.B. After this call _both_ argp->fh and resp->fh need an fh_put
279 nfsd_proc_create(struct svc_rqst
*rqstp
)
281 struct nfsd_createargs
*argp
= rqstp
->rq_argp
;
282 struct nfsd_diropres
*resp
= rqstp
->rq_resp
;
283 svc_fh
*dirfhp
= &argp
->fh
;
284 svc_fh
*newfhp
= &resp
->fh
;
285 struct iattr
*attr
= &argp
->attrs
;
286 struct nfsd_attrs attrs
= {
290 struct dentry
*dchild
;
293 dev_t rdev
= 0, wanted
= new_decode_dev(attr
->ia_size
);
295 dprintk("nfsd: CREATE %s %.*s\n",
296 SVCFH_fmt(dirfhp
), argp
->len
, argp
->name
);
298 /* First verify the parent file handle */
299 resp
->status
= fh_verify(rqstp
, dirfhp
, S_IFDIR
, NFSD_MAY_EXEC
);
300 if (resp
->status
!= nfs_ok
)
301 goto done
; /* must fh_put dirfhp even on error */
303 /* Check for NFSD_MAY_WRITE in nfsd_create if necessary */
305 resp
->status
= nfserr_exist
;
306 if (isdotent(argp
->name
, argp
->len
))
308 hosterr
= fh_want_write(dirfhp
);
310 resp
->status
= nfserrno(hosterr
);
314 inode_lock_nested(dirfhp
->fh_dentry
->d_inode
, I_MUTEX_PARENT
);
315 dchild
= lookup_one_len(argp
->name
, dirfhp
->fh_dentry
, argp
->len
);
316 if (IS_ERR(dchild
)) {
317 resp
->status
= nfserrno(PTR_ERR(dchild
));
320 fh_init(newfhp
, NFS_FHSIZE
);
321 resp
->status
= fh_compose(newfhp
, dirfhp
->fh_export
, dchild
, dirfhp
);
322 if (!resp
->status
&& d_really_is_negative(dchild
))
323 resp
->status
= nfserr_noent
;
326 if (resp
->status
!= nfserr_noent
)
329 * If the new file handle wasn't verified, we can't tell
330 * whether the file exists or not. Time to bail ...
332 resp
->status
= nfserr_acces
;
333 if (!newfhp
->fh_dentry
) {
335 "nfsd_proc_create: file handle not verified\n");
340 inode
= d_inode(newfhp
->fh_dentry
);
342 /* Unfudge the mode bits */
343 if (attr
->ia_valid
& ATTR_MODE
) {
344 type
= attr
->ia_mode
& S_IFMT
;
345 mode
= attr
->ia_mode
& ~S_IFMT
;
347 /* no type, so if target exists, assume same as that,
348 * else assume a file */
350 type
= inode
->i_mode
& S_IFMT
;
354 /* reserve rdev for later checking */
355 rdev
= inode
->i_rdev
;
356 attr
->ia_valid
|= ATTR_SIZE
;
360 /* this is probably a permission check..
361 * at least IRIX implements perm checking on
362 * echo thing > device-special-file-or-pipe
363 * by doing a CREATE with type==0
365 resp
->status
= nfsd_permission(
369 NFSD_MAY_WRITE
|NFSD_MAY_LOCAL_ACCESS
);
370 if (resp
->status
&& resp
->status
!= nfserr_rofs
)
377 type
= inode
->i_mode
& S_IFMT
;
378 mode
= inode
->i_mode
& ~S_IFMT
;
384 attr
->ia_valid
|= ATTR_MODE
;
385 attr
->ia_mode
= mode
;
387 /* Special treatment for non-regular files according to the
388 * gospel of sun micro
390 if (type
!= S_IFREG
) {
391 if (type
!= S_IFBLK
&& type
!= S_IFCHR
) {
393 } else if (type
== S_IFCHR
&& !(attr
->ia_valid
& ATTR_SIZE
)) {
394 /* If you think you've seen the worst, grok this. */
397 /* Okay, char or block special */
402 /* we've used the SIZE information, so discard it */
403 attr
->ia_valid
&= ~ATTR_SIZE
;
405 /* Make sure the type and device matches */
406 resp
->status
= nfserr_exist
;
407 if (inode
&& inode_wrong_type(inode
, type
))
411 resp
->status
= nfs_ok
;
413 /* File doesn't exist. Create it and set attrs */
414 resp
->status
= nfsd_create_locked(rqstp
, dirfhp
, &attrs
, type
,
416 } else if (type
== S_IFREG
) {
417 dprintk("nfsd: existing %s, valid=%x, size=%ld\n",
418 argp
->name
, attr
->ia_valid
, (long) attr
->ia_size
);
419 /* File already exists. We ignore all attributes except
420 * size, so that creat() behaves exactly like
421 * open(..., O_CREAT|O_TRUNC|O_WRONLY).
423 attr
->ia_valid
&= ATTR_SIZE
;
425 resp
->status
= nfsd_setattr(rqstp
, newfhp
, &attrs
,
430 inode_unlock(dirfhp
->fh_dentry
->d_inode
);
431 fh_drop_write(dirfhp
);
434 if (resp
->status
!= nfs_ok
)
436 resp
->status
= fh_getattr(&resp
->fh
, &resp
->stat
);
438 resp
->status
= nfsd_map_status(resp
->status
);
443 nfsd_proc_remove(struct svc_rqst
*rqstp
)
445 struct nfsd_diropargs
*argp
= rqstp
->rq_argp
;
446 struct nfsd_stat
*resp
= rqstp
->rq_resp
;
448 dprintk("nfsd: REMOVE %s %.*s\n", SVCFH_fmt(&argp
->fh
),
449 argp
->len
, argp
->name
);
451 /* Unlink. -SIFDIR means file must not be a directory */
452 resp
->status
= nfsd_unlink(rqstp
, &argp
->fh
, -S_IFDIR
,
453 argp
->name
, argp
->len
);
455 resp
->status
= nfsd_map_status(resp
->status
);
460 nfsd_proc_rename(struct svc_rqst
*rqstp
)
462 struct nfsd_renameargs
*argp
= rqstp
->rq_argp
;
463 struct nfsd_stat
*resp
= rqstp
->rq_resp
;
465 dprintk("nfsd: RENAME %s %.*s -> \n",
466 SVCFH_fmt(&argp
->ffh
), argp
->flen
, argp
->fname
);
467 dprintk("nfsd: -> %s %.*s\n",
468 SVCFH_fmt(&argp
->tfh
), argp
->tlen
, argp
->tname
);
470 resp
->status
= nfsd_rename(rqstp
, &argp
->ffh
, argp
->fname
, argp
->flen
,
471 &argp
->tfh
, argp
->tname
, argp
->tlen
);
474 resp
->status
= nfsd_map_status(resp
->status
);
479 nfsd_proc_link(struct svc_rqst
*rqstp
)
481 struct nfsd_linkargs
*argp
= rqstp
->rq_argp
;
482 struct nfsd_stat
*resp
= rqstp
->rq_resp
;
484 dprintk("nfsd: LINK %s ->\n",
485 SVCFH_fmt(&argp
->ffh
));
486 dprintk("nfsd: %s %.*s\n",
487 SVCFH_fmt(&argp
->tfh
),
491 resp
->status
= nfsd_link(rqstp
, &argp
->tfh
, argp
->tname
, argp
->tlen
,
495 resp
->status
= nfsd_map_status(resp
->status
);
500 nfsd_proc_symlink(struct svc_rqst
*rqstp
)
502 struct nfsd_symlinkargs
*argp
= rqstp
->rq_argp
;
503 struct nfsd_stat
*resp
= rqstp
->rq_resp
;
504 struct nfsd_attrs attrs
= {
505 .na_iattr
= &argp
->attrs
,
509 if (argp
->tlen
> NFS_MAXPATHLEN
) {
510 resp
->status
= nfserr_nametoolong
;
514 argp
->tname
= svc_fill_symlink_pathname(rqstp
, &argp
->first
,
515 page_address(rqstp
->rq_arg
.pages
[0]),
517 if (IS_ERR(argp
->tname
)) {
518 resp
->status
= nfserrno(PTR_ERR(argp
->tname
));
522 dprintk("nfsd: SYMLINK %s %.*s -> %.*s\n",
523 SVCFH_fmt(&argp
->ffh
), argp
->flen
, argp
->fname
,
524 argp
->tlen
, argp
->tname
);
526 fh_init(&newfh
, NFS_FHSIZE
);
527 resp
->status
= nfsd_symlink(rqstp
, &argp
->ffh
, argp
->fname
, argp
->flen
,
528 argp
->tname
, &attrs
, &newfh
);
534 resp
->status
= nfsd_map_status(resp
->status
);
539 * Make directory. This operation is not idempotent.
540 * N.B. After this call resp->fh needs an fh_put
543 nfsd_proc_mkdir(struct svc_rqst
*rqstp
)
545 struct nfsd_createargs
*argp
= rqstp
->rq_argp
;
546 struct nfsd_diropres
*resp
= rqstp
->rq_resp
;
547 struct nfsd_attrs attrs
= {
548 .na_iattr
= &argp
->attrs
,
551 dprintk("nfsd: MKDIR %s %.*s\n", SVCFH_fmt(&argp
->fh
), argp
->len
, argp
->name
);
553 if (resp
->fh
.fh_dentry
) {
555 "nfsd_proc_mkdir: response already verified??\n");
558 argp
->attrs
.ia_valid
&= ~ATTR_SIZE
;
559 fh_init(&resp
->fh
, NFS_FHSIZE
);
560 resp
->status
= nfsd_create(rqstp
, &argp
->fh
, argp
->name
, argp
->len
,
561 &attrs
, S_IFDIR
, 0, &resp
->fh
);
563 if (resp
->status
!= nfs_ok
)
566 resp
->status
= fh_getattr(&resp
->fh
, &resp
->stat
);
568 resp
->status
= nfsd_map_status(resp
->status
);
576 nfsd_proc_rmdir(struct svc_rqst
*rqstp
)
578 struct nfsd_diropargs
*argp
= rqstp
->rq_argp
;
579 struct nfsd_stat
*resp
= rqstp
->rq_resp
;
581 dprintk("nfsd: RMDIR %s %.*s\n", SVCFH_fmt(&argp
->fh
), argp
->len
, argp
->name
);
583 resp
->status
= nfsd_unlink(rqstp
, &argp
->fh
, S_IFDIR
,
584 argp
->name
, argp
->len
);
586 resp
->status
= nfsd_map_status(resp
->status
);
590 static void nfsd_init_dirlist_pages(struct svc_rqst
*rqstp
,
591 struct nfsd_readdirres
*resp
,
594 struct xdr_buf
*buf
= &resp
->dirlist
;
595 struct xdr_stream
*xdr
= &resp
->xdr
;
597 memset(buf
, 0, sizeof(*buf
));
599 /* Reserve room for the NULL ptr & eof flag (-2 words) */
600 buf
->buflen
= clamp(count
, (u32
)(XDR_UNIT
* 2), (u32
)PAGE_SIZE
);
601 buf
->buflen
-= XDR_UNIT
* 2;
602 buf
->pages
= rqstp
->rq_next_page
;
603 rqstp
->rq_next_page
++;
605 xdr_init_encode_pages(xdr
, buf
, buf
->pages
, NULL
);
609 * Read a portion of a directory.
612 nfsd_proc_readdir(struct svc_rqst
*rqstp
)
614 struct nfsd_readdirargs
*argp
= rqstp
->rq_argp
;
615 struct nfsd_readdirres
*resp
= rqstp
->rq_resp
;
618 dprintk("nfsd: READDIR %s %d bytes at %d\n",
619 SVCFH_fmt(&argp
->fh
),
620 argp
->count
, argp
->cookie
);
622 nfsd_init_dirlist_pages(rqstp
, resp
, argp
->count
);
624 resp
->common
.err
= nfs_ok
;
625 resp
->cookie_offset
= 0;
626 offset
= argp
->cookie
;
627 resp
->status
= nfsd_readdir(rqstp
, &argp
->fh
, &offset
,
628 &resp
->common
, nfssvc_encode_entry
);
629 nfssvc_encode_nfscookie(resp
, offset
);
632 resp
->status
= nfsd_map_status(resp
->status
);
637 * Get file system info
640 nfsd_proc_statfs(struct svc_rqst
*rqstp
)
642 struct nfsd_fhandle
*argp
= rqstp
->rq_argp
;
643 struct nfsd_statfsres
*resp
= rqstp
->rq_resp
;
645 dprintk("nfsd: STATFS %s\n", SVCFH_fmt(&argp
->fh
));
647 resp
->status
= nfsd_statfs(rqstp
, &argp
->fh
, &resp
->stats
,
648 NFSD_MAY_BYPASS_GSS_ON_ROOT
);
650 resp
->status
= nfsd_map_status(resp
->status
);
655 * NFSv2 Server procedures.
656 * Only the results of non-idempotent operations are cached.
659 #define ST 1 /* status */
660 #define FH 8 /* filehandle */
661 #define AT 18 /* attributes */
663 static const struct svc_procedure nfsd_procedures2
[18] = {
665 .pc_func
= nfsd_proc_null
,
666 .pc_decode
= nfssvc_decode_voidarg
,
667 .pc_encode
= nfssvc_encode_voidres
,
668 .pc_argsize
= sizeof(struct nfsd_voidargs
),
669 .pc_argzero
= sizeof(struct nfsd_voidargs
),
670 .pc_ressize
= sizeof(struct nfsd_voidres
),
671 .pc_cachetype
= RC_NOCACHE
,
675 [NFSPROC_GETATTR
] = {
676 .pc_func
= nfsd_proc_getattr
,
677 .pc_decode
= nfssvc_decode_fhandleargs
,
678 .pc_encode
= nfssvc_encode_attrstatres
,
679 .pc_release
= nfssvc_release_attrstat
,
680 .pc_argsize
= sizeof(struct nfsd_fhandle
),
681 .pc_argzero
= sizeof(struct nfsd_fhandle
),
682 .pc_ressize
= sizeof(struct nfsd_attrstat
),
683 .pc_cachetype
= RC_NOCACHE
,
684 .pc_xdrressize
= ST
+AT
,
685 .pc_name
= "GETATTR",
687 [NFSPROC_SETATTR
] = {
688 .pc_func
= nfsd_proc_setattr
,
689 .pc_decode
= nfssvc_decode_sattrargs
,
690 .pc_encode
= nfssvc_encode_attrstatres
,
691 .pc_release
= nfssvc_release_attrstat
,
692 .pc_argsize
= sizeof(struct nfsd_sattrargs
),
693 .pc_argzero
= sizeof(struct nfsd_sattrargs
),
694 .pc_ressize
= sizeof(struct nfsd_attrstat
),
695 .pc_cachetype
= RC_REPLBUFF
,
696 .pc_xdrressize
= ST
+AT
,
697 .pc_name
= "SETATTR",
700 .pc_func
= nfsd_proc_root
,
701 .pc_decode
= nfssvc_decode_voidarg
,
702 .pc_encode
= nfssvc_encode_voidres
,
703 .pc_argsize
= sizeof(struct nfsd_voidargs
),
704 .pc_argzero
= sizeof(struct nfsd_voidargs
),
705 .pc_ressize
= sizeof(struct nfsd_voidres
),
706 .pc_cachetype
= RC_NOCACHE
,
711 .pc_func
= nfsd_proc_lookup
,
712 .pc_decode
= nfssvc_decode_diropargs
,
713 .pc_encode
= nfssvc_encode_diropres
,
714 .pc_release
= nfssvc_release_diropres
,
715 .pc_argsize
= sizeof(struct nfsd_diropargs
),
716 .pc_argzero
= sizeof(struct nfsd_diropargs
),
717 .pc_ressize
= sizeof(struct nfsd_diropres
),
718 .pc_cachetype
= RC_NOCACHE
,
719 .pc_xdrressize
= ST
+FH
+AT
,
722 [NFSPROC_READLINK
] = {
723 .pc_func
= nfsd_proc_readlink
,
724 .pc_decode
= nfssvc_decode_fhandleargs
,
725 .pc_encode
= nfssvc_encode_readlinkres
,
726 .pc_argsize
= sizeof(struct nfsd_fhandle
),
727 .pc_argzero
= sizeof(struct nfsd_fhandle
),
728 .pc_ressize
= sizeof(struct nfsd_readlinkres
),
729 .pc_cachetype
= RC_NOCACHE
,
730 .pc_xdrressize
= ST
+1+NFS_MAXPATHLEN
/4,
731 .pc_name
= "READLINK",
734 .pc_func
= nfsd_proc_read
,
735 .pc_decode
= nfssvc_decode_readargs
,
736 .pc_encode
= nfssvc_encode_readres
,
737 .pc_release
= nfssvc_release_readres
,
738 .pc_argsize
= sizeof(struct nfsd_readargs
),
739 .pc_argzero
= sizeof(struct nfsd_readargs
),
740 .pc_ressize
= sizeof(struct nfsd_readres
),
741 .pc_cachetype
= RC_NOCACHE
,
742 .pc_xdrressize
= ST
+AT
+1+NFSSVC_MAXBLKSIZE_V2
/4,
745 [NFSPROC_WRITECACHE
] = {
746 .pc_func
= nfsd_proc_writecache
,
747 .pc_decode
= nfssvc_decode_voidarg
,
748 .pc_encode
= nfssvc_encode_voidres
,
749 .pc_argsize
= sizeof(struct nfsd_voidargs
),
750 .pc_argzero
= sizeof(struct nfsd_voidargs
),
751 .pc_ressize
= sizeof(struct nfsd_voidres
),
752 .pc_cachetype
= RC_NOCACHE
,
754 .pc_name
= "WRITECACHE",
757 .pc_func
= nfsd_proc_write
,
758 .pc_decode
= nfssvc_decode_writeargs
,
759 .pc_encode
= nfssvc_encode_attrstatres
,
760 .pc_release
= nfssvc_release_attrstat
,
761 .pc_argsize
= sizeof(struct nfsd_writeargs
),
762 .pc_argzero
= sizeof(struct nfsd_writeargs
),
763 .pc_ressize
= sizeof(struct nfsd_attrstat
),
764 .pc_cachetype
= RC_REPLBUFF
,
765 .pc_xdrressize
= ST
+AT
,
769 .pc_func
= nfsd_proc_create
,
770 .pc_decode
= nfssvc_decode_createargs
,
771 .pc_encode
= nfssvc_encode_diropres
,
772 .pc_release
= nfssvc_release_diropres
,
773 .pc_argsize
= sizeof(struct nfsd_createargs
),
774 .pc_argzero
= sizeof(struct nfsd_createargs
),
775 .pc_ressize
= sizeof(struct nfsd_diropres
),
776 .pc_cachetype
= RC_REPLBUFF
,
777 .pc_xdrressize
= ST
+FH
+AT
,
781 .pc_func
= nfsd_proc_remove
,
782 .pc_decode
= nfssvc_decode_diropargs
,
783 .pc_encode
= nfssvc_encode_statres
,
784 .pc_argsize
= sizeof(struct nfsd_diropargs
),
785 .pc_argzero
= sizeof(struct nfsd_diropargs
),
786 .pc_ressize
= sizeof(struct nfsd_stat
),
787 .pc_cachetype
= RC_REPLSTAT
,
792 .pc_func
= nfsd_proc_rename
,
793 .pc_decode
= nfssvc_decode_renameargs
,
794 .pc_encode
= nfssvc_encode_statres
,
795 .pc_argsize
= sizeof(struct nfsd_renameargs
),
796 .pc_argzero
= sizeof(struct nfsd_renameargs
),
797 .pc_ressize
= sizeof(struct nfsd_stat
),
798 .pc_cachetype
= RC_REPLSTAT
,
803 .pc_func
= nfsd_proc_link
,
804 .pc_decode
= nfssvc_decode_linkargs
,
805 .pc_encode
= nfssvc_encode_statres
,
806 .pc_argsize
= sizeof(struct nfsd_linkargs
),
807 .pc_argzero
= sizeof(struct nfsd_linkargs
),
808 .pc_ressize
= sizeof(struct nfsd_stat
),
809 .pc_cachetype
= RC_REPLSTAT
,
813 [NFSPROC_SYMLINK
] = {
814 .pc_func
= nfsd_proc_symlink
,
815 .pc_decode
= nfssvc_decode_symlinkargs
,
816 .pc_encode
= nfssvc_encode_statres
,
817 .pc_argsize
= sizeof(struct nfsd_symlinkargs
),
818 .pc_argzero
= sizeof(struct nfsd_symlinkargs
),
819 .pc_ressize
= sizeof(struct nfsd_stat
),
820 .pc_cachetype
= RC_REPLSTAT
,
822 .pc_name
= "SYMLINK",
825 .pc_func
= nfsd_proc_mkdir
,
826 .pc_decode
= nfssvc_decode_createargs
,
827 .pc_encode
= nfssvc_encode_diropres
,
828 .pc_release
= nfssvc_release_diropres
,
829 .pc_argsize
= sizeof(struct nfsd_createargs
),
830 .pc_argzero
= sizeof(struct nfsd_createargs
),
831 .pc_ressize
= sizeof(struct nfsd_diropres
),
832 .pc_cachetype
= RC_REPLBUFF
,
833 .pc_xdrressize
= ST
+FH
+AT
,
837 .pc_func
= nfsd_proc_rmdir
,
838 .pc_decode
= nfssvc_decode_diropargs
,
839 .pc_encode
= nfssvc_encode_statres
,
840 .pc_argsize
= sizeof(struct nfsd_diropargs
),
841 .pc_argzero
= sizeof(struct nfsd_diropargs
),
842 .pc_ressize
= sizeof(struct nfsd_stat
),
843 .pc_cachetype
= RC_REPLSTAT
,
847 [NFSPROC_READDIR
] = {
848 .pc_func
= nfsd_proc_readdir
,
849 .pc_decode
= nfssvc_decode_readdirargs
,
850 .pc_encode
= nfssvc_encode_readdirres
,
851 .pc_argsize
= sizeof(struct nfsd_readdirargs
),
852 .pc_argzero
= sizeof(struct nfsd_readdirargs
),
853 .pc_ressize
= sizeof(struct nfsd_readdirres
),
854 .pc_cachetype
= RC_NOCACHE
,
855 .pc_name
= "READDIR",
858 .pc_func
= nfsd_proc_statfs
,
859 .pc_decode
= nfssvc_decode_fhandleargs
,
860 .pc_encode
= nfssvc_encode_statfsres
,
861 .pc_argsize
= sizeof(struct nfsd_fhandle
),
862 .pc_argzero
= sizeof(struct nfsd_fhandle
),
863 .pc_ressize
= sizeof(struct nfsd_statfsres
),
864 .pc_cachetype
= RC_NOCACHE
,
865 .pc_xdrressize
= ST
+5,
870 static DEFINE_PER_CPU_ALIGNED(unsigned long,
871 nfsd_count2
[ARRAY_SIZE(nfsd_procedures2
)]);
872 const struct svc_version nfsd_version2
= {
874 .vs_nproc
= ARRAY_SIZE(nfsd_procedures2
),
875 .vs_proc
= nfsd_procedures2
,
876 .vs_count
= nfsd_count2
,
877 .vs_dispatch
= nfsd_dispatch
,
878 .vs_xdrsize
= NFS2_SVC_XDRSIZE
,