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