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