xref: /openbmc/linux/fs/nfsd/nfs3proc.c (revision 1fa6ac37)
1 /*
2  * Process version 3 NFS requests.
3  *
4  * Copyright (C) 1996, 1997, 1998 Olaf Kirch <okir@monad.swb.de>
5  */
6 
7 #include <linux/fs.h>
8 #include <linux/ext2_fs.h>
9 #include <linux/magic.h>
10 
11 #include "cache.h"
12 #include "xdr3.h"
13 #include "vfs.h"
14 
15 #define NFSDDBG_FACILITY		NFSDDBG_PROC
16 
17 #define RETURN_STATUS(st)	{ resp->status = (st); return (st); }
18 
19 static int	nfs3_ftypes[] = {
20 	0,			/* NF3NON */
21 	S_IFREG,		/* NF3REG */
22 	S_IFDIR,		/* NF3DIR */
23 	S_IFBLK,		/* NF3BLK */
24 	S_IFCHR,		/* NF3CHR */
25 	S_IFLNK,		/* NF3LNK */
26 	S_IFSOCK,		/* NF3SOCK */
27 	S_IFIFO,		/* NF3FIFO */
28 };
29 
30 /*
31  * NULL call.
32  */
33 static __be32
34 nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
35 {
36 	return nfs_ok;
37 }
38 
39 /*
40  * Get a file's attributes
41  */
42 static __be32
43 nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle  *argp,
44 					   struct nfsd3_attrstat *resp)
45 {
46 	int	err;
47 	__be32	nfserr;
48 
49 	dprintk("nfsd: GETATTR(3)  %s\n",
50 		SVCFH_fmt(&argp->fh));
51 
52 	fh_copy(&resp->fh, &argp->fh);
53 	nfserr = fh_verify(rqstp, &resp->fh, 0,
54 			NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
55 	if (nfserr)
56 		RETURN_STATUS(nfserr);
57 
58 	err = vfs_getattr(resp->fh.fh_export->ex_path.mnt,
59 			  resp->fh.fh_dentry, &resp->stat);
60 	nfserr = nfserrno(err);
61 
62 	RETURN_STATUS(nfserr);
63 }
64 
65 /*
66  * Set a file's attributes
67  */
68 static __be32
69 nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp,
70 					   struct nfsd3_attrstat  *resp)
71 {
72 	__be32	nfserr;
73 
74 	dprintk("nfsd: SETATTR(3)  %s\n",
75 				SVCFH_fmt(&argp->fh));
76 
77 	fh_copy(&resp->fh, &argp->fh);
78 	nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,
79 			      argp->check_guard, argp->guardtime);
80 	RETURN_STATUS(nfserr);
81 }
82 
83 /*
84  * Look up a path name component
85  */
86 static __be32
87 nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
88 					  struct nfsd3_diropres  *resp)
89 {
90 	__be32	nfserr;
91 
92 	dprintk("nfsd: LOOKUP(3)   %s %.*s\n",
93 				SVCFH_fmt(&argp->fh),
94 				argp->len,
95 				argp->name);
96 
97 	fh_copy(&resp->dirfh, &argp->fh);
98 	fh_init(&resp->fh, NFS3_FHSIZE);
99 
100 	nfserr = nfsd_lookup(rqstp, &resp->dirfh,
101 				    argp->name,
102 				    argp->len,
103 				    &resp->fh);
104 	RETURN_STATUS(nfserr);
105 }
106 
107 /*
108  * Check file access
109  */
110 static __be32
111 nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
112 					  struct nfsd3_accessres *resp)
113 {
114 	__be32	nfserr;
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 	nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
123 	RETURN_STATUS(nfserr);
124 }
125 
126 /*
127  * Read a symlink.
128  */
129 static __be32
130 nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd3_readlinkargs *argp,
131 					   struct nfsd3_readlinkres *resp)
132 {
133 	__be32 nfserr;
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 	nfserr = nfsd_readlink(rqstp, &resp->fh, argp->buffer, &resp->len);
141 	RETURN_STATUS(nfserr);
142 }
143 
144 /*
145  * Read a portion of a file.
146  */
147 static __be32
148 nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
149 				        struct nfsd3_readres  *resp)
150 {
151 	__be32	nfserr;
152 	u32	max_blocksize = svc_max_payload(rqstp);
153 
154 	dprintk("nfsd: READ(3) %s %lu bytes at %lu\n",
155 				SVCFH_fmt(&argp->fh),
156 				(unsigned long) argp->count,
157 				(unsigned long) argp->offset);
158 
159 	/* Obtain buffer pointer for payload.
160 	 * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
161 	 * + 1 (xdr opaque byte count) = 26
162 	 */
163 
164 	resp->count = argp->count;
165 	if (max_blocksize < resp->count)
166 		resp->count = max_blocksize;
167 
168 	svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
169 
170 	fh_copy(&resp->fh, &argp->fh);
171 	nfserr = nfsd_read(rqstp, &resp->fh, NULL,
172 				  argp->offset,
173 			   	  rqstp->rq_vec, argp->vlen,
174 				  &resp->count);
175 	if (nfserr == 0) {
176 		struct inode	*inode = resp->fh.fh_dentry->d_inode;
177 
178 		resp->eof = (argp->offset + resp->count) >= inode->i_size;
179 	}
180 
181 	RETURN_STATUS(nfserr);
182 }
183 
184 /*
185  * Write data to a file
186  */
187 static __be32
188 nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
189 					 struct nfsd3_writeres  *resp)
190 {
191 	__be32	nfserr;
192 	unsigned long cnt = argp->len;
193 
194 	dprintk("nfsd: WRITE(3)    %s %d bytes at %ld%s\n",
195 				SVCFH_fmt(&argp->fh),
196 				argp->len,
197 				(unsigned long) argp->offset,
198 				argp->stable? " stable" : "");
199 
200 	fh_copy(&resp->fh, &argp->fh);
201 	resp->committed = argp->stable;
202 	nfserr = nfsd_write(rqstp, &resp->fh, NULL,
203 				   argp->offset,
204 				   rqstp->rq_vec, argp->vlen,
205 				   &cnt,
206 				   &resp->committed);
207 	resp->count = cnt;
208 	RETURN_STATUS(nfserr);
209 }
210 
211 /*
212  * With NFSv3, CREATE processing is a lot easier than with NFSv2.
213  * At least in theory; we'll see how it fares in practice when the
214  * first reports about SunOS compatibility problems start to pour in...
215  */
216 static __be32
217 nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
218 					  struct nfsd3_diropres   *resp)
219 {
220 	svc_fh		*dirfhp, *newfhp = NULL;
221 	struct iattr	*attr;
222 	__be32		nfserr;
223 
224 	dprintk("nfsd: CREATE(3)   %s %.*s\n",
225 				SVCFH_fmt(&argp->fh),
226 				argp->len,
227 				argp->name);
228 
229 	dirfhp = fh_copy(&resp->dirfh, &argp->fh);
230 	newfhp = fh_init(&resp->fh, NFS3_FHSIZE);
231 	attr   = &argp->attrs;
232 
233 	/* Get the directory inode */
234 	nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_CREATE);
235 	if (nfserr)
236 		RETURN_STATUS(nfserr);
237 
238 	/* Unfudge the mode bits */
239 	attr->ia_mode &= ~S_IFMT;
240 	if (!(attr->ia_valid & ATTR_MODE)) {
241 		attr->ia_valid |= ATTR_MODE;
242 		attr->ia_mode = S_IFREG;
243 	} else {
244 		attr->ia_mode = (attr->ia_mode & ~S_IFMT) | S_IFREG;
245 	}
246 
247 	/* Now create the file and set attributes */
248 	nfserr = nfsd_create_v3(rqstp, dirfhp, argp->name, argp->len,
249 				attr, newfhp,
250 				argp->createmode, argp->verf, NULL, NULL);
251 
252 	RETURN_STATUS(nfserr);
253 }
254 
255 /*
256  * Make directory. This operation is not idempotent.
257  */
258 static __be32
259 nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
260 					 struct nfsd3_diropres   *resp)
261 {
262 	__be32	nfserr;
263 
264 	dprintk("nfsd: MKDIR(3)    %s %.*s\n",
265 				SVCFH_fmt(&argp->fh),
266 				argp->len,
267 				argp->name);
268 
269 	argp->attrs.ia_valid &= ~ATTR_SIZE;
270 	fh_copy(&resp->dirfh, &argp->fh);
271 	fh_init(&resp->fh, NFS3_FHSIZE);
272 	nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
273 				    &argp->attrs, S_IFDIR, 0, &resp->fh);
274 
275 	RETURN_STATUS(nfserr);
276 }
277 
278 static __be32
279 nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp,
280 					   struct nfsd3_diropres    *resp)
281 {
282 	__be32	nfserr;
283 
284 	dprintk("nfsd: SYMLINK(3)  %s %.*s -> %.*s\n",
285 				SVCFH_fmt(&argp->ffh),
286 				argp->flen, argp->fname,
287 				argp->tlen, argp->tname);
288 
289 	fh_copy(&resp->dirfh, &argp->ffh);
290 	fh_init(&resp->fh, NFS3_FHSIZE);
291 	nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen,
292 						   argp->tname, argp->tlen,
293 						   &resp->fh, &argp->attrs);
294 	RETURN_STATUS(nfserr);
295 }
296 
297 /*
298  * Make socket/fifo/device.
299  */
300 static __be32
301 nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp,
302 					 struct nfsd3_diropres  *resp)
303 {
304 	__be32	nfserr;
305 	int type;
306 	dev_t	rdev = 0;
307 
308 	dprintk("nfsd: MKNOD(3)    %s %.*s\n",
309 				SVCFH_fmt(&argp->fh),
310 				argp->len,
311 				argp->name);
312 
313 	fh_copy(&resp->dirfh, &argp->fh);
314 	fh_init(&resp->fh, NFS3_FHSIZE);
315 
316 	if (argp->ftype == 0 || argp->ftype >= NF3BAD)
317 		RETURN_STATUS(nfserr_inval);
318 	if (argp->ftype == NF3CHR || argp->ftype == NF3BLK) {
319 		rdev = MKDEV(argp->major, argp->minor);
320 		if (MAJOR(rdev) != argp->major ||
321 		    MINOR(rdev) != argp->minor)
322 			RETURN_STATUS(nfserr_inval);
323 	} else
324 		if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO)
325 			RETURN_STATUS(nfserr_inval);
326 
327 	type = nfs3_ftypes[argp->ftype];
328 	nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
329 				    &argp->attrs, type, rdev, &resp->fh);
330 
331 	RETURN_STATUS(nfserr);
332 }
333 
334 /*
335  * Remove file/fifo/socket etc.
336  */
337 static __be32
338 nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
339 					  struct nfsd3_attrstat  *resp)
340 {
341 	__be32	nfserr;
342 
343 	dprintk("nfsd: REMOVE(3)   %s %.*s\n",
344 				SVCFH_fmt(&argp->fh),
345 				argp->len,
346 				argp->name);
347 
348 	/* Unlink. -S_IFDIR means file must not be a directory */
349 	fh_copy(&resp->fh, &argp->fh);
350 	nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len);
351 	RETURN_STATUS(nfserr);
352 }
353 
354 /*
355  * Remove a directory
356  */
357 static __be32
358 nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
359 					 struct nfsd3_attrstat  *resp)
360 {
361 	__be32	nfserr;
362 
363 	dprintk("nfsd: RMDIR(3)    %s %.*s\n",
364 				SVCFH_fmt(&argp->fh),
365 				argp->len,
366 				argp->name);
367 
368 	fh_copy(&resp->fh, &argp->fh);
369 	nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len);
370 	RETURN_STATUS(nfserr);
371 }
372 
373 static __be32
374 nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp,
375 					  struct nfsd3_renameres  *resp)
376 {
377 	__be32	nfserr;
378 
379 	dprintk("nfsd: RENAME(3)   %s %.*s ->\n",
380 				SVCFH_fmt(&argp->ffh),
381 				argp->flen,
382 				argp->fname);
383 	dprintk("nfsd: -> %s %.*s\n",
384 				SVCFH_fmt(&argp->tfh),
385 				argp->tlen,
386 				argp->tname);
387 
388 	fh_copy(&resp->ffh, &argp->ffh);
389 	fh_copy(&resp->tfh, &argp->tfh);
390 	nfserr = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen,
391 				    &resp->tfh, argp->tname, argp->tlen);
392 	RETURN_STATUS(nfserr);
393 }
394 
395 static __be32
396 nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp,
397 					struct nfsd3_linkres  *resp)
398 {
399 	__be32	nfserr;
400 
401 	dprintk("nfsd: LINK(3)     %s ->\n",
402 				SVCFH_fmt(&argp->ffh));
403 	dprintk("nfsd:   -> %s %.*s\n",
404 				SVCFH_fmt(&argp->tfh),
405 				argp->tlen,
406 				argp->tname);
407 
408 	fh_copy(&resp->fh,  &argp->ffh);
409 	fh_copy(&resp->tfh, &argp->tfh);
410 	nfserr = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen,
411 				  &resp->fh);
412 	RETURN_STATUS(nfserr);
413 }
414 
415 /*
416  * Read a portion of a directory.
417  */
418 static __be32
419 nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
420 					   struct nfsd3_readdirres  *resp)
421 {
422 	__be32		nfserr;
423 	int		count;
424 
425 	dprintk("nfsd: READDIR(3)  %s %d bytes at %d\n",
426 				SVCFH_fmt(&argp->fh),
427 				argp->count, (u32) argp->cookie);
428 
429 	/* Make sure we've room for the NULL ptr & eof flag, and shrink to
430 	 * client read size */
431 	count = (argp->count >> 2) - 2;
432 
433 	/* Read directory and encode entries on the fly */
434 	fh_copy(&resp->fh, &argp->fh);
435 
436 	resp->buflen = count;
437 	resp->common.err = nfs_ok;
438 	resp->buffer = argp->buffer;
439 	resp->rqstp = rqstp;
440 	nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t*) &argp->cookie,
441 					&resp->common, nfs3svc_encode_entry);
442 	memcpy(resp->verf, argp->verf, 8);
443 	resp->count = resp->buffer - argp->buffer;
444 	if (resp->offset)
445 		xdr_encode_hyper(resp->offset, argp->cookie);
446 
447 	RETURN_STATUS(nfserr);
448 }
449 
450 /*
451  * Read a portion of a directory, including file handles and attrs.
452  * For now, we choose to ignore the dircount parameter.
453  */
454 static __be32
455 nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
456 					       struct nfsd3_readdirres  *resp)
457 {
458 	__be32	nfserr;
459 	int	count = 0;
460 	loff_t	offset;
461 	int	i;
462 	caddr_t	page_addr = NULL;
463 
464 	dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n",
465 				SVCFH_fmt(&argp->fh),
466 				argp->count, (u32) argp->cookie);
467 
468 	/* Convert byte count to number of words (i.e. >> 2),
469 	 * and reserve room for the NULL ptr & eof flag (-2 words) */
470 	resp->count = (argp->count >> 2) - 2;
471 
472 	/* Read directory and encode entries on the fly */
473 	fh_copy(&resp->fh, &argp->fh);
474 
475 	resp->common.err = nfs_ok;
476 	resp->buffer = argp->buffer;
477 	resp->buflen = resp->count;
478 	resp->rqstp = rqstp;
479 	offset = argp->cookie;
480 	nfserr = nfsd_readdir(rqstp, &resp->fh,
481 				     &offset,
482 				     &resp->common,
483 				     nfs3svc_encode_entry_plus);
484 	memcpy(resp->verf, argp->verf, 8);
485 	for (i=1; i<rqstp->rq_resused ; i++) {
486 		page_addr = page_address(rqstp->rq_respages[i]);
487 
488 		if (((caddr_t)resp->buffer >= page_addr) &&
489 		    ((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) {
490 			count += (caddr_t)resp->buffer - page_addr;
491 			break;
492 		}
493 		count += PAGE_SIZE;
494 	}
495 	resp->count = count >> 2;
496 	if (resp->offset) {
497 		if (unlikely(resp->offset1)) {
498 			/* we ended up with offset on a page boundary */
499 			*resp->offset = htonl(offset >> 32);
500 			*resp->offset1 = htonl(offset & 0xffffffff);
501 			resp->offset1 = NULL;
502 		} else {
503 			xdr_encode_hyper(resp->offset, offset);
504 		}
505 	}
506 
507 	RETURN_STATUS(nfserr);
508 }
509 
510 /*
511  * Get file system stats
512  */
513 static __be32
514 nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle    *argp,
515 					   struct nfsd3_fsstatres *resp)
516 {
517 	__be32	nfserr;
518 
519 	dprintk("nfsd: FSSTAT(3)   %s\n",
520 				SVCFH_fmt(&argp->fh));
521 
522 	nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0);
523 	fh_put(&argp->fh);
524 	RETURN_STATUS(nfserr);
525 }
526 
527 /*
528  * Get file system info
529  */
530 static __be32
531 nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle    *argp,
532 					   struct nfsd3_fsinfores *resp)
533 {
534 	__be32	nfserr;
535 	u32	max_blocksize = svc_max_payload(rqstp);
536 
537 	dprintk("nfsd: FSINFO(3)   %s\n",
538 				SVCFH_fmt(&argp->fh));
539 
540 	resp->f_rtmax  = max_blocksize;
541 	resp->f_rtpref = max_blocksize;
542 	resp->f_rtmult = PAGE_SIZE;
543 	resp->f_wtmax  = max_blocksize;
544 	resp->f_wtpref = max_blocksize;
545 	resp->f_wtmult = PAGE_SIZE;
546 	resp->f_dtpref = PAGE_SIZE;
547 	resp->f_maxfilesize = ~(u32) 0;
548 	resp->f_properties = NFS3_FSF_DEFAULT;
549 
550 	nfserr = fh_verify(rqstp, &argp->fh, 0,
551 			NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
552 
553 	/* Check special features of the file system. May request
554 	 * different read/write sizes for file systems known to have
555 	 * problems with large blocks */
556 	if (nfserr == 0) {
557 		struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb;
558 
559 		/* Note that we don't care for remote fs's here */
560 		if (sb->s_magic == MSDOS_SUPER_MAGIC) {
561 			resp->f_properties = NFS3_FSF_BILLYBOY;
562 		}
563 		resp->f_maxfilesize = sb->s_maxbytes;
564 	}
565 
566 	fh_put(&argp->fh);
567 	RETURN_STATUS(nfserr);
568 }
569 
570 /*
571  * Get pathconf info for the specified file
572  */
573 static __be32
574 nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle      *argp,
575 					     struct nfsd3_pathconfres *resp)
576 {
577 	__be32	nfserr;
578 
579 	dprintk("nfsd: PATHCONF(3) %s\n",
580 				SVCFH_fmt(&argp->fh));
581 
582 	/* Set default pathconf */
583 	resp->p_link_max = 255;		/* at least */
584 	resp->p_name_max = 255;		/* at least */
585 	resp->p_no_trunc = 0;
586 	resp->p_chown_restricted = 1;
587 	resp->p_case_insensitive = 0;
588 	resp->p_case_preserving = 1;
589 
590 	nfserr = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
591 
592 	if (nfserr == 0) {
593 		struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb;
594 
595 		/* Note that we don't care for remote fs's here */
596 		switch (sb->s_magic) {
597 		case EXT2_SUPER_MAGIC:
598 			resp->p_link_max = EXT2_LINK_MAX;
599 			resp->p_name_max = EXT2_NAME_LEN;
600 			break;
601 		case MSDOS_SUPER_MAGIC:
602 			resp->p_case_insensitive = 1;
603 			resp->p_case_preserving  = 0;
604 			break;
605 		}
606 	}
607 
608 	fh_put(&argp->fh);
609 	RETURN_STATUS(nfserr);
610 }
611 
612 
613 /*
614  * Commit a file (range) to stable storage.
615  */
616 static __be32
617 nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp,
618 					   struct nfsd3_commitres  *resp)
619 {
620 	__be32	nfserr;
621 
622 	dprintk("nfsd: COMMIT(3)   %s %u@%Lu\n",
623 				SVCFH_fmt(&argp->fh),
624 				argp->count,
625 				(unsigned long long) argp->offset);
626 
627 	if (argp->offset > NFS_OFFSET_MAX)
628 		RETURN_STATUS(nfserr_inval);
629 
630 	fh_copy(&resp->fh, &argp->fh);
631 	nfserr = nfsd_commit(rqstp, &resp->fh, argp->offset, argp->count);
632 
633 	RETURN_STATUS(nfserr);
634 }
635 
636 
637 /*
638  * NFSv3 Server procedures.
639  * Only the results of non-idempotent operations are cached.
640  */
641 #define nfs3svc_decode_fhandleargs	nfs3svc_decode_fhandle
642 #define nfs3svc_encode_attrstatres	nfs3svc_encode_attrstat
643 #define nfs3svc_encode_wccstatres	nfs3svc_encode_wccstat
644 #define nfsd3_mkdirargs			nfsd3_createargs
645 #define nfsd3_readdirplusargs		nfsd3_readdirargs
646 #define nfsd3_fhandleargs		nfsd_fhandle
647 #define nfsd3_fhandleres		nfsd3_attrstat
648 #define nfsd3_attrstatres		nfsd3_attrstat
649 #define nfsd3_wccstatres		nfsd3_attrstat
650 #define nfsd3_createres			nfsd3_diropres
651 #define nfsd3_voidres			nfsd3_voidargs
652 struct nfsd3_voidargs { int dummy; };
653 
654 #define PROC(name, argt, rest, relt, cache, respsize)	\
655  { (svc_procfunc) nfsd3_proc_##name,		\
656    (kxdrproc_t) nfs3svc_decode_##argt##args,	\
657    (kxdrproc_t) nfs3svc_encode_##rest##res,	\
658    (kxdrproc_t) nfs3svc_release_##relt,		\
659    sizeof(struct nfsd3_##argt##args),		\
660    sizeof(struct nfsd3_##rest##res),		\
661    0,						\
662    cache,					\
663    respsize,					\
664  }
665 
666 #define ST 1		/* status*/
667 #define FH 17		/* filehandle with length */
668 #define AT 21		/* attributes */
669 #define pAT (1+AT)	/* post attributes - conditional */
670 #define WC (7+pAT)	/* WCC attributes */
671 
672 static struct svc_procedure		nfsd_procedures3[22] = {
673 	[NFS3PROC_NULL] = {
674 		.pc_func = (svc_procfunc) nfsd3_proc_null,
675 		.pc_encode = (kxdrproc_t) nfs3svc_encode_voidres,
676 		.pc_argsize = sizeof(struct nfsd3_voidargs),
677 		.pc_ressize = sizeof(struct nfsd3_voidres),
678 		.pc_cachetype = RC_NOCACHE,
679 		.pc_xdrressize = ST,
680 	},
681 	[NFS3PROC_GETATTR] = {
682 		.pc_func = (svc_procfunc) nfsd3_proc_getattr,
683 		.pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
684 		.pc_encode = (kxdrproc_t) nfs3svc_encode_attrstatres,
685 		.pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
686 		.pc_argsize = sizeof(struct nfsd3_fhandleargs),
687 		.pc_ressize = sizeof(struct nfsd3_attrstatres),
688 		.pc_cachetype = RC_NOCACHE,
689 		.pc_xdrressize = ST+AT,
690 	},
691 	[NFS3PROC_SETATTR] = {
692 		.pc_func = (svc_procfunc) nfsd3_proc_setattr,
693 		.pc_decode = (kxdrproc_t) nfs3svc_decode_sattrargs,
694 		.pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres,
695 		.pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
696 		.pc_argsize = sizeof(struct nfsd3_sattrargs),
697 		.pc_ressize = sizeof(struct nfsd3_wccstatres),
698 		.pc_cachetype = RC_REPLBUFF,
699 		.pc_xdrressize = ST+WC,
700 	},
701 	[NFS3PROC_LOOKUP] = {
702 		.pc_func = (svc_procfunc) nfsd3_proc_lookup,
703 		.pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs,
704 		.pc_encode = (kxdrproc_t) nfs3svc_encode_diropres,
705 		.pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
706 		.pc_argsize = sizeof(struct nfsd3_diropargs),
707 		.pc_ressize = sizeof(struct nfsd3_diropres),
708 		.pc_cachetype = RC_NOCACHE,
709 		.pc_xdrressize = ST+FH+pAT+pAT,
710 	},
711 	[NFS3PROC_ACCESS] = {
712 		.pc_func = (svc_procfunc) nfsd3_proc_access,
713 		.pc_decode = (kxdrproc_t) nfs3svc_decode_accessargs,
714 		.pc_encode = (kxdrproc_t) nfs3svc_encode_accessres,
715 		.pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
716 		.pc_argsize = sizeof(struct nfsd3_accessargs),
717 		.pc_ressize = sizeof(struct nfsd3_accessres),
718 		.pc_cachetype = RC_NOCACHE,
719 		.pc_xdrressize = ST+pAT+1,
720 	},
721 	[NFS3PROC_READLINK] = {
722 		.pc_func = (svc_procfunc) nfsd3_proc_readlink,
723 		.pc_decode = (kxdrproc_t) nfs3svc_decode_readlinkargs,
724 		.pc_encode = (kxdrproc_t) nfs3svc_encode_readlinkres,
725 		.pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
726 		.pc_argsize = sizeof(struct nfsd3_readlinkargs),
727 		.pc_ressize = sizeof(struct nfsd3_readlinkres),
728 		.pc_cachetype = RC_NOCACHE,
729 		.pc_xdrressize = ST+pAT+1+NFS3_MAXPATHLEN/4,
730 	},
731 	[NFS3PROC_READ] = {
732 		.pc_func = (svc_procfunc) nfsd3_proc_read,
733 		.pc_decode = (kxdrproc_t) nfs3svc_decode_readargs,
734 		.pc_encode = (kxdrproc_t) nfs3svc_encode_readres,
735 		.pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
736 		.pc_argsize = sizeof(struct nfsd3_readargs),
737 		.pc_ressize = sizeof(struct nfsd3_readres),
738 		.pc_cachetype = RC_NOCACHE,
739 		.pc_xdrressize = ST+pAT+4+NFSSVC_MAXBLKSIZE/4,
740 	},
741 	[NFS3PROC_WRITE] = {
742 		.pc_func = (svc_procfunc) nfsd3_proc_write,
743 		.pc_decode = (kxdrproc_t) nfs3svc_decode_writeargs,
744 		.pc_encode = (kxdrproc_t) nfs3svc_encode_writeres,
745 		.pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
746 		.pc_argsize = sizeof(struct nfsd3_writeargs),
747 		.pc_ressize = sizeof(struct nfsd3_writeres),
748 		.pc_cachetype = RC_REPLBUFF,
749 		.pc_xdrressize = ST+WC+4,
750 	},
751 	[NFS3PROC_CREATE] = {
752 		.pc_func = (svc_procfunc) nfsd3_proc_create,
753 		.pc_decode = (kxdrproc_t) nfs3svc_decode_createargs,
754 		.pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
755 		.pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
756 		.pc_argsize = sizeof(struct nfsd3_createargs),
757 		.pc_ressize = sizeof(struct nfsd3_createres),
758 		.pc_cachetype = RC_REPLBUFF,
759 		.pc_xdrressize = ST+(1+FH+pAT)+WC,
760 	},
761 	[NFS3PROC_MKDIR] = {
762 		.pc_func = (svc_procfunc) nfsd3_proc_mkdir,
763 		.pc_decode = (kxdrproc_t) nfs3svc_decode_mkdirargs,
764 		.pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
765 		.pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
766 		.pc_argsize = sizeof(struct nfsd3_mkdirargs),
767 		.pc_ressize = sizeof(struct nfsd3_createres),
768 		.pc_cachetype = RC_REPLBUFF,
769 		.pc_xdrressize = ST+(1+FH+pAT)+WC,
770 	},
771 	[NFS3PROC_SYMLINK] = {
772 		.pc_func = (svc_procfunc) nfsd3_proc_symlink,
773 		.pc_decode = (kxdrproc_t) nfs3svc_decode_symlinkargs,
774 		.pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
775 		.pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
776 		.pc_argsize = sizeof(struct nfsd3_symlinkargs),
777 		.pc_ressize = sizeof(struct nfsd3_createres),
778 		.pc_cachetype = RC_REPLBUFF,
779 		.pc_xdrressize = ST+(1+FH+pAT)+WC,
780 	},
781 	[NFS3PROC_MKNOD] = {
782 		.pc_func = (svc_procfunc) nfsd3_proc_mknod,
783 		.pc_decode = (kxdrproc_t) nfs3svc_decode_mknodargs,
784 		.pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
785 		.pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
786 		.pc_argsize = sizeof(struct nfsd3_mknodargs),
787 		.pc_ressize = sizeof(struct nfsd3_createres),
788 		.pc_cachetype = RC_REPLBUFF,
789 		.pc_xdrressize = ST+(1+FH+pAT)+WC,
790 	},
791 	[NFS3PROC_REMOVE] = {
792 		.pc_func = (svc_procfunc) nfsd3_proc_remove,
793 		.pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs,
794 		.pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres,
795 		.pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
796 		.pc_argsize = sizeof(struct nfsd3_diropargs),
797 		.pc_ressize = sizeof(struct nfsd3_wccstatres),
798 		.pc_cachetype = RC_REPLBUFF,
799 		.pc_xdrressize = ST+WC,
800 	},
801 	[NFS3PROC_RMDIR] = {
802 		.pc_func = (svc_procfunc) nfsd3_proc_rmdir,
803 		.pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs,
804 		.pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres,
805 		.pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
806 		.pc_argsize = sizeof(struct nfsd3_diropargs),
807 		.pc_ressize = sizeof(struct nfsd3_wccstatres),
808 		.pc_cachetype = RC_REPLBUFF,
809 		.pc_xdrressize = ST+WC,
810 	},
811 	[NFS3PROC_RENAME] = {
812 		.pc_func = (svc_procfunc) nfsd3_proc_rename,
813 		.pc_decode = (kxdrproc_t) nfs3svc_decode_renameargs,
814 		.pc_encode = (kxdrproc_t) nfs3svc_encode_renameres,
815 		.pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
816 		.pc_argsize = sizeof(struct nfsd3_renameargs),
817 		.pc_ressize = sizeof(struct nfsd3_renameres),
818 		.pc_cachetype = RC_REPLBUFF,
819 		.pc_xdrressize = ST+WC+WC,
820 	},
821 	[NFS3PROC_LINK] = {
822 		.pc_func = (svc_procfunc) nfsd3_proc_link,
823 		.pc_decode = (kxdrproc_t) nfs3svc_decode_linkargs,
824 		.pc_encode = (kxdrproc_t) nfs3svc_encode_linkres,
825 		.pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
826 		.pc_argsize = sizeof(struct nfsd3_linkargs),
827 		.pc_ressize = sizeof(struct nfsd3_linkres),
828 		.pc_cachetype = RC_REPLBUFF,
829 		.pc_xdrressize = ST+pAT+WC,
830 	},
831 	[NFS3PROC_READDIR] = {
832 		.pc_func = (svc_procfunc) nfsd3_proc_readdir,
833 		.pc_decode = (kxdrproc_t) nfs3svc_decode_readdirargs,
834 		.pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres,
835 		.pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
836 		.pc_argsize = sizeof(struct nfsd3_readdirargs),
837 		.pc_ressize = sizeof(struct nfsd3_readdirres),
838 		.pc_cachetype = RC_NOCACHE,
839 	},
840 	[NFS3PROC_READDIRPLUS] = {
841 		.pc_func = (svc_procfunc) nfsd3_proc_readdirplus,
842 		.pc_decode = (kxdrproc_t) nfs3svc_decode_readdirplusargs,
843 		.pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres,
844 		.pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
845 		.pc_argsize = sizeof(struct nfsd3_readdirplusargs),
846 		.pc_ressize = sizeof(struct nfsd3_readdirres),
847 		.pc_cachetype = RC_NOCACHE,
848 	},
849 	[NFS3PROC_FSSTAT] = {
850 		.pc_func = (svc_procfunc) nfsd3_proc_fsstat,
851 		.pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
852 		.pc_encode = (kxdrproc_t) nfs3svc_encode_fsstatres,
853 		.pc_argsize = sizeof(struct nfsd3_fhandleargs),
854 		.pc_ressize = sizeof(struct nfsd3_fsstatres),
855 		.pc_cachetype = RC_NOCACHE,
856 		.pc_xdrressize = ST+pAT+2*6+1,
857 	},
858 	[NFS3PROC_FSINFO] = {
859 		.pc_func = (svc_procfunc) nfsd3_proc_fsinfo,
860 		.pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
861 		.pc_encode = (kxdrproc_t) nfs3svc_encode_fsinfores,
862 		.pc_argsize = sizeof(struct nfsd3_fhandleargs),
863 		.pc_ressize = sizeof(struct nfsd3_fsinfores),
864 		.pc_cachetype = RC_NOCACHE,
865 		.pc_xdrressize = ST+pAT+12,
866 	},
867 	[NFS3PROC_PATHCONF] = {
868 		.pc_func = (svc_procfunc) nfsd3_proc_pathconf,
869 		.pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
870 		.pc_encode = (kxdrproc_t) nfs3svc_encode_pathconfres,
871 		.pc_argsize = sizeof(struct nfsd3_fhandleargs),
872 		.pc_ressize = sizeof(struct nfsd3_pathconfres),
873 		.pc_cachetype = RC_NOCACHE,
874 		.pc_xdrressize = ST+pAT+6,
875 	},
876 	[NFS3PROC_COMMIT] = {
877 		.pc_func = (svc_procfunc) nfsd3_proc_commit,
878 		.pc_decode = (kxdrproc_t) nfs3svc_decode_commitargs,
879 		.pc_encode = (kxdrproc_t) nfs3svc_encode_commitres,
880 		.pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
881 		.pc_argsize = sizeof(struct nfsd3_commitargs),
882 		.pc_ressize = sizeof(struct nfsd3_commitres),
883 		.pc_cachetype = RC_NOCACHE,
884 		.pc_xdrressize = ST+WC+2,
885 	},
886 };
887 
888 struct svc_version	nfsd_version3 = {
889 		.vs_vers	= 3,
890 		.vs_nproc	= 22,
891 		.vs_proc	= nfsd_procedures3,
892 		.vs_dispatch	= nfsd_dispatch,
893 		.vs_xdrsize	= NFS3_SVC_XDRSIZE,
894 };
895