Root/fs/nfsd/export.c

1/*
2 * NFS exporting and validation.
3 *
4 * We maintain a list of clients, each of which has a list of
5 * exports. To export an fs to a given client, you first have
6 * to create the client entry with NFSCTL_ADDCLIENT, which
7 * creates a client control block and adds it to the hash
8 * table. Then, you call NFSCTL_EXPORT for each fs.
9 *
10 *
11 * Copyright (C) 1995, 1996 Olaf Kirch, <okir@monad.swb.de>
12 */
13
14#include <linux/slab.h>
15#include <linux/namei.h>
16#include <linux/module.h>
17#include <linux/exportfs.h>
18
19#include <linux/nfsd/syscall.h>
20#include <net/ipv6.h>
21
22#include "nfsd.h"
23#include "nfsfh.h"
24
25#define NFSDDBG_FACILITY NFSDDBG_EXPORT
26
27typedef struct auth_domain svc_client;
28typedef struct svc_export svc_export;
29
30/*
31 * We have two caches.
32 * One maps client+vfsmnt+dentry to export options - the export map
33 * The other maps client+filehandle-fragment to export options. - the expkey map
34 *
35 * The export options are actually stored in the first map, and the
36 * second map contains a reference to the entry in the first map.
37 */
38
39#define EXPKEY_HASHBITS 8
40#define EXPKEY_HASHMAX (1 << EXPKEY_HASHBITS)
41#define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1)
42static struct cache_head *expkey_table[EXPKEY_HASHMAX];
43
44static void expkey_put(struct kref *ref)
45{
46    struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref);
47
48    if (test_bit(CACHE_VALID, &key->h.flags) &&
49        !test_bit(CACHE_NEGATIVE, &key->h.flags))
50        path_put(&key->ek_path);
51    auth_domain_put(key->ek_client);
52    kfree(key);
53}
54
55static void expkey_request(struct cache_detail *cd,
56               struct cache_head *h,
57               char **bpp, int *blen)
58{
59    /* client fsidtype \xfsid */
60    struct svc_expkey *ek = container_of(h, struct svc_expkey, h);
61    char type[5];
62
63    qword_add(bpp, blen, ek->ek_client->name);
64    snprintf(type, 5, "%d", ek->ek_fsidtype);
65    qword_add(bpp, blen, type);
66    qword_addhex(bpp, blen, (char*)ek->ek_fsid, key_len(ek->ek_fsidtype));
67    (*bpp)[-1] = '\n';
68}
69
70static int expkey_upcall(struct cache_detail *cd, struct cache_head *h)
71{
72    return sunrpc_cache_pipe_upcall(cd, h, expkey_request);
73}
74
75static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old);
76static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *);
77static struct cache_detail svc_expkey_cache;
78
79static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
80{
81    /* client fsidtype fsid [path] */
82    char *buf;
83    int len;
84    struct auth_domain *dom = NULL;
85    int err;
86    int fsidtype;
87    char *ep;
88    struct svc_expkey key;
89    struct svc_expkey *ek = NULL;
90
91    if (mesg[mlen-1] != '\n')
92        return -EINVAL;
93    mesg[mlen-1] = 0;
94
95    buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
96    err = -ENOMEM;
97    if (!buf)
98        goto out;
99
100    err = -EINVAL;
101    if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
102        goto out;
103
104    err = -ENOENT;
105    dom = auth_domain_find(buf);
106    if (!dom)
107        goto out;
108    dprintk("found domain %s\n", buf);
109
110    err = -EINVAL;
111    if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
112        goto out;
113    fsidtype = simple_strtoul(buf, &ep, 10);
114    if (*ep)
115        goto out;
116    dprintk("found fsidtype %d\n", fsidtype);
117    if (key_len(fsidtype)==0) /* invalid type */
118        goto out;
119    if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
120        goto out;
121    dprintk("found fsid length %d\n", len);
122    if (len != key_len(fsidtype))
123        goto out;
124
125    /* OK, we seem to have a valid key */
126    key.h.flags = 0;
127    key.h.expiry_time = get_expiry(&mesg);
128    if (key.h.expiry_time == 0)
129        goto out;
130
131    key.ek_client = dom;
132    key.ek_fsidtype = fsidtype;
133    memcpy(key.ek_fsid, buf, len);
134
135    ek = svc_expkey_lookup(&key);
136    err = -ENOMEM;
137    if (!ek)
138        goto out;
139
140    /* now we want a pathname, or empty meaning NEGATIVE */
141    err = -EINVAL;
142    len = qword_get(&mesg, buf, PAGE_SIZE);
143    if (len < 0)
144        goto out;
145    dprintk("Path seems to be <%s>\n", buf);
146    err = 0;
147    if (len == 0) {
148        set_bit(CACHE_NEGATIVE, &key.h.flags);
149        ek = svc_expkey_update(&key, ek);
150        if (!ek)
151            err = -ENOMEM;
152    } else {
153        err = kern_path(buf, 0, &key.ek_path);
154        if (err)
155            goto out;
156
157        dprintk("Found the path %s\n", buf);
158
159        ek = svc_expkey_update(&key, ek);
160        if (!ek)
161            err = -ENOMEM;
162        path_put(&key.ek_path);
163    }
164    cache_flush();
165 out:
166    if (ek)
167        cache_put(&ek->h, &svc_expkey_cache);
168    if (dom)
169        auth_domain_put(dom);
170    kfree(buf);
171    return err;
172}
173
174static int expkey_show(struct seq_file *m,
175               struct cache_detail *cd,
176               struct cache_head *h)
177{
178    struct svc_expkey *ek ;
179    int i;
180
181    if (h ==NULL) {
182        seq_puts(m, "#domain fsidtype fsid [path]\n");
183        return 0;
184    }
185    ek = container_of(h, struct svc_expkey, h);
186    seq_printf(m, "%s %d 0x", ek->ek_client->name,
187           ek->ek_fsidtype);
188    for (i=0; i < key_len(ek->ek_fsidtype)/4; i++)
189        seq_printf(m, "%08x", ek->ek_fsid[i]);
190    if (test_bit(CACHE_VALID, &h->flags) &&
191        !test_bit(CACHE_NEGATIVE, &h->flags)) {
192        seq_printf(m, " ");
193        seq_path(m, &ek->ek_path, "\\ \t\n");
194    }
195    seq_printf(m, "\n");
196    return 0;
197}
198
199static inline int expkey_match (struct cache_head *a, struct cache_head *b)
200{
201    struct svc_expkey *orig = container_of(a, struct svc_expkey, h);
202    struct svc_expkey *new = container_of(b, struct svc_expkey, h);
203
204    if (orig->ek_fsidtype != new->ek_fsidtype ||
205        orig->ek_client != new->ek_client ||
206        memcmp(orig->ek_fsid, new->ek_fsid, key_len(orig->ek_fsidtype)) != 0)
207        return 0;
208    return 1;
209}
210
211static inline void expkey_init(struct cache_head *cnew,
212                   struct cache_head *citem)
213{
214    struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);
215    struct svc_expkey *item = container_of(citem, struct svc_expkey, h);
216
217    kref_get(&item->ek_client->ref);
218    new->ek_client = item->ek_client;
219    new->ek_fsidtype = item->ek_fsidtype;
220
221    memcpy(new->ek_fsid, item->ek_fsid, sizeof(new->ek_fsid));
222}
223
224static inline void expkey_update(struct cache_head *cnew,
225                   struct cache_head *citem)
226{
227    struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);
228    struct svc_expkey *item = container_of(citem, struct svc_expkey, h);
229
230    new->ek_path = item->ek_path;
231    path_get(&item->ek_path);
232}
233
234static struct cache_head *expkey_alloc(void)
235{
236    struct svc_expkey *i = kmalloc(sizeof(*i), GFP_KERNEL);
237    if (i)
238        return &i->h;
239    else
240        return NULL;
241}
242
243static struct cache_detail svc_expkey_cache = {
244    .owner = THIS_MODULE,
245    .hash_size = EXPKEY_HASHMAX,
246    .hash_table = expkey_table,
247    .name = "nfsd.fh",
248    .cache_put = expkey_put,
249    .cache_upcall = expkey_upcall,
250    .cache_parse = expkey_parse,
251    .cache_show = expkey_show,
252    .match = expkey_match,
253    .init = expkey_init,
254    .update = expkey_update,
255    .alloc = expkey_alloc,
256};
257
258static int
259svc_expkey_hash(struct svc_expkey *item)
260{
261    int hash = item->ek_fsidtype;
262    char * cp = (char*)item->ek_fsid;
263    int len = key_len(item->ek_fsidtype);
264
265    hash ^= hash_mem(cp, len, EXPKEY_HASHBITS);
266    hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS);
267    hash &= EXPKEY_HASHMASK;
268    return hash;
269}
270
271static struct svc_expkey *
272svc_expkey_lookup(struct svc_expkey *item)
273{
274    struct cache_head *ch;
275    int hash = svc_expkey_hash(item);
276
277    ch = sunrpc_cache_lookup(&svc_expkey_cache, &item->h,
278                 hash);
279    if (ch)
280        return container_of(ch, struct svc_expkey, h);
281    else
282        return NULL;
283}
284
285static struct svc_expkey *
286svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old)
287{
288    struct cache_head *ch;
289    int hash = svc_expkey_hash(new);
290
291    ch = sunrpc_cache_update(&svc_expkey_cache, &new->h,
292                 &old->h, hash);
293    if (ch)
294        return container_of(ch, struct svc_expkey, h);
295    else
296        return NULL;
297}
298
299
300#define EXPORT_HASHBITS 8
301#define EXPORT_HASHMAX (1<< EXPORT_HASHBITS)
302
303static struct cache_head *export_table[EXPORT_HASHMAX];
304
305static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc)
306{
307    int i;
308
309    for (i = 0; i < fsloc->locations_count; i++) {
310        kfree(fsloc->locations[i].path);
311        kfree(fsloc->locations[i].hosts);
312    }
313    kfree(fsloc->locations);
314}
315
316static void svc_export_put(struct kref *ref)
317{
318    struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
319    path_put(&exp->ex_path);
320    auth_domain_put(exp->ex_client);
321    kfree(exp->ex_pathname);
322    nfsd4_fslocs_free(&exp->ex_fslocs);
323    kfree(exp);
324}
325
326static void svc_export_request(struct cache_detail *cd,
327                   struct cache_head *h,
328                   char **bpp, int *blen)
329{
330    /* client path */
331    struct svc_export *exp = container_of(h, struct svc_export, h);
332    char *pth;
333
334    qword_add(bpp, blen, exp->ex_client->name);
335    pth = d_path(&exp->ex_path, *bpp, *blen);
336    if (IS_ERR(pth)) {
337        /* is this correct? */
338        (*bpp)[0] = '\n';
339        return;
340    }
341    qword_add(bpp, blen, pth);
342    (*bpp)[-1] = '\n';
343}
344
345static int svc_export_upcall(struct cache_detail *cd, struct cache_head *h)
346{
347    return sunrpc_cache_pipe_upcall(cd, h, svc_export_request);
348}
349
350static struct svc_export *svc_export_update(struct svc_export *new,
351                        struct svc_export *old);
352static struct svc_export *svc_export_lookup(struct svc_export *);
353
354static int check_export(struct inode *inode, int *flags, unsigned char *uuid)
355{
356
357    /*
358     * We currently export only dirs, regular files, and (for v4
359     * pseudoroot) symlinks.
360     */
361    if (!S_ISDIR(inode->i_mode) &&
362        !S_ISLNK(inode->i_mode) &&
363        !S_ISREG(inode->i_mode))
364        return -ENOTDIR;
365
366    /*
367     * Mountd should never pass down a writeable V4ROOT export, but,
368     * just to make sure:
369     */
370    if (*flags & NFSEXP_V4ROOT)
371        *flags |= NFSEXP_READONLY;
372
373    /* There are two requirements on a filesystem to be exportable.
374     * 1: We must be able to identify the filesystem from a number.
375     * either a device number (so FS_REQUIRES_DEV needed)
376     * or an FSID number (so NFSEXP_FSID or ->uuid is needed).
377     * 2: We must be able to find an inode from a filehandle.
378     * This means that s_export_op must be set.
379     */
380    if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) &&
381        !(*flags & NFSEXP_FSID) &&
382        uuid == NULL) {
383        dprintk("exp_export: export of non-dev fs without fsid\n");
384        return -EINVAL;
385    }
386
387    if (!inode->i_sb->s_export_op ||
388        !inode->i_sb->s_export_op->fh_to_dentry) {
389        dprintk("exp_export: export of invalid fs type.\n");
390        return -EINVAL;
391    }
392
393    return 0;
394
395}
396
397#ifdef CONFIG_NFSD_V4
398
399static int
400fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc)
401{
402    int len;
403    int migrated, i, err;
404
405    /* listsize */
406    err = get_int(mesg, &fsloc->locations_count);
407    if (err)
408        return err;
409    if (fsloc->locations_count > MAX_FS_LOCATIONS)
410        return -EINVAL;
411    if (fsloc->locations_count == 0)
412        return 0;
413
414    fsloc->locations = kzalloc(fsloc->locations_count
415            * sizeof(struct nfsd4_fs_location), GFP_KERNEL);
416    if (!fsloc->locations)
417        return -ENOMEM;
418    for (i=0; i < fsloc->locations_count; i++) {
419        /* colon separated host list */
420        err = -EINVAL;
421        len = qword_get(mesg, buf, PAGE_SIZE);
422        if (len <= 0)
423            goto out_free_all;
424        err = -ENOMEM;
425        fsloc->locations[i].hosts = kstrdup(buf, GFP_KERNEL);
426        if (!fsloc->locations[i].hosts)
427            goto out_free_all;
428        err = -EINVAL;
429        /* slash separated path component list */
430        len = qword_get(mesg, buf, PAGE_SIZE);
431        if (len <= 0)
432            goto out_free_all;
433        err = -ENOMEM;
434        fsloc->locations[i].path = kstrdup(buf, GFP_KERNEL);
435        if (!fsloc->locations[i].path)
436            goto out_free_all;
437    }
438    /* migrated */
439    err = get_int(mesg, &migrated);
440    if (err)
441        goto out_free_all;
442    err = -EINVAL;
443    if (migrated < 0 || migrated > 1)
444        goto out_free_all;
445    fsloc->migrated = migrated;
446    return 0;
447out_free_all:
448    nfsd4_fslocs_free(fsloc);
449    return err;
450}
451
452static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp)
453{
454    int listsize, err;
455    struct exp_flavor_info *f;
456
457    err = get_int(mesg, &listsize);
458    if (err)
459        return err;
460    if (listsize < 0 || listsize > MAX_SECINFO_LIST)
461        return -EINVAL;
462
463    for (f = exp->ex_flavors; f < exp->ex_flavors + listsize; f++) {
464        err = get_int(mesg, &f->pseudoflavor);
465        if (err)
466            return err;
467        /*
468         * XXX: It would be nice to also check whether this
469         * pseudoflavor is supported, so we can discover the
470         * problem at export time instead of when a client fails
471         * to authenticate.
472         */
473        err = get_int(mesg, &f->flags);
474        if (err)
475            return err;
476        /* Only some flags are allowed to differ between flavors: */
477        if (~NFSEXP_SECINFO_FLAGS & (f->flags ^ exp->ex_flags))
478            return -EINVAL;
479    }
480    exp->ex_nflavors = listsize;
481    return 0;
482}
483
484#else /* CONFIG_NFSD_V4 */
485static inline int
486fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc){return 0;}
487static inline int
488secinfo_parse(char **mesg, char *buf, struct svc_export *exp) { return 0; }
489#endif
490
491static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
492{
493    /* client path expiry [flags anonuid anongid fsid] */
494    char *buf;
495    int len;
496    int err;
497    struct auth_domain *dom = NULL;
498    struct svc_export exp = {}, *expp;
499    int an_int;
500
501    if (mesg[mlen-1] != '\n')
502        return -EINVAL;
503    mesg[mlen-1] = 0;
504
505    buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
506    if (!buf)
507        return -ENOMEM;
508
509    /* client */
510    err = -EINVAL;
511    len = qword_get(&mesg, buf, PAGE_SIZE);
512    if (len <= 0)
513        goto out;
514
515    err = -ENOENT;
516    dom = auth_domain_find(buf);
517    if (!dom)
518        goto out;
519
520    /* path */
521    err = -EINVAL;
522    if ((len = qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
523        goto out1;
524
525    err = kern_path(buf, 0, &exp.ex_path);
526    if (err)
527        goto out1;
528
529    exp.ex_client = dom;
530
531    err = -ENOMEM;
532    exp.ex_pathname = kstrdup(buf, GFP_KERNEL);
533    if (!exp.ex_pathname)
534        goto out2;
535
536    /* expiry */
537    err = -EINVAL;
538    exp.h.expiry_time = get_expiry(&mesg);
539    if (exp.h.expiry_time == 0)
540        goto out3;
541
542    /* flags */
543    err = get_int(&mesg, &an_int);
544    if (err == -ENOENT) {
545        err = 0;
546        set_bit(CACHE_NEGATIVE, &exp.h.flags);
547    } else {
548        if (err || an_int < 0)
549            goto out3;
550        exp.ex_flags= an_int;
551    
552        /* anon uid */
553        err = get_int(&mesg, &an_int);
554        if (err)
555            goto out3;
556        exp.ex_anon_uid= an_int;
557
558        /* anon gid */
559        err = get_int(&mesg, &an_int);
560        if (err)
561            goto out3;
562        exp.ex_anon_gid= an_int;
563
564        /* fsid */
565        err = get_int(&mesg, &an_int);
566        if (err)
567            goto out3;
568        exp.ex_fsid = an_int;
569
570        while ((len = qword_get(&mesg, buf, PAGE_SIZE)) > 0) {
571            if (strcmp(buf, "fsloc") == 0)
572                err = fsloc_parse(&mesg, buf, &exp.ex_fslocs);
573            else if (strcmp(buf, "uuid") == 0) {
574                /* expect a 16 byte uuid encoded as \xXXXX... */
575                len = qword_get(&mesg, buf, PAGE_SIZE);
576                if (len != 16)
577                    err = -EINVAL;
578                else {
579                    exp.ex_uuid =
580                        kmemdup(buf, 16, GFP_KERNEL);
581                    if (exp.ex_uuid == NULL)
582                        err = -ENOMEM;
583                }
584            } else if (strcmp(buf, "secinfo") == 0)
585                err = secinfo_parse(&mesg, buf, &exp);
586            else
587                /* quietly ignore unknown words and anything
588                 * following. Newer user-space can try to set
589                 * new values, then see what the result was.
590                 */
591                break;
592            if (err)
593                goto out4;
594        }
595
596        err = check_export(exp.ex_path.dentry->d_inode, &exp.ex_flags,
597                   exp.ex_uuid);
598        if (err)
599            goto out4;
600    }
601
602    expp = svc_export_lookup(&exp);
603    if (expp)
604        expp = svc_export_update(&exp, expp);
605    else
606        err = -ENOMEM;
607    cache_flush();
608    if (expp == NULL)
609        err = -ENOMEM;
610    else
611        exp_put(expp);
612out4:
613    nfsd4_fslocs_free(&exp.ex_fslocs);
614    kfree(exp.ex_uuid);
615out3:
616    kfree(exp.ex_pathname);
617out2:
618    path_put(&exp.ex_path);
619out1:
620    auth_domain_put(dom);
621out:
622    kfree(buf);
623    return err;
624}
625
626static void exp_flags(struct seq_file *m, int flag, int fsid,
627        uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs);
628static void show_secinfo(struct seq_file *m, struct svc_export *exp);
629
630static int svc_export_show(struct seq_file *m,
631               struct cache_detail *cd,
632               struct cache_head *h)
633{
634    struct svc_export *exp ;
635
636    if (h ==NULL) {
637        seq_puts(m, "#path domain(flags)\n");
638        return 0;
639    }
640    exp = container_of(h, struct svc_export, h);
641    seq_path(m, &exp->ex_path, " \t\n\\");
642    seq_putc(m, '\t');
643    seq_escape(m, exp->ex_client->name, " \t\n\\");
644    seq_putc(m, '(');
645    if (test_bit(CACHE_VALID, &h->flags) &&
646        !test_bit(CACHE_NEGATIVE, &h->flags)) {
647        exp_flags(m, exp->ex_flags, exp->ex_fsid,
648              exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs);
649        if (exp->ex_uuid) {
650            int i;
651            seq_puts(m, ",uuid=");
652            for (i=0; i<16; i++) {
653                if ((i&3) == 0 && i)
654                    seq_putc(m, ':');
655                seq_printf(m, "%02x", exp->ex_uuid[i]);
656            }
657        }
658        show_secinfo(m, exp);
659    }
660    seq_puts(m, ")\n");
661    return 0;
662}
663static int svc_export_match(struct cache_head *a, struct cache_head *b)
664{
665    struct svc_export *orig = container_of(a, struct svc_export, h);
666    struct svc_export *new = container_of(b, struct svc_export, h);
667    return orig->ex_client == new->ex_client &&
668        orig->ex_path.dentry == new->ex_path.dentry &&
669        orig->ex_path.mnt == new->ex_path.mnt;
670}
671
672static void svc_export_init(struct cache_head *cnew, struct cache_head *citem)
673{
674    struct svc_export *new = container_of(cnew, struct svc_export, h);
675    struct svc_export *item = container_of(citem, struct svc_export, h);
676
677    kref_get(&item->ex_client->ref);
678    new->ex_client = item->ex_client;
679    new->ex_path.dentry = dget(item->ex_path.dentry);
680    new->ex_path.mnt = mntget(item->ex_path.mnt);
681    new->ex_pathname = NULL;
682    new->ex_fslocs.locations = NULL;
683    new->ex_fslocs.locations_count = 0;
684    new->ex_fslocs.migrated = 0;
685}
686
687static void export_update(struct cache_head *cnew, struct cache_head *citem)
688{
689    struct svc_export *new = container_of(cnew, struct svc_export, h);
690    struct svc_export *item = container_of(citem, struct svc_export, h);
691    int i;
692
693    new->ex_flags = item->ex_flags;
694    new->ex_anon_uid = item->ex_anon_uid;
695    new->ex_anon_gid = item->ex_anon_gid;
696    new->ex_fsid = item->ex_fsid;
697    new->ex_uuid = item->ex_uuid;
698    item->ex_uuid = NULL;
699    new->ex_pathname = item->ex_pathname;
700    item->ex_pathname = NULL;
701    new->ex_fslocs.locations = item->ex_fslocs.locations;
702    item->ex_fslocs.locations = NULL;
703    new->ex_fslocs.locations_count = item->ex_fslocs.locations_count;
704    item->ex_fslocs.locations_count = 0;
705    new->ex_fslocs.migrated = item->ex_fslocs.migrated;
706    item->ex_fslocs.migrated = 0;
707    new->ex_nflavors = item->ex_nflavors;
708    for (i = 0; i < MAX_SECINFO_LIST; i++) {
709        new->ex_flavors[i] = item->ex_flavors[i];
710    }
711}
712
713static struct cache_head *svc_export_alloc(void)
714{
715    struct svc_export *i = kmalloc(sizeof(*i), GFP_KERNEL);
716    if (i)
717        return &i->h;
718    else
719        return NULL;
720}
721
722struct cache_detail svc_export_cache = {
723    .owner = THIS_MODULE,
724    .hash_size = EXPORT_HASHMAX,
725    .hash_table = export_table,
726    .name = "nfsd.export",
727    .cache_put = svc_export_put,
728    .cache_upcall = svc_export_upcall,
729    .cache_parse = svc_export_parse,
730    .cache_show = svc_export_show,
731    .match = svc_export_match,
732    .init = svc_export_init,
733    .update = export_update,
734    .alloc = svc_export_alloc,
735};
736
737static int
738svc_export_hash(struct svc_export *exp)
739{
740    int hash;
741
742    hash = hash_ptr(exp->ex_client, EXPORT_HASHBITS);
743    hash ^= hash_ptr(exp->ex_path.dentry, EXPORT_HASHBITS);
744    hash ^= hash_ptr(exp->ex_path.mnt, EXPORT_HASHBITS);
745    return hash;
746}
747
748static struct svc_export *
749svc_export_lookup(struct svc_export *exp)
750{
751    struct cache_head *ch;
752    int hash = svc_export_hash(exp);
753
754    ch = sunrpc_cache_lookup(&svc_export_cache, &exp->h,
755                 hash);
756    if (ch)
757        return container_of(ch, struct svc_export, h);
758    else
759        return NULL;
760}
761
762static struct svc_export *
763svc_export_update(struct svc_export *new, struct svc_export *old)
764{
765    struct cache_head *ch;
766    int hash = svc_export_hash(old);
767
768    ch = sunrpc_cache_update(&svc_export_cache, &new->h,
769                 &old->h,
770                 hash);
771    if (ch)
772        return container_of(ch, struct svc_export, h);
773    else
774        return NULL;
775}
776
777
778static struct svc_expkey *
779exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
780{
781    struct svc_expkey key, *ek;
782    int err;
783    
784    if (!clp)
785        return ERR_PTR(-ENOENT);
786
787    key.ek_client = clp;
788    key.ek_fsidtype = fsid_type;
789    memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
790
791    ek = svc_expkey_lookup(&key);
792    if (ek == NULL)
793        return ERR_PTR(-ENOMEM);
794    err = cache_check(&svc_expkey_cache, &ek->h, reqp);
795    if (err)
796        return ERR_PTR(err);
797    return ek;
798}
799
800#ifdef CONFIG_NFSD_DEPRECATED
801static int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv,
802               struct svc_export *exp)
803{
804    struct svc_expkey key, *ek;
805
806    key.ek_client = clp;
807    key.ek_fsidtype = fsid_type;
808    memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
809    key.ek_path = exp->ex_path;
810    key.h.expiry_time = NEVER;
811    key.h.flags = 0;
812
813    ek = svc_expkey_lookup(&key);
814    if (ek)
815        ek = svc_expkey_update(&key,ek);
816    if (ek) {
817        cache_put(&ek->h, &svc_expkey_cache);
818        return 0;
819    }
820    return -ENOMEM;
821}
822
823/*
824 * Find the client's export entry matching xdev/xino.
825 */
826static inline struct svc_expkey *
827exp_get_key(svc_client *clp, dev_t dev, ino_t ino)
828{
829    u32 fsidv[3];
830    
831    if (old_valid_dev(dev)) {
832        mk_fsid(FSID_DEV, fsidv, dev, ino, 0, NULL);
833        return exp_find_key(clp, FSID_DEV, fsidv, NULL);
834    }
835    mk_fsid(FSID_ENCODE_DEV, fsidv, dev, ino, 0, NULL);
836    return exp_find_key(clp, FSID_ENCODE_DEV, fsidv, NULL);
837}
838
839/*
840 * Find the client's export entry matching fsid
841 */
842static inline struct svc_expkey *
843exp_get_fsid_key(svc_client *clp, int fsid)
844{
845    u32 fsidv[2];
846
847    mk_fsid(FSID_NUM, fsidv, 0, 0, fsid, NULL);
848
849    return exp_find_key(clp, FSID_NUM, fsidv, NULL);
850}
851#endif
852
853static svc_export *exp_get_by_name(svc_client *clp, const struct path *path,
854                     struct cache_req *reqp)
855{
856    struct svc_export *exp, key;
857    int err;
858
859    if (!clp)
860        return ERR_PTR(-ENOENT);
861
862    key.ex_client = clp;
863    key.ex_path = *path;
864
865    exp = svc_export_lookup(&key);
866    if (exp == NULL)
867        return ERR_PTR(-ENOMEM);
868    err = cache_check(&svc_export_cache, &exp->h, reqp);
869    if (err)
870        return ERR_PTR(err);
871    return exp;
872}
873
874/*
875 * Find the export entry for a given dentry.
876 */
877static struct svc_export *exp_parent(svc_client *clp, struct path *path)
878{
879    struct dentry *saved = dget(path->dentry);
880    svc_export *exp = exp_get_by_name(clp, path, NULL);
881
882    while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
883        struct dentry *parent = dget_parent(path->dentry);
884        dput(path->dentry);
885        path->dentry = parent;
886        exp = exp_get_by_name(clp, path, NULL);
887    }
888    dput(path->dentry);
889    path->dentry = saved;
890    return exp;
891}
892
893#ifdef CONFIG_NFSD_DEPRECATED
894/*
895 * Hashtable locking. Write locks are placed only by user processes
896 * wanting to modify export information.
897 * Write locking only done in this file. Read locking
898 * needed externally.
899 */
900
901static DECLARE_RWSEM(hash_sem);
902
903void
904exp_readlock(void)
905{
906    down_read(&hash_sem);
907}
908
909static inline void
910exp_writelock(void)
911{
912    down_write(&hash_sem);
913}
914
915void
916exp_readunlock(void)
917{
918    up_read(&hash_sem);
919}
920
921static inline void
922exp_writeunlock(void)
923{
924    up_write(&hash_sem);
925}
926#else
927
928/* hash_sem not needed once deprecated interface is removed */
929void exp_readlock(void) {}
930static inline void exp_writelock(void){}
931void exp_readunlock(void) {}
932static inline void exp_writeunlock(void){}
933
934#endif
935
936#ifdef CONFIG_NFSD_DEPRECATED
937static void exp_do_unexport(svc_export *unexp);
938static int exp_verify_string(char *cp, int max);
939
940static void exp_fsid_unhash(struct svc_export *exp)
941{
942    struct svc_expkey *ek;
943
944    if ((exp->ex_flags & NFSEXP_FSID) == 0)
945        return;
946
947    ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid);
948    if (!IS_ERR(ek)) {
949        sunrpc_invalidate(&ek->h, &svc_expkey_cache);
950        cache_put(&ek->h, &svc_expkey_cache);
951    }
952}
953
954static int exp_fsid_hash(svc_client *clp, struct svc_export *exp)
955{
956    u32 fsid[2];
957 
958    if ((exp->ex_flags & NFSEXP_FSID) == 0)
959        return 0;
960
961    mk_fsid(FSID_NUM, fsid, 0, 0, exp->ex_fsid, NULL);
962    return exp_set_key(clp, FSID_NUM, fsid, exp);
963}
964
965static int exp_hash(struct auth_domain *clp, struct svc_export *exp)
966{
967    u32 fsid[2];
968    struct inode *inode = exp->ex_path.dentry->d_inode;
969    dev_t dev = inode->i_sb->s_dev;
970
971    if (old_valid_dev(dev)) {
972        mk_fsid(FSID_DEV, fsid, dev, inode->i_ino, 0, NULL);
973        return exp_set_key(clp, FSID_DEV, fsid, exp);
974    }
975    mk_fsid(FSID_ENCODE_DEV, fsid, dev, inode->i_ino, 0, NULL);
976    return exp_set_key(clp, FSID_ENCODE_DEV, fsid, exp);
977}
978
979static void exp_unhash(struct svc_export *exp)
980{
981    struct svc_expkey *ek;
982    struct inode *inode = exp->ex_path.dentry->d_inode;
983
984    ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino);
985    if (!IS_ERR(ek)) {
986        sunrpc_invalidate(&ek->h, &svc_expkey_cache);
987        cache_put(&ek->h, &svc_expkey_cache);
988    }
989}
990    
991/*
992 * Export a file system.
993 */
994int
995exp_export(struct nfsctl_export *nxp)
996{
997    svc_client *clp;
998    struct svc_export *exp = NULL;
999    struct svc_export new;
1000    struct svc_expkey *fsid_key = NULL;
1001    struct path path;
1002    int err;
1003
1004    /* Consistency check */
1005    err = -EINVAL;
1006    if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) ||
1007        !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
1008        goto out;
1009
1010    dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n",
1011            nxp->ex_client, nxp->ex_path,
1012            (unsigned)nxp->ex_dev, (long)nxp->ex_ino,
1013            nxp->ex_flags);
1014
1015    /* Try to lock the export table for update */
1016    exp_writelock();
1017
1018    /* Look up client info */
1019    if (!(clp = auth_domain_find(nxp->ex_client)))
1020        goto out_unlock;
1021
1022
1023    /* Look up the dentry */
1024    err = kern_path(nxp->ex_path, 0, &path);
1025    if (err)
1026        goto out_put_clp;
1027    err = -EINVAL;
1028
1029    exp = exp_get_by_name(clp, &path, NULL);
1030
1031    memset(&new, 0, sizeof(new));
1032
1033    /* must make sure there won't be an ex_fsid clash */
1034    if ((nxp->ex_flags & NFSEXP_FSID) &&
1035        (!IS_ERR(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev))) &&
1036        fsid_key->ek_path.mnt &&
1037        (fsid_key->ek_path.mnt != path.mnt ||
1038         fsid_key->ek_path.dentry != path.dentry))
1039        goto finish;
1040
1041    if (!IS_ERR(exp)) {
1042        /* just a flags/id/fsid update */
1043
1044        exp_fsid_unhash(exp);
1045        exp->ex_flags = nxp->ex_flags;
1046        exp->ex_anon_uid = nxp->ex_anon_uid;
1047        exp->ex_anon_gid = nxp->ex_anon_gid;
1048        exp->ex_fsid = nxp->ex_dev;
1049
1050        err = exp_fsid_hash(clp, exp);
1051        goto finish;
1052    }
1053
1054    err = check_export(path.dentry->d_inode, &nxp->ex_flags, NULL);
1055    if (err) goto finish;
1056
1057    err = -ENOMEM;
1058
1059    dprintk("nfsd: creating export entry %p for client %p\n", exp, clp);
1060
1061    new.h.expiry_time = NEVER;
1062    new.h.flags = 0;
1063    new.ex_pathname = kstrdup(nxp->ex_path, GFP_KERNEL);
1064    if (!new.ex_pathname)
1065        goto finish;
1066    new.ex_client = clp;
1067    new.ex_path = path;
1068    new.ex_flags = nxp->ex_flags;
1069    new.ex_anon_uid = nxp->ex_anon_uid;
1070    new.ex_anon_gid = nxp->ex_anon_gid;
1071    new.ex_fsid = nxp->ex_dev;
1072
1073    exp = svc_export_lookup(&new);
1074    if (exp)
1075        exp = svc_export_update(&new, exp);
1076
1077    if (!exp)
1078        goto finish;
1079
1080    if (exp_hash(clp, exp) ||
1081        exp_fsid_hash(clp, exp)) {
1082        /* failed to create at least one index */
1083        exp_do_unexport(exp);
1084        cache_flush();
1085    } else
1086        err = 0;
1087finish:
1088    kfree(new.ex_pathname);
1089    if (!IS_ERR_OR_NULL(exp))
1090        exp_put(exp);
1091    if (!IS_ERR_OR_NULL(fsid_key))
1092        cache_put(&fsid_key->h, &svc_expkey_cache);
1093    path_put(&path);
1094out_put_clp:
1095    auth_domain_put(clp);
1096out_unlock:
1097    exp_writeunlock();
1098out:
1099    return err;
1100}
1101
1102/*
1103 * Unexport a file system. The export entry has already
1104 * been removed from the client's list of exported fs's.
1105 */
1106static void
1107exp_do_unexport(svc_export *unexp)
1108{
1109    sunrpc_invalidate(&unexp->h, &svc_export_cache);
1110    exp_unhash(unexp);
1111    exp_fsid_unhash(unexp);
1112}
1113
1114
1115/*
1116 * unexport syscall.
1117 */
1118int
1119exp_unexport(struct nfsctl_export *nxp)
1120{
1121    struct auth_domain *dom;
1122    svc_export *exp;
1123    struct path path;
1124    int err;
1125
1126    /* Consistency check */
1127    if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) ||
1128        !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
1129        return -EINVAL;
1130
1131    exp_writelock();
1132
1133    err = -EINVAL;
1134    dom = auth_domain_find(nxp->ex_client);
1135    if (!dom) {
1136        dprintk("nfsd: unexport couldn't find %s\n", nxp->ex_client);
1137        goto out_unlock;
1138    }
1139
1140    err = kern_path(nxp->ex_path, 0, &path);
1141    if (err)
1142        goto out_domain;
1143
1144    err = -EINVAL;
1145    exp = exp_get_by_name(dom, &path, NULL);
1146    path_put(&path);
1147    if (IS_ERR(exp))
1148        goto out_domain;
1149
1150    exp_do_unexport(exp);
1151    exp_put(exp);
1152    err = 0;
1153
1154out_domain:
1155    auth_domain_put(dom);
1156    cache_flush();
1157out_unlock:
1158    exp_writeunlock();
1159    return err;
1160}
1161#endif /* CONFIG_NFSD_DEPRECATED */
1162
1163/*
1164 * Obtain the root fh on behalf of a client.
1165 * This could be done in user space, but I feel that it adds some safety
1166 * since its harder to fool a kernel module than a user space program.
1167 */
1168int
1169exp_rootfh(svc_client *clp, char *name, struct knfsd_fh *f, int maxsize)
1170{
1171    struct svc_export *exp;
1172    struct path path;
1173    struct inode *inode;
1174    struct svc_fh fh;
1175    int err;
1176
1177    err = -EPERM;
1178    /* NB: we probably ought to check that it's NUL-terminated */
1179    if (kern_path(name, 0, &path)) {
1180        printk("nfsd: exp_rootfh path not found %s", name);
1181        return err;
1182    }
1183    inode = path.dentry->d_inode;
1184
1185    dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n",
1186         name, path.dentry, clp->name,
1187         inode->i_sb->s_id, inode->i_ino);
1188    exp = exp_parent(clp, &path);
1189    if (IS_ERR(exp)) {
1190        err = PTR_ERR(exp);
1191        goto out;
1192    }
1193
1194    /*
1195     * fh must be initialized before calling fh_compose
1196     */
1197    fh_init(&fh, maxsize);
1198    if (fh_compose(&fh, exp, path.dentry, NULL))
1199        err = -EINVAL;
1200    else
1201        err = 0;
1202    memcpy(f, &fh.fh_handle, sizeof(struct knfsd_fh));
1203    fh_put(&fh);
1204    exp_put(exp);
1205out:
1206    path_put(&path);
1207    return err;
1208}
1209
1210static struct svc_export *exp_find(struct auth_domain *clp, int fsid_type,
1211                   u32 *fsidv, struct cache_req *reqp)
1212{
1213    struct svc_export *exp;
1214    struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);
1215    if (IS_ERR(ek))
1216        return ERR_CAST(ek);
1217
1218    exp = exp_get_by_name(clp, &ek->ek_path, reqp);
1219    cache_put(&ek->h, &svc_expkey_cache);
1220
1221    if (IS_ERR(exp))
1222        return ERR_CAST(exp);
1223    return exp;
1224}
1225
1226__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
1227{
1228    struct exp_flavor_info *f;
1229    struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
1230
1231    /* legacy gss-only clients are always OK: */
1232    if (exp->ex_client == rqstp->rq_gssclient)
1233        return 0;
1234    /* ip-address based client; check sec= export option: */
1235    for (f = exp->ex_flavors; f < end; f++) {
1236        if (f->pseudoflavor == rqstp->rq_flavor)
1237            return 0;
1238    }
1239    /* defaults in absence of sec= options: */
1240    if (exp->ex_nflavors == 0) {
1241        if (rqstp->rq_flavor == RPC_AUTH_NULL ||
1242            rqstp->rq_flavor == RPC_AUTH_UNIX)
1243            return 0;
1244    }
1245    return nfserr_wrongsec;
1246}
1247
1248/*
1249 * Uses rq_client and rq_gssclient to find an export; uses rq_client (an
1250 * auth_unix client) if it's available and has secinfo information;
1251 * otherwise, will try to use rq_gssclient.
1252 *
1253 * Called from functions that handle requests; functions that do work on
1254 * behalf of mountd are passed a single client name to use, and should
1255 * use exp_get_by_name() or exp_find().
1256 */
1257struct svc_export *
1258rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path)
1259{
1260    struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
1261
1262    if (rqstp->rq_client == NULL)
1263        goto gss;
1264
1265    /* First try the auth_unix client: */
1266    exp = exp_get_by_name(rqstp->rq_client, path, &rqstp->rq_chandle);
1267    if (PTR_ERR(exp) == -ENOENT)
1268        goto gss;
1269    if (IS_ERR(exp))
1270        return exp;
1271    /* If it has secinfo, assume there are no gss/... clients */
1272    if (exp->ex_nflavors > 0)
1273        return exp;
1274gss:
1275    /* Otherwise, try falling back on gss client */
1276    if (rqstp->rq_gssclient == NULL)
1277        return exp;
1278    gssexp = exp_get_by_name(rqstp->rq_gssclient, path, &rqstp->rq_chandle);
1279    if (PTR_ERR(gssexp) == -ENOENT)
1280        return exp;
1281    if (!IS_ERR(exp))
1282        exp_put(exp);
1283    return gssexp;
1284}
1285
1286struct svc_export *
1287rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv)
1288{
1289    struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
1290
1291    if (rqstp->rq_client == NULL)
1292        goto gss;
1293
1294    /* First try the auth_unix client: */
1295    exp = exp_find(rqstp->rq_client, fsid_type, fsidv, &rqstp->rq_chandle);
1296    if (PTR_ERR(exp) == -ENOENT)
1297        goto gss;
1298    if (IS_ERR(exp))
1299        return exp;
1300    /* If it has secinfo, assume there are no gss/... clients */
1301    if (exp->ex_nflavors > 0)
1302        return exp;
1303gss:
1304    /* Otherwise, try falling back on gss client */
1305    if (rqstp->rq_gssclient == NULL)
1306        return exp;
1307    gssexp = exp_find(rqstp->rq_gssclient, fsid_type, fsidv,
1308                        &rqstp->rq_chandle);
1309    if (PTR_ERR(gssexp) == -ENOENT)
1310        return exp;
1311    if (!IS_ERR(exp))
1312        exp_put(exp);
1313    return gssexp;
1314}
1315
1316struct svc_export *
1317rqst_exp_parent(struct svc_rqst *rqstp, struct path *path)
1318{
1319    struct dentry *saved = dget(path->dentry);
1320    struct svc_export *exp = rqst_exp_get_by_name(rqstp, path);
1321
1322    while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
1323        struct dentry *parent = dget_parent(path->dentry);
1324        dput(path->dentry);
1325        path->dentry = parent;
1326        exp = rqst_exp_get_by_name(rqstp, path);
1327    }
1328    dput(path->dentry);
1329    path->dentry = saved;
1330    return exp;
1331}
1332
1333static struct svc_export *find_fsidzero_export(struct svc_rqst *rqstp)
1334{
1335    u32 fsidv[2];
1336
1337    mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
1338
1339    return rqst_exp_find(rqstp, FSID_NUM, fsidv);
1340}
1341
1342/*
1343 * Called when we need the filehandle for the root of the pseudofs,
1344 * for a given NFSv4 client. The root is defined to be the
1345 * export point with fsid==0
1346 */
1347__be32
1348exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
1349{
1350    struct svc_export *exp;
1351    __be32 rv;
1352
1353    exp = find_fsidzero_export(rqstp);
1354    if (IS_ERR(exp))
1355        return nfserrno(PTR_ERR(exp));
1356    rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL);
1357    exp_put(exp);
1358    return rv;
1359}
1360
1361/* Iterator */
1362
1363static void *e_start(struct seq_file *m, loff_t *pos)
1364    __acquires(svc_export_cache.hash_lock)
1365{
1366    loff_t n = *pos;
1367    unsigned hash, export;
1368    struct cache_head *ch;
1369    
1370    exp_readlock();
1371    read_lock(&svc_export_cache.hash_lock);
1372    if (!n--)
1373        return SEQ_START_TOKEN;
1374    hash = n >> 32;
1375    export = n & ((1LL<<32) - 1);
1376
1377    
1378    for (ch=export_table[hash]; ch; ch=ch->next)
1379        if (!export--)
1380            return ch;
1381    n &= ~((1LL<<32) - 1);
1382    do {
1383        hash++;
1384        n += 1LL<<32;
1385    } while(hash < EXPORT_HASHMAX && export_table[hash]==NULL);
1386    if (hash >= EXPORT_HASHMAX)
1387        return NULL;
1388    *pos = n+1;
1389    return export_table[hash];
1390}
1391
1392static void *e_next(struct seq_file *m, void *p, loff_t *pos)
1393{
1394    struct cache_head *ch = p;
1395    int hash = (*pos >> 32);
1396
1397    if (p == SEQ_START_TOKEN)
1398        hash = 0;
1399    else if (ch->next == NULL) {
1400        hash++;
1401        *pos += 1LL<<32;
1402    } else {
1403        ++*pos;
1404        return ch->next;
1405    }
1406    *pos &= ~((1LL<<32) - 1);
1407    while (hash < EXPORT_HASHMAX && export_table[hash] == NULL) {
1408        hash++;
1409        *pos += 1LL<<32;
1410    }
1411    if (hash >= EXPORT_HASHMAX)
1412        return NULL;
1413    ++*pos;
1414    return export_table[hash];
1415}
1416
1417static void e_stop(struct seq_file *m, void *p)
1418    __releases(svc_export_cache.hash_lock)
1419{
1420    read_unlock(&svc_export_cache.hash_lock);
1421    exp_readunlock();
1422}
1423
1424static struct flags {
1425    int flag;
1426    char *name[2];
1427} expflags[] = {
1428    { NFSEXP_READONLY, {"ro", "rw"}},
1429    { NFSEXP_INSECURE_PORT, {"insecure", ""}},
1430    { NFSEXP_ROOTSQUASH, {"root_squash", "no_root_squash"}},
1431    { NFSEXP_ALLSQUASH, {"all_squash", ""}},
1432    { NFSEXP_ASYNC, {"async", "sync"}},
1433    { NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}},
1434    { NFSEXP_NOHIDE, {"nohide", ""}},
1435    { NFSEXP_CROSSMOUNT, {"crossmnt", ""}},
1436    { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
1437    { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
1438    { NFSEXP_V4ROOT, {"v4root", ""}},
1439    { 0, {"", ""}}
1440};
1441
1442static void show_expflags(struct seq_file *m, int flags, int mask)
1443{
1444    struct flags *flg;
1445    int state, first = 0;
1446
1447    for (flg = expflags; flg->flag; flg++) {
1448        if (flg->flag & ~mask)
1449            continue;
1450        state = (flg->flag & flags) ? 0 : 1;
1451        if (*flg->name[state])
1452            seq_printf(m, "%s%s", first++?",":"", flg->name[state]);
1453    }
1454}
1455
1456static void show_secinfo_flags(struct seq_file *m, int flags)
1457{
1458    seq_printf(m, ",");
1459    show_expflags(m, flags, NFSEXP_SECINFO_FLAGS);
1460}
1461
1462static bool secinfo_flags_equal(int f, int g)
1463{
1464    f &= NFSEXP_SECINFO_FLAGS;
1465    g &= NFSEXP_SECINFO_FLAGS;
1466    return f == g;
1467}
1468
1469static int show_secinfo_run(struct seq_file *m, struct exp_flavor_info **fp, struct exp_flavor_info *end)
1470{
1471    int flags;
1472
1473    flags = (*fp)->flags;
1474    seq_printf(m, ",sec=%d", (*fp)->pseudoflavor);
1475    (*fp)++;
1476    while (*fp != end && secinfo_flags_equal(flags, (*fp)->flags)) {
1477        seq_printf(m, ":%d", (*fp)->pseudoflavor);
1478        (*fp)++;
1479    }
1480    return flags;
1481}
1482
1483static void show_secinfo(struct seq_file *m, struct svc_export *exp)
1484{
1485    struct exp_flavor_info *f;
1486    struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
1487    int flags;
1488
1489    if (exp->ex_nflavors == 0)
1490        return;
1491    f = exp->ex_flavors;
1492    flags = show_secinfo_run(m, &f, end);
1493    if (!secinfo_flags_equal(flags, exp->ex_flags))
1494        show_secinfo_flags(m, flags);
1495    while (f != end) {
1496        flags = show_secinfo_run(m, &f, end);
1497        show_secinfo_flags(m, flags);
1498    }
1499}
1500
1501static void exp_flags(struct seq_file *m, int flag, int fsid,
1502        uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc)
1503{
1504    show_expflags(m, flag, NFSEXP_ALLFLAGS);
1505    if (flag & NFSEXP_FSID)
1506        seq_printf(m, ",fsid=%d", fsid);
1507    if (anonu != (uid_t)-2 && anonu != (0x10000-2))
1508        seq_printf(m, ",anonuid=%u", anonu);
1509    if (anong != (gid_t)-2 && anong != (0x10000-2))
1510        seq_printf(m, ",anongid=%u", anong);
1511    if (fsloc && fsloc->locations_count > 0) {
1512        char *loctype = (fsloc->migrated) ? "refer" : "replicas";
1513        int i;
1514
1515        seq_printf(m, ",%s=", loctype);
1516        seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\");
1517        seq_putc(m, '@');
1518        seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\");
1519        for (i = 1; i < fsloc->locations_count; i++) {
1520            seq_putc(m, ';');
1521            seq_escape(m, fsloc->locations[i].path, ",;@ \t\n\\");
1522            seq_putc(m, '@');
1523            seq_escape(m, fsloc->locations[i].hosts, ",;@ \t\n\\");
1524        }
1525    }
1526}
1527
1528static int e_show(struct seq_file *m, void *p)
1529{
1530    struct cache_head *cp = p;
1531    struct svc_export *exp = container_of(cp, struct svc_export, h);
1532
1533    if (p == SEQ_START_TOKEN) {
1534        seq_puts(m, "# Version 1.1\n");
1535        seq_puts(m, "# Path Client(Flags) # IPs\n");
1536        return 0;
1537    }
1538
1539    cache_get(&exp->h);
1540    if (cache_check(&svc_export_cache, &exp->h, NULL))
1541        return 0;
1542    cache_put(&exp->h, &svc_export_cache);
1543    return svc_export_show(m, &svc_export_cache, cp);
1544}
1545
1546const struct seq_operations nfs_exports_op = {
1547    .start = e_start,
1548    .next = e_next,
1549    .stop = e_stop,
1550    .show = e_show,
1551};
1552
1553#ifdef CONFIG_NFSD_DEPRECATED
1554/*
1555 * Add or modify a client.
1556 * Change requests may involve the list of host addresses. The list of
1557 * exports and possibly existing uid maps are left untouched.
1558 */
1559int
1560exp_addclient(struct nfsctl_client *ncp)
1561{
1562    struct auth_domain *dom;
1563    int i, err;
1564    struct in6_addr addr6;
1565
1566    /* First, consistency check. */
1567    err = -EINVAL;
1568    if (! exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX))
1569        goto out;
1570    if (ncp->cl_naddr > NFSCLNT_ADDRMAX)
1571        goto out;
1572
1573    /* Lock the hashtable */
1574    exp_writelock();
1575
1576    dom = unix_domain_find(ncp->cl_ident);
1577
1578    err = -ENOMEM;
1579    if (!dom)
1580        goto out_unlock;
1581
1582    /* Insert client into hashtable. */
1583    for (i = 0; i < ncp->cl_naddr; i++) {
1584        ipv6_addr_set_v4mapped(ncp->cl_addrlist[i].s_addr, &addr6);
1585        auth_unix_add_addr(&init_net, &addr6, dom);
1586    }
1587    auth_unix_forget_old(dom);
1588    auth_domain_put(dom);
1589
1590    err = 0;
1591
1592out_unlock:
1593    exp_writeunlock();
1594out:
1595    return err;
1596}
1597
1598/*
1599 * Delete a client given an identifier.
1600 */
1601int
1602exp_delclient(struct nfsctl_client *ncp)
1603{
1604    int err;
1605    struct auth_domain *dom;
1606
1607    err = -EINVAL;
1608    if (!exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX))
1609        goto out;
1610
1611    /* Lock the hashtable */
1612    exp_writelock();
1613
1614    dom = auth_domain_find(ncp->cl_ident);
1615    /* just make sure that no addresses work
1616     * and that it will expire soon
1617     */
1618    if (dom) {
1619        err = auth_unix_forget_old(dom);
1620        auth_domain_put(dom);
1621    }
1622
1623    exp_writeunlock();
1624out:
1625    return err;
1626}
1627
1628/*
1629 * Verify that string is non-empty and does not exceed max length.
1630 */
1631static int
1632exp_verify_string(char *cp, int max)
1633{
1634    int i;
1635
1636    for (i = 0; i < max; i++)
1637        if (!cp[i])
1638            return i;
1639    cp[i] = 0;
1640    printk(KERN_NOTICE "nfsd: couldn't validate string %s\n", cp);
1641    return 0;
1642}
1643#endif /* CONFIG_NFSD_DEPRECATED */
1644
1645/*
1646 * Initialize the exports module.
1647 */
1648int
1649nfsd_export_init(void)
1650{
1651    int rv;
1652    dprintk("nfsd: initializing export module.\n");
1653
1654    rv = cache_register(&svc_export_cache);
1655    if (rv)
1656        return rv;
1657    rv = cache_register(&svc_expkey_cache);
1658    if (rv)
1659        cache_unregister(&svc_export_cache);
1660    return rv;
1661
1662}
1663
1664/*
1665 * Flush exports table - called when last nfsd thread is killed
1666 */
1667void
1668nfsd_export_flush(void)
1669{
1670    exp_writelock();
1671    cache_purge(&svc_expkey_cache);
1672    cache_purge(&svc_export_cache);
1673    exp_writeunlock();
1674}
1675
1676/*
1677 * Shutdown the exports module.
1678 */
1679void
1680nfsd_export_shutdown(void)
1681{
1682
1683    dprintk("nfsd: shutting down export module.\n");
1684
1685    exp_writelock();
1686
1687    cache_unregister(&svc_expkey_cache);
1688    cache_unregister(&svc_export_cache);
1689    svcauth_unix_purge();
1690
1691    exp_writeunlock();
1692    dprintk("nfsd: export shutdown complete.\n");
1693}
1694

Archive Download this file



interactive