Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
nfs3proc.c
Go to the documentation of this file.
1 /*
2  * Process version 3 NFS requests.
3  *
4  * Copyright (C) 1996, 1997, 1998 Olaf Kirch <[email protected]>
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,
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 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,
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 %Lu%s\n",
195  SVCFH_fmt(&argp->fh),
196  argp->len,
197  (unsigned long 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 = do_nfsd_create(rqstp, dirfhp, argp->name, argp->len,
249  attr, newfhp,
250  argp->createmode, (u32 *)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  fh_unlock(&resp->dirfh);
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)
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)
323  } else
324  if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO)
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  fh_unlock(&resp->dirfh);
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  fh_unlock(&resp->fh);
352  RETURN_STATUS(nfserr);
353 }
354 
355 /*
356  * Remove a directory
357  */
358 static __be32
359 nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
360  struct nfsd3_attrstat *resp)
361 {
362  __be32 nfserr;
363 
364  dprintk("nfsd: RMDIR(3) %s %.*s\n",
365  SVCFH_fmt(&argp->fh),
366  argp->len,
367  argp->name);
368 
369  fh_copy(&resp->fh, &argp->fh);
370  nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len);
371  fh_unlock(&resp->fh);
372  RETURN_STATUS(nfserr);
373 }
374 
375 static __be32
376 nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp,
377  struct nfsd3_renameres *resp)
378 {
379  __be32 nfserr;
380 
381  dprintk("nfsd: RENAME(3) %s %.*s ->\n",
382  SVCFH_fmt(&argp->ffh),
383  argp->flen,
384  argp->fname);
385  dprintk("nfsd: -> %s %.*s\n",
386  SVCFH_fmt(&argp->tfh),
387  argp->tlen,
388  argp->tname);
389 
390  fh_copy(&resp->ffh, &argp->ffh);
391  fh_copy(&resp->tfh, &argp->tfh);
392  nfserr = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen,
393  &resp->tfh, argp->tname, argp->tlen);
394  RETURN_STATUS(nfserr);
395 }
396 
397 static __be32
398 nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp,
399  struct nfsd3_linkres *resp)
400 {
401  __be32 nfserr;
402 
403  dprintk("nfsd: LINK(3) %s ->\n",
404  SVCFH_fmt(&argp->ffh));
405  dprintk("nfsd: -> %s %.*s\n",
406  SVCFH_fmt(&argp->tfh),
407  argp->tlen,
408  argp->tname);
409 
410  fh_copy(&resp->fh, &argp->ffh);
411  fh_copy(&resp->tfh, &argp->tfh);
412  nfserr = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen,
413  &resp->fh);
414  RETURN_STATUS(nfserr);
415 }
416 
417 /*
418  * Read a portion of a directory.
419  */
420 static __be32
421 nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
422  struct nfsd3_readdirres *resp)
423 {
424  __be32 nfserr;
425  int count;
426 
427  dprintk("nfsd: READDIR(3) %s %d bytes at %d\n",
428  SVCFH_fmt(&argp->fh),
429  argp->count, (u32) argp->cookie);
430 
431  /* Make sure we've room for the NULL ptr & eof flag, and shrink to
432  * client read size */
433  count = (argp->count >> 2) - 2;
434 
435  /* Read directory and encode entries on the fly */
436  fh_copy(&resp->fh, &argp->fh);
437 
438  resp->buflen = count;
439  resp->common.err = nfs_ok;
440  resp->buffer = argp->buffer;
441  resp->rqstp = rqstp;
442  nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t*) &argp->cookie,
443  &resp->common, nfs3svc_encode_entry);
444  memcpy(resp->verf, argp->verf, 8);
445  resp->count = resp->buffer - argp->buffer;
446  if (resp->offset)
447  xdr_encode_hyper(resp->offset, argp->cookie);
448 
449  RETURN_STATUS(nfserr);
450 }
451 
452 /*
453  * Read a portion of a directory, including file handles and attrs.
454  * For now, we choose to ignore the dircount parameter.
455  */
456 static __be32
457 nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
458  struct nfsd3_readdirres *resp)
459 {
460  __be32 nfserr;
461  int count = 0;
462  loff_t offset;
463  int i;
464  caddr_t page_addr = NULL;
465 
466  dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n",
467  SVCFH_fmt(&argp->fh),
468  argp->count, (u32) argp->cookie);
469 
470  /* Convert byte count to number of words (i.e. >> 2),
471  * and reserve room for the NULL ptr & eof flag (-2 words) */
472  resp->count = (argp->count >> 2) - 2;
473 
474  /* Read directory and encode entries on the fly */
475  fh_copy(&resp->fh, &argp->fh);
476 
477  resp->common.err = nfs_ok;
478  resp->buffer = argp->buffer;
479  resp->buflen = resp->count;
480  resp->rqstp = rqstp;
481  offset = argp->cookie;
482  nfserr = nfsd_readdir(rqstp, &resp->fh,
483  &offset,
484  &resp->common,
486  memcpy(resp->verf, argp->verf, 8);
487  for (i=1; i<rqstp->rq_resused ; i++) {
488  page_addr = page_address(rqstp->rq_respages[i]);
489 
490  if (((caddr_t)resp->buffer >= page_addr) &&
491  ((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) {
492  count += (caddr_t)resp->buffer - page_addr;
493  break;
494  }
495  count += PAGE_SIZE;
496  }
497  resp->count = count >> 2;
498  if (resp->offset) {
499  if (unlikely(resp->offset1)) {
500  /* we ended up with offset on a page boundary */
501  *resp->offset = htonl(offset >> 32);
502  *resp->offset1 = htonl(offset & 0xffffffff);
503  resp->offset1 = NULL;
504  } else {
505  xdr_encode_hyper(resp->offset, offset);
506  }
507  }
508 
509  RETURN_STATUS(nfserr);
510 }
511 
512 /*
513  * Get file system stats
514  */
515 static __be32
516 nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
517  struct nfsd3_fsstatres *resp)
518 {
519  __be32 nfserr;
520 
521  dprintk("nfsd: FSSTAT(3) %s\n",
522  SVCFH_fmt(&argp->fh));
523 
524  nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0);
525  fh_put(&argp->fh);
526  RETURN_STATUS(nfserr);
527 }
528 
529 /*
530  * Get file system info
531  */
532 static __be32
533 nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
534  struct nfsd3_fsinfores *resp)
535 {
536  __be32 nfserr;
537  u32 max_blocksize = svc_max_payload(rqstp);
538 
539  dprintk("nfsd: FSINFO(3) %s\n",
540  SVCFH_fmt(&argp->fh));
541 
542  resp->f_rtmax = max_blocksize;
543  resp->f_rtpref = max_blocksize;
544  resp->f_rtmult = PAGE_SIZE;
545  resp->f_wtmax = max_blocksize;
546  resp->f_wtpref = max_blocksize;
547  resp->f_wtmult = PAGE_SIZE;
548  resp->f_dtpref = PAGE_SIZE;
549  resp->f_maxfilesize = ~(u32) 0;
551 
552  nfserr = fh_verify(rqstp, &argp->fh, 0,
554 
555  /* Check special features of the file system. May request
556  * different read/write sizes for file systems known to have
557  * problems with large blocks */
558  if (nfserr == 0) {
559  struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb;
560 
561  /* Note that we don't care for remote fs's here */
562  if (sb->s_magic == MSDOS_SUPER_MAGIC) {
564  }
565  resp->f_maxfilesize = sb->s_maxbytes;
566  }
567 
568  fh_put(&argp->fh);
569  RETURN_STATUS(nfserr);
570 }
571 
572 /*
573  * Get pathconf info for the specified file
574  */
575 static __be32
576 nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
577  struct nfsd3_pathconfres *resp)
578 {
579  __be32 nfserr;
580 
581  dprintk("nfsd: PATHCONF(3) %s\n",
582  SVCFH_fmt(&argp->fh));
583 
584  /* Set default pathconf */
585  resp->p_link_max = 255; /* at least */
586  resp->p_name_max = 255; /* at least */
587  resp->p_no_trunc = 0;
588  resp->p_chown_restricted = 1;
589  resp->p_case_insensitive = 0;
590  resp->p_case_preserving = 1;
591 
592  nfserr = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
593 
594  if (nfserr == 0) {
595  struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb;
596 
597  /* Note that we don't care for remote fs's here */
598  switch (sb->s_magic) {
599  case EXT2_SUPER_MAGIC:
600  resp->p_link_max = EXT2_LINK_MAX;
601  resp->p_name_max = EXT2_NAME_LEN;
602  break;
603  case MSDOS_SUPER_MAGIC:
604  resp->p_case_insensitive = 1;
605  resp->p_case_preserving = 0;
606  break;
607  }
608  }
609 
610  fh_put(&argp->fh);
611  RETURN_STATUS(nfserr);
612 }
613 
614 
615 /*
616  * Commit a file (range) to stable storage.
617  */
618 static __be32
619 nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp,
620  struct nfsd3_commitres *resp)
621 {
622  __be32 nfserr;
623 
624  dprintk("nfsd: COMMIT(3) %s %u@%Lu\n",
625  SVCFH_fmt(&argp->fh),
626  argp->count,
627  (unsigned long long) argp->offset);
628 
629  if (argp->offset > NFS_OFFSET_MAX)
631 
632  fh_copy(&resp->fh, &argp->fh);
633  nfserr = nfsd_commit(rqstp, &resp->fh, argp->offset, argp->count);
634 
635  RETURN_STATUS(nfserr);
636 }
637 
638 
639 /*
640  * NFSv3 Server procedures.
641  * Only the results of non-idempotent operations are cached.
642  */
643 #define nfs3svc_decode_fhandleargs nfs3svc_decode_fhandle
644 #define nfs3svc_encode_attrstatres nfs3svc_encode_attrstat
645 #define nfs3svc_encode_wccstatres nfs3svc_encode_wccstat
646 #define nfsd3_mkdirargs nfsd3_createargs
647 #define nfsd3_readdirplusargs nfsd3_readdirargs
648 #define nfsd3_fhandleargs nfsd_fhandle
649 #define nfsd3_fhandleres nfsd3_attrstat
650 #define nfsd3_attrstatres nfsd3_attrstat
651 #define nfsd3_wccstatres nfsd3_attrstat
652 #define nfsd3_createres nfsd3_diropres
653 #define nfsd3_voidres nfsd3_voidargs
654 struct nfsd3_voidargs { int dummy; };
655 
656 #define PROC(name, argt, rest, relt, cache, respsize) \
657  { (svc_procfunc) nfsd3_proc_##name, \
658  (kxdrproc_t) nfs3svc_decode_##argt##args, \
659  (kxdrproc_t) nfs3svc_encode_##rest##res, \
660  (kxdrproc_t) nfs3svc_release_##relt, \
661  sizeof(struct nfsd3_##argt##args), \
662  sizeof(struct nfsd3_##rest##res), \
663  0, \
664  cache, \
665  respsize, \
666  }
667 
668 #define ST 1 /* status*/
669 #define FH 17 /* filehandle with length */
670 #define AT 21 /* attributes */
671 #define pAT (1+AT) /* post attributes - conditional */
672 #define WC (7+pAT) /* WCC attributes */
673 
674 static struct svc_procedure nfsd_procedures3[22] = {
675  [NFS3PROC_NULL] = {
676  .pc_func = (svc_procfunc) nfsd3_proc_null,
677  .pc_encode = (kxdrproc_t) nfs3svc_encode_voidres,
678  .pc_argsize = sizeof(struct nfsd3_voidargs),
679  .pc_ressize = sizeof(struct nfsd3_voidres),
680  .pc_cachetype = RC_NOCACHE,
681  .pc_xdrressize = ST,
682  },
683  [NFS3PROC_GETATTR] = {
684  .pc_func = (svc_procfunc) nfsd3_proc_getattr,
685  .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
686  .pc_encode = (kxdrproc_t) nfs3svc_encode_attrstatres,
687  .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
688  .pc_argsize = sizeof(struct nfsd3_fhandleargs),
689  .pc_ressize = sizeof(struct nfsd3_attrstatres),
690  .pc_cachetype = RC_NOCACHE,
691  .pc_xdrressize = ST+AT,
692  },
693  [NFS3PROC_SETATTR] = {
694  .pc_func = (svc_procfunc) nfsd3_proc_setattr,
695  .pc_decode = (kxdrproc_t) nfs3svc_decode_sattrargs,
696  .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres,
697  .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
698  .pc_argsize = sizeof(struct nfsd3_sattrargs),
699  .pc_ressize = sizeof(struct nfsd3_wccstatres),
700  .pc_cachetype = RC_REPLBUFF,
701  .pc_xdrressize = ST+WC,
702  },
703  [NFS3PROC_LOOKUP] = {
704  .pc_func = (svc_procfunc) nfsd3_proc_lookup,
705  .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs,
706  .pc_encode = (kxdrproc_t) nfs3svc_encode_diropres,
707  .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
708  .pc_argsize = sizeof(struct nfsd3_diropargs),
709  .pc_ressize = sizeof(struct nfsd3_diropres),
710  .pc_cachetype = RC_NOCACHE,
711  .pc_xdrressize = ST+FH+pAT+pAT,
712  },
713  [NFS3PROC_ACCESS] = {
714  .pc_func = (svc_procfunc) nfsd3_proc_access,
715  .pc_decode = (kxdrproc_t) nfs3svc_decode_accessargs,
716  .pc_encode = (kxdrproc_t) nfs3svc_encode_accessres,
717  .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
718  .pc_argsize = sizeof(struct nfsd3_accessargs),
719  .pc_ressize = sizeof(struct nfsd3_accessres),
720  .pc_cachetype = RC_NOCACHE,
721  .pc_xdrressize = ST+pAT+1,
722  },
723  [NFS3PROC_READLINK] = {
724  .pc_func = (svc_procfunc) nfsd3_proc_readlink,
725  .pc_decode = (kxdrproc_t) nfs3svc_decode_readlinkargs,
726  .pc_encode = (kxdrproc_t) nfs3svc_encode_readlinkres,
727  .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
728  .pc_argsize = sizeof(struct nfsd3_readlinkargs),
729  .pc_ressize = sizeof(struct nfsd3_readlinkres),
730  .pc_cachetype = RC_NOCACHE,
731  .pc_xdrressize = ST+pAT+1+NFS3_MAXPATHLEN/4,
732  },
733  [NFS3PROC_READ] = {
734  .pc_func = (svc_procfunc) nfsd3_proc_read,
735  .pc_decode = (kxdrproc_t) nfs3svc_decode_readargs,
736  .pc_encode = (kxdrproc_t) nfs3svc_encode_readres,
737  .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
738  .pc_argsize = sizeof(struct nfsd3_readargs),
739  .pc_ressize = sizeof(struct nfsd3_readres),
740  .pc_cachetype = RC_NOCACHE,
741  .pc_xdrressize = ST+pAT+4+NFSSVC_MAXBLKSIZE/4,
742  },
743  [NFS3PROC_WRITE] = {
744  .pc_func = (svc_procfunc) nfsd3_proc_write,
745  .pc_decode = (kxdrproc_t) nfs3svc_decode_writeargs,
746  .pc_encode = (kxdrproc_t) nfs3svc_encode_writeres,
747  .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
748  .pc_argsize = sizeof(struct nfsd3_writeargs),
749  .pc_ressize = sizeof(struct nfsd3_writeres),
750  .pc_cachetype = RC_REPLBUFF,
751  .pc_xdrressize = ST+WC+4,
752  },
753  [NFS3PROC_CREATE] = {
754  .pc_func = (svc_procfunc) nfsd3_proc_create,
755  .pc_decode = (kxdrproc_t) nfs3svc_decode_createargs,
756  .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
757  .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
758  .pc_argsize = sizeof(struct nfsd3_createargs),
759  .pc_ressize = sizeof(struct nfsd3_createres),
760  .pc_cachetype = RC_REPLBUFF,
761  .pc_xdrressize = ST+(1+FH+pAT)+WC,
762  },
763  [NFS3PROC_MKDIR] = {
764  .pc_func = (svc_procfunc) nfsd3_proc_mkdir,
765  .pc_decode = (kxdrproc_t) nfs3svc_decode_mkdirargs,
766  .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
767  .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
768  .pc_argsize = sizeof(struct nfsd3_mkdirargs),
769  .pc_ressize = sizeof(struct nfsd3_createres),
770  .pc_cachetype = RC_REPLBUFF,
771  .pc_xdrressize = ST+(1+FH+pAT)+WC,
772  },
773  [NFS3PROC_SYMLINK] = {
774  .pc_func = (svc_procfunc) nfsd3_proc_symlink,
775  .pc_decode = (kxdrproc_t) nfs3svc_decode_symlinkargs,
776  .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
777  .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
778  .pc_argsize = sizeof(struct nfsd3_symlinkargs),
779  .pc_ressize = sizeof(struct nfsd3_createres),
780  .pc_cachetype = RC_REPLBUFF,
781  .pc_xdrressize = ST+(1+FH+pAT)+WC,
782  },
783  [NFS3PROC_MKNOD] = {
784  .pc_func = (svc_procfunc) nfsd3_proc_mknod,
785  .pc_decode = (kxdrproc_t) nfs3svc_decode_mknodargs,
786  .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
787  .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
788  .pc_argsize = sizeof(struct nfsd3_mknodargs),
789  .pc_ressize = sizeof(struct nfsd3_createres),
790  .pc_cachetype = RC_REPLBUFF,
791  .pc_xdrressize = ST+(1+FH+pAT)+WC,
792  },
793  [NFS3PROC_REMOVE] = {
794  .pc_func = (svc_procfunc) nfsd3_proc_remove,
795  .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs,
796  .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres,
797  .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
798  .pc_argsize = sizeof(struct nfsd3_diropargs),
799  .pc_ressize = sizeof(struct nfsd3_wccstatres),
800  .pc_cachetype = RC_REPLBUFF,
801  .pc_xdrressize = ST+WC,
802  },
803  [NFS3PROC_RMDIR] = {
804  .pc_func = (svc_procfunc) nfsd3_proc_rmdir,
805  .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs,
806  .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres,
807  .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
808  .pc_argsize = sizeof(struct nfsd3_diropargs),
809  .pc_ressize = sizeof(struct nfsd3_wccstatres),
810  .pc_cachetype = RC_REPLBUFF,
811  .pc_xdrressize = ST+WC,
812  },
813  [NFS3PROC_RENAME] = {
814  .pc_func = (svc_procfunc) nfsd3_proc_rename,
815  .pc_decode = (kxdrproc_t) nfs3svc_decode_renameargs,
816  .pc_encode = (kxdrproc_t) nfs3svc_encode_renameres,
817  .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
818  .pc_argsize = sizeof(struct nfsd3_renameargs),
819  .pc_ressize = sizeof(struct nfsd3_renameres),
820  .pc_cachetype = RC_REPLBUFF,
821  .pc_xdrressize = ST+WC+WC,
822  },
823  [NFS3PROC_LINK] = {
824  .pc_func = (svc_procfunc) nfsd3_proc_link,
825  .pc_decode = (kxdrproc_t) nfs3svc_decode_linkargs,
826  .pc_encode = (kxdrproc_t) nfs3svc_encode_linkres,
827  .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
828  .pc_argsize = sizeof(struct nfsd3_linkargs),
829  .pc_ressize = sizeof(struct nfsd3_linkres),
830  .pc_cachetype = RC_REPLBUFF,
831  .pc_xdrressize = ST+pAT+WC,
832  },
833  [NFS3PROC_READDIR] = {
834  .pc_func = (svc_procfunc) nfsd3_proc_readdir,
835  .pc_decode = (kxdrproc_t) nfs3svc_decode_readdirargs,
836  .pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres,
837  .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
838  .pc_argsize = sizeof(struct nfsd3_readdirargs),
839  .pc_ressize = sizeof(struct nfsd3_readdirres),
840  .pc_cachetype = RC_NOCACHE,
841  },
843  .pc_func = (svc_procfunc) nfsd3_proc_readdirplus,
844  .pc_decode = (kxdrproc_t) nfs3svc_decode_readdirplusargs,
845  .pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres,
846  .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
847  .pc_argsize = sizeof(struct nfsd3_readdirplusargs),
848  .pc_ressize = sizeof(struct nfsd3_readdirres),
849  .pc_cachetype = RC_NOCACHE,
850  },
851  [NFS3PROC_FSSTAT] = {
852  .pc_func = (svc_procfunc) nfsd3_proc_fsstat,
853  .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
854  .pc_encode = (kxdrproc_t) nfs3svc_encode_fsstatres,
855  .pc_argsize = sizeof(struct nfsd3_fhandleargs),
856  .pc_ressize = sizeof(struct nfsd3_fsstatres),
857  .pc_cachetype = RC_NOCACHE,
858  .pc_xdrressize = ST+pAT+2*6+1,
859  },
860  [NFS3PROC_FSINFO] = {
861  .pc_func = (svc_procfunc) nfsd3_proc_fsinfo,
862  .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
863  .pc_encode = (kxdrproc_t) nfs3svc_encode_fsinfores,
864  .pc_argsize = sizeof(struct nfsd3_fhandleargs),
865  .pc_ressize = sizeof(struct nfsd3_fsinfores),
866  .pc_cachetype = RC_NOCACHE,
867  .pc_xdrressize = ST+pAT+12,
868  },
869  [NFS3PROC_PATHCONF] = {
870  .pc_func = (svc_procfunc) nfsd3_proc_pathconf,
871  .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
872  .pc_encode = (kxdrproc_t) nfs3svc_encode_pathconfres,
873  .pc_argsize = sizeof(struct nfsd3_fhandleargs),
874  .pc_ressize = sizeof(struct nfsd3_pathconfres),
875  .pc_cachetype = RC_NOCACHE,
876  .pc_xdrressize = ST+pAT+6,
877  },
878  [NFS3PROC_COMMIT] = {
879  .pc_func = (svc_procfunc) nfsd3_proc_commit,
880  .pc_decode = (kxdrproc_t) nfs3svc_decode_commitargs,
881  .pc_encode = (kxdrproc_t) nfs3svc_encode_commitres,
882  .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
883  .pc_argsize = sizeof(struct nfsd3_commitargs),
884  .pc_ressize = sizeof(struct nfsd3_commitres),
885  .pc_cachetype = RC_NOCACHE,
886  .pc_xdrressize = ST+WC+2,
887  },
888 };
889 
891  .vs_vers = 3,
892  .vs_nproc = 22,
893  .vs_proc = nfsd_procedures3,
894  .vs_dispatch = nfsd_dispatch,
895  .vs_xdrsize = NFS3_SVC_XDRSIZE,
896 };