Merge branch 'upstream' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev
[sfrench/cifs-2.6.git] / 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/sched.h>
20 #include <linux/stat.h>
21 #include <linux/in.h>
22 #include <linux/seq_file.h>
23 #include <linux/syscalls.h>
24 #include <linux/rwsem.h>
25 #include <linux/dcache.h>
26 #include <linux/namei.h>
27 #include <linux/mount.h>
28 #include <linux/hash.h>
29 #include <linux/module.h>
30
31 #include <linux/sunrpc/svc.h>
32 #include <linux/nfsd/nfsd.h>
33 #include <linux/nfsd/nfsfh.h>
34 #include <linux/nfsd/syscall.h>
35 #include <linux/lockd/bind.h>
36
37 #define NFSDDBG_FACILITY        NFSDDBG_EXPORT
38 #define NFSD_PARANOIA 1
39
40 typedef struct auth_domain      svc_client;
41 typedef struct svc_export       svc_export;
42
43 static void             exp_do_unexport(svc_export *unexp);
44 static int              exp_verify_string(char *cp, int max);
45
46 /*
47  * We have two caches.
48  * One maps client+vfsmnt+dentry to export options - the export map
49  * The other maps client+filehandle-fragment to export options. - the expkey map
50  *
51  * The export options are actually stored in the first map, and the
52  * second map contains a reference to the entry in the first map.
53  */
54
55 #define EXPKEY_HASHBITS         8
56 #define EXPKEY_HASHMAX          (1 << EXPKEY_HASHBITS)
57 #define EXPKEY_HASHMASK         (EXPKEY_HASHMAX -1)
58 static struct cache_head *expkey_table[EXPKEY_HASHMAX];
59
60 static inline int svc_expkey_hash(struct svc_expkey *item)
61 {
62         int hash = item->ek_fsidtype;
63         char * cp = (char*)item->ek_fsid;
64         int len = key_len(item->ek_fsidtype);
65
66         hash ^= hash_mem(cp, len, EXPKEY_HASHBITS);
67         hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS);
68         return hash & EXPKEY_HASHMASK;
69 }
70
71 void expkey_put(struct cache_head *item, struct cache_detail *cd)
72 {
73         if (cache_put(item, cd)) {
74                 struct svc_expkey *key = container_of(item, struct svc_expkey, h);
75                 if (test_bit(CACHE_VALID, &item->flags) &&
76                     !test_bit(CACHE_NEGATIVE, &item->flags))
77                         exp_put(key->ek_export);
78                 auth_domain_put(key->ek_client);
79                 kfree(key);
80         }
81 }
82
83 static void expkey_request(struct cache_detail *cd,
84                            struct cache_head *h,
85                            char **bpp, int *blen)
86 {
87         /* client fsidtype \xfsid */
88         struct svc_expkey *ek = container_of(h, struct svc_expkey, h);
89         char type[5];
90
91         qword_add(bpp, blen, ek->ek_client->name);
92         snprintf(type, 5, "%d", ek->ek_fsidtype);
93         qword_add(bpp, blen, type);
94         qword_addhex(bpp, blen, (char*)ek->ek_fsid, key_len(ek->ek_fsidtype));
95         (*bpp)[-1] = '\n';
96 }
97
98 static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *, int);
99 static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
100 {
101         /* client fsidtype fsid [path] */
102         char *buf;
103         int len;
104         struct auth_domain *dom = NULL;
105         int err;
106         int fsidtype;
107         char *ep;
108         struct svc_expkey key;
109
110         if (mesg[mlen-1] != '\n')
111                 return -EINVAL;
112         mesg[mlen-1] = 0;
113
114         buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
115         err = -ENOMEM;
116         if (!buf) goto out;
117
118         err = -EINVAL;
119         if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
120                 goto out;
121
122         err = -ENOENT;
123         dom = auth_domain_find(buf);
124         if (!dom)
125                 goto out;
126         dprintk("found domain %s\n", buf);
127
128         err = -EINVAL;
129         if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
130                 goto out;
131         fsidtype = simple_strtoul(buf, &ep, 10);
132         if (*ep)
133                 goto out;
134         dprintk("found fsidtype %d\n", fsidtype);
135         if (fsidtype > 2)
136                 goto out;
137         if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
138                 goto out;
139         dprintk("found fsid length %d\n", len);
140         if (len != key_len(fsidtype))
141                 goto out;
142
143         /* OK, we seem to have a valid key */
144         key.h.flags = 0;
145         key.h.expiry_time = get_expiry(&mesg);
146         if (key.h.expiry_time == 0)
147                 goto out;
148
149         key.ek_client = dom;    
150         key.ek_fsidtype = fsidtype;
151         memcpy(key.ek_fsid, buf, len);
152
153         /* now we want a pathname, or empty meaning NEGATIVE  */
154         if ((len=qword_get(&mesg, buf, PAGE_SIZE)) < 0)
155                 goto out;
156         dprintk("Path seems to be <%s>\n", buf);
157         err = 0;
158         if (len == 0) {
159                 struct svc_expkey *ek;
160                 set_bit(CACHE_NEGATIVE, &key.h.flags);
161                 ek = svc_expkey_lookup(&key, 1);
162                 if (ek)
163                         expkey_put(&ek->h, &svc_expkey_cache);
164         } else {
165                 struct nameidata nd;
166                 struct svc_expkey *ek;
167                 struct svc_export *exp;
168                 err = path_lookup(buf, 0, &nd);
169                 if (err)
170                         goto out;
171
172                 dprintk("Found the path %s\n", buf);
173                 exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL);
174
175                 err = -ENOENT;
176                 if (!exp)
177                         goto out_nd;
178                 key.ek_export = exp;
179                 dprintk("And found export\n");
180                 
181                 ek = svc_expkey_lookup(&key, 1);
182                 if (ek)
183                         expkey_put(&ek->h, &svc_expkey_cache);
184                 exp_put(exp);
185                 err = 0;
186         out_nd:
187                 path_release(&nd);
188         }
189         cache_flush();
190  out:
191         if (dom)
192                 auth_domain_put(dom);
193         if (buf)
194                 kfree(buf);
195         return err;
196 }
197
198 static int expkey_show(struct seq_file *m,
199                        struct cache_detail *cd,
200                        struct cache_head *h)
201 {
202         struct svc_expkey *ek ;
203
204         if (h ==NULL) {
205                 seq_puts(m, "#domain fsidtype fsid [path]\n");
206                 return 0;
207         }
208         ek = container_of(h, struct svc_expkey, h);
209         seq_printf(m, "%s %d 0x%08x", ek->ek_client->name,
210                    ek->ek_fsidtype, ek->ek_fsid[0]);
211         if (ek->ek_fsidtype != 1)
212                 seq_printf(m, "%08x", ek->ek_fsid[1]);
213         if (ek->ek_fsidtype == 2)
214                 seq_printf(m, "%08x", ek->ek_fsid[2]);
215         if (test_bit(CACHE_VALID, &h->flags) && 
216             !test_bit(CACHE_NEGATIVE, &h->flags)) {
217                 seq_printf(m, " ");
218                 seq_path(m, ek->ek_export->ex_mnt, ek->ek_export->ex_dentry, "\\ \t\n");
219         }
220         seq_printf(m, "\n");
221         return 0;
222 }
223         
224 struct cache_detail svc_expkey_cache = {
225         .owner          = THIS_MODULE,
226         .hash_size      = EXPKEY_HASHMAX,
227         .hash_table     = expkey_table,
228         .name           = "nfsd.fh",
229         .cache_put      = expkey_put,
230         .cache_request  = expkey_request,
231         .cache_parse    = expkey_parse,
232         .cache_show     = expkey_show,
233 };
234
235 static inline int svc_expkey_match (struct svc_expkey *a, struct svc_expkey *b)
236 {
237         if (a->ek_fsidtype != b->ek_fsidtype ||
238             a->ek_client != b->ek_client ||
239             memcmp(a->ek_fsid, b->ek_fsid, key_len(a->ek_fsidtype)) != 0)
240                 return 0;
241         return 1;
242 }
243
244 static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *item)
245 {
246         cache_get(&item->ek_client->h);
247         new->ek_client = item->ek_client;
248         new->ek_fsidtype = item->ek_fsidtype;
249         new->ek_fsid[0] = item->ek_fsid[0];
250         new->ek_fsid[1] = item->ek_fsid[1];
251         new->ek_fsid[2] = item->ek_fsid[2];
252 }
253
254 static inline void svc_expkey_update(struct svc_expkey *new, struct svc_expkey *item)
255 {
256         cache_get(&item->ek_export->h);
257         new->ek_export = item->ek_export;
258 }
259
260 static DefineSimpleCacheLookup(svc_expkey,0) /* no inplace updates */
261
262 #define EXPORT_HASHBITS         8
263 #define EXPORT_HASHMAX          (1<< EXPORT_HASHBITS)
264 #define EXPORT_HASHMASK         (EXPORT_HASHMAX -1)
265
266 static struct cache_head *export_table[EXPORT_HASHMAX];
267
268 static inline int svc_export_hash(struct svc_export *item)
269 {
270         int rv;
271
272         rv = hash_ptr(item->ex_client, EXPORT_HASHBITS);
273         rv ^= hash_ptr(item->ex_dentry, EXPORT_HASHBITS);
274         rv ^= hash_ptr(item->ex_mnt, EXPORT_HASHBITS);
275         return rv;
276 }
277
278 void svc_export_put(struct cache_head *item, struct cache_detail *cd)
279 {
280         if (cache_put(item, cd)) {
281                 struct svc_export *exp = container_of(item, struct svc_export, h);
282                 dput(exp->ex_dentry);
283                 mntput(exp->ex_mnt);
284                 auth_domain_put(exp->ex_client);
285                 kfree(exp);
286         }
287 }
288
289 static void svc_export_request(struct cache_detail *cd,
290                                struct cache_head *h,
291                                char **bpp, int *blen)
292 {
293         /*  client path */
294         struct svc_export *exp = container_of(h, struct svc_export, h);
295         char *pth;
296
297         qword_add(bpp, blen, exp->ex_client->name);
298         pth = d_path(exp->ex_dentry, exp->ex_mnt, *bpp, *blen);
299         if (IS_ERR(pth)) {
300                 /* is this correct? */
301                 (*bpp)[0] = '\n';
302                 return;
303         }
304         qword_add(bpp, blen, pth);
305         (*bpp)[-1] = '\n';
306 }
307
308 static struct svc_export *svc_export_lookup(struct svc_export *, int);
309
310 static int check_export(struct inode *inode, int flags)
311 {
312
313         /* We currently export only dirs and regular files.
314          * This is what umountd does.
315          */
316         if (!S_ISDIR(inode->i_mode) &&
317             !S_ISREG(inode->i_mode))
318                 return -ENOTDIR;
319
320         /* There are two requirements on a filesystem to be exportable.
321          * 1:  We must be able to identify the filesystem from a number.
322          *       either a device number (so FS_REQUIRES_DEV needed)
323          *       or an FSID number (so NFSEXP_FSID needed).
324          * 2:  We must be able to find an inode from a filehandle.
325          *       This means that s_export_op must be set.
326          */
327         if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) &&
328             !(flags & NFSEXP_FSID)) {
329                 dprintk("exp_export: export of non-dev fs without fsid");
330                 return -EINVAL;
331         }
332         if (!inode->i_sb->s_export_op) {
333                 dprintk("exp_export: export of invalid fs type.\n");
334                 return -EINVAL;
335         }
336
337         /* Ok, we can export it */;
338         if (!inode->i_sb->s_export_op->find_exported_dentry)
339                 inode->i_sb->s_export_op->find_exported_dentry =
340                         find_exported_dentry;
341         return 0;
342
343 }
344
345 static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
346 {
347         /* client path expiry [flags anonuid anongid fsid] */
348         char *buf;
349         int len;
350         int err;
351         struct auth_domain *dom = NULL;
352         struct nameidata nd;
353         struct svc_export exp, *expp;
354         int an_int;
355
356         nd.dentry = NULL;
357
358         if (mesg[mlen-1] != '\n')
359                 return -EINVAL;
360         mesg[mlen-1] = 0;
361
362         buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
363         err = -ENOMEM;
364         if (!buf) goto out;
365
366         /* client */
367         len = qword_get(&mesg, buf, PAGE_SIZE);
368         err = -EINVAL;
369         if (len <= 0) goto out;
370
371         err = -ENOENT;
372         dom = auth_domain_find(buf);
373         if (!dom)
374                 goto out;
375
376         /* path */
377         err = -EINVAL;
378         if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
379                 goto out;
380         err = path_lookup(buf, 0, &nd);
381         if (err) goto out;
382
383         exp.h.flags = 0;
384         exp.ex_client = dom;
385         exp.ex_mnt = nd.mnt;
386         exp.ex_dentry = nd.dentry;
387
388         /* expiry */
389         err = -EINVAL;
390         exp.h.expiry_time = get_expiry(&mesg);
391         if (exp.h.expiry_time == 0)
392                 goto out;
393
394         /* flags */
395         err = get_int(&mesg, &an_int);
396         if (err == -ENOENT)
397                 set_bit(CACHE_NEGATIVE, &exp.h.flags);
398         else {
399                 if (err || an_int < 0) goto out;        
400                 exp.ex_flags= an_int;
401         
402                 /* anon uid */
403                 err = get_int(&mesg, &an_int);
404                 if (err) goto out;
405                 exp.ex_anon_uid= an_int;
406
407                 /* anon gid */
408                 err = get_int(&mesg, &an_int);
409                 if (err) goto out;
410                 exp.ex_anon_gid= an_int;
411
412                 /* fsid */
413                 err = get_int(&mesg, &an_int);
414                 if (err) goto out;
415                 exp.ex_fsid = an_int;
416
417                 err = check_export(nd.dentry->d_inode, exp.ex_flags);
418                 if (err) goto out;
419         }
420
421         expp = svc_export_lookup(&exp, 1);
422         if (expp)
423                 exp_put(expp);
424         err = 0;
425         cache_flush();
426  out:
427         if (nd.dentry)
428                 path_release(&nd);
429         if (dom)
430                 auth_domain_put(dom);
431         if (buf)
432                 kfree(buf);
433         return err;
434 }
435
436 static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t anong);
437
438 static int svc_export_show(struct seq_file *m,
439                            struct cache_detail *cd,
440                            struct cache_head *h)
441 {
442         struct svc_export *exp ;
443
444         if (h ==NULL) {
445                 seq_puts(m, "#path domain(flags)\n");
446                 return 0;
447         }
448         exp = container_of(h, struct svc_export, h);
449         seq_path(m, exp->ex_mnt, exp->ex_dentry, " \t\n\\");
450         seq_putc(m, '\t');
451         seq_escape(m, exp->ex_client->name, " \t\n\\");
452         seq_putc(m, '(');
453         if (test_bit(CACHE_VALID, &h->flags) && 
454             !test_bit(CACHE_NEGATIVE, &h->flags))
455                 exp_flags(m, exp->ex_flags, exp->ex_fsid, 
456                           exp->ex_anon_uid, exp->ex_anon_gid);
457         seq_puts(m, ")\n");
458         return 0;
459 }
460 struct cache_detail svc_export_cache = {
461         .owner          = THIS_MODULE,
462         .hash_size      = EXPORT_HASHMAX,
463         .hash_table     = export_table,
464         .name           = "nfsd.export",
465         .cache_put      = svc_export_put,
466         .cache_request  = svc_export_request,
467         .cache_parse    = svc_export_parse,
468         .cache_show     = svc_export_show,
469 };
470
471 static inline int svc_export_match(struct svc_export *a, struct svc_export *b)
472 {
473         return a->ex_client == b->ex_client &&
474                 a->ex_dentry == b->ex_dentry &&
475                 a->ex_mnt == b->ex_mnt;
476 }
477 static inline void svc_export_init(struct svc_export *new, struct svc_export *item)
478 {
479         cache_get(&item->ex_client->h);
480         new->ex_client = item->ex_client;
481         new->ex_dentry = dget(item->ex_dentry);
482         new->ex_mnt = mntget(item->ex_mnt);
483 }
484
485 static inline void svc_export_update(struct svc_export *new, struct svc_export *item)
486 {
487         new->ex_flags = item->ex_flags;
488         new->ex_anon_uid = item->ex_anon_uid;
489         new->ex_anon_gid = item->ex_anon_gid;
490         new->ex_fsid = item->ex_fsid;
491 }
492
493 static DefineSimpleCacheLookup(svc_export,1) /* allow inplace updates */
494
495
496 struct svc_expkey *
497 exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
498 {
499         struct svc_expkey key, *ek;
500         int err;
501         
502         if (!clp)
503                 return NULL;
504
505         key.ek_client = clp;
506         key.ek_fsidtype = fsid_type;
507         memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
508
509         ek = svc_expkey_lookup(&key, 0);
510         if (ek != NULL)
511                 if ((err = cache_check(&svc_expkey_cache, &ek->h, reqp)))
512                         ek = ERR_PTR(err);
513         return ek;
514 }
515
516 static int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv,
517                        struct svc_export *exp)
518 {
519         struct svc_expkey key, *ek;
520
521         key.ek_client = clp;
522         key.ek_fsidtype = fsid_type;
523         memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
524         key.ek_export = exp;
525         key.h.expiry_time = NEVER;
526         key.h.flags = 0;
527
528         ek = svc_expkey_lookup(&key, 1);
529         if (ek) {
530                 expkey_put(&ek->h, &svc_expkey_cache);
531                 return 0;
532         }
533         return -ENOMEM;
534 }
535
536 /*
537  * Find the client's export entry matching xdev/xino.
538  */
539 static inline struct svc_expkey *
540 exp_get_key(svc_client *clp, dev_t dev, ino_t ino)
541 {
542         u32 fsidv[3];
543         
544         if (old_valid_dev(dev)) {
545                 mk_fsid_v0(fsidv, dev, ino);
546                 return exp_find_key(clp, 0, fsidv, NULL);
547         }
548         mk_fsid_v3(fsidv, dev, ino);
549         return exp_find_key(clp, 3, fsidv, NULL);
550 }
551
552 /*
553  * Find the client's export entry matching fsid
554  */
555 static inline struct svc_expkey *
556 exp_get_fsid_key(svc_client *clp, int fsid)
557 {
558         u32 fsidv[2];
559
560         mk_fsid_v1(fsidv, fsid);
561
562         return exp_find_key(clp, 1, fsidv, NULL);
563 }
564
565 svc_export *
566 exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry,
567                 struct cache_req *reqp)
568 {
569         struct svc_export *exp, key;
570         
571         if (!clp)
572                 return NULL;
573
574         key.ex_client = clp;
575         key.ex_mnt = mnt;
576         key.ex_dentry = dentry;
577
578         exp = svc_export_lookup(&key, 0);
579         if (exp != NULL) 
580                 switch (cache_check(&svc_export_cache, &exp->h, reqp)) {
581                 case 0: break;
582                 case -EAGAIN:
583                         exp = ERR_PTR(-EAGAIN);
584                         break;
585                 default:
586                         exp = NULL;
587                 }
588
589         return exp;
590 }
591
592 /*
593  * Find the export entry for a given dentry.
594  */
595 struct svc_export *
596 exp_parent(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry,
597            struct cache_req *reqp)
598 {
599         svc_export *exp;
600
601         dget(dentry);
602         exp = exp_get_by_name(clp, mnt, dentry, reqp);
603
604         while (exp == NULL && !IS_ROOT(dentry)) {
605                 struct dentry *parent;
606
607                 parent = dget_parent(dentry);
608                 dput(dentry);
609                 dentry = parent;
610                 exp = exp_get_by_name(clp, mnt, dentry, reqp);
611         }
612         dput(dentry);
613         return exp;
614 }
615
616 /*
617  * Hashtable locking. Write locks are placed only by user processes
618  * wanting to modify export information.
619  * Write locking only done in this file.  Read locking
620  * needed externally.
621  */
622
623 static DECLARE_RWSEM(hash_sem);
624
625 void
626 exp_readlock(void)
627 {
628         down_read(&hash_sem);
629 }
630
631 static inline void
632 exp_writelock(void)
633 {
634         down_write(&hash_sem);
635 }
636
637 void
638 exp_readunlock(void)
639 {
640         up_read(&hash_sem);
641 }
642
643 static inline void
644 exp_writeunlock(void)
645 {
646         up_write(&hash_sem);
647 }
648
649 static void exp_fsid_unhash(struct svc_export *exp)
650 {
651         struct svc_expkey *ek;
652
653         if ((exp->ex_flags & NFSEXP_FSID) == 0)
654                 return;
655
656         ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid);
657         if (ek && !IS_ERR(ek)) {
658                 ek->h.expiry_time = get_seconds()-1;
659                 expkey_put(&ek->h, &svc_expkey_cache);
660         }
661         svc_expkey_cache.nextcheck = get_seconds();
662 }
663
664 static int exp_fsid_hash(svc_client *clp, struct svc_export *exp)
665 {
666         u32 fsid[2];
667  
668         if ((exp->ex_flags & NFSEXP_FSID) == 0)
669                 return 0;
670
671         mk_fsid_v1(fsid, exp->ex_fsid);
672         return exp_set_key(clp, 1, fsid, exp);
673 }
674
675 static int exp_hash(struct auth_domain *clp, struct svc_export *exp)
676 {
677         u32 fsid[2];
678         struct inode *inode = exp->ex_dentry->d_inode;
679         dev_t dev = inode->i_sb->s_dev;
680
681         if (old_valid_dev(dev)) {
682                 mk_fsid_v0(fsid, dev, inode->i_ino);
683                 return exp_set_key(clp, 0, fsid, exp);
684         }
685         mk_fsid_v3(fsid, dev, inode->i_ino);
686         return exp_set_key(clp, 3, fsid, exp);
687 }
688
689 static void exp_unhash(struct svc_export *exp)
690 {
691         struct svc_expkey *ek;
692         struct inode *inode = exp->ex_dentry->d_inode;
693
694         ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino);
695         if (ek && !IS_ERR(ek)) {
696                 ek->h.expiry_time = get_seconds()-1;
697                 expkey_put(&ek->h, &svc_expkey_cache);
698         }
699         svc_expkey_cache.nextcheck = get_seconds();
700 }
701         
702 /*
703  * Export a file system.
704  */
705 int
706 exp_export(struct nfsctl_export *nxp)
707 {
708         svc_client      *clp;
709         struct svc_export       *exp = NULL;
710         struct svc_export       new;
711         struct svc_expkey       *fsid_key = NULL;
712         struct nameidata nd;
713         int             err;
714
715         /* Consistency check */
716         err = -EINVAL;
717         if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) ||
718             !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
719                 goto out;
720
721         dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n",
722                         nxp->ex_client, nxp->ex_path,
723                         (unsigned)nxp->ex_dev, (long)nxp->ex_ino,
724                         nxp->ex_flags);
725
726         /* Try to lock the export table for update */
727         exp_writelock();
728
729         /* Look up client info */
730         if (!(clp = auth_domain_find(nxp->ex_client)))
731                 goto out_unlock;
732
733
734         /* Look up the dentry */
735         err = path_lookup(nxp->ex_path, 0, &nd);
736         if (err)
737                 goto out_unlock;
738         err = -EINVAL;
739
740         exp = exp_get_by_name(clp, nd.mnt, nd.dentry, NULL);
741
742         /* must make sure there won't be an ex_fsid clash */
743         if ((nxp->ex_flags & NFSEXP_FSID) &&
744             (fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) &&
745             !IS_ERR(fsid_key) &&
746             fsid_key->ek_export &&
747             fsid_key->ek_export != exp)
748                 goto finish;
749
750         if (exp) {
751                 /* just a flags/id/fsid update */
752
753                 exp_fsid_unhash(exp);
754                 exp->ex_flags    = nxp->ex_flags;
755                 exp->ex_anon_uid = nxp->ex_anon_uid;
756                 exp->ex_anon_gid = nxp->ex_anon_gid;
757                 exp->ex_fsid     = nxp->ex_dev;
758
759                 err = exp_fsid_hash(clp, exp);
760                 goto finish;
761         }
762
763         err = check_export(nd.dentry->d_inode, nxp->ex_flags);
764         if (err) goto finish;
765
766         err = -ENOMEM;
767
768         dprintk("nfsd: creating export entry %p for client %p\n", exp, clp);
769
770         new.h.expiry_time = NEVER;
771         new.h.flags = 0;
772         new.ex_client = clp;
773         new.ex_mnt = nd.mnt;
774         new.ex_dentry = nd.dentry;
775         new.ex_flags = nxp->ex_flags;
776         new.ex_anon_uid = nxp->ex_anon_uid;
777         new.ex_anon_gid = nxp->ex_anon_gid;
778         new.ex_fsid = nxp->ex_dev;
779
780         exp = svc_export_lookup(&new, 1);
781
782         if (exp == NULL)
783                 goto finish;
784
785         err = 0;
786
787         if (exp_hash(clp, exp) ||
788             exp_fsid_hash(clp, exp)) {
789                 /* failed to create at least one index */
790                 exp_do_unexport(exp);
791                 cache_flush();
792                 err = -ENOMEM;
793         }
794
795 finish:
796         if (exp)
797                 exp_put(exp);
798         if (fsid_key && !IS_ERR(fsid_key))
799                 expkey_put(&fsid_key->h, &svc_expkey_cache);
800         if (clp)
801                 auth_domain_put(clp);
802         path_release(&nd);
803 out_unlock:
804         exp_writeunlock();
805 out:
806         return err;
807 }
808
809 /*
810  * Unexport a file system. The export entry has already
811  * been removed from the client's list of exported fs's.
812  */
813 static void
814 exp_do_unexport(svc_export *unexp)
815 {
816         unexp->h.expiry_time = get_seconds()-1;
817         svc_export_cache.nextcheck = get_seconds();
818         exp_unhash(unexp);
819         exp_fsid_unhash(unexp);
820 }
821
822
823 /*
824  * unexport syscall.
825  */
826 int
827 exp_unexport(struct nfsctl_export *nxp)
828 {
829         struct auth_domain *dom;
830         svc_export *exp;
831         struct nameidata nd;
832         int             err;
833
834         /* Consistency check */
835         if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) ||
836             !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
837                 return -EINVAL;
838
839         exp_writelock();
840
841         err = -EINVAL;
842         dom = auth_domain_find(nxp->ex_client);
843         if (!dom) {
844                 dprintk("nfsd: unexport couldn't find %s\n", nxp->ex_client);
845                 goto out_unlock;
846         }
847
848         err = path_lookup(nxp->ex_path, 0, &nd);
849         if (err)
850                 goto out_domain;
851
852         err = -EINVAL;
853         exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL);
854         path_release(&nd);
855         if (!exp)
856                 goto out_domain;
857
858         exp_do_unexport(exp);
859         exp_put(exp);
860         err = 0;
861
862 out_domain:
863         auth_domain_put(dom);
864         cache_flush();
865 out_unlock:
866         exp_writeunlock();
867         return err;
868 }
869
870 /*
871  * Obtain the root fh on behalf of a client.
872  * This could be done in user space, but I feel that it adds some safety
873  * since its harder to fool a kernel module than a user space program.
874  */
875 int
876 exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize)
877 {
878         struct svc_export       *exp;
879         struct nameidata        nd;
880         struct inode            *inode;
881         struct svc_fh           fh;
882         int                     err;
883
884         err = -EPERM;
885         /* NB: we probably ought to check that it's NUL-terminated */
886         if (path_lookup(path, 0, &nd)) {
887                 printk("nfsd: exp_rootfh path not found %s", path);
888                 return err;
889         }
890         inode = nd.dentry->d_inode;
891
892         dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n",
893                  path, nd.dentry, clp->name,
894                  inode->i_sb->s_id, inode->i_ino);
895         exp = exp_parent(clp, nd.mnt, nd.dentry, NULL);
896         if (!exp) {
897                 dprintk("nfsd: exp_rootfh export not found.\n");
898                 goto out;
899         }
900
901         /*
902          * fh must be initialized before calling fh_compose
903          */
904         fh_init(&fh, maxsize);
905         if (fh_compose(&fh, exp, nd.dentry, NULL))
906                 err = -EINVAL;
907         else
908                 err = 0;
909         memcpy(f, &fh.fh_handle, sizeof(struct knfsd_fh));
910         fh_put(&fh);
911         exp_put(exp);
912 out:
913         path_release(&nd);
914         return err;
915 }
916
917 /*
918  * Called when we need the filehandle for the root of the pseudofs,
919  * for a given NFSv4 client.   The root is defined to be the
920  * export point with fsid==0
921  */
922 int
923 exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
924                struct cache_req *creq)
925 {
926         struct svc_expkey *fsid_key;
927         int rv;
928         u32 fsidv[2];
929
930         mk_fsid_v1(fsidv, 0);
931
932         fsid_key = exp_find_key(clp, 1, fsidv, creq);
933         if (IS_ERR(fsid_key) && PTR_ERR(fsid_key) == -EAGAIN)
934                 return nfserr_dropit;
935         if (!fsid_key || IS_ERR(fsid_key))
936                 return nfserr_perm;
937
938         rv = fh_compose(fhp, fsid_key->ek_export, 
939                           fsid_key->ek_export->ex_dentry, NULL);
940         expkey_put(&fsid_key->h, &svc_expkey_cache);
941         return rv;
942 }
943
944 /* Iterator */
945
946 static void *e_start(struct seq_file *m, loff_t *pos)
947 {
948         loff_t n = *pos;
949         unsigned hash, export;
950         struct cache_head *ch;
951         
952         exp_readlock();
953         read_lock(&svc_export_cache.hash_lock);
954         if (!n--)
955                 return (void *)1;
956         hash = n >> 32;
957         export = n & ((1LL<<32) - 1);
958
959         
960         for (ch=export_table[hash]; ch; ch=ch->next)
961                 if (!export--)
962                         return ch;
963         n &= ~((1LL<<32) - 1);
964         do {
965                 hash++;
966                 n += 1LL<<32;
967         } while(hash < EXPORT_HASHMAX && export_table[hash]==NULL);
968         if (hash >= EXPORT_HASHMAX)
969                 return NULL;
970         *pos = n+1;
971         return export_table[hash];
972 }
973
974 static void *e_next(struct seq_file *m, void *p, loff_t *pos)
975 {
976         struct cache_head *ch = p;
977         int hash = (*pos >> 32);
978
979         if (p == (void *)1)
980                 hash = 0;
981         else if (ch->next == NULL) {
982                 hash++;
983                 *pos += 1LL<<32;
984         } else {
985                 ++*pos;
986                 return ch->next;
987         }
988         *pos &= ~((1LL<<32) - 1);
989         while (hash < EXPORT_HASHMAX && export_table[hash] == NULL) {
990                 hash++;
991                 *pos += 1LL<<32;
992         }
993         if (hash >= EXPORT_HASHMAX)
994                 return NULL;
995         ++*pos;
996         return export_table[hash];
997 }
998
999 static void e_stop(struct seq_file *m, void *p)
1000 {
1001         read_unlock(&svc_export_cache.hash_lock);
1002         exp_readunlock();
1003 }
1004
1005 static struct flags {
1006         int flag;
1007         char *name[2];
1008 } expflags[] = {
1009         { NFSEXP_READONLY, {"ro", "rw"}},
1010         { NFSEXP_INSECURE_PORT, {"insecure", ""}},
1011         { NFSEXP_ROOTSQUASH, {"root_squash", "no_root_squash"}},
1012         { NFSEXP_ALLSQUASH, {"all_squash", ""}},
1013         { NFSEXP_ASYNC, {"async", "sync"}},
1014         { NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}},
1015         { NFSEXP_NOHIDE, {"nohide", ""}},
1016         { NFSEXP_CROSSMOUNT, {"crossmnt", ""}},
1017         { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
1018         { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
1019 #ifdef MSNFS
1020         { NFSEXP_MSNFS, {"msnfs", ""}},
1021 #endif
1022         { 0, {"", ""}}
1023 };
1024
1025 static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t anong)
1026 {
1027         int first = 0;
1028         struct flags *flg;
1029
1030         for (flg = expflags; flg->flag; flg++) {
1031                 int state = (flg->flag & flag)?0:1;
1032                 if (*flg->name[state])
1033                         seq_printf(m, "%s%s", first++?",":"", flg->name[state]);
1034         }
1035         if (flag & NFSEXP_FSID)
1036                 seq_printf(m, "%sfsid=%d", first++?",":"", fsid);
1037         if (anonu != (uid_t)-2 && anonu != (0x10000-2))
1038                 seq_printf(m, "%sanonuid=%d", first++?",":"", anonu);
1039         if (anong != (gid_t)-2 && anong != (0x10000-2))
1040                 seq_printf(m, "%sanongid=%d", first++?",":"", anong);
1041 }
1042
1043 static int e_show(struct seq_file *m, void *p)
1044 {
1045         struct cache_head *cp = p;
1046         struct svc_export *exp = container_of(cp, struct svc_export, h);
1047         svc_client *clp;
1048
1049         if (p == (void *)1) {
1050                 seq_puts(m, "# Version 1.1\n");
1051                 seq_puts(m, "# Path Client(Flags) # IPs\n");
1052                 return 0;
1053         }
1054
1055         clp = exp->ex_client;
1056         cache_get(&exp->h);
1057         if (cache_check(&svc_export_cache, &exp->h, NULL))
1058                 return 0;
1059         if (cache_put(&exp->h, &svc_export_cache)) BUG();
1060         return svc_export_show(m, &svc_export_cache, cp);
1061 }
1062
1063 struct seq_operations nfs_exports_op = {
1064         .start  = e_start,
1065         .next   = e_next,
1066         .stop   = e_stop,
1067         .show   = e_show,
1068 };
1069
1070 /*
1071  * Add or modify a client.
1072  * Change requests may involve the list of host addresses. The list of
1073  * exports and possibly existing uid maps are left untouched.
1074  */
1075 int
1076 exp_addclient(struct nfsctl_client *ncp)
1077 {
1078         struct auth_domain      *dom;
1079         int                     i, err;
1080
1081         /* First, consistency check. */
1082         err = -EINVAL;
1083         if (! exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX))
1084                 goto out;
1085         if (ncp->cl_naddr > NFSCLNT_ADDRMAX)
1086                 goto out;
1087
1088         /* Lock the hashtable */
1089         exp_writelock();
1090
1091         dom = unix_domain_find(ncp->cl_ident);
1092
1093         err = -ENOMEM;
1094         if (!dom)
1095                 goto out_unlock;
1096
1097         /* Insert client into hashtable. */
1098         for (i = 0; i < ncp->cl_naddr; i++)
1099                 auth_unix_add_addr(ncp->cl_addrlist[i], dom);
1100
1101         auth_unix_forget_old(dom);
1102         auth_domain_put(dom);
1103
1104         err = 0;
1105
1106 out_unlock:
1107         exp_writeunlock();
1108 out:
1109         return err;
1110 }
1111
1112 /*
1113  * Delete a client given an identifier.
1114  */
1115 int
1116 exp_delclient(struct nfsctl_client *ncp)
1117 {
1118         int             err;
1119         struct auth_domain *dom;
1120
1121         err = -EINVAL;
1122         if (!exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX))
1123                 goto out;
1124
1125         /* Lock the hashtable */
1126         exp_writelock();
1127
1128         dom = auth_domain_find(ncp->cl_ident);
1129         /* just make sure that no addresses work 
1130          * and that it will expire soon 
1131          */
1132         if (dom) {
1133                 err = auth_unix_forget_old(dom);
1134                 dom->h.expiry_time = get_seconds();
1135                 auth_domain_put(dom);
1136         }
1137
1138         exp_writeunlock();
1139 out:
1140         return err;
1141 }
1142
1143 /*
1144  * Verify that string is non-empty and does not exceed max length.
1145  */
1146 static int
1147 exp_verify_string(char *cp, int max)
1148 {
1149         int     i;
1150
1151         for (i = 0; i < max; i++)
1152                 if (!cp[i])
1153                         return i;
1154         cp[i] = 0;
1155         printk(KERN_NOTICE "nfsd: couldn't validate string %s\n", cp);
1156         return 0;
1157 }
1158
1159 /*
1160  * Initialize the exports module.
1161  */
1162 void
1163 nfsd_export_init(void)
1164 {
1165         dprintk("nfsd: initializing export module.\n");
1166
1167         cache_register(&svc_export_cache);
1168         cache_register(&svc_expkey_cache);
1169
1170 }
1171
1172 /*
1173  * Flush exports table - called when last nfsd thread is killed
1174  */
1175 void
1176 nfsd_export_flush(void)
1177 {
1178         exp_writelock();
1179         cache_purge(&svc_expkey_cache);
1180         cache_purge(&svc_export_cache);
1181         exp_writeunlock();
1182 }
1183
1184 /*
1185  * Shutdown the exports module.
1186  */
1187 void
1188 nfsd_export_shutdown(void)
1189 {
1190
1191         dprintk("nfsd: shutting down export module.\n");
1192
1193         exp_writelock();
1194
1195         if (cache_unregister(&svc_expkey_cache))
1196                 printk(KERN_ERR "nfsd: failed to unregister expkey cache\n");
1197         if (cache_unregister(&svc_export_cache))
1198                 printk(KERN_ERR "nfsd: failed to unregister export cache\n");
1199         svcauth_unix_purge();
1200
1201         exp_writeunlock();
1202         dprintk("nfsd: export shutdown complete.\n");
1203 }