Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
nfsproc.c
Go to the documentation of this file.
1 /*
2  * Process version 2 NFS requests.
3  *
4  * Copyright (C) 1995-1997 Olaf Kirch <[email protected]>
5  */
6 
7 #include <linux/namei.h>
8 
9 #include "cache.h"
10 #include "xdr.h"
11 #include "vfs.h"
12 
13 typedef struct svc_rqst svc_rqst;
14 typedef struct svc_buf svc_buf;
15 
16 #define NFSDDBG_FACILITY NFSDDBG_PROC
17 
18 
19 static __be32
20 nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
21 {
22  return nfs_ok;
23 }
24 
25 static __be32
26 nfsd_return_attrs(__be32 err, struct nfsd_attrstat *resp)
27 {
28  if (err) return err;
29  return nfserrno(vfs_getattr(resp->fh.fh_export->ex_path.mnt,
30  resp->fh.fh_dentry,
31  &resp->stat));
32 }
33 static __be32
34 nfsd_return_dirop(__be32 err, struct nfsd_diropres *resp)
35 {
36  if (err) return err;
37  return nfserrno(vfs_getattr(resp->fh.fh_export->ex_path.mnt,
38  resp->fh.fh_dentry,
39  &resp->stat));
40 }
41 /*
42  * Get a file's attributes
43  * N.B. After this call resp->fh needs an fh_put
44  */
45 static __be32
46 nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
47  struct nfsd_attrstat *resp)
48 {
49  __be32 nfserr;
50  dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
51 
52  fh_copy(&resp->fh, &argp->fh);
53  nfserr = fh_verify(rqstp, &resp->fh, 0,
55  return nfsd_return_attrs(nfserr, resp);
56 }
57 
58 /*
59  * Set a file's attributes
60  * N.B. After this call resp->fh needs an fh_put
61  */
62 static __be32
63 nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp,
64  struct nfsd_attrstat *resp)
65 {
66  __be32 nfserr;
67  dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n",
68  SVCFH_fmt(&argp->fh),
69  argp->attrs.ia_valid, (long) argp->attrs.ia_size);
70 
71  fh_copy(&resp->fh, &argp->fh);
72  nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,0, (time_t)0);
73  return nfsd_return_attrs(nfserr, resp);
74 }
75 
76 /*
77  * Look up a path name component
78  * Note: the dentry in the resp->fh may be negative if the file
79  * doesn't exist yet.
80  * N.B. After this call resp->fh needs an fh_put
81  */
82 static __be32
83 nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
84  struct nfsd_diropres *resp)
85 {
86  __be32 nfserr;
87 
88  dprintk("nfsd: LOOKUP %s %.*s\n",
89  SVCFH_fmt(&argp->fh), argp->len, argp->name);
90 
91  fh_init(&resp->fh, NFS_FHSIZE);
92  nfserr = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len,
93  &resp->fh);
94 
95  fh_put(&argp->fh);
96  return nfsd_return_dirop(nfserr, resp);
97 }
98 
99 /*
100  * Read a symlink.
101  */
102 static __be32
103 nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_readlinkargs *argp,
104  struct nfsd_readlinkres *resp)
105 {
106  __be32 nfserr;
107 
108  dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh));
109 
110  /* Read the symlink. */
111  resp->len = NFS_MAXPATHLEN;
112  nfserr = nfsd_readlink(rqstp, &argp->fh, argp->buffer, &resp->len);
113 
114  fh_put(&argp->fh);
115  return nfserr;
116 }
117 
118 /*
119  * Read a portion of a file.
120  * N.B. After this call resp->fh needs an fh_put
121  */
122 static __be32
123 nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
124  struct nfsd_readres *resp)
125 {
126  __be32 nfserr;
127 
128  dprintk("nfsd: READ %s %d bytes at %d\n",
129  SVCFH_fmt(&argp->fh),
130  argp->count, argp->offset);
131 
132  /* Obtain buffer pointer for payload. 19 is 1 word for
133  * status, 17 words for fattr, and 1 word for the byte count.
134  */
135 
136  if (NFSSVC_MAXBLKSIZE_V2 < argp->count) {
137  char buf[RPC_MAX_ADDRBUFLEN];
139  "oversized read request from %s (%d bytes)\n",
140  svc_print_addr(rqstp, buf, sizeof(buf)),
141  argp->count);
142  argp->count = NFSSVC_MAXBLKSIZE_V2;
143  }
144  svc_reserve_auth(rqstp, (19<<2) + argp->count + 4);
145 
146  resp->count = argp->count;
147  nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh),
148  argp->offset,
149  rqstp->rq_vec, argp->vlen,
150  &resp->count);
151 
152  if (nfserr) return nfserr;
153  return nfserrno(vfs_getattr(resp->fh.fh_export->ex_path.mnt,
154  resp->fh.fh_dentry,
155  &resp->stat));
156 }
157 
158 /*
159  * Write data to a file
160  * N.B. After this call resp->fh needs an fh_put
161  */
162 static __be32
163 nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp,
164  struct nfsd_attrstat *resp)
165 {
166  __be32 nfserr;
167  int stable = 1;
168  unsigned long cnt = argp->len;
169 
170  dprintk("nfsd: WRITE %s %d bytes at %d\n",
171  SVCFH_fmt(&argp->fh),
172  argp->len, argp->offset);
173 
174  nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
175  argp->offset,
176  rqstp->rq_vec, argp->vlen,
177  &cnt,
178  &stable);
179  return nfsd_return_attrs(nfserr, resp);
180 }
181 
182 /*
183  * CREATE processing is complicated. The keyword here is `overloaded.'
184  * The parent directory is kept locked between the check for existence
185  * and the actual create() call in compliance with VFS protocols.
186  * N.B. After this call _both_ argp->fh and resp->fh need an fh_put
187  */
188 static __be32
189 nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
190  struct nfsd_diropres *resp)
191 {
192  svc_fh *dirfhp = &argp->fh;
193  svc_fh *newfhp = &resp->fh;
194  struct iattr *attr = &argp->attrs;
195  struct inode *inode;
196  struct dentry *dchild;
197  int type, mode;
198  __be32 nfserr;
199  int hosterr;
200  dev_t rdev = 0, wanted = new_decode_dev(attr->ia_size);
201 
202  dprintk("nfsd: CREATE %s %.*s\n",
203  SVCFH_fmt(dirfhp), argp->len, argp->name);
204 
205  /* First verify the parent file handle */
206  nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC);
207  if (nfserr)
208  goto done; /* must fh_put dirfhp even on error */
209 
210  /* Check for NFSD_MAY_WRITE in nfsd_create if necessary */
211 
212  nfserr = nfserr_acces;
213  if (!argp->len)
214  goto done;
215  nfserr = nfserr_exist;
216  if (isdotent(argp->name, argp->len))
217  goto done;
218  hosterr = fh_want_write(dirfhp);
219  if (hosterr) {
220  nfserr = nfserrno(hosterr);
221  goto done;
222  }
223 
224  fh_lock_nested(dirfhp, I_MUTEX_PARENT);
225  dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
226  if (IS_ERR(dchild)) {
227  nfserr = nfserrno(PTR_ERR(dchild));
228  goto out_unlock;
229  }
230  fh_init(newfhp, NFS_FHSIZE);
231  nfserr = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp);
232  if (!nfserr && !dchild->d_inode)
233  nfserr = nfserr_noent;
234  dput(dchild);
235  if (nfserr) {
236  if (nfserr != nfserr_noent)
237  goto out_unlock;
238  /*
239  * If the new file handle wasn't verified, we can't tell
240  * whether the file exists or not. Time to bail ...
241  */
242  nfserr = nfserr_acces;
243  if (!newfhp->fh_dentry) {
245  "nfsd_proc_create: file handle not verified\n");
246  goto out_unlock;
247  }
248  }
249 
250  inode = newfhp->fh_dentry->d_inode;
251 
252  /* Unfudge the mode bits */
253  if (attr->ia_valid & ATTR_MODE) {
254  type = attr->ia_mode & S_IFMT;
255  mode = attr->ia_mode & ~S_IFMT;
256  if (!type) {
257  /* no type, so if target exists, assume same as that,
258  * else assume a file */
259  if (inode) {
260  type = inode->i_mode & S_IFMT;
261  switch(type) {
262  case S_IFCHR:
263  case S_IFBLK:
264  /* reserve rdev for later checking */
265  rdev = inode->i_rdev;
266  attr->ia_valid |= ATTR_SIZE;
267 
268  /* FALLTHROUGH */
269  case S_IFIFO:
270  /* this is probably a permission check..
271  * at least IRIX implements perm checking on
272  * echo thing > device-special-file-or-pipe
273  * by doing a CREATE with type==0
274  */
275  nfserr = nfsd_permission(rqstp,
276  newfhp->fh_export,
277  newfhp->fh_dentry,
279  if (nfserr && nfserr != nfserr_rofs)
280  goto out_unlock;
281  }
282  } else
283  type = S_IFREG;
284  }
285  } else if (inode) {
286  type = inode->i_mode & S_IFMT;
287  mode = inode->i_mode & ~S_IFMT;
288  } else {
289  type = S_IFREG;
290  mode = 0; /* ??? */
291  }
292 
293  attr->ia_valid |= ATTR_MODE;
294  attr->ia_mode = mode;
295 
296  /* Special treatment for non-regular files according to the
297  * gospel of sun micro
298  */
299  if (type != S_IFREG) {
300  if (type != S_IFBLK && type != S_IFCHR) {
301  rdev = 0;
302  } else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) {
303  /* If you think you've seen the worst, grok this. */
304  type = S_IFIFO;
305  } else {
306  /* Okay, char or block special */
307  if (!rdev)
308  rdev = wanted;
309  }
310 
311  /* we've used the SIZE information, so discard it */
312  attr->ia_valid &= ~ATTR_SIZE;
313 
314  /* Make sure the type and device matches */
315  nfserr = nfserr_exist;
316  if (inode && type != (inode->i_mode & S_IFMT))
317  goto out_unlock;
318  }
319 
320  nfserr = 0;
321  if (!inode) {
322  /* File doesn't exist. Create it and set attrs */
323  nfserr = nfsd_create(rqstp, dirfhp, argp->name, argp->len,
324  attr, type, rdev, newfhp);
325  } else if (type == S_IFREG) {
326  dprintk("nfsd: existing %s, valid=%x, size=%ld\n",
327  argp->name, attr->ia_valid, (long) attr->ia_size);
328  /* File already exists. We ignore all attributes except
329  * size, so that creat() behaves exactly like
330  * open(..., O_CREAT|O_TRUNC|O_WRONLY).
331  */
332  attr->ia_valid &= ATTR_SIZE;
333  if (attr->ia_valid)
334  nfserr = nfsd_setattr(rqstp, newfhp, attr, 0, (time_t)0);
335  }
336 
337 out_unlock:
338  /* We don't really need to unlock, as fh_put does it. */
339  fh_unlock(dirfhp);
340  fh_drop_write(dirfhp);
341 done:
342  fh_put(dirfhp);
343  return nfsd_return_dirop(nfserr, resp);
344 }
345 
346 static __be32
347 nfsd_proc_remove(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
348  void *resp)
349 {
350  __be32 nfserr;
351 
352  dprintk("nfsd: REMOVE %s %.*s\n", SVCFH_fmt(&argp->fh),
353  argp->len, argp->name);
354 
355  /* Unlink. -SIFDIR means file must not be a directory */
356  nfserr = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR, argp->name, argp->len);
357  fh_put(&argp->fh);
358  return nfserr;
359 }
360 
361 static __be32
362 nfsd_proc_rename(struct svc_rqst *rqstp, struct nfsd_renameargs *argp,
363  void *resp)
364 {
365  __be32 nfserr;
366 
367  dprintk("nfsd: RENAME %s %.*s -> \n",
368  SVCFH_fmt(&argp->ffh), argp->flen, argp->fname);
369  dprintk("nfsd: -> %s %.*s\n",
370  SVCFH_fmt(&argp->tfh), argp->tlen, argp->tname);
371 
372  nfserr = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen,
373  &argp->tfh, argp->tname, argp->tlen);
374  fh_put(&argp->ffh);
375  fh_put(&argp->tfh);
376  return nfserr;
377 }
378 
379 static __be32
380 nfsd_proc_link(struct svc_rqst *rqstp, struct nfsd_linkargs *argp,
381  void *resp)
382 {
383  __be32 nfserr;
384 
385  dprintk("nfsd: LINK %s ->\n",
386  SVCFH_fmt(&argp->ffh));
387  dprintk("nfsd: %s %.*s\n",
388  SVCFH_fmt(&argp->tfh),
389  argp->tlen,
390  argp->tname);
391 
392  nfserr = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen,
393  &argp->ffh);
394  fh_put(&argp->ffh);
395  fh_put(&argp->tfh);
396  return nfserr;
397 }
398 
399 static __be32
400 nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp,
401  void *resp)
402 {
403  struct svc_fh newfh;
404  __be32 nfserr;
405 
406  dprintk("nfsd: SYMLINK %s %.*s -> %.*s\n",
407  SVCFH_fmt(&argp->ffh), argp->flen, argp->fname,
408  argp->tlen, argp->tname);
409 
410  fh_init(&newfh, NFS_FHSIZE);
411  /*
412  * Create the link, look up new file and set attrs.
413  */
414  nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
415  argp->tname, argp->tlen,
416  &newfh, &argp->attrs);
417 
418 
419  fh_put(&argp->ffh);
420  fh_put(&newfh);
421  return nfserr;
422 }
423 
424 /*
425  * Make directory. This operation is not idempotent.
426  * N.B. After this call resp->fh needs an fh_put
427  */
428 static __be32
429 nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
430  struct nfsd_diropres *resp)
431 {
432  __be32 nfserr;
433 
434  dprintk("nfsd: MKDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
435 
436  if (resp->fh.fh_dentry) {
438  "nfsd_proc_mkdir: response already verified??\n");
439  }
440 
441  argp->attrs.ia_valid &= ~ATTR_SIZE;
442  fh_init(&resp->fh, NFS_FHSIZE);
443  nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
444  &argp->attrs, S_IFDIR, 0, &resp->fh);
445  fh_put(&argp->fh);
446  return nfsd_return_dirop(nfserr, resp);
447 }
448 
449 /*
450  * Remove a directory
451  */
452 static __be32
453 nfsd_proc_rmdir(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
454  void *resp)
455 {
456  __be32 nfserr;
457 
458  dprintk("nfsd: RMDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
459 
460  nfserr = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, argp->name, argp->len);
461  fh_put(&argp->fh);
462  return nfserr;
463 }
464 
465 /*
466  * Read a portion of a directory.
467  */
468 static __be32
469 nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp,
470  struct nfsd_readdirres *resp)
471 {
472  int count;
473  __be32 nfserr;
474  loff_t offset;
475 
476  dprintk("nfsd: READDIR %s %d bytes at %d\n",
477  SVCFH_fmt(&argp->fh),
478  argp->count, argp->cookie);
479 
480  /* Shrink to the client read size */
481  count = (argp->count >> 2) - 2;
482 
483  /* Make sure we've room for the NULL ptr & eof flag */
484  count -= 2;
485  if (count < 0)
486  count = 0;
487 
488  resp->buffer = argp->buffer;
489  resp->offset = NULL;
490  resp->buflen = count;
491  resp->common.err = nfs_ok;
492  /* Read directory and encode entries on the fly */
493  offset = argp->cookie;
494  nfserr = nfsd_readdir(rqstp, &argp->fh, &offset,
495  &resp->common, nfssvc_encode_entry);
496 
497  resp->count = resp->buffer - argp->buffer;
498  if (resp->offset)
499  *resp->offset = htonl(offset);
500 
501  fh_put(&argp->fh);
502  return nfserr;
503 }
504 
505 /*
506  * Get file system info
507  */
508 static __be32
509 nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
510  struct nfsd_statfsres *resp)
511 {
512  __be32 nfserr;
513 
514  dprintk("nfsd: STATFS %s\n", SVCFH_fmt(&argp->fh));
515 
516  nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats,
518  fh_put(&argp->fh);
519  return nfserr;
520 }
521 
522 /*
523  * NFSv2 Server procedures.
524  * Only the results of non-idempotent operations are cached.
525  */
526 struct nfsd_void { int dummy; };
527 
528 #define ST 1 /* status */
529 #define FH 8 /* filehandle */
530 #define AT 18 /* attributes */
531 
532 static struct svc_procedure nfsd_procedures2[18] = {
533  [NFSPROC_NULL] = {
534  .pc_func = (svc_procfunc) nfsd_proc_null,
535  .pc_decode = (kxdrproc_t) nfssvc_decode_void,
536  .pc_encode = (kxdrproc_t) nfssvc_encode_void,
537  .pc_argsize = sizeof(struct nfsd_void),
538  .pc_ressize = sizeof(struct nfsd_void),
539  .pc_cachetype = RC_NOCACHE,
540  .pc_xdrressize = ST,
541  },
542  [NFSPROC_GETATTR] = {
543  .pc_func = (svc_procfunc) nfsd_proc_getattr,
544  .pc_decode = (kxdrproc_t) nfssvc_decode_fhandle,
545  .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat,
546  .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
547  .pc_argsize = sizeof(struct nfsd_fhandle),
548  .pc_ressize = sizeof(struct nfsd_attrstat),
549  .pc_cachetype = RC_NOCACHE,
550  .pc_xdrressize = ST+AT,
551  },
552  [NFSPROC_SETATTR] = {
553  .pc_func = (svc_procfunc) nfsd_proc_setattr,
554  .pc_decode = (kxdrproc_t) nfssvc_decode_sattrargs,
555  .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat,
556  .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
557  .pc_argsize = sizeof(struct nfsd_sattrargs),
558  .pc_ressize = sizeof(struct nfsd_attrstat),
559  .pc_cachetype = RC_REPLBUFF,
560  .pc_xdrressize = ST+AT,
561  },
562  [NFSPROC_ROOT] = {
563  .pc_decode = (kxdrproc_t) nfssvc_decode_void,
564  .pc_encode = (kxdrproc_t) nfssvc_encode_void,
565  .pc_argsize = sizeof(struct nfsd_void),
566  .pc_ressize = sizeof(struct nfsd_void),
567  .pc_cachetype = RC_NOCACHE,
568  .pc_xdrressize = ST,
569  },
570  [NFSPROC_LOOKUP] = {
571  .pc_func = (svc_procfunc) nfsd_proc_lookup,
572  .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs,
573  .pc_encode = (kxdrproc_t) nfssvc_encode_diropres,
574  .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
575  .pc_argsize = sizeof(struct nfsd_diropargs),
576  .pc_ressize = sizeof(struct nfsd_diropres),
577  .pc_cachetype = RC_NOCACHE,
578  .pc_xdrressize = ST+FH+AT,
579  },
580  [NFSPROC_READLINK] = {
581  .pc_func = (svc_procfunc) nfsd_proc_readlink,
582  .pc_decode = (kxdrproc_t) nfssvc_decode_readlinkargs,
583  .pc_encode = (kxdrproc_t) nfssvc_encode_readlinkres,
584  .pc_argsize = sizeof(struct nfsd_readlinkargs),
585  .pc_ressize = sizeof(struct nfsd_readlinkres),
586  .pc_cachetype = RC_NOCACHE,
587  .pc_xdrressize = ST+1+NFS_MAXPATHLEN/4,
588  },
589  [NFSPROC_READ] = {
590  .pc_func = (svc_procfunc) nfsd_proc_read,
591  .pc_decode = (kxdrproc_t) nfssvc_decode_readargs,
592  .pc_encode = (kxdrproc_t) nfssvc_encode_readres,
593  .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
594  .pc_argsize = sizeof(struct nfsd_readargs),
595  .pc_ressize = sizeof(struct nfsd_readres),
596  .pc_cachetype = RC_NOCACHE,
597  .pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4,
598  },
599  [NFSPROC_WRITECACHE] = {
600  .pc_decode = (kxdrproc_t) nfssvc_decode_void,
601  .pc_encode = (kxdrproc_t) nfssvc_encode_void,
602  .pc_argsize = sizeof(struct nfsd_void),
603  .pc_ressize = sizeof(struct nfsd_void),
604  .pc_cachetype = RC_NOCACHE,
605  .pc_xdrressize = ST,
606  },
607  [NFSPROC_WRITE] = {
608  .pc_func = (svc_procfunc) nfsd_proc_write,
609  .pc_decode = (kxdrproc_t) nfssvc_decode_writeargs,
610  .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat,
611  .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
612  .pc_argsize = sizeof(struct nfsd_writeargs),
613  .pc_ressize = sizeof(struct nfsd_attrstat),
614  .pc_cachetype = RC_REPLBUFF,
615  .pc_xdrressize = ST+AT,
616  },
617  [NFSPROC_CREATE] = {
618  .pc_func = (svc_procfunc) nfsd_proc_create,
619  .pc_decode = (kxdrproc_t) nfssvc_decode_createargs,
620  .pc_encode = (kxdrproc_t) nfssvc_encode_diropres,
621  .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
622  .pc_argsize = sizeof(struct nfsd_createargs),
623  .pc_ressize = sizeof(struct nfsd_diropres),
624  .pc_cachetype = RC_REPLBUFF,
625  .pc_xdrressize = ST+FH+AT,
626  },
627  [NFSPROC_REMOVE] = {
628  .pc_func = (svc_procfunc) nfsd_proc_remove,
629  .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs,
630  .pc_encode = (kxdrproc_t) nfssvc_encode_void,
631  .pc_argsize = sizeof(struct nfsd_diropargs),
632  .pc_ressize = sizeof(struct nfsd_void),
633  .pc_cachetype = RC_REPLSTAT,
634  .pc_xdrressize = ST,
635  },
636  [NFSPROC_RENAME] = {
637  .pc_func = (svc_procfunc) nfsd_proc_rename,
638  .pc_decode = (kxdrproc_t) nfssvc_decode_renameargs,
639  .pc_encode = (kxdrproc_t) nfssvc_encode_void,
640  .pc_argsize = sizeof(struct nfsd_renameargs),
641  .pc_ressize = sizeof(struct nfsd_void),
642  .pc_cachetype = RC_REPLSTAT,
643  .pc_xdrressize = ST,
644  },
645  [NFSPROC_LINK] = {
646  .pc_func = (svc_procfunc) nfsd_proc_link,
647  .pc_decode = (kxdrproc_t) nfssvc_decode_linkargs,
648  .pc_encode = (kxdrproc_t) nfssvc_encode_void,
649  .pc_argsize = sizeof(struct nfsd_linkargs),
650  .pc_ressize = sizeof(struct nfsd_void),
651  .pc_cachetype = RC_REPLSTAT,
652  .pc_xdrressize = ST,
653  },
654  [NFSPROC_SYMLINK] = {
655  .pc_func = (svc_procfunc) nfsd_proc_symlink,
656  .pc_decode = (kxdrproc_t) nfssvc_decode_symlinkargs,
657  .pc_encode = (kxdrproc_t) nfssvc_encode_void,
658  .pc_argsize = sizeof(struct nfsd_symlinkargs),
659  .pc_ressize = sizeof(struct nfsd_void),
660  .pc_cachetype = RC_REPLSTAT,
661  .pc_xdrressize = ST,
662  },
663  [NFSPROC_MKDIR] = {
664  .pc_func = (svc_procfunc) nfsd_proc_mkdir,
665  .pc_decode = (kxdrproc_t) nfssvc_decode_createargs,
666  .pc_encode = (kxdrproc_t) nfssvc_encode_diropres,
667  .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
668  .pc_argsize = sizeof(struct nfsd_createargs),
669  .pc_ressize = sizeof(struct nfsd_diropres),
670  .pc_cachetype = RC_REPLBUFF,
671  .pc_xdrressize = ST+FH+AT,
672  },
673  [NFSPROC_RMDIR] = {
674  .pc_func = (svc_procfunc) nfsd_proc_rmdir,
675  .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs,
676  .pc_encode = (kxdrproc_t) nfssvc_encode_void,
677  .pc_argsize = sizeof(struct nfsd_diropargs),
678  .pc_ressize = sizeof(struct nfsd_void),
679  .pc_cachetype = RC_REPLSTAT,
680  .pc_xdrressize = ST,
681  },
682  [NFSPROC_READDIR] = {
683  .pc_func = (svc_procfunc) nfsd_proc_readdir,
684  .pc_decode = (kxdrproc_t) nfssvc_decode_readdirargs,
685  .pc_encode = (kxdrproc_t) nfssvc_encode_readdirres,
686  .pc_argsize = sizeof(struct nfsd_readdirargs),
687  .pc_ressize = sizeof(struct nfsd_readdirres),
688  .pc_cachetype = RC_NOCACHE,
689  },
690  [NFSPROC_STATFS] = {
691  .pc_func = (svc_procfunc) nfsd_proc_statfs,
692  .pc_decode = (kxdrproc_t) nfssvc_decode_fhandle,
693  .pc_encode = (kxdrproc_t) nfssvc_encode_statfsres,
694  .pc_argsize = sizeof(struct nfsd_fhandle),
695  .pc_ressize = sizeof(struct nfsd_statfsres),
696  .pc_cachetype = RC_NOCACHE,
697  .pc_xdrressize = ST+5,
698  },
699 };
700 
701 
703  .vs_vers = 2,
704  .vs_nproc = 18,
705  .vs_proc = nfsd_procedures2,
706  .vs_dispatch = nfsd_dispatch,
707  .vs_xdrsize = NFS2_SVC_XDRSIZE,
708 };
709 
710 /*
711  * Map errnos to NFS errnos.
712  */
713 __be32
714 nfserrno (int errno)
715 {
716  static struct {
717  __be32 nfserr;
718  int syserr;
719  } nfs_errtbl[] = {
720  { nfs_ok, 0 },
721  { nfserr_perm, -EPERM },
722  { nfserr_noent, -ENOENT },
723  { nfserr_io, -EIO },
724  { nfserr_nxio, -ENXIO },
725  { nfserr_acces, -EACCES },
726  { nfserr_exist, -EEXIST },
727  { nfserr_xdev, -EXDEV },
728  { nfserr_mlink, -EMLINK },
729  { nfserr_nodev, -ENODEV },
730  { nfserr_notdir, -ENOTDIR },
731  { nfserr_isdir, -EISDIR },
732  { nfserr_inval, -EINVAL },
733  { nfserr_fbig, -EFBIG },
734  { nfserr_nospc, -ENOSPC },
735  { nfserr_rofs, -EROFS },
736  { nfserr_mlink, -EMLINK },
739 #ifdef EDQUOT
740  { nfserr_dquot, -EDQUOT },
741 #endif
742  { nfserr_stale, -ESTALE },
745  { nfserr_jukebox, -EAGAIN },
747  { nfserr_jukebox, -ENOMEM },
748  { nfserr_io, -ETXTBSY },
752  };
753  int i;
754 
755  for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) {
756  if (nfs_errtbl[i].syserr == errno)
757  return nfs_errtbl[i].nfserr;
758  }
759  printk (KERN_INFO "nfsd: non-standard errno: %d\n", errno);
760  return nfserr_io;
761 }
762