Root/fs/nfsd/nfsproc.c

1/*
2 * Process version 2 NFS requests.
3 *
4 * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
5 */
6
7#include <linux/namei.h>
8
9#include "cache.h"
10#include "xdr.h"
11#include "vfs.h"
12
13typedef struct svc_rqst svc_rqst;
14typedef struct svc_buf svc_buf;
15
16#define NFSDDBG_FACILITY NFSDDBG_PROC
17
18
19static __be32
20nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
21{
22    return nfs_ok;
23}
24
25static __be32
26nfsd_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}
33static __be32
34nfsd_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 */
45static __be32
46nfsd_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,
54            NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
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 */
62static __be32
63nfsd_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 */
82static __be32
83nfsd_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 */
102static __be32
103nfsd_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 */
122static __be32
123nfsd_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];
138        printk(KERN_NOTICE
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 */
162static __be32
163nfsd_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 */
188static __be32
189nfsd_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    dev_t rdev = 0, wanted = new_decode_dev(attr->ia_size);
200
201    dprintk("nfsd: CREATE %s %.*s\n",
202        SVCFH_fmt(dirfhp), argp->len, argp->name);
203
204    /* First verify the parent file handle */
205    nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC);
206    if (nfserr)
207        goto done; /* must fh_put dirfhp even on error */
208
209    /* Check for NFSD_MAY_WRITE in nfsd_create if necessary */
210
211    nfserr = nfserr_acces;
212    if (!argp->len)
213        goto done;
214    nfserr = nfserr_exist;
215    if (isdotent(argp->name, argp->len))
216        goto done;
217    fh_lock_nested(dirfhp, I_MUTEX_PARENT);
218    dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
219    if (IS_ERR(dchild)) {
220        nfserr = nfserrno(PTR_ERR(dchild));
221        goto out_unlock;
222    }
223    fh_init(newfhp, NFS_FHSIZE);
224    nfserr = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp);
225    if (!nfserr && !dchild->d_inode)
226        nfserr = nfserr_noent;
227    dput(dchild);
228    if (nfserr) {
229        if (nfserr != nfserr_noent)
230            goto out_unlock;
231        /*
232         * If the new file handle wasn't verified, we can't tell
233         * whether the file exists or not. Time to bail ...
234         */
235        nfserr = nfserr_acces;
236        if (!newfhp->fh_dentry) {
237            printk(KERN_WARNING
238                "nfsd_proc_create: file handle not verified\n");
239            goto out_unlock;
240        }
241    }
242
243    inode = newfhp->fh_dentry->d_inode;
244
245    /* Unfudge the mode bits */
246    if (attr->ia_valid & ATTR_MODE) {
247        type = attr->ia_mode & S_IFMT;
248        mode = attr->ia_mode & ~S_IFMT;
249        if (!type) {
250            /* no type, so if target exists, assume same as that,
251             * else assume a file */
252            if (inode) {
253                type = inode->i_mode & S_IFMT;
254                switch(type) {
255                case S_IFCHR:
256                case S_IFBLK:
257                    /* reserve rdev for later checking */
258                    rdev = inode->i_rdev;
259                    attr->ia_valid |= ATTR_SIZE;
260
261                    /* FALLTHROUGH */
262                case S_IFIFO:
263                    /* this is probably a permission check..
264                     * at least IRIX implements perm checking on
265                     * echo thing > device-special-file-or-pipe
266                     * by doing a CREATE with type==0
267                     */
268                    nfserr = nfsd_permission(rqstp,
269                                 newfhp->fh_export,
270                                 newfhp->fh_dentry,
271                                 NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS);
272                    if (nfserr && nfserr != nfserr_rofs)
273                        goto out_unlock;
274                }
275            } else
276                type = S_IFREG;
277        }
278    } else if (inode) {
279        type = inode->i_mode & S_IFMT;
280        mode = inode->i_mode & ~S_IFMT;
281    } else {
282        type = S_IFREG;
283        mode = 0; /* ??? */
284    }
285
286    attr->ia_valid |= ATTR_MODE;
287    attr->ia_mode = mode;
288
289    /* Special treatment for non-regular files according to the
290     * gospel of sun micro
291     */
292    if (type != S_IFREG) {
293        if (type != S_IFBLK && type != S_IFCHR) {
294            rdev = 0;
295        } else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) {
296            /* If you think you've seen the worst, grok this. */
297            type = S_IFIFO;
298        } else {
299            /* Okay, char or block special */
300            if (!rdev)
301                rdev = wanted;
302        }
303
304        /* we've used the SIZE information, so discard it */
305        attr->ia_valid &= ~ATTR_SIZE;
306
307        /* Make sure the type and device matches */
308        nfserr = nfserr_exist;
309        if (inode && type != (inode->i_mode & S_IFMT))
310            goto out_unlock;
311    }
312
313    nfserr = 0;
314    if (!inode) {
315        /* File doesn't exist. Create it and set attrs */
316        nfserr = nfsd_create(rqstp, dirfhp, argp->name, argp->len,
317                    attr, type, rdev, newfhp);
318    } else if (type == S_IFREG) {
319        dprintk("nfsd: existing %s, valid=%x, size=%ld\n",
320            argp->name, attr->ia_valid, (long) attr->ia_size);
321        /* File already exists. We ignore all attributes except
322         * size, so that creat() behaves exactly like
323         * open(..., O_CREAT|O_TRUNC|O_WRONLY).
324         */
325        attr->ia_valid &= ATTR_SIZE;
326        if (attr->ia_valid)
327            nfserr = nfsd_setattr(rqstp, newfhp, attr, 0, (time_t)0);
328    }
329
330out_unlock:
331    /* We don't really need to unlock, as fh_put does it. */
332    fh_unlock(dirfhp);
333
334done:
335    fh_put(dirfhp);
336    return nfsd_return_dirop(nfserr, resp);
337}
338
339static __be32
340nfsd_proc_remove(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
341                     void *resp)
342{
343    __be32 nfserr;
344
345    dprintk("nfsd: REMOVE %s %.*s\n", SVCFH_fmt(&argp->fh),
346        argp->len, argp->name);
347
348    /* Unlink. -SIFDIR means file must not be a directory */
349    nfserr = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR, argp->name, argp->len);
350    fh_put(&argp->fh);
351    return nfserr;
352}
353
354static __be32
355nfsd_proc_rename(struct svc_rqst *rqstp, struct nfsd_renameargs *argp,
356                       void *resp)
357{
358    __be32 nfserr;
359
360    dprintk("nfsd: RENAME %s %.*s -> \n",
361        SVCFH_fmt(&argp->ffh), argp->flen, argp->fname);
362    dprintk("nfsd: -> %s %.*s\n",
363        SVCFH_fmt(&argp->tfh), argp->tlen, argp->tname);
364
365    nfserr = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen,
366                    &argp->tfh, argp->tname, argp->tlen);
367    fh_put(&argp->ffh);
368    fh_put(&argp->tfh);
369    return nfserr;
370}
371
372static __be32
373nfsd_proc_link(struct svc_rqst *rqstp, struct nfsd_linkargs *argp,
374                void *resp)
375{
376    __be32 nfserr;
377
378    dprintk("nfsd: LINK %s ->\n",
379        SVCFH_fmt(&argp->ffh));
380    dprintk("nfsd: %s %.*s\n",
381        SVCFH_fmt(&argp->tfh),
382        argp->tlen,
383        argp->tname);
384
385    nfserr = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen,
386                  &argp->ffh);
387    fh_put(&argp->ffh);
388    fh_put(&argp->tfh);
389    return nfserr;
390}
391
392static __be32
393nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp,
394                          void *resp)
395{
396    struct svc_fh newfh;
397    __be32 nfserr;
398
399    dprintk("nfsd: SYMLINK %s %.*s -> %.*s\n",
400        SVCFH_fmt(&argp->ffh), argp->flen, argp->fname,
401        argp->tlen, argp->tname);
402
403    fh_init(&newfh, NFS_FHSIZE);
404    /*
405     * Create the link, look up new file and set attrs.
406     */
407    nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
408                         argp->tname, argp->tlen,
409                          &newfh, &argp->attrs);
410
411
412    fh_put(&argp->ffh);
413    fh_put(&newfh);
414    return nfserr;
415}
416
417/*
418 * Make directory. This operation is not idempotent.
419 * N.B. After this call resp->fh needs an fh_put
420 */
421static __be32
422nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
423                    struct nfsd_diropres *resp)
424{
425    __be32 nfserr;
426
427    dprintk("nfsd: MKDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
428
429    if (resp->fh.fh_dentry) {
430        printk(KERN_WARNING
431            "nfsd_proc_mkdir: response already verified??\n");
432    }
433
434    argp->attrs.ia_valid &= ~ATTR_SIZE;
435    fh_init(&resp->fh, NFS_FHSIZE);
436    nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
437                    &argp->attrs, S_IFDIR, 0, &resp->fh);
438    fh_put(&argp->fh);
439    return nfsd_return_dirop(nfserr, resp);
440}
441
442/*
443 * Remove a directory
444 */
445static __be32
446nfsd_proc_rmdir(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
447                     void *resp)
448{
449    __be32 nfserr;
450
451    dprintk("nfsd: RMDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
452
453    nfserr = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, argp->name, argp->len);
454    fh_put(&argp->fh);
455    return nfserr;
456}
457
458/*
459 * Read a portion of a directory.
460 */
461static __be32
462nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp,
463                      struct nfsd_readdirres *resp)
464{
465    int count;
466    __be32 nfserr;
467    loff_t offset;
468
469    dprintk("nfsd: READDIR %s %d bytes at %d\n",
470        SVCFH_fmt(&argp->fh),
471        argp->count, argp->cookie);
472
473    /* Shrink to the client read size */
474    count = (argp->count >> 2) - 2;
475
476    /* Make sure we've room for the NULL ptr & eof flag */
477    count -= 2;
478    if (count < 0)
479        count = 0;
480
481    resp->buffer = argp->buffer;
482    resp->offset = NULL;
483    resp->buflen = count;
484    resp->common.err = nfs_ok;
485    /* Read directory and encode entries on the fly */
486    offset = argp->cookie;
487    nfserr = nfsd_readdir(rqstp, &argp->fh, &offset,
488                  &resp->common, nfssvc_encode_entry);
489
490    resp->count = resp->buffer - argp->buffer;
491    if (resp->offset)
492        *resp->offset = htonl(offset);
493
494    fh_put(&argp->fh);
495    return nfserr;
496}
497
498/*
499 * Get file system info
500 */
501static __be32
502nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
503                      struct nfsd_statfsres *resp)
504{
505    __be32 nfserr;
506
507    dprintk("nfsd: STATFS %s\n", SVCFH_fmt(&argp->fh));
508
509    nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats,
510            NFSD_MAY_BYPASS_GSS_ON_ROOT);
511    fh_put(&argp->fh);
512    return nfserr;
513}
514
515/*
516 * NFSv2 Server procedures.
517 * Only the results of non-idempotent operations are cached.
518 */
519struct nfsd_void { int dummy; };
520
521#define ST 1 /* status */
522#define FH 8 /* filehandle */
523#define AT 18 /* attributes */
524
525static struct svc_procedure nfsd_procedures2[18] = {
526    [NFSPROC_NULL] = {
527        .pc_func = (svc_procfunc) nfsd_proc_null,
528        .pc_decode = (kxdrproc_t) nfssvc_decode_void,
529        .pc_encode = (kxdrproc_t) nfssvc_encode_void,
530        .pc_argsize = sizeof(struct nfsd_void),
531        .pc_ressize = sizeof(struct nfsd_void),
532        .pc_cachetype = RC_NOCACHE,
533        .pc_xdrressize = ST,
534    },
535    [NFSPROC_GETATTR] = {
536        .pc_func = (svc_procfunc) nfsd_proc_getattr,
537        .pc_decode = (kxdrproc_t) nfssvc_decode_fhandle,
538        .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat,
539        .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
540        .pc_argsize = sizeof(struct nfsd_fhandle),
541        .pc_ressize = sizeof(struct nfsd_attrstat),
542        .pc_cachetype = RC_NOCACHE,
543        .pc_xdrressize = ST+AT,
544    },
545    [NFSPROC_SETATTR] = {
546        .pc_func = (svc_procfunc) nfsd_proc_setattr,
547        .pc_decode = (kxdrproc_t) nfssvc_decode_sattrargs,
548        .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat,
549        .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
550        .pc_argsize = sizeof(struct nfsd_sattrargs),
551        .pc_ressize = sizeof(struct nfsd_attrstat),
552        .pc_cachetype = RC_REPLBUFF,
553        .pc_xdrressize = ST+AT,
554    },
555    [NFSPROC_ROOT] = {
556        .pc_decode = (kxdrproc_t) nfssvc_decode_void,
557        .pc_encode = (kxdrproc_t) nfssvc_encode_void,
558        .pc_argsize = sizeof(struct nfsd_void),
559        .pc_ressize = sizeof(struct nfsd_void),
560        .pc_cachetype = RC_NOCACHE,
561        .pc_xdrressize = ST,
562    },
563    [NFSPROC_LOOKUP] = {
564        .pc_func = (svc_procfunc) nfsd_proc_lookup,
565        .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs,
566        .pc_encode = (kxdrproc_t) nfssvc_encode_diropres,
567        .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
568        .pc_argsize = sizeof(struct nfsd_diropargs),
569        .pc_ressize = sizeof(struct nfsd_diropres),
570        .pc_cachetype = RC_NOCACHE,
571        .pc_xdrressize = ST+FH+AT,
572    },
573    [NFSPROC_READLINK] = {
574        .pc_func = (svc_procfunc) nfsd_proc_readlink,
575        .pc_decode = (kxdrproc_t) nfssvc_decode_readlinkargs,
576        .pc_encode = (kxdrproc_t) nfssvc_encode_readlinkres,
577        .pc_argsize = sizeof(struct nfsd_readlinkargs),
578        .pc_ressize = sizeof(struct nfsd_readlinkres),
579        .pc_cachetype = RC_NOCACHE,
580        .pc_xdrressize = ST+1+NFS_MAXPATHLEN/4,
581    },
582    [NFSPROC_READ] = {
583        .pc_func = (svc_procfunc) nfsd_proc_read,
584        .pc_decode = (kxdrproc_t) nfssvc_decode_readargs,
585        .pc_encode = (kxdrproc_t) nfssvc_encode_readres,
586        .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
587        .pc_argsize = sizeof(struct nfsd_readargs),
588        .pc_ressize = sizeof(struct nfsd_readres),
589        .pc_cachetype = RC_NOCACHE,
590        .pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4,
591    },
592    [NFSPROC_WRITECACHE] = {
593        .pc_decode = (kxdrproc_t) nfssvc_decode_void,
594        .pc_encode = (kxdrproc_t) nfssvc_encode_void,
595        .pc_argsize = sizeof(struct nfsd_void),
596        .pc_ressize = sizeof(struct nfsd_void),
597        .pc_cachetype = RC_NOCACHE,
598        .pc_xdrressize = ST,
599    },
600    [NFSPROC_WRITE] = {
601        .pc_func = (svc_procfunc) nfsd_proc_write,
602        .pc_decode = (kxdrproc_t) nfssvc_decode_writeargs,
603        .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat,
604        .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
605        .pc_argsize = sizeof(struct nfsd_writeargs),
606        .pc_ressize = sizeof(struct nfsd_attrstat),
607        .pc_cachetype = RC_REPLBUFF,
608        .pc_xdrressize = ST+AT,
609    },
610    [NFSPROC_CREATE] = {
611        .pc_func = (svc_procfunc) nfsd_proc_create,
612        .pc_decode = (kxdrproc_t) nfssvc_decode_createargs,
613        .pc_encode = (kxdrproc_t) nfssvc_encode_diropres,
614        .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
615        .pc_argsize = sizeof(struct nfsd_createargs),
616        .pc_ressize = sizeof(struct nfsd_diropres),
617        .pc_cachetype = RC_REPLBUFF,
618        .pc_xdrressize = ST+FH+AT,
619    },
620    [NFSPROC_REMOVE] = {
621        .pc_func = (svc_procfunc) nfsd_proc_remove,
622        .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs,
623        .pc_encode = (kxdrproc_t) nfssvc_encode_void,
624        .pc_argsize = sizeof(struct nfsd_diropargs),
625        .pc_ressize = sizeof(struct nfsd_void),
626        .pc_cachetype = RC_REPLSTAT,
627        .pc_xdrressize = ST,
628    },
629    [NFSPROC_RENAME] = {
630        .pc_func = (svc_procfunc) nfsd_proc_rename,
631        .pc_decode = (kxdrproc_t) nfssvc_decode_renameargs,
632        .pc_encode = (kxdrproc_t) nfssvc_encode_void,
633        .pc_argsize = sizeof(struct nfsd_renameargs),
634        .pc_ressize = sizeof(struct nfsd_void),
635        .pc_cachetype = RC_REPLSTAT,
636        .pc_xdrressize = ST,
637    },
638    [NFSPROC_LINK] = {
639        .pc_func = (svc_procfunc) nfsd_proc_link,
640        .pc_decode = (kxdrproc_t) nfssvc_decode_linkargs,
641        .pc_encode = (kxdrproc_t) nfssvc_encode_void,
642        .pc_argsize = sizeof(struct nfsd_linkargs),
643        .pc_ressize = sizeof(struct nfsd_void),
644        .pc_cachetype = RC_REPLSTAT,
645        .pc_xdrressize = ST,
646    },
647    [NFSPROC_SYMLINK] = {
648        .pc_func = (svc_procfunc) nfsd_proc_symlink,
649        .pc_decode = (kxdrproc_t) nfssvc_decode_symlinkargs,
650        .pc_encode = (kxdrproc_t) nfssvc_encode_void,
651        .pc_argsize = sizeof(struct nfsd_symlinkargs),
652        .pc_ressize = sizeof(struct nfsd_void),
653        .pc_cachetype = RC_REPLSTAT,
654        .pc_xdrressize = ST,
655    },
656    [NFSPROC_MKDIR] = {
657        .pc_func = (svc_procfunc) nfsd_proc_mkdir,
658        .pc_decode = (kxdrproc_t) nfssvc_decode_createargs,
659        .pc_encode = (kxdrproc_t) nfssvc_encode_diropres,
660        .pc_release = (kxdrproc_t) nfssvc_release_fhandle,
661        .pc_argsize = sizeof(struct nfsd_createargs),
662        .pc_ressize = sizeof(struct nfsd_diropres),
663        .pc_cachetype = RC_REPLBUFF,
664        .pc_xdrressize = ST+FH+AT,
665    },
666    [NFSPROC_RMDIR] = {
667        .pc_func = (svc_procfunc) nfsd_proc_rmdir,
668        .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs,
669        .pc_encode = (kxdrproc_t) nfssvc_encode_void,
670        .pc_argsize = sizeof(struct nfsd_diropargs),
671        .pc_ressize = sizeof(struct nfsd_void),
672        .pc_cachetype = RC_REPLSTAT,
673        .pc_xdrressize = ST,
674    },
675    [NFSPROC_READDIR] = {
676        .pc_func = (svc_procfunc) nfsd_proc_readdir,
677        .pc_decode = (kxdrproc_t) nfssvc_decode_readdirargs,
678        .pc_encode = (kxdrproc_t) nfssvc_encode_readdirres,
679        .pc_argsize = sizeof(struct nfsd_readdirargs),
680        .pc_ressize = sizeof(struct nfsd_readdirres),
681        .pc_cachetype = RC_NOCACHE,
682    },
683    [NFSPROC_STATFS] = {
684        .pc_func = (svc_procfunc) nfsd_proc_statfs,
685        .pc_decode = (kxdrproc_t) nfssvc_decode_fhandle,
686        .pc_encode = (kxdrproc_t) nfssvc_encode_statfsres,
687        .pc_argsize = sizeof(struct nfsd_fhandle),
688        .pc_ressize = sizeof(struct nfsd_statfsres),
689        .pc_cachetype = RC_NOCACHE,
690        .pc_xdrressize = ST+5,
691    },
692};
693
694
695struct svc_version nfsd_version2 = {
696        .vs_vers = 2,
697        .vs_nproc = 18,
698        .vs_proc = nfsd_procedures2,
699        .vs_dispatch = nfsd_dispatch,
700        .vs_xdrsize = NFS2_SVC_XDRSIZE,
701};
702
703/*
704 * Map errnos to NFS errnos.
705 */
706__be32
707nfserrno (int errno)
708{
709    static struct {
710        __be32 nfserr;
711        int syserr;
712    } nfs_errtbl[] = {
713        { nfs_ok, 0 },
714        { nfserr_perm, -EPERM },
715        { nfserr_noent, -ENOENT },
716        { nfserr_io, -EIO },
717        { nfserr_nxio, -ENXIO },
718        { nfserr_acces, -EACCES },
719        { nfserr_exist, -EEXIST },
720        { nfserr_xdev, -EXDEV },
721        { nfserr_mlink, -EMLINK },
722        { nfserr_nodev, -ENODEV },
723        { nfserr_notdir, -ENOTDIR },
724        { nfserr_isdir, -EISDIR },
725        { nfserr_inval, -EINVAL },
726        { nfserr_fbig, -EFBIG },
727        { nfserr_nospc, -ENOSPC },
728        { nfserr_rofs, -EROFS },
729        { nfserr_mlink, -EMLINK },
730        { nfserr_nametoolong, -ENAMETOOLONG },
731        { nfserr_notempty, -ENOTEMPTY },
732#ifdef EDQUOT
733        { nfserr_dquot, -EDQUOT },
734#endif
735        { nfserr_stale, -ESTALE },
736        { nfserr_jukebox, -ETIMEDOUT },
737        { nfserr_jukebox, -ERESTARTSYS },
738        { nfserr_jukebox, -EAGAIN },
739        { nfserr_jukebox, -EWOULDBLOCK },
740        { nfserr_jukebox, -ENOMEM },
741        { nfserr_io, -ETXTBSY },
742        { nfserr_notsupp, -EOPNOTSUPP },
743        { nfserr_toosmall, -ETOOSMALL },
744        { nfserr_serverfault, -ESERVERFAULT },
745    };
746    int i;
747
748    for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) {
749        if (nfs_errtbl[i].syserr == errno)
750            return nfs_errtbl[i].nfserr;
751    }
752    printk (KERN_INFO "nfsd: non-standard errno: %d\n", errno);
753    return nfserr_io;
754}
755
756

Archive Download this file



interactive