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