xref: /linux/fs/nfsd/nfsproc.c (revision 24168c5e6dfbdd5b414f048f47f75d64533296ca)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Process version 2 NFS requests.
4  *
5  * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
6  */
7 
8 #include <linux/namei.h>
9 
10 #include "cache.h"
11 #include "xdr.h"
12 #include "vfs.h"
13 
14 #define NFSDDBG_FACILITY		NFSDDBG_PROC
15 
16 static __be32
17 nfsd_proc_null(struct svc_rqst *rqstp)
18 {
19 	return rpc_success;
20 }
21 
22 /*
23  * Get a file's attributes
24  * N.B. After this call resp->fh needs an fh_put
25  */
26 static __be32
27 nfsd_proc_getattr(struct svc_rqst *rqstp)
28 {
29 	struct nfsd_fhandle *argp = rqstp->rq_argp;
30 	struct nfsd_attrstat *resp = rqstp->rq_resp;
31 
32 	dprintk("nfsd: GETATTR  %s\n", SVCFH_fmt(&argp->fh));
33 
34 	fh_copy(&resp->fh, &argp->fh);
35 	resp->status = fh_verify(rqstp, &resp->fh, 0,
36 				 NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
37 	if (resp->status != nfs_ok)
38 		goto out;
39 	resp->status = fh_getattr(&resp->fh, &resp->stat);
40 out:
41 	return rpc_success;
42 }
43 
44 /*
45  * Set a file's attributes
46  * N.B. After this call resp->fh needs an fh_put
47  */
48 static __be32
49 nfsd_proc_setattr(struct svc_rqst *rqstp)
50 {
51 	struct nfsd_sattrargs *argp = rqstp->rq_argp;
52 	struct nfsd_attrstat *resp = rqstp->rq_resp;
53 	struct iattr *iap = &argp->attrs;
54 	struct nfsd_attrs attrs = {
55 		.na_iattr	= iap,
56 	};
57 	struct svc_fh *fhp;
58 
59 	dprintk("nfsd: SETATTR  %s, valid=%x, size=%ld\n",
60 		SVCFH_fmt(&argp->fh),
61 		argp->attrs.ia_valid, (long) argp->attrs.ia_size);
62 
63 	fhp = fh_copy(&resp->fh, &argp->fh);
64 
65 	/*
66 	 * NFSv2 does not differentiate between "set-[ac]time-to-now"
67 	 * which only requires access, and "set-[ac]time-to-X" which
68 	 * requires ownership.
69 	 * So if it looks like it might be "set both to the same time which
70 	 * is close to now", and if setattr_prepare fails, then we
71 	 * convert to "set to now" instead of "set to explicit time"
72 	 *
73 	 * We only call setattr_prepare as the last test as technically
74 	 * it is not an interface that we should be using.
75 	 */
76 #define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
77 #define	MAX_TOUCH_TIME_ERROR (30*60)
78 	if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET &&
79 	    iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) {
80 		/*
81 		 * Looks probable.
82 		 *
83 		 * Now just make sure time is in the right ballpark.
84 		 * Solaris, at least, doesn't seem to care what the time
85 		 * request is.  We require it be within 30 minutes of now.
86 		 */
87 		time64_t delta = iap->ia_atime.tv_sec - ktime_get_real_seconds();
88 
89 		resp->status = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
90 		if (resp->status != nfs_ok)
91 			goto out;
92 
93 		if (delta < 0)
94 			delta = -delta;
95 		if (delta < MAX_TOUCH_TIME_ERROR &&
96 		    setattr_prepare(&nop_mnt_idmap, fhp->fh_dentry, iap) != 0) {
97 			/*
98 			 * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME.
99 			 * This will cause notify_change to set these times
100 			 * to "now"
101 			 */
102 			iap->ia_valid &= ~BOTH_TIME_SET;
103 		}
104 	}
105 
106 	resp->status = nfsd_setattr(rqstp, fhp, &attrs, NULL);
107 	if (resp->status != nfs_ok)
108 		goto out;
109 
110 	resp->status = fh_getattr(&resp->fh, &resp->stat);
111 out:
112 	return rpc_success;
113 }
114 
115 /* Obsolete, replaced by MNTPROC_MNT. */
116 static __be32
117 nfsd_proc_root(struct svc_rqst *rqstp)
118 {
119 	return rpc_success;
120 }
121 
122 /*
123  * Look up a path name component
124  * Note: the dentry in the resp->fh may be negative if the file
125  * doesn't exist yet.
126  * N.B. After this call resp->fh needs an fh_put
127  */
128 static __be32
129 nfsd_proc_lookup(struct svc_rqst *rqstp)
130 {
131 	struct nfsd_diropargs *argp = rqstp->rq_argp;
132 	struct nfsd_diropres *resp = rqstp->rq_resp;
133 
134 	dprintk("nfsd: LOOKUP   %s %.*s\n",
135 		SVCFH_fmt(&argp->fh), argp->len, argp->name);
136 
137 	fh_init(&resp->fh, NFS_FHSIZE);
138 	resp->status = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len,
139 				   &resp->fh);
140 	fh_put(&argp->fh);
141 	if (resp->status != nfs_ok)
142 		goto out;
143 
144 	resp->status = fh_getattr(&resp->fh, &resp->stat);
145 out:
146 	return rpc_success;
147 }
148 
149 /*
150  * Read a symlink.
151  */
152 static __be32
153 nfsd_proc_readlink(struct svc_rqst *rqstp)
154 {
155 	struct nfsd_fhandle *argp = rqstp->rq_argp;
156 	struct nfsd_readlinkres *resp = rqstp->rq_resp;
157 
158 	dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh));
159 
160 	/* Read the symlink. */
161 	resp->len = NFS_MAXPATHLEN;
162 	resp->page = *(rqstp->rq_next_page++);
163 	resp->status = nfsd_readlink(rqstp, &argp->fh,
164 				     page_address(resp->page), &resp->len);
165 
166 	fh_put(&argp->fh);
167 	return rpc_success;
168 }
169 
170 /*
171  * Read a portion of a file.
172  * N.B. After this call resp->fh needs an fh_put
173  */
174 static __be32
175 nfsd_proc_read(struct svc_rqst *rqstp)
176 {
177 	struct nfsd_readargs *argp = rqstp->rq_argp;
178 	struct nfsd_readres *resp = rqstp->rq_resp;
179 	u32 eof;
180 
181 	dprintk("nfsd: READ    %s %d bytes at %d\n",
182 		SVCFH_fmt(&argp->fh),
183 		argp->count, argp->offset);
184 
185 	argp->count = min_t(u32, argp->count, NFSSVC_MAXBLKSIZE_V2);
186 	argp->count = min_t(u32, argp->count, rqstp->rq_res.buflen);
187 
188 	resp->pages = rqstp->rq_next_page;
189 
190 	/* Obtain buffer pointer for payload. 19 is 1 word for
191 	 * status, 17 words for fattr, and 1 word for the byte count.
192 	 */
193 	svc_reserve_auth(rqstp, (19<<2) + argp->count + 4);
194 
195 	resp->count = argp->count;
196 	fh_copy(&resp->fh, &argp->fh);
197 	resp->status = nfsd_read(rqstp, &resp->fh, argp->offset,
198 				 &resp->count, &eof);
199 	if (resp->status == nfs_ok)
200 		resp->status = fh_getattr(&resp->fh, &resp->stat);
201 	else if (resp->status == nfserr_jukebox)
202 		set_bit(RQ_DROPME, &rqstp->rq_flags);
203 	return rpc_success;
204 }
205 
206 /* Reserved */
207 static __be32
208 nfsd_proc_writecache(struct svc_rqst *rqstp)
209 {
210 	return rpc_success;
211 }
212 
213 /*
214  * Write data to a file
215  * N.B. After this call resp->fh needs an fh_put
216  */
217 static __be32
218 nfsd_proc_write(struct svc_rqst *rqstp)
219 {
220 	struct nfsd_writeargs *argp = rqstp->rq_argp;
221 	struct nfsd_attrstat *resp = rqstp->rq_resp;
222 	unsigned long cnt = argp->len;
223 	unsigned int nvecs;
224 
225 	dprintk("nfsd: WRITE    %s %u bytes at %d\n",
226 		SVCFH_fmt(&argp->fh),
227 		argp->len, argp->offset);
228 
229 	nvecs = svc_fill_write_vector(rqstp, &argp->payload);
230 
231 	resp->status = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
232 				  argp->offset, rqstp->rq_vec, nvecs,
233 				  &cnt, NFS_DATA_SYNC, NULL);
234 	if (resp->status == nfs_ok)
235 		resp->status = fh_getattr(&resp->fh, &resp->stat);
236 	else if (resp->status == nfserr_jukebox)
237 		set_bit(RQ_DROPME, &rqstp->rq_flags);
238 	return rpc_success;
239 }
240 
241 /*
242  * CREATE processing is complicated. The keyword here is `overloaded.'
243  * The parent directory is kept locked between the check for existence
244  * and the actual create() call in compliance with VFS protocols.
245  * N.B. After this call _both_ argp->fh and resp->fh need an fh_put
246  */
247 static __be32
248 nfsd_proc_create(struct svc_rqst *rqstp)
249 {
250 	struct nfsd_createargs *argp = rqstp->rq_argp;
251 	struct nfsd_diropres *resp = rqstp->rq_resp;
252 	svc_fh		*dirfhp = &argp->fh;
253 	svc_fh		*newfhp = &resp->fh;
254 	struct iattr	*attr = &argp->attrs;
255 	struct nfsd_attrs attrs = {
256 		.na_iattr	= attr,
257 	};
258 	struct inode	*inode;
259 	struct dentry	*dchild;
260 	int		type, mode;
261 	int		hosterr;
262 	dev_t		rdev = 0, wanted = new_decode_dev(attr->ia_size);
263 
264 	dprintk("nfsd: CREATE   %s %.*s\n",
265 		SVCFH_fmt(dirfhp), argp->len, argp->name);
266 
267 	/* First verify the parent file handle */
268 	resp->status = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC);
269 	if (resp->status != nfs_ok)
270 		goto done; /* must fh_put dirfhp even on error */
271 
272 	/* Check for NFSD_MAY_WRITE in nfsd_create if necessary */
273 
274 	resp->status = nfserr_exist;
275 	if (isdotent(argp->name, argp->len))
276 		goto done;
277 	hosterr = fh_want_write(dirfhp);
278 	if (hosterr) {
279 		resp->status = nfserrno(hosterr);
280 		goto done;
281 	}
282 
283 	inode_lock_nested(dirfhp->fh_dentry->d_inode, I_MUTEX_PARENT);
284 	dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
285 	if (IS_ERR(dchild)) {
286 		resp->status = nfserrno(PTR_ERR(dchild));
287 		goto out_unlock;
288 	}
289 	fh_init(newfhp, NFS_FHSIZE);
290 	resp->status = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp);
291 	if (!resp->status && d_really_is_negative(dchild))
292 		resp->status = nfserr_noent;
293 	dput(dchild);
294 	if (resp->status) {
295 		if (resp->status != nfserr_noent)
296 			goto out_unlock;
297 		/*
298 		 * If the new file handle wasn't verified, we can't tell
299 		 * whether the file exists or not. Time to bail ...
300 		 */
301 		resp->status = nfserr_acces;
302 		if (!newfhp->fh_dentry) {
303 			printk(KERN_WARNING
304 				"nfsd_proc_create: file handle not verified\n");
305 			goto out_unlock;
306 		}
307 	}
308 
309 	inode = d_inode(newfhp->fh_dentry);
310 
311 	/* Unfudge the mode bits */
312 	if (attr->ia_valid & ATTR_MODE) {
313 		type = attr->ia_mode & S_IFMT;
314 		mode = attr->ia_mode & ~S_IFMT;
315 		if (!type) {
316 			/* no type, so if target exists, assume same as that,
317 			 * else assume a file */
318 			if (inode) {
319 				type = inode->i_mode & S_IFMT;
320 				switch(type) {
321 				case S_IFCHR:
322 				case S_IFBLK:
323 					/* reserve rdev for later checking */
324 					rdev = inode->i_rdev;
325 					attr->ia_valid |= ATTR_SIZE;
326 
327 					fallthrough;
328 				case S_IFIFO:
329 					/* this is probably a permission check..
330 					 * at least IRIX implements perm checking on
331 					 *   echo thing > device-special-file-or-pipe
332 					 * by doing a CREATE with type==0
333 					 */
334 					resp->status = nfsd_permission(rqstp,
335 								 newfhp->fh_export,
336 								 newfhp->fh_dentry,
337 								 NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS);
338 					if (resp->status && resp->status != nfserr_rofs)
339 						goto out_unlock;
340 				}
341 			} else
342 				type = S_IFREG;
343 		}
344 	} else if (inode) {
345 		type = inode->i_mode & S_IFMT;
346 		mode = inode->i_mode & ~S_IFMT;
347 	} else {
348 		type = S_IFREG;
349 		mode = 0;	/* ??? */
350 	}
351 
352 	attr->ia_valid |= ATTR_MODE;
353 	attr->ia_mode = mode;
354 
355 	/* Special treatment for non-regular files according to the
356 	 * gospel of sun micro
357 	 */
358 	if (type != S_IFREG) {
359 		if (type != S_IFBLK && type != S_IFCHR) {
360 			rdev = 0;
361 		} else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) {
362 			/* If you think you've seen the worst, grok this. */
363 			type = S_IFIFO;
364 		} else {
365 			/* Okay, char or block special */
366 			if (!rdev)
367 				rdev = wanted;
368 		}
369 
370 		/* we've used the SIZE information, so discard it */
371 		attr->ia_valid &= ~ATTR_SIZE;
372 
373 		/* Make sure the type and device matches */
374 		resp->status = nfserr_exist;
375 		if (inode && inode_wrong_type(inode, type))
376 			goto out_unlock;
377 	}
378 
379 	resp->status = nfs_ok;
380 	if (!inode) {
381 		/* File doesn't exist. Create it and set attrs */
382 		resp->status = nfsd_create_locked(rqstp, dirfhp, &attrs, type,
383 						  rdev, newfhp);
384 	} else if (type == S_IFREG) {
385 		dprintk("nfsd:   existing %s, valid=%x, size=%ld\n",
386 			argp->name, attr->ia_valid, (long) attr->ia_size);
387 		/* File already exists. We ignore all attributes except
388 		 * size, so that creat() behaves exactly like
389 		 * open(..., O_CREAT|O_TRUNC|O_WRONLY).
390 		 */
391 		attr->ia_valid &= ATTR_SIZE;
392 		if (attr->ia_valid)
393 			resp->status = nfsd_setattr(rqstp, newfhp, &attrs,
394 						    NULL);
395 	}
396 
397 out_unlock:
398 	inode_unlock(dirfhp->fh_dentry->d_inode);
399 	fh_drop_write(dirfhp);
400 done:
401 	fh_put(dirfhp);
402 	if (resp->status != nfs_ok)
403 		goto out;
404 	resp->status = fh_getattr(&resp->fh, &resp->stat);
405 out:
406 	return rpc_success;
407 }
408 
409 static __be32
410 nfsd_proc_remove(struct svc_rqst *rqstp)
411 {
412 	struct nfsd_diropargs *argp = rqstp->rq_argp;
413 	struct nfsd_stat *resp = rqstp->rq_resp;
414 
415 	dprintk("nfsd: REMOVE   %s %.*s\n", SVCFH_fmt(&argp->fh),
416 		argp->len, argp->name);
417 
418 	/* Unlink. -SIFDIR means file must not be a directory */
419 	resp->status = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR,
420 				   argp->name, argp->len);
421 	fh_put(&argp->fh);
422 	return rpc_success;
423 }
424 
425 static __be32
426 nfsd_proc_rename(struct svc_rqst *rqstp)
427 {
428 	struct nfsd_renameargs *argp = rqstp->rq_argp;
429 	struct nfsd_stat *resp = rqstp->rq_resp;
430 
431 	dprintk("nfsd: RENAME   %s %.*s -> \n",
432 		SVCFH_fmt(&argp->ffh), argp->flen, argp->fname);
433 	dprintk("nfsd:        ->  %s %.*s\n",
434 		SVCFH_fmt(&argp->tfh), argp->tlen, argp->tname);
435 
436 	resp->status = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen,
437 				   &argp->tfh, argp->tname, argp->tlen);
438 	fh_put(&argp->ffh);
439 	fh_put(&argp->tfh);
440 	return rpc_success;
441 }
442 
443 static __be32
444 nfsd_proc_link(struct svc_rqst *rqstp)
445 {
446 	struct nfsd_linkargs *argp = rqstp->rq_argp;
447 	struct nfsd_stat *resp = rqstp->rq_resp;
448 
449 	dprintk("nfsd: LINK     %s ->\n",
450 		SVCFH_fmt(&argp->ffh));
451 	dprintk("nfsd:    %s %.*s\n",
452 		SVCFH_fmt(&argp->tfh),
453 		argp->tlen,
454 		argp->tname);
455 
456 	resp->status = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen,
457 				 &argp->ffh);
458 	fh_put(&argp->ffh);
459 	fh_put(&argp->tfh);
460 	return rpc_success;
461 }
462 
463 static __be32
464 nfsd_proc_symlink(struct svc_rqst *rqstp)
465 {
466 	struct nfsd_symlinkargs *argp = rqstp->rq_argp;
467 	struct nfsd_stat *resp = rqstp->rq_resp;
468 	struct nfsd_attrs attrs = {
469 		.na_iattr	= &argp->attrs,
470 	};
471 	struct svc_fh	newfh;
472 
473 	if (argp->tlen > NFS_MAXPATHLEN) {
474 		resp->status = nfserr_nametoolong;
475 		goto out;
476 	}
477 
478 	argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first,
479 						page_address(rqstp->rq_arg.pages[0]),
480 						argp->tlen);
481 	if (IS_ERR(argp->tname)) {
482 		resp->status = nfserrno(PTR_ERR(argp->tname));
483 		goto out;
484 	}
485 
486 	dprintk("nfsd: SYMLINK  %s %.*s -> %.*s\n",
487 		SVCFH_fmt(&argp->ffh), argp->flen, argp->fname,
488 		argp->tlen, argp->tname);
489 
490 	fh_init(&newfh, NFS_FHSIZE);
491 	resp->status = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
492 				    argp->tname, &attrs, &newfh);
493 
494 	kfree(argp->tname);
495 	fh_put(&argp->ffh);
496 	fh_put(&newfh);
497 out:
498 	return rpc_success;
499 }
500 
501 /*
502  * Make directory. This operation is not idempotent.
503  * N.B. After this call resp->fh needs an fh_put
504  */
505 static __be32
506 nfsd_proc_mkdir(struct svc_rqst *rqstp)
507 {
508 	struct nfsd_createargs *argp = rqstp->rq_argp;
509 	struct nfsd_diropres *resp = rqstp->rq_resp;
510 	struct nfsd_attrs attrs = {
511 		.na_iattr	= &argp->attrs,
512 	};
513 
514 	dprintk("nfsd: MKDIR    %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
515 
516 	if (resp->fh.fh_dentry) {
517 		printk(KERN_WARNING
518 			"nfsd_proc_mkdir: response already verified??\n");
519 	}
520 
521 	argp->attrs.ia_valid &= ~ATTR_SIZE;
522 	fh_init(&resp->fh, NFS_FHSIZE);
523 	resp->status = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
524 				   &attrs, S_IFDIR, 0, &resp->fh);
525 	fh_put(&argp->fh);
526 	if (resp->status != nfs_ok)
527 		goto out;
528 
529 	resp->status = fh_getattr(&resp->fh, &resp->stat);
530 out:
531 	return rpc_success;
532 }
533 
534 /*
535  * Remove a directory
536  */
537 static __be32
538 nfsd_proc_rmdir(struct svc_rqst *rqstp)
539 {
540 	struct nfsd_diropargs *argp = rqstp->rq_argp;
541 	struct nfsd_stat *resp = rqstp->rq_resp;
542 
543 	dprintk("nfsd: RMDIR    %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
544 
545 	resp->status = nfsd_unlink(rqstp, &argp->fh, S_IFDIR,
546 				   argp->name, argp->len);
547 	fh_put(&argp->fh);
548 	return rpc_success;
549 }
550 
551 static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp,
552 				    struct nfsd_readdirres *resp,
553 				    u32 count)
554 {
555 	struct xdr_buf *buf = &resp->dirlist;
556 	struct xdr_stream *xdr = &resp->xdr;
557 
558 	memset(buf, 0, sizeof(*buf));
559 
560 	/* Reserve room for the NULL ptr & eof flag (-2 words) */
561 	buf->buflen = clamp(count, (u32)(XDR_UNIT * 2), (u32)PAGE_SIZE);
562 	buf->buflen -= XDR_UNIT * 2;
563 	buf->pages = rqstp->rq_next_page;
564 	rqstp->rq_next_page++;
565 
566 	xdr_init_encode_pages(xdr, buf, buf->pages,  NULL);
567 }
568 
569 /*
570  * Read a portion of a directory.
571  */
572 static __be32
573 nfsd_proc_readdir(struct svc_rqst *rqstp)
574 {
575 	struct nfsd_readdirargs *argp = rqstp->rq_argp;
576 	struct nfsd_readdirres *resp = rqstp->rq_resp;
577 	loff_t		offset;
578 
579 	dprintk("nfsd: READDIR  %s %d bytes at %d\n",
580 		SVCFH_fmt(&argp->fh),
581 		argp->count, argp->cookie);
582 
583 	nfsd_init_dirlist_pages(rqstp, resp, argp->count);
584 
585 	resp->common.err = nfs_ok;
586 	resp->cookie_offset = 0;
587 	offset = argp->cookie;
588 	resp->status = nfsd_readdir(rqstp, &argp->fh, &offset,
589 				    &resp->common, nfssvc_encode_entry);
590 	nfssvc_encode_nfscookie(resp, offset);
591 
592 	fh_put(&argp->fh);
593 	return rpc_success;
594 }
595 
596 /*
597  * Get file system info
598  */
599 static __be32
600 nfsd_proc_statfs(struct svc_rqst *rqstp)
601 {
602 	struct nfsd_fhandle *argp = rqstp->rq_argp;
603 	struct nfsd_statfsres *resp = rqstp->rq_resp;
604 
605 	dprintk("nfsd: STATFS   %s\n", SVCFH_fmt(&argp->fh));
606 
607 	resp->status = nfsd_statfs(rqstp, &argp->fh, &resp->stats,
608 				   NFSD_MAY_BYPASS_GSS_ON_ROOT);
609 	fh_put(&argp->fh);
610 	return rpc_success;
611 }
612 
613 /*
614  * NFSv2 Server procedures.
615  * Only the results of non-idempotent operations are cached.
616  */
617 
618 #define ST 1		/* status */
619 #define FH 8		/* filehandle */
620 #define	AT 18		/* attributes */
621 
622 static const struct svc_procedure nfsd_procedures2[18] = {
623 	[NFSPROC_NULL] = {
624 		.pc_func = nfsd_proc_null,
625 		.pc_decode = nfssvc_decode_voidarg,
626 		.pc_encode = nfssvc_encode_voidres,
627 		.pc_argsize = sizeof(struct nfsd_voidargs),
628 		.pc_argzero = sizeof(struct nfsd_voidargs),
629 		.pc_ressize = sizeof(struct nfsd_voidres),
630 		.pc_cachetype = RC_NOCACHE,
631 		.pc_xdrressize = 0,
632 		.pc_name = "NULL",
633 	},
634 	[NFSPROC_GETATTR] = {
635 		.pc_func = nfsd_proc_getattr,
636 		.pc_decode = nfssvc_decode_fhandleargs,
637 		.pc_encode = nfssvc_encode_attrstatres,
638 		.pc_release = nfssvc_release_attrstat,
639 		.pc_argsize = sizeof(struct nfsd_fhandle),
640 		.pc_argzero = sizeof(struct nfsd_fhandle),
641 		.pc_ressize = sizeof(struct nfsd_attrstat),
642 		.pc_cachetype = RC_NOCACHE,
643 		.pc_xdrressize = ST+AT,
644 		.pc_name = "GETATTR",
645 	},
646 	[NFSPROC_SETATTR] = {
647 		.pc_func = nfsd_proc_setattr,
648 		.pc_decode = nfssvc_decode_sattrargs,
649 		.pc_encode = nfssvc_encode_attrstatres,
650 		.pc_release = nfssvc_release_attrstat,
651 		.pc_argsize = sizeof(struct nfsd_sattrargs),
652 		.pc_argzero = sizeof(struct nfsd_sattrargs),
653 		.pc_ressize = sizeof(struct nfsd_attrstat),
654 		.pc_cachetype = RC_REPLBUFF,
655 		.pc_xdrressize = ST+AT,
656 		.pc_name = "SETATTR",
657 	},
658 	[NFSPROC_ROOT] = {
659 		.pc_func = nfsd_proc_root,
660 		.pc_decode = nfssvc_decode_voidarg,
661 		.pc_encode = nfssvc_encode_voidres,
662 		.pc_argsize = sizeof(struct nfsd_voidargs),
663 		.pc_argzero = sizeof(struct nfsd_voidargs),
664 		.pc_ressize = sizeof(struct nfsd_voidres),
665 		.pc_cachetype = RC_NOCACHE,
666 		.pc_xdrressize = 0,
667 		.pc_name = "ROOT",
668 	},
669 	[NFSPROC_LOOKUP] = {
670 		.pc_func = nfsd_proc_lookup,
671 		.pc_decode = nfssvc_decode_diropargs,
672 		.pc_encode = nfssvc_encode_diropres,
673 		.pc_release = nfssvc_release_diropres,
674 		.pc_argsize = sizeof(struct nfsd_diropargs),
675 		.pc_argzero = sizeof(struct nfsd_diropargs),
676 		.pc_ressize = sizeof(struct nfsd_diropres),
677 		.pc_cachetype = RC_NOCACHE,
678 		.pc_xdrressize = ST+FH+AT,
679 		.pc_name = "LOOKUP",
680 	},
681 	[NFSPROC_READLINK] = {
682 		.pc_func = nfsd_proc_readlink,
683 		.pc_decode = nfssvc_decode_fhandleargs,
684 		.pc_encode = nfssvc_encode_readlinkres,
685 		.pc_argsize = sizeof(struct nfsd_fhandle),
686 		.pc_argzero = sizeof(struct nfsd_fhandle),
687 		.pc_ressize = sizeof(struct nfsd_readlinkres),
688 		.pc_cachetype = RC_NOCACHE,
689 		.pc_xdrressize = ST+1+NFS_MAXPATHLEN/4,
690 		.pc_name = "READLINK",
691 	},
692 	[NFSPROC_READ] = {
693 		.pc_func = nfsd_proc_read,
694 		.pc_decode = nfssvc_decode_readargs,
695 		.pc_encode = nfssvc_encode_readres,
696 		.pc_release = nfssvc_release_readres,
697 		.pc_argsize = sizeof(struct nfsd_readargs),
698 		.pc_argzero = sizeof(struct nfsd_readargs),
699 		.pc_ressize = sizeof(struct nfsd_readres),
700 		.pc_cachetype = RC_NOCACHE,
701 		.pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4,
702 		.pc_name = "READ",
703 	},
704 	[NFSPROC_WRITECACHE] = {
705 		.pc_func = nfsd_proc_writecache,
706 		.pc_decode = nfssvc_decode_voidarg,
707 		.pc_encode = nfssvc_encode_voidres,
708 		.pc_argsize = sizeof(struct nfsd_voidargs),
709 		.pc_argzero = sizeof(struct nfsd_voidargs),
710 		.pc_ressize = sizeof(struct nfsd_voidres),
711 		.pc_cachetype = RC_NOCACHE,
712 		.pc_xdrressize = 0,
713 		.pc_name = "WRITECACHE",
714 	},
715 	[NFSPROC_WRITE] = {
716 		.pc_func = nfsd_proc_write,
717 		.pc_decode = nfssvc_decode_writeargs,
718 		.pc_encode = nfssvc_encode_attrstatres,
719 		.pc_release = nfssvc_release_attrstat,
720 		.pc_argsize = sizeof(struct nfsd_writeargs),
721 		.pc_argzero = sizeof(struct nfsd_writeargs),
722 		.pc_ressize = sizeof(struct nfsd_attrstat),
723 		.pc_cachetype = RC_REPLBUFF,
724 		.pc_xdrressize = ST+AT,
725 		.pc_name = "WRITE",
726 	},
727 	[NFSPROC_CREATE] = {
728 		.pc_func = nfsd_proc_create,
729 		.pc_decode = nfssvc_decode_createargs,
730 		.pc_encode = nfssvc_encode_diropres,
731 		.pc_release = nfssvc_release_diropres,
732 		.pc_argsize = sizeof(struct nfsd_createargs),
733 		.pc_argzero = sizeof(struct nfsd_createargs),
734 		.pc_ressize = sizeof(struct nfsd_diropres),
735 		.pc_cachetype = RC_REPLBUFF,
736 		.pc_xdrressize = ST+FH+AT,
737 		.pc_name = "CREATE",
738 	},
739 	[NFSPROC_REMOVE] = {
740 		.pc_func = nfsd_proc_remove,
741 		.pc_decode = nfssvc_decode_diropargs,
742 		.pc_encode = nfssvc_encode_statres,
743 		.pc_argsize = sizeof(struct nfsd_diropargs),
744 		.pc_argzero = sizeof(struct nfsd_diropargs),
745 		.pc_ressize = sizeof(struct nfsd_stat),
746 		.pc_cachetype = RC_REPLSTAT,
747 		.pc_xdrressize = ST,
748 		.pc_name = "REMOVE",
749 	},
750 	[NFSPROC_RENAME] = {
751 		.pc_func = nfsd_proc_rename,
752 		.pc_decode = nfssvc_decode_renameargs,
753 		.pc_encode = nfssvc_encode_statres,
754 		.pc_argsize = sizeof(struct nfsd_renameargs),
755 		.pc_argzero = sizeof(struct nfsd_renameargs),
756 		.pc_ressize = sizeof(struct nfsd_stat),
757 		.pc_cachetype = RC_REPLSTAT,
758 		.pc_xdrressize = ST,
759 		.pc_name = "RENAME",
760 	},
761 	[NFSPROC_LINK] = {
762 		.pc_func = nfsd_proc_link,
763 		.pc_decode = nfssvc_decode_linkargs,
764 		.pc_encode = nfssvc_encode_statres,
765 		.pc_argsize = sizeof(struct nfsd_linkargs),
766 		.pc_argzero = sizeof(struct nfsd_linkargs),
767 		.pc_ressize = sizeof(struct nfsd_stat),
768 		.pc_cachetype = RC_REPLSTAT,
769 		.pc_xdrressize = ST,
770 		.pc_name = "LINK",
771 	},
772 	[NFSPROC_SYMLINK] = {
773 		.pc_func = nfsd_proc_symlink,
774 		.pc_decode = nfssvc_decode_symlinkargs,
775 		.pc_encode = nfssvc_encode_statres,
776 		.pc_argsize = sizeof(struct nfsd_symlinkargs),
777 		.pc_argzero = sizeof(struct nfsd_symlinkargs),
778 		.pc_ressize = sizeof(struct nfsd_stat),
779 		.pc_cachetype = RC_REPLSTAT,
780 		.pc_xdrressize = ST,
781 		.pc_name = "SYMLINK",
782 	},
783 	[NFSPROC_MKDIR] = {
784 		.pc_func = nfsd_proc_mkdir,
785 		.pc_decode = nfssvc_decode_createargs,
786 		.pc_encode = nfssvc_encode_diropres,
787 		.pc_release = nfssvc_release_diropres,
788 		.pc_argsize = sizeof(struct nfsd_createargs),
789 		.pc_argzero = sizeof(struct nfsd_createargs),
790 		.pc_ressize = sizeof(struct nfsd_diropres),
791 		.pc_cachetype = RC_REPLBUFF,
792 		.pc_xdrressize = ST+FH+AT,
793 		.pc_name = "MKDIR",
794 	},
795 	[NFSPROC_RMDIR] = {
796 		.pc_func = nfsd_proc_rmdir,
797 		.pc_decode = nfssvc_decode_diropargs,
798 		.pc_encode = nfssvc_encode_statres,
799 		.pc_argsize = sizeof(struct nfsd_diropargs),
800 		.pc_argzero = sizeof(struct nfsd_diropargs),
801 		.pc_ressize = sizeof(struct nfsd_stat),
802 		.pc_cachetype = RC_REPLSTAT,
803 		.pc_xdrressize = ST,
804 		.pc_name = "RMDIR",
805 	},
806 	[NFSPROC_READDIR] = {
807 		.pc_func = nfsd_proc_readdir,
808 		.pc_decode = nfssvc_decode_readdirargs,
809 		.pc_encode = nfssvc_encode_readdirres,
810 		.pc_argsize = sizeof(struct nfsd_readdirargs),
811 		.pc_argzero = sizeof(struct nfsd_readdirargs),
812 		.pc_ressize = sizeof(struct nfsd_readdirres),
813 		.pc_cachetype = RC_NOCACHE,
814 		.pc_name = "READDIR",
815 	},
816 	[NFSPROC_STATFS] = {
817 		.pc_func = nfsd_proc_statfs,
818 		.pc_decode = nfssvc_decode_fhandleargs,
819 		.pc_encode = nfssvc_encode_statfsres,
820 		.pc_argsize = sizeof(struct nfsd_fhandle),
821 		.pc_argzero = sizeof(struct nfsd_fhandle),
822 		.pc_ressize = sizeof(struct nfsd_statfsres),
823 		.pc_cachetype = RC_NOCACHE,
824 		.pc_xdrressize = ST+5,
825 		.pc_name = "STATFS",
826 	},
827 };
828 
829 static DEFINE_PER_CPU_ALIGNED(unsigned long,
830 			      nfsd_count2[ARRAY_SIZE(nfsd_procedures2)]);
831 const struct svc_version nfsd_version2 = {
832 	.vs_vers	= 2,
833 	.vs_nproc	= ARRAY_SIZE(nfsd_procedures2),
834 	.vs_proc	= nfsd_procedures2,
835 	.vs_count	= nfsd_count2,
836 	.vs_dispatch	= nfsd_dispatch,
837 	.vs_xdrsize	= NFS2_SVC_XDRSIZE,
838 };
839