xref: /linux/fs/nfsd/nfs3proc.c (revision d141ec2825b4d3ec52f27c43bdd864090159273a)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Process version 3 NFS requests.
4  *
5  * Copyright (C) 1996, 1997, 1998 Olaf Kirch <okir@monad.swb.de>
6  */
7 
8 #include <linux/fs.h>
9 #include <linux/ext2_fs.h>
10 #include <linux/magic.h>
11 #include <linux/namei.h>
12 
13 #include "cache.h"
14 #include "xdr3.h"
15 #include "vfs.h"
16 #include "filecache.h"
17 #include "trace.h"
18 
19 #define NFSDDBG_FACILITY		NFSDDBG_PROC
20 
21 static int	nfs3_ftypes[] = {
22 	0,			/* NF3NON */
23 	S_IFREG,		/* NF3REG */
24 	S_IFDIR,		/* NF3DIR */
25 	S_IFBLK,		/* NF3BLK */
26 	S_IFCHR,		/* NF3CHR */
27 	S_IFLNK,		/* NF3LNK */
28 	S_IFSOCK,		/* NF3SOCK */
29 	S_IFIFO,		/* NF3FIFO */
30 };
31 
32 /*
33  * Reject a client-supplied atime or mtime whose nanoseconds field is out
34  * of range. Such a value is well-formed on the wire but is not a valid
35  * timespec64, and storing it verbatim can corrupt on-disk timestamps.
36  * tv_nsec is a long, so it is cast to unsigned long (the same width) to
37  * catch both an over-large value and one that became negative when an
38  * out-of-range u32 wire nseconds was assigned to a 32-bit long.
39  */
nfsd3_time_in_range(const struct iattr * iap)40 static bool nfsd3_time_in_range(const struct iattr *iap)
41 {
42 	if ((iap->ia_valid & ATTR_ATIME_SET) &&
43 	    (unsigned long)iap->ia_atime.tv_nsec >= NSEC_PER_SEC)
44 		return false;
45 	if ((iap->ia_valid & ATTR_MTIME_SET) &&
46 	    (unsigned long)iap->ia_mtime.tv_nsec >= NSEC_PER_SEC)
47 		return false;
48 	return true;
49 }
50 
nfsd3_map_status(__be32 status)51 static __be32 nfsd3_map_status(__be32 status)
52 {
53 	switch (status) {
54 	case nfs_ok:
55 		break;
56 	case nfserr_nofilehandle:
57 		status = nfserr_badhandle;
58 		break;
59 	case nfserr_wrongsec:
60 	case nfserr_file_open:
61 		status = nfserr_acces;
62 		break;
63 	case nfserr_symlink_not_dir:
64 		status = nfserr_notdir;
65 		break;
66 	case nfserr_symlink:
67 	case nfserr_wrong_type:
68 		status = nfserr_inval;
69 		break;
70 	}
71 	return status;
72 }
73 
74 /*
75  * NULL call.
76  */
77 static __be32
nfsd3_proc_null(struct svc_rqst * rqstp)78 nfsd3_proc_null(struct svc_rqst *rqstp)
79 {
80 	return rpc_success;
81 }
82 
83 /*
84  * Get a file's attributes
85  */
86 static __be32
nfsd3_proc_getattr(struct svc_rqst * rqstp)87 nfsd3_proc_getattr(struct svc_rqst *rqstp)
88 {
89 	struct nfsd_fhandle *argp = rqstp->rq_argp;
90 	struct nfsd3_attrstat *resp = rqstp->rq_resp;
91 
92 	trace_nfsd_vfs_getattr(rqstp, &argp->fh);
93 
94 	fh_copy(&resp->fh, &argp->fh);
95 	resp->status = fh_verify(rqstp, &resp->fh, 0,
96 				 NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
97 	if (resp->status != nfs_ok)
98 		goto out;
99 
100 	resp->status = fh_getattr(&resp->fh, &resp->stat);
101 out:
102 	resp->status = nfsd3_map_status(resp->status);
103 	return rpc_success;
104 }
105 
106 /*
107  * Set a file's attributes
108  */
109 static __be32
nfsd3_proc_setattr(struct svc_rqst * rqstp)110 nfsd3_proc_setattr(struct svc_rqst *rqstp)
111 {
112 	struct nfsd3_sattrargs *argp = rqstp->rq_argp;
113 	struct nfsd3_attrstat *resp = rqstp->rq_resp;
114 	struct nfsd_attrs attrs = {
115 		.na_iattr	= &argp->attrs,
116 	};
117 	const struct timespec64 *guardtime = NULL;
118 
119 	dprintk("nfsd: SETATTR(3)  %s\n",
120 				SVCFH_fmt(&argp->fh));
121 
122 	fh_copy(&resp->fh, &argp->fh);
123 	if (!nfsd3_time_in_range(&argp->attrs)) {
124 		resp->status = nfserr_inval;
125 		goto out;
126 	}
127 	if (argp->check_guard)
128 		guardtime = &argp->guardtime;
129 	resp->status = nfsd_setattr(rqstp, &resp->fh, &attrs, guardtime);
130 out:
131 	resp->status = nfsd3_map_status(resp->status);
132 	return rpc_success;
133 }
134 
135 /*
136  * Look up a path name component
137  */
138 static __be32
nfsd3_proc_lookup(struct svc_rqst * rqstp)139 nfsd3_proc_lookup(struct svc_rqst *rqstp)
140 {
141 	struct nfsd3_diropargs *argp = rqstp->rq_argp;
142 	struct nfsd3_diropres  *resp = rqstp->rq_resp;
143 
144 	dprintk("nfsd: LOOKUP(3)   %s %.*s\n",
145 				SVCFH_fmt(&argp->fh),
146 				argp->len,
147 				argp->name);
148 
149 	fh_copy(&resp->dirfh, &argp->fh);
150 	fh_init(&resp->fh, NFS3_FHSIZE);
151 
152 	resp->status = nfsd_lookup(rqstp, &resp->dirfh,
153 				   argp->name, argp->len,
154 				   &resp->fh);
155 	resp->status = nfsd3_map_status(resp->status);
156 	return rpc_success;
157 }
158 
159 /*
160  * Check file access
161  */
162 static __be32
nfsd3_proc_access(struct svc_rqst * rqstp)163 nfsd3_proc_access(struct svc_rqst *rqstp)
164 {
165 	struct nfsd3_accessargs *argp = rqstp->rq_argp;
166 	struct nfsd3_accessres *resp = rqstp->rq_resp;
167 
168 	dprintk("nfsd: ACCESS(3)   %s 0x%x\n",
169 				SVCFH_fmt(&argp->fh),
170 				argp->access);
171 
172 	fh_copy(&resp->fh, &argp->fh);
173 	resp->access = argp->access;
174 	resp->status = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
175 	resp->status = nfsd3_map_status(resp->status);
176 	return rpc_success;
177 }
178 
179 /*
180  * Read a symlink.
181  */
182 static __be32
nfsd3_proc_readlink(struct svc_rqst * rqstp)183 nfsd3_proc_readlink(struct svc_rqst *rqstp)
184 {
185 	struct nfsd_fhandle *argp = rqstp->rq_argp;
186 	struct nfsd3_readlinkres *resp = rqstp->rq_resp;
187 
188 	dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh));
189 
190 	/* Read the symlink. */
191 	fh_copy(&resp->fh, &argp->fh);
192 	resp->len = NFS3_MAXPATHLEN;
193 	resp->pages = rqstp->rq_next_page++;
194 	resp->status = nfsd_readlink(rqstp, &resp->fh,
195 				     page_address(*resp->pages), &resp->len);
196 	resp->status = nfsd3_map_status(resp->status);
197 	return rpc_success;
198 }
199 
200 /*
201  * Read a portion of a file.
202  */
203 static __be32
nfsd3_proc_read(struct svc_rqst * rqstp)204 nfsd3_proc_read(struct svc_rqst *rqstp)
205 {
206 	struct nfsd3_readargs *argp = rqstp->rq_argp;
207 	struct nfsd3_readres *resp = rqstp->rq_resp;
208 
209 	dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n",
210 				SVCFH_fmt(&argp->fh),
211 				(unsigned long) argp->count,
212 				(unsigned long long) argp->offset);
213 
214 	argp->count = min_t(u32, argp->count, svc_max_payload(rqstp));
215 	argp->count = min_t(u32, argp->count, rqstp->rq_res.buflen);
216 	if (argp->offset > (u64)OFFSET_MAX)
217 		argp->offset = (u64)OFFSET_MAX;
218 	if (argp->offset + argp->count > (u64)OFFSET_MAX)
219 		argp->count = (u64)OFFSET_MAX - argp->offset;
220 
221 	resp->pages = rqstp->rq_next_page;
222 
223 	/* Obtain buffer pointer for payload.
224 	 * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
225 	 * + 1 (xdr opaque byte count) = 26
226 	 */
227 	resp->count = argp->count;
228 	svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3) << 2) +
229 			 resp->count + 4);
230 
231 	fh_copy(&resp->fh, &argp->fh);
232 	resp->status = nfsd_read(rqstp, &resp->fh, argp->offset,
233 				 &resp->count, &resp->eof);
234 	resp->status = nfsd3_map_status(resp->status);
235 	return rpc_success;
236 }
237 
238 /*
239  * Write data to a file
240  */
241 static __be32
nfsd3_proc_write(struct svc_rqst * rqstp)242 nfsd3_proc_write(struct svc_rqst *rqstp)
243 {
244 	struct nfsd3_writeargs *argp = rqstp->rq_argp;
245 	struct nfsd3_writeres *resp = rqstp->rq_resp;
246 	unsigned long cnt = argp->len;
247 
248 	dprintk("nfsd: WRITE(3)    %s %d bytes at %Lu%s\n",
249 				SVCFH_fmt(&argp->fh),
250 				argp->len,
251 				(unsigned long long) argp->offset,
252 				argp->stable ? " stable" : "");
253 
254 	resp->status = nfserr_fbig;
255 	if (argp->offset > (u64)OFFSET_MAX ||
256 	    argp->offset + argp->len > (u64)OFFSET_MAX)
257 		return rpc_success;
258 
259 	fh_copy(&resp->fh, &argp->fh);
260 	resp->committed = argp->stable;
261 	resp->status = nfsd_write(rqstp, &resp->fh, argp->offset,
262 				  &argp->payload, &cnt,
263 				  resp->committed, resp->verf);
264 	resp->count = cnt;
265 	resp->status = nfsd3_map_status(resp->status);
266 	return rpc_success;
267 }
268 
269 /*
270  * Implement NFSv3's unchecked, guarded, and exclusive CREATE
271  * semantics for regular files. Except for the created file,
272  * this operation is stateless on the server.
273  *
274  * Upon return, caller must release @fhp and @resfhp.
275  */
276 static __be32
nfsd3_create_file(struct svc_rqst * rqstp,struct svc_fh * fhp,struct svc_fh * resfhp,struct nfsd3_createargs * argp)277 nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
278 		  struct svc_fh *resfhp, struct nfsd3_createargs *argp)
279 {
280 	struct iattr *iap = &argp->attrs;
281 	struct dentry *parent, *child;
282 	struct nfsd_attrs attrs = {
283 		.na_iattr	= iap,
284 	};
285 	__u32 v_mtime, v_atime;
286 	struct inode *inode;
287 	__be32 status;
288 	int host_err;
289 
290 	trace_nfsd_vfs_create(rqstp, fhp, S_IFREG, argp->name, argp->len);
291 
292 	if (!nfsd3_time_in_range(iap))
293 		return nfserr_inval;
294 	if (name_is_dot_dotdot(argp->name, argp->len))
295 		return nfserr_exist;
296 	if (!(iap->ia_valid & ATTR_MODE))
297 		iap->ia_mode = 0;
298 
299 	status = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
300 	if (status != nfs_ok)
301 		return status;
302 
303 	parent = fhp->fh_dentry;
304 	inode = d_inode(parent);
305 
306 	host_err = fh_want_write(fhp);
307 	if (host_err)
308 		return nfserrno(host_err);
309 
310 	child = start_creating(&nop_mnt_idmap, parent,
311 			       &QSTR_LEN(argp->name, argp->len));
312 	if (IS_ERR(child)) {
313 		status = nfserrno(PTR_ERR(child));
314 		goto out_write;
315 	}
316 
317 	if (d_really_is_negative(child)) {
318 		status = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
319 		if (status != nfs_ok)
320 			goto out;
321 	}
322 
323 	status = fh_compose(resfhp, fhp->fh_export, child, fhp);
324 	if (status != nfs_ok)
325 		goto out;
326 
327 	v_mtime = 0;
328 	v_atime = 0;
329 	if (argp->createmode == NFS3_CREATE_EXCLUSIVE) {
330 		u32 *verifier = (u32 *)argp->verf;
331 
332 		/*
333 		 * Solaris 7 gets confused (bugid 4218508) if these have
334 		 * the high bit set, as do xfs filesystems without the
335 		 * "bigtime" feature. So just clear the high bits.
336 		 */
337 		v_mtime = verifier[0] & 0x7fffffff;
338 		v_atime = verifier[1] & 0x7fffffff;
339 	}
340 
341 	if (d_really_is_positive(child)) {
342 		status = nfs_ok;
343 
344 		switch (argp->createmode) {
345 		case NFS3_CREATE_UNCHECKED:
346 			if (!d_is_reg(child))
347 				break;
348 			iap->ia_valid &= ATTR_SIZE;
349 			goto set_attr;
350 		case NFS3_CREATE_GUARDED:
351 			status = nfserr_exist;
352 			break;
353 		case NFS3_CREATE_EXCLUSIVE:
354 			if (inode_get_mtime_sec(d_inode(child)) == v_mtime &&
355 			    inode_get_atime_sec(d_inode(child)) == v_atime &&
356 			    d_inode(child)->i_size == 0) {
357 				break;
358 			}
359 			status = nfserr_exist;
360 		}
361 		goto out;
362 	}
363 
364 	if (!IS_POSIXACL(inode))
365 		iap->ia_mode &= ~current_umask();
366 
367 	status = fh_fill_pre_attrs(fhp);
368 	if (status != nfs_ok)
369 		goto out;
370 	host_err = vfs_create(&nop_mnt_idmap, child, iap->ia_mode, NULL);
371 	if (host_err < 0) {
372 		status = nfserrno(host_err);
373 		goto out;
374 	}
375 	fh_fill_post_attrs(fhp);
376 
377 	/* A newly created file already has a file size of zero. */
378 	if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0))
379 		iap->ia_valid &= ~ATTR_SIZE;
380 	if (argp->createmode == NFS3_CREATE_EXCLUSIVE) {
381 		iap->ia_valid = ATTR_MTIME | ATTR_ATIME |
382 				ATTR_MTIME_SET | ATTR_ATIME_SET;
383 		iap->ia_mtime.tv_sec = v_mtime;
384 		iap->ia_atime.tv_sec = v_atime;
385 		iap->ia_mtime.tv_nsec = 0;
386 		iap->ia_atime.tv_nsec = 0;
387 	}
388 
389 set_attr:
390 	status = nfsd_create_setattr(rqstp, fhp, resfhp, &attrs);
391 
392 out:
393 	end_creating(child);
394 out_write:
395 	fh_drop_write(fhp);
396 	return status;
397 }
398 
399 static __be32
nfsd3_proc_create(struct svc_rqst * rqstp)400 nfsd3_proc_create(struct svc_rqst *rqstp)
401 {
402 	struct nfsd3_createargs *argp = rqstp->rq_argp;
403 	struct nfsd3_diropres *resp = rqstp->rq_resp;
404 	svc_fh *dirfhp, *newfhp;
405 
406 	dirfhp = fh_copy(&resp->dirfh, &argp->fh);
407 	newfhp = fh_init(&resp->fh, NFS3_FHSIZE);
408 
409 	resp->status = nfsd3_create_file(rqstp, dirfhp, newfhp, argp);
410 	resp->status = nfsd3_map_status(resp->status);
411 	return rpc_success;
412 }
413 
414 /*
415  * Make directory. This operation is not idempotent.
416  */
417 static __be32
nfsd3_proc_mkdir(struct svc_rqst * rqstp)418 nfsd3_proc_mkdir(struct svc_rqst *rqstp)
419 {
420 	struct nfsd3_createargs *argp = rqstp->rq_argp;
421 	struct nfsd3_diropres *resp = rqstp->rq_resp;
422 	struct nfsd_attrs attrs = {
423 		.na_iattr	= &argp->attrs,
424 	};
425 
426 	argp->attrs.ia_valid &= ~ATTR_SIZE;
427 	fh_copy(&resp->dirfh, &argp->fh);
428 	fh_init(&resp->fh, NFS3_FHSIZE);
429 	if (!nfsd3_time_in_range(&argp->attrs)) {
430 		resp->status = nfserr_inval;
431 		goto out;
432 	}
433 	resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
434 				   &attrs, S_IFDIR, 0, &resp->fh);
435 out:
436 	resp->status = nfsd3_map_status(resp->status);
437 	return rpc_success;
438 }
439 
440 static __be32
nfsd3_proc_symlink(struct svc_rqst * rqstp)441 nfsd3_proc_symlink(struct svc_rqst *rqstp)
442 {
443 	struct nfsd3_symlinkargs *argp = rqstp->rq_argp;
444 	struct nfsd3_diropres *resp = rqstp->rq_resp;
445 	struct nfsd_attrs attrs = {
446 		.na_iattr	= &argp->attrs,
447 	};
448 
449 	if (!nfsd3_time_in_range(&argp->attrs)) {
450 		resp->status = nfserr_inval;
451 		goto out;
452 	}
453 	if (argp->tlen == 0) {
454 		resp->status = nfserr_inval;
455 		goto out;
456 	}
457 	if (argp->tlen > NFS3_MAXPATHLEN) {
458 		resp->status = nfserr_nametoolong;
459 		goto out;
460 	}
461 
462 	argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first,
463 						page_address(rqstp->rq_arg.pages[0]),
464 						argp->tlen);
465 	if (IS_ERR(argp->tname)) {
466 		resp->status = nfserrno(PTR_ERR(argp->tname));
467 		goto out;
468 	}
469 
470 	fh_copy(&resp->dirfh, &argp->ffh);
471 	fh_init(&resp->fh, NFS3_FHSIZE);
472 	resp->status = nfsd_symlink(rqstp, &resp->dirfh, argp->fname,
473 				    argp->flen, argp->tname, &attrs, &resp->fh);
474 	kfree(argp->tname);
475 out:
476 	resp->status = nfsd3_map_status(resp->status);
477 	return rpc_success;
478 }
479 
480 /*
481  * Make socket/fifo/device.
482  */
483 static __be32
nfsd3_proc_mknod(struct svc_rqst * rqstp)484 nfsd3_proc_mknod(struct svc_rqst *rqstp)
485 {
486 	struct nfsd3_mknodargs *argp = rqstp->rq_argp;
487 	struct nfsd3_diropres  *resp = rqstp->rq_resp;
488 	struct nfsd_attrs attrs = {
489 		.na_iattr	= &argp->attrs,
490 	};
491 	int type;
492 	dev_t	rdev = 0;
493 
494 	fh_copy(&resp->dirfh, &argp->fh);
495 	fh_init(&resp->fh, NFS3_FHSIZE);
496 
497 	if (argp->ftype == NF3CHR || argp->ftype == NF3BLK) {
498 		rdev = MKDEV(argp->major, argp->minor);
499 		if (MAJOR(rdev) != argp->major ||
500 		    MINOR(rdev) != argp->minor) {
501 			resp->status = nfserr_inval;
502 			goto out;
503 		}
504 	} else if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO) {
505 		resp->status = nfserr_badtype;
506 		goto out;
507 	}
508 
509 	if (!nfsd3_time_in_range(&argp->attrs)) {
510 		resp->status = nfserr_inval;
511 		goto out;
512 	}
513 
514 	type = nfs3_ftypes[argp->ftype];
515 	resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
516 				   &attrs, type, rdev, &resp->fh);
517 out:
518 	resp->status = nfsd3_map_status(resp->status);
519 	return rpc_success;
520 }
521 
522 /*
523  * Remove file/fifo/socket etc.
524  */
525 static __be32
nfsd3_proc_remove(struct svc_rqst * rqstp)526 nfsd3_proc_remove(struct svc_rqst *rqstp)
527 {
528 	struct nfsd3_diropargs *argp = rqstp->rq_argp;
529 	struct nfsd3_attrstat *resp = rqstp->rq_resp;
530 
531 	/* Unlink. -S_IFDIR means file must not be a directory */
532 	fh_copy(&resp->fh, &argp->fh);
533 	resp->status = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR,
534 				   argp->name, argp->len);
535 	resp->status = nfsd3_map_status(resp->status);
536 	return rpc_success;
537 }
538 
539 /*
540  * Remove a directory
541  */
542 static __be32
nfsd3_proc_rmdir(struct svc_rqst * rqstp)543 nfsd3_proc_rmdir(struct svc_rqst *rqstp)
544 {
545 	struct nfsd3_diropargs *argp = rqstp->rq_argp;
546 	struct nfsd3_attrstat *resp = rqstp->rq_resp;
547 
548 	fh_copy(&resp->fh, &argp->fh);
549 	resp->status = nfsd_unlink(rqstp, &resp->fh, S_IFDIR,
550 				   argp->name, argp->len);
551 	resp->status = nfsd3_map_status(resp->status);
552 	return rpc_success;
553 }
554 
555 static __be32
nfsd3_proc_rename(struct svc_rqst * rqstp)556 nfsd3_proc_rename(struct svc_rqst *rqstp)
557 {
558 	struct nfsd3_renameargs *argp = rqstp->rq_argp;
559 	struct nfsd3_renameres *resp = rqstp->rq_resp;
560 
561 	fh_copy(&resp->ffh, &argp->ffh);
562 	fh_copy(&resp->tfh, &argp->tfh);
563 	resp->status = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen,
564 				   &resp->tfh, argp->tname, argp->tlen);
565 	resp->status = nfsd3_map_status(resp->status);
566 	return rpc_success;
567 }
568 
569 static __be32
nfsd3_proc_link(struct svc_rqst * rqstp)570 nfsd3_proc_link(struct svc_rqst *rqstp)
571 {
572 	struct nfsd3_linkargs *argp = rqstp->rq_argp;
573 	struct nfsd3_linkres  *resp = rqstp->rq_resp;
574 
575 	fh_copy(&resp->fh,  &argp->ffh);
576 	fh_copy(&resp->tfh, &argp->tfh);
577 	resp->status = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen,
578 				 &resp->fh);
579 	resp->status = nfsd3_map_status(resp->status);
580 	return rpc_success;
581 }
582 
nfsd3_init_dirlist_pages(struct svc_rqst * rqstp,struct nfsd3_readdirres * resp,u32 count)583 static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp,
584 				     struct nfsd3_readdirres *resp,
585 				     u32 count)
586 {
587 	struct xdr_buf *buf = &resp->dirlist;
588 	struct xdr_stream *xdr = &resp->xdr;
589 	unsigned int sendbuf = min_t(unsigned int, rqstp->rq_res.buflen,
590 				     svc_max_payload(rqstp));
591 
592 	memset(buf, 0, sizeof(*buf));
593 
594 	/* Reserve room for the NULL ptr & eof flag (-2 words) */
595 	buf->buflen = clamp(count, (u32)(XDR_UNIT * 2), sendbuf);
596 	buf->buflen -= XDR_UNIT * 2;
597 	buf->pages = rqstp->rq_next_page;
598 	rqstp->rq_next_page += (buf->buflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
599 
600 	xdr_init_encode_pages(xdr, buf);
601 }
602 
603 /*
604  * Read a portion of a directory.
605  */
606 static __be32
nfsd3_proc_readdir(struct svc_rqst * rqstp)607 nfsd3_proc_readdir(struct svc_rqst *rqstp)
608 {
609 	struct nfsd3_readdirargs *argp = rqstp->rq_argp;
610 	struct nfsd3_readdirres  *resp = rqstp->rq_resp;
611 	loff_t		offset;
612 
613 	trace_nfsd_vfs_readdir(rqstp, &argp->fh, argp->count, argp->cookie);
614 
615 	nfsd3_init_dirlist_pages(rqstp, resp, argp->count);
616 
617 	fh_copy(&resp->fh, &argp->fh);
618 	resp->common.err = nfs_ok;
619 	resp->cookie_offset = 0;
620 	resp->rqstp = rqstp;
621 	offset = argp->cookie;
622 	resp->status = nfsd_readdir(rqstp, &resp->fh, &offset,
623 				    &resp->common, nfs3svc_encode_entry3);
624 	memcpy(resp->verf, argp->verf, 8);
625 	nfs3svc_encode_cookie3(resp, offset);
626 
627 	/* Recycle only pages that were part of the reply */
628 	rqstp->rq_next_page = resp->xdr.page_ptr + 1;
629 
630 	resp->status = nfsd3_map_status(resp->status);
631 	return rpc_success;
632 }
633 
634 /*
635  * Read a portion of a directory, including file handles and attrs.
636  * For now, we choose to ignore the dircount parameter.
637  */
638 static __be32
nfsd3_proc_readdirplus(struct svc_rqst * rqstp)639 nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
640 {
641 	struct nfsd3_readdirargs *argp = rqstp->rq_argp;
642 	struct nfsd3_readdirres  *resp = rqstp->rq_resp;
643 	loff_t	offset;
644 
645 	trace_nfsd_vfs_readdir(rqstp, &argp->fh, argp->count, argp->cookie);
646 
647 	nfsd3_init_dirlist_pages(rqstp, resp, argp->count);
648 
649 	fh_copy(&resp->fh, &argp->fh);
650 	resp->common.err = nfs_ok;
651 	resp->cookie_offset = 0;
652 	resp->rqstp = rqstp;
653 	offset = argp->cookie;
654 
655 	resp->status = fh_verify(rqstp, &resp->fh, S_IFDIR, NFSD_MAY_NOP);
656 	if (resp->status != nfs_ok)
657 		goto out;
658 
659 	if (resp->fh.fh_export->ex_flags & NFSEXP_NOREADDIRPLUS) {
660 		resp->status = nfserr_notsupp;
661 		goto out;
662 	}
663 
664 	resp->status = nfsd_readdir(rqstp, &resp->fh, &offset,
665 				    &resp->common, nfs3svc_encode_entryplus3);
666 	memcpy(resp->verf, argp->verf, 8);
667 	nfs3svc_encode_cookie3(resp, offset);
668 
669 	/* Recycle only pages that were part of the reply */
670 	rqstp->rq_next_page = resp->xdr.page_ptr + 1;
671 
672 out:
673 	resp->status = nfsd3_map_status(resp->status);
674 	return rpc_success;
675 }
676 
677 /*
678  * Get file system stats
679  */
680 static __be32
nfsd3_proc_fsstat(struct svc_rqst * rqstp)681 nfsd3_proc_fsstat(struct svc_rqst *rqstp)
682 {
683 	struct nfsd_fhandle *argp = rqstp->rq_argp;
684 	struct nfsd3_fsstatres *resp = rqstp->rq_resp;
685 
686 	resp->status = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0);
687 	fh_put(&argp->fh);
688 	resp->status = nfsd3_map_status(resp->status);
689 	return rpc_success;
690 }
691 
692 /*
693  * Get file system info
694  */
695 static __be32
nfsd3_proc_fsinfo(struct svc_rqst * rqstp)696 nfsd3_proc_fsinfo(struct svc_rqst *rqstp)
697 {
698 	struct nfsd_fhandle *argp = rqstp->rq_argp;
699 	struct nfsd3_fsinfores *resp = rqstp->rq_resp;
700 	u32	max_blocksize = svc_max_payload(rqstp);
701 
702 	dprintk("nfsd: FSINFO(3)   %s\n",
703 				SVCFH_fmt(&argp->fh));
704 
705 	resp->f_rtmax  = max_blocksize;
706 	resp->f_rtpref = max_blocksize;
707 	resp->f_rtmult = PAGE_SIZE;
708 	resp->f_wtmax  = max_blocksize;
709 	resp->f_wtpref = max_blocksize;
710 	resp->f_wtmult = PAGE_SIZE;
711 	resp->f_dtpref = max_blocksize;
712 	resp->f_maxfilesize = ~(u32) 0;
713 	resp->f_properties = NFS3_FSF_DEFAULT;
714 
715 	resp->status = fh_verify(rqstp, &argp->fh, 0,
716 				 NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
717 
718 	/* Check special features of the file system. May request
719 	 * different read/write sizes for file systems known to have
720 	 * problems with large blocks */
721 	if (resp->status == nfs_ok) {
722 		struct super_block *sb = argp->fh.fh_dentry->d_sb;
723 
724 		/* Note that we don't care for remote fs's here */
725 		if (sb->s_magic == MSDOS_SUPER_MAGIC) {
726 			resp->f_properties = NFS3_FSF_BILLYBOY;
727 		}
728 		resp->f_maxfilesize = sb->s_maxbytes;
729 	}
730 
731 	fh_put(&argp->fh);
732 	resp->status = nfsd3_map_status(resp->status);
733 	return rpc_success;
734 }
735 
736 /*
737  * Get pathconf info for the specified file
738  */
739 static __be32
nfsd3_proc_pathconf(struct svc_rqst * rqstp)740 nfsd3_proc_pathconf(struct svc_rqst *rqstp)
741 {
742 	struct nfsd_fhandle *argp = rqstp->rq_argp;
743 	struct nfsd3_pathconfres *resp = rqstp->rq_resp;
744 
745 	dprintk("nfsd: PATHCONF(3) %s\n",
746 				SVCFH_fmt(&argp->fh));
747 
748 	/* Set default pathconf */
749 	resp->p_link_max = 255;		/* at least */
750 	resp->p_name_max = 255;		/* at least */
751 	resp->p_no_trunc = 0;
752 	resp->p_chown_restricted = 1;
753 	resp->p_case_insensitive = false;
754 	resp->p_case_preserving = true;
755 
756 	resp->status = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
757 
758 	if (resp->status == nfs_ok) {
759 		struct super_block *sb = argp->fh.fh_dentry->d_sb;
760 		int err;
761 
762 		if (sb->s_magic == EXT2_SUPER_MAGIC) {
763 			resp->p_link_max = EXT2_LINK_MAX;
764 			resp->p_name_max = EXT2_NAME_LEN;
765 		}
766 
767 		err = nfsd_get_case_info(argp->fh.fh_dentry,
768 					 &resp->p_case_insensitive,
769 					 &resp->p_case_preserving);
770 		/*
771 		 * RFC 1813 lists NFS3ERR_STALE, NFS3ERR_BADHANDLE, and
772 		 * NFS3ERR_SERVERFAULT as the only PATHCONF errors.
773 		 */
774 		switch (err) {
775 		case 0:
776 		case -EOPNOTSUPP:
777 			/* Both arms leave the output booleans valid. */
778 			break;
779 		case -EACCES:
780 		case -EPERM:
781 			/*
782 			 * Policy denied the query. Report STALE so the
783 			 * handle is unusable without implying a server
784 			 * malfunction.
785 			 */
786 			resp->status = nfserr_stale;
787 			break;
788 		case -ESTALE:
789 			resp->status = nfserr_stale;
790 			break;
791 		default:
792 			resp->status = nfserr_serverfault;
793 			break;
794 		}
795 	}
796 
797 	fh_put(&argp->fh);
798 	resp->status = nfsd3_map_status(resp->status);
799 	return rpc_success;
800 }
801 
802 /*
803  * Commit a file (range) to stable storage.
804  */
805 static __be32
nfsd3_proc_commit(struct svc_rqst * rqstp)806 nfsd3_proc_commit(struct svc_rqst *rqstp)
807 {
808 	struct nfsd3_commitargs *argp = rqstp->rq_argp;
809 	struct nfsd3_commitres *resp = rqstp->rq_resp;
810 	struct nfsd_file *nf;
811 
812 	dprintk("nfsd: COMMIT(3)   %s %u@%Lu\n",
813 				SVCFH_fmt(&argp->fh),
814 				argp->count,
815 				(unsigned long long) argp->offset);
816 
817 	fh_copy(&resp->fh, &argp->fh);
818 	resp->status = nfsd_file_acquire_gc(rqstp, &resp->fh, NFSD_MAY_WRITE |
819 					    NFSD_MAY_NOT_BREAK_LEASE, &nf);
820 	if (resp->status)
821 		goto out;
822 	resp->status = nfsd_commit(rqstp, &resp->fh, nf, argp->offset,
823 				   argp->count, resp->verf);
824 	nfsd_file_put(nf);
825 out:
826 	resp->status = nfsd3_map_status(resp->status);
827 	return rpc_success;
828 }
829 
830 
831 /*
832  * NFSv3 Server procedures.
833  * Only the results of non-idempotent operations are cached.
834  */
835 #define nfs3svc_encode_attrstatres	nfs3svc_encode_attrstat
836 #define nfs3svc_encode_wccstatres	nfs3svc_encode_wccstat
837 #define nfsd3_mkdirargs			nfsd3_createargs
838 #define nfsd3_readdirplusargs		nfsd3_readdirargs
839 #define nfsd3_fhandleargs		nfsd_fhandle
840 #define nfsd3_attrstatres		nfsd3_attrstat
841 #define nfsd3_wccstatres		nfsd3_attrstat
842 #define nfsd3_createres			nfsd3_diropres
843 
844 #define ST 1		/* status*/
845 #define FH 17		/* filehandle with length */
846 #define AT 21		/* attributes */
847 #define pAT (1+AT)	/* post attributes - conditional */
848 #define WC (7+pAT)	/* WCC attributes */
849 
850 static const struct svc_procedure nfsd_procedures3[22] = {
851 	[NFS3PROC_NULL] = {
852 		.pc_func = nfsd3_proc_null,
853 		.pc_decode = nfssvc_decode_voidarg,
854 		.pc_encode = nfssvc_encode_voidres,
855 		.pc_argsize = sizeof(struct nfsd_voidargs),
856 		.pc_argzero = sizeof(struct nfsd_voidargs),
857 		.pc_ressize = sizeof(struct nfsd_voidres),
858 		.pc_cachetype = RC_NOCACHE,
859 		.pc_xdrressize = ST,
860 		.pc_name = "NULL",
861 	},
862 	[NFS3PROC_GETATTR] = {
863 		.pc_func = nfsd3_proc_getattr,
864 		.pc_decode = nfs3svc_decode_fhandleargs,
865 		.pc_encode = nfs3svc_encode_getattrres,
866 		.pc_release = nfs3svc_release_fhandle,
867 		.pc_argsize = sizeof(struct nfsd_fhandle),
868 		.pc_argzero = sizeof(struct nfsd_fhandle),
869 		.pc_ressize = sizeof(struct nfsd3_attrstatres),
870 		.pc_cachetype = RC_NOCACHE,
871 		.pc_xdrressize = ST+AT,
872 		.pc_name = "GETATTR",
873 	},
874 	[NFS3PROC_SETATTR] = {
875 		.pc_func = nfsd3_proc_setattr,
876 		.pc_decode = nfs3svc_decode_sattrargs,
877 		.pc_encode = nfs3svc_encode_wccstatres,
878 		.pc_release = nfs3svc_release_fhandle,
879 		.pc_argsize = sizeof(struct nfsd3_sattrargs),
880 		.pc_argzero = sizeof(struct nfsd3_sattrargs),
881 		.pc_ressize = sizeof(struct nfsd3_wccstatres),
882 		.pc_cachetype = RC_REPLBUFF,
883 		.pc_xdrressize = ST+WC,
884 		.pc_name = "SETATTR",
885 	},
886 	[NFS3PROC_LOOKUP] = {
887 		.pc_func = nfsd3_proc_lookup,
888 		.pc_decode = nfs3svc_decode_diropargs,
889 		.pc_encode = nfs3svc_encode_lookupres,
890 		.pc_release = nfs3svc_release_fhandle2,
891 		.pc_argsize = sizeof(struct nfsd3_diropargs),
892 		.pc_argzero = sizeof(struct nfsd3_diropargs),
893 		.pc_ressize = sizeof(struct nfsd3_diropres),
894 		.pc_cachetype = RC_NOCACHE,
895 		.pc_xdrressize = ST+FH+pAT+pAT,
896 		.pc_name = "LOOKUP",
897 	},
898 	[NFS3PROC_ACCESS] = {
899 		.pc_func = nfsd3_proc_access,
900 		.pc_decode = nfs3svc_decode_accessargs,
901 		.pc_encode = nfs3svc_encode_accessres,
902 		.pc_release = nfs3svc_release_fhandle,
903 		.pc_argsize = sizeof(struct nfsd3_accessargs),
904 		.pc_argzero = sizeof(struct nfsd3_accessargs),
905 		.pc_ressize = sizeof(struct nfsd3_accessres),
906 		.pc_cachetype = RC_NOCACHE,
907 		.pc_xdrressize = ST+pAT+1,
908 		.pc_name = "ACCESS",
909 	},
910 	[NFS3PROC_READLINK] = {
911 		.pc_func = nfsd3_proc_readlink,
912 		.pc_decode = nfs3svc_decode_fhandleargs,
913 		.pc_encode = nfs3svc_encode_readlinkres,
914 		.pc_release = nfs3svc_release_fhandle,
915 		.pc_argsize = sizeof(struct nfsd_fhandle),
916 		.pc_argzero = sizeof(struct nfsd_fhandle),
917 		.pc_ressize = sizeof(struct nfsd3_readlinkres),
918 		.pc_cachetype = RC_NOCACHE,
919 		.pc_xdrressize = ST+pAT+1+NFS3_MAXPATHLEN/4,
920 		.pc_name = "READLINK",
921 	},
922 	[NFS3PROC_READ] = {
923 		.pc_func = nfsd3_proc_read,
924 		.pc_decode = nfs3svc_decode_readargs,
925 		.pc_encode = nfs3svc_encode_readres,
926 		.pc_release = nfs3svc_release_fhandle,
927 		.pc_argsize = sizeof(struct nfsd3_readargs),
928 		.pc_argzero = sizeof(struct nfsd3_readargs),
929 		.pc_ressize = sizeof(struct nfsd3_readres),
930 		.pc_cachetype = RC_NOCACHE,
931 		.pc_xdrressize = ST+pAT+4+NFSSVC_MAXBLKSIZE/4,
932 		.pc_name = "READ",
933 	},
934 	[NFS3PROC_WRITE] = {
935 		.pc_func = nfsd3_proc_write,
936 		.pc_decode = nfs3svc_decode_writeargs,
937 		.pc_encode = nfs3svc_encode_writeres,
938 		.pc_release = nfs3svc_release_fhandle,
939 		.pc_argsize = sizeof(struct nfsd3_writeargs),
940 		.pc_argzero = sizeof(struct nfsd3_writeargs),
941 		.pc_ressize = sizeof(struct nfsd3_writeres),
942 		.pc_cachetype = RC_REPLBUFF,
943 		.pc_xdrressize = ST+WC+4,
944 		.pc_name = "WRITE",
945 	},
946 	[NFS3PROC_CREATE] = {
947 		.pc_func = nfsd3_proc_create,
948 		.pc_decode = nfs3svc_decode_createargs,
949 		.pc_encode = nfs3svc_encode_createres,
950 		.pc_release = nfs3svc_release_fhandle2,
951 		.pc_argsize = sizeof(struct nfsd3_createargs),
952 		.pc_argzero = sizeof(struct nfsd3_createargs),
953 		.pc_ressize = sizeof(struct nfsd3_createres),
954 		.pc_cachetype = RC_REPLBUFF,
955 		.pc_xdrressize = ST+(1+FH+pAT)+WC,
956 		.pc_name = "CREATE",
957 	},
958 	[NFS3PROC_MKDIR] = {
959 		.pc_func = nfsd3_proc_mkdir,
960 		.pc_decode = nfs3svc_decode_mkdirargs,
961 		.pc_encode = nfs3svc_encode_createres,
962 		.pc_release = nfs3svc_release_fhandle2,
963 		.pc_argsize = sizeof(struct nfsd3_mkdirargs),
964 		.pc_argzero = sizeof(struct nfsd3_mkdirargs),
965 		.pc_ressize = sizeof(struct nfsd3_createres),
966 		.pc_cachetype = RC_REPLBUFF,
967 		.pc_xdrressize = ST+(1+FH+pAT)+WC,
968 		.pc_name = "MKDIR",
969 	},
970 	[NFS3PROC_SYMLINK] = {
971 		.pc_func = nfsd3_proc_symlink,
972 		.pc_decode = nfs3svc_decode_symlinkargs,
973 		.pc_encode = nfs3svc_encode_createres,
974 		.pc_release = nfs3svc_release_fhandle2,
975 		.pc_argsize = sizeof(struct nfsd3_symlinkargs),
976 		.pc_argzero = sizeof(struct nfsd3_symlinkargs),
977 		.pc_ressize = sizeof(struct nfsd3_createres),
978 		.pc_cachetype = RC_REPLBUFF,
979 		.pc_xdrressize = ST+(1+FH+pAT)+WC,
980 		.pc_name = "SYMLINK",
981 	},
982 	[NFS3PROC_MKNOD] = {
983 		.pc_func = nfsd3_proc_mknod,
984 		.pc_decode = nfs3svc_decode_mknodargs,
985 		.pc_encode = nfs3svc_encode_createres,
986 		.pc_release = nfs3svc_release_fhandle2,
987 		.pc_argsize = sizeof(struct nfsd3_mknodargs),
988 		.pc_argzero = sizeof(struct nfsd3_mknodargs),
989 		.pc_ressize = sizeof(struct nfsd3_createres),
990 		.pc_cachetype = RC_REPLBUFF,
991 		.pc_xdrressize = ST+(1+FH+pAT)+WC,
992 		.pc_name = "MKNOD",
993 	},
994 	[NFS3PROC_REMOVE] = {
995 		.pc_func = nfsd3_proc_remove,
996 		.pc_decode = nfs3svc_decode_diropargs,
997 		.pc_encode = nfs3svc_encode_wccstatres,
998 		.pc_release = nfs3svc_release_fhandle,
999 		.pc_argsize = sizeof(struct nfsd3_diropargs),
1000 		.pc_argzero = sizeof(struct nfsd3_diropargs),
1001 		.pc_ressize = sizeof(struct nfsd3_wccstatres),
1002 		.pc_cachetype = RC_REPLBUFF,
1003 		.pc_xdrressize = ST+WC,
1004 		.pc_name = "REMOVE",
1005 	},
1006 	[NFS3PROC_RMDIR] = {
1007 		.pc_func = nfsd3_proc_rmdir,
1008 		.pc_decode = nfs3svc_decode_diropargs,
1009 		.pc_encode = nfs3svc_encode_wccstatres,
1010 		.pc_release = nfs3svc_release_fhandle,
1011 		.pc_argsize = sizeof(struct nfsd3_diropargs),
1012 		.pc_argzero = sizeof(struct nfsd3_diropargs),
1013 		.pc_ressize = sizeof(struct nfsd3_wccstatres),
1014 		.pc_cachetype = RC_REPLBUFF,
1015 		.pc_xdrressize = ST+WC,
1016 		.pc_name = "RMDIR",
1017 	},
1018 	[NFS3PROC_RENAME] = {
1019 		.pc_func = nfsd3_proc_rename,
1020 		.pc_decode = nfs3svc_decode_renameargs,
1021 		.pc_encode = nfs3svc_encode_renameres,
1022 		.pc_release = nfs3svc_release_fhandle2,
1023 		.pc_argsize = sizeof(struct nfsd3_renameargs),
1024 		.pc_argzero = sizeof(struct nfsd3_renameargs),
1025 		.pc_ressize = sizeof(struct nfsd3_renameres),
1026 		.pc_cachetype = RC_REPLBUFF,
1027 		.pc_xdrressize = ST+WC+WC,
1028 		.pc_name = "RENAME",
1029 	},
1030 	[NFS3PROC_LINK] = {
1031 		.pc_func = nfsd3_proc_link,
1032 		.pc_decode = nfs3svc_decode_linkargs,
1033 		.pc_encode = nfs3svc_encode_linkres,
1034 		.pc_release = nfs3svc_release_fhandle2,
1035 		.pc_argsize = sizeof(struct nfsd3_linkargs),
1036 		.pc_argzero = sizeof(struct nfsd3_linkargs),
1037 		.pc_ressize = sizeof(struct nfsd3_linkres),
1038 		.pc_cachetype = RC_REPLBUFF,
1039 		.pc_xdrressize = ST+pAT+WC,
1040 		.pc_name = "LINK",
1041 	},
1042 	[NFS3PROC_READDIR] = {
1043 		.pc_func = nfsd3_proc_readdir,
1044 		.pc_decode = nfs3svc_decode_readdirargs,
1045 		.pc_encode = nfs3svc_encode_readdirres,
1046 		.pc_release = nfs3svc_release_fhandle,
1047 		.pc_argsize = sizeof(struct nfsd3_readdirargs),
1048 		.pc_argzero = sizeof(struct nfsd3_readdirargs),
1049 		.pc_ressize = sizeof(struct nfsd3_readdirres),
1050 		.pc_cachetype = RC_NOCACHE,
1051 		.pc_name = "READDIR",
1052 	},
1053 	[NFS3PROC_READDIRPLUS] = {
1054 		.pc_func = nfsd3_proc_readdirplus,
1055 		.pc_decode = nfs3svc_decode_readdirplusargs,
1056 		.pc_encode = nfs3svc_encode_readdirres,
1057 		.pc_release = nfs3svc_release_fhandle,
1058 		.pc_argsize = sizeof(struct nfsd3_readdirplusargs),
1059 		.pc_argzero = sizeof(struct nfsd3_readdirplusargs),
1060 		.pc_ressize = sizeof(struct nfsd3_readdirres),
1061 		.pc_cachetype = RC_NOCACHE,
1062 		.pc_name = "READDIRPLUS",
1063 	},
1064 	[NFS3PROC_FSSTAT] = {
1065 		.pc_func = nfsd3_proc_fsstat,
1066 		.pc_decode = nfs3svc_decode_fhandleargs,
1067 		.pc_encode = nfs3svc_encode_fsstatres,
1068 		.pc_argsize = sizeof(struct nfsd3_fhandleargs),
1069 		.pc_argzero = sizeof(struct nfsd3_fhandleargs),
1070 		.pc_ressize = sizeof(struct nfsd3_fsstatres),
1071 		.pc_cachetype = RC_NOCACHE,
1072 		.pc_xdrressize = ST+pAT+2*6+1,
1073 		.pc_name = "FSSTAT",
1074 	},
1075 	[NFS3PROC_FSINFO] = {
1076 		.pc_func = nfsd3_proc_fsinfo,
1077 		.pc_decode = nfs3svc_decode_fhandleargs,
1078 		.pc_encode = nfs3svc_encode_fsinfores,
1079 		.pc_argsize = sizeof(struct nfsd3_fhandleargs),
1080 		.pc_argzero = sizeof(struct nfsd3_fhandleargs),
1081 		.pc_ressize = sizeof(struct nfsd3_fsinfores),
1082 		.pc_cachetype = RC_NOCACHE,
1083 		.pc_xdrressize = ST+pAT+12,
1084 		.pc_name = "FSINFO",
1085 	},
1086 	[NFS3PROC_PATHCONF] = {
1087 		.pc_func = nfsd3_proc_pathconf,
1088 		.pc_decode = nfs3svc_decode_fhandleargs,
1089 		.pc_encode = nfs3svc_encode_pathconfres,
1090 		.pc_argsize = sizeof(struct nfsd3_fhandleargs),
1091 		.pc_argzero = sizeof(struct nfsd3_fhandleargs),
1092 		.pc_ressize = sizeof(struct nfsd3_pathconfres),
1093 		.pc_cachetype = RC_NOCACHE,
1094 		.pc_xdrressize = ST+pAT+6,
1095 		.pc_name = "PATHCONF",
1096 	},
1097 	[NFS3PROC_COMMIT] = {
1098 		.pc_func = nfsd3_proc_commit,
1099 		.pc_decode = nfs3svc_decode_commitargs,
1100 		.pc_encode = nfs3svc_encode_commitres,
1101 		.pc_release = nfs3svc_release_fhandle,
1102 		.pc_argsize = sizeof(struct nfsd3_commitargs),
1103 		.pc_argzero = sizeof(struct nfsd3_commitargs),
1104 		.pc_ressize = sizeof(struct nfsd3_commitres),
1105 		.pc_cachetype = RC_NOCACHE,
1106 		.pc_xdrressize = ST+WC+2,
1107 		.pc_name = "COMMIT",
1108 	},
1109 };
1110 
1111 const struct svc_version nfsd_version3 = {
1112 	.vs_vers	= 3,
1113 	.vs_nproc	= ARRAY_SIZE(nfsd_procedures3),
1114 	.vs_proc	= nfsd_procedures3,
1115 	.vs_dispatch	= nfsd_dispatch,
1116 	.vs_xdrsize	= NFS3_SVC_XDRSIZE,
1117 };
1118