[PATCH] PATCH - Create "export_operations" interface for filesystems to describe
[opensuse:kernel.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/rwsem.h>
24
25 #include <linux/sunrpc/svc.h>
26 #include <linux/nfsd/nfsd.h>
27 #include <linux/nfsd/nfsfh.h>
28 #include <linux/nfsd/syscall.h>
29 #include <linux/lockd/bind.h>
30
31 #define NFSDDBG_FACILITY        NFSDDBG_EXPORT
32 #define NFSD_PARANOIA 1
33
34 typedef struct svc_client       svc_client;
35 typedef struct svc_export       svc_export;
36
37 static svc_export *     exp_parent(svc_client *clp, struct super_block *sb,
38                                         struct dentry *dentry);
39 static svc_export *     exp_child(svc_client *clp, struct super_block *sb,
40                                         struct dentry *dentry);
41 static void             exp_unexport_all(svc_client *clp);
42 static void             exp_do_unexport(svc_export *unexp);
43 static svc_client *     exp_getclientbyname(char *name);
44 static void             exp_freeclient(svc_client *clp);
45 static void             exp_unhashclient(svc_client *clp);
46 static int              exp_verify_string(char *cp, int max);
47
48 #define CLIENT_HASHBITS         6
49 #define CLIENT_HASHMAX          (1 << CLIENT_HASHBITS)
50 #define CLIENT_HASHMASK         (CLIENT_HASHMAX - 1)
51 #define CLIENT_HASH(a) \
52                 ((((a)>>24) ^ ((a)>>16) ^ ((a)>>8) ^(a)) & CLIENT_HASHMASK)
53 /* XXX: is this adequate for 32bit kdev_t ? */
54 #define EXPORT_HASH(dev)        (minor(dev) & (NFSCLNT_EXPMAX - 1))
55 #define EXPORT_FSID_HASH(fsid)  ((fsid) & (NFSCLNT_EXPMAX - 1))
56
57 struct svc_clnthash {
58         struct svc_clnthash *   h_next;
59         struct in_addr          h_addr;
60         struct svc_client *     h_client;
61 };
62 static struct svc_clnthash *    clnt_hash[CLIENT_HASHMAX];
63 static svc_client *             clients;
64
65
66 /*
67  * Find the client's export entry matching xdev/xino.
68  */
69 svc_export *
70 exp_get(svc_client *clp, kdev_t dev, ino_t ino)
71 {
72         struct list_head *head, *p;
73         
74         if (!clp)
75                 return NULL;
76
77         head = &clp->cl_export[EXPORT_HASH(dev)];
78         list_for_each(p, head) {
79                 svc_export *exp = list_entry(p, svc_export, ex_hash);
80                 if (exp->ex_ino == ino && kdev_same(exp->ex_dev, dev))
81                         return exp;
82         }
83         return NULL;
84 }
85
86 /*
87  * Find the client's export entry matching fsid
88  */
89 svc_export *
90 exp_get_fsid(svc_client *clp, int fsid)
91 {
92         struct list_head *head, *p;
93
94
95         if (!clp)
96                 return NULL;
97
98         head = &clp->cl_expfsid[EXPORT_FSID_HASH(fsid)];
99         list_for_each(p, head) {
100                 svc_export *exp = list_entry(p, svc_export, ex_fsid_hash);
101                 if (exp->ex_fsid == fsid)
102                         return exp;
103         }
104         return NULL;
105 }
106
107 svc_export *
108 exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry)
109 {
110         struct list_head *head, *p;
111         int hash = EXPORT_HASH(mnt->mnt_sb->s_dev);
112
113         if (!clp)
114                 return NULL;
115
116         head = &clp->cl_export[hash];
117         list_for_each(p, head) {
118                 svc_export *exp = list_entry(p, svc_export, ex_hash);
119                 if (exp->ex_dentry == dentry && exp->ex_mnt == mnt)
120                         break;
121         }
122         return NULL;
123 }
124
125 /*
126  * Find the export entry for a given dentry.  <gam3@acm.org>
127  */
128 static svc_export *
129 exp_parent(svc_client *clp, struct super_block *sb, struct dentry *dentry)
130 {
131         struct list_head *head = &clp->cl_export[EXPORT_HASH(sb->s_dev)];
132         struct list_head *p;
133
134         spin_lock(&dcache_lock);
135         list_for_each(p, head) {
136                 svc_export *exp = list_entry(p, svc_export, ex_hash);
137                 if (is_subdir(dentry, exp->ex_dentry)) {
138                         spin_unlock(&dcache_lock);
139                         return exp;
140                 }
141         }
142         spin_unlock(&dcache_lock);
143         return NULL;
144 }
145
146 /*
147  * Find the child export entry for a given fs. This function is used
148  * only by the export syscall to keep the export tree consistent.
149  * <gam3@acm.org>
150  */
151 static svc_export *
152 exp_child(svc_client *clp, struct super_block *sb, struct dentry *dentry)
153 {
154         struct list_head *head = &clp->cl_export[EXPORT_HASH(sb->s_dev)];
155         struct list_head *p;
156         struct dentry *ndentry;
157
158         spin_lock(&dcache_lock);
159         list_for_each(p, head) {
160                 svc_export *exp = list_entry(p, svc_export, ex_hash);
161                 ndentry = exp->ex_dentry;
162                 if (ndentry && is_subdir(ndentry->d_parent, dentry)) {
163                         spin_unlock(&dcache_lock);
164                         return exp;
165                 }
166         }
167         spin_unlock(&dcache_lock);
168         return NULL;
169 }
170
171 /* Update parent pointers of all exports */
172 static void exp_change_parents(svc_client *clp, svc_export *old, svc_export *new)
173 {
174         struct list_head *head = &clp->cl_list;
175         struct list_head *p;
176
177         list_for_each(p, head) {
178                 svc_export *exp = list_entry(p, svc_export, ex_list);
179                 if (exp->ex_parent == old)
180                         exp->ex_parent = new;
181         }
182 }
183
184 /*
185  * Hashtable locking. Write locks are placed only by user processes
186  * wanting to modify export information.
187  * Write locking only done in this file.  Read locking
188  * needed externally.
189  */
190
191 static DECLARE_RWSEM(hash_sem);
192
193 void
194 exp_readlock(void)
195 {
196         down_read(&hash_sem);
197 }
198
199 static inline void
200 exp_writelock(void)
201 {
202         down_write(&hash_sem);
203 }
204
205 void
206 exp_readunlock(void)
207 {
208         up_read(&hash_sem);
209 }
210
211 static inline void
212 exp_writeunlock(void)
213 {
214         up_write(&hash_sem);
215 }
216
217 static void exp_fsid_unhash(struct svc_export *exp)
218 {
219
220         if ((exp->ex_flags & NFSEXP_FSID) == 0)
221                 return;
222
223         list_del_init(&exp->ex_fsid_hash);
224 }
225
226 static void exp_fsid_hash(struct svc_client *clp, struct svc_export *exp)
227 {
228         struct list_head *head;
229
230         if ((exp->ex_flags & NFSEXP_FSID) == 0)
231                 return;
232         head = clp->cl_expfsid + EXPORT_FSID_HASH(exp->ex_fsid);
233         list_add(&exp->ex_fsid_hash, head);
234 }
235
236 extern struct dentry *
237 find_exported_dentry(struct super_block *sb, void *obj, void *parent,
238                      int (*acceptable)(void *context, struct dentry *de),
239                      void *context);
240 /*
241  * Export a file system.
242  */
243 int
244 exp_export(struct nfsctl_export *nxp)
245 {
246         svc_client      *clp;
247         svc_export      *exp = NULL, *parent;
248         svc_export      *fsid_exp;
249         struct nameidata nd;
250         struct inode    *inode = NULL;
251         int             err;
252         kdev_t          dev;
253         ino_t           ino;
254
255         /* Consistency check */
256         err = -EINVAL;
257         if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) ||
258             !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
259                 goto out;
260
261         dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n",
262                         nxp->ex_client, nxp->ex_path,
263                         nxp->ex_dev, (long) nxp->ex_ino, nxp->ex_flags);
264
265         /* Try to lock the export table for update */
266         exp_writelock();
267
268         /* Look up client info */
269         if (!(clp = exp_getclientbyname(nxp->ex_client)))
270                 goto out_unlock;
271
272
273         /* Look up the dentry */
274         err = path_lookup(nxp->ex_path, 0, &nd);
275         if (err)
276                 goto out_unlock;
277         inode = nd.dentry->d_inode;
278         dev = inode->i_dev;
279         ino = inode->i_ino;
280         err = -EINVAL;
281
282         exp = exp_get(clp, dev, ino);
283
284         /* must make sure there wont be an ex_fsid clash */
285         if ((nxp->ex_flags & NFSEXP_FSID) &&
286             (fsid_exp = exp_get_fsid(clp, nxp->ex_dev)) &&
287             fsid_exp != exp)
288                 goto finish;
289
290         if (exp != NULL) {
291                 /* just a flags/id/fsid update */
292
293                 exp_fsid_unhash(exp);
294                 exp->ex_flags    = nxp->ex_flags;
295                 exp->ex_anon_uid = nxp->ex_anon_uid;
296                 exp->ex_anon_gid = nxp->ex_anon_gid;
297                 exp->ex_fsid     = nxp->ex_dev;
298                 exp_fsid_hash(clp, exp);
299                 err = 0;
300                 goto finish;
301         }
302
303         /* We currently export only dirs and regular files.
304          * This is what umountd does.
305          */
306         err = -ENOTDIR;
307         if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode))
308                 goto finish;
309
310         err = -EINVAL;
311         /* There are two requirements on a filesystem to be exportable.
312          * 1:  We must be able to identify the filesystem from a number.
313          *       either a device number (so FS_REQUIRES_DEV needed)
314          *       or an FSID number (so NFSEXP_FSID needed).
315          * 2:  We must be able to find an inode from a filehandle.
316          *       either using fh_to_dentry (prefered)
317          *       or using read_inode (the hack).
318          */
319         if (((inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV)
320               || (nxp->ex_flags & NFSEXP_FSID))
321             &&
322             (inode->i_sb->s_op->read_inode
323              || inode->i_sb->s_export_op
324              || inode->i_sb->s_op->fh_to_dentry)) 
325                 /* Ok, we can export it */;
326         else {
327                 dprintk("exp_export: export of invalid fs type.\n");
328                 goto finish;
329         }
330         if (inode->i_sb->s_export_op &&
331             !inode->i_sb->s_export_op->find_exported_dentry)
332                 inode->i_sb->s_export_op->find_exported_dentry =
333                         find_exported_dentry;
334
335         if ((parent = exp_child(clp, inode->i_sb, nd.dentry)) != NULL) {
336                 dprintk("exp_export: export not valid (Rule 3).\n");
337                 goto finish;
338         }
339         /* Is this is a sub-export, must be a proper subset of FS */
340         if ((parent = exp_parent(clp, inode->i_sb, nd.dentry)) != NULL) {
341                 dprintk("exp_export: sub-export not valid (Rule 2).\n");
342                 goto finish;
343         }
344
345         err = -ENOMEM;
346         if (!(exp = kmalloc(sizeof(*exp), GFP_USER)))
347                 goto finish;
348         dprintk("nfsd: created export entry %p for client %p\n", exp, clp);
349
350         strcpy(exp->ex_path, nxp->ex_path);
351         exp->ex_client = clp;
352         exp->ex_parent = parent;
353         exp->ex_mnt = mntget(nd.mnt);
354         exp->ex_dentry = dget(nd.dentry);
355         exp->ex_flags = nxp->ex_flags;
356         exp->ex_dev = dev;
357         exp->ex_ino = ino;
358         exp->ex_anon_uid = nxp->ex_anon_uid;
359         exp->ex_anon_gid = nxp->ex_anon_gid;
360         exp->ex_fsid = nxp->ex_dev;
361
362
363         /* Update parent pointers of all exports */
364         if (parent)
365                 exp_change_parents(clp, parent, exp);
366
367         list_add(&exp->ex_hash, clp->cl_export + EXPORT_HASH(dev));
368         list_add_tail(&exp->ex_list, &clp->cl_list);
369
370         exp_fsid_hash(clp, exp);
371
372         err = 0;
373
374 finish:
375         path_release(&nd);
376 out_unlock:
377         exp_writeunlock();
378 out:
379         return err;
380 }
381
382 /*
383  * Unexport a file system. The export entry has already
384  * been removed from the client's list of exported fs's.
385  */
386 static void
387 exp_do_unexport(svc_export *unexp)
388 {
389         struct dentry   *dentry;
390         struct vfsmount *mnt;
391         struct inode    *inode;
392
393         list_del(&unexp->ex_list);
394         list_del(&unexp->ex_hash);
395         exp_fsid_unhash(unexp);
396         /* Update parent pointers. */
397         exp_change_parents(unexp->ex_client, unexp, unexp->ex_parent);
398         dentry = unexp->ex_dentry;
399         mnt = unexp->ex_mnt;
400         inode = dentry->d_inode;
401         if (!kdev_same(unexp->ex_dev, inode->i_dev) || unexp->ex_ino != inode->i_ino)
402                 printk(KERN_WARNING "nfsd: bad dentry in unexport!\n");
403         dput(dentry);
404         mntput(mnt);
405
406         kfree(unexp);
407 }
408
409 /*
410  * Revoke all exports for a given client.
411  */
412 static void
413 exp_unexport_all(svc_client *clp)
414 {
415         struct list_head *p = &clp->cl_list;
416
417         dprintk("unexporting all fs's for clnt %p\n", clp);
418
419         while (!list_empty(p)) {
420                 svc_export *exp = list_entry(p->next, svc_export, ex_list);
421                 exp_do_unexport(exp);
422         }
423 }
424
425 /*
426  * unexport syscall.
427  */
428 int
429 exp_unexport(struct nfsctl_export *nxp)
430 {
431         svc_client      *clp;
432         int             err;
433
434         /* Consistency check */
435         if (!exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
436                 return -EINVAL;
437
438         exp_writelock();
439
440         err = -EINVAL;
441         clp = exp_getclientbyname(nxp->ex_client);
442         if (clp) {
443                 kdev_t ex_dev = to_kdev_t(nxp->ex_dev);
444                 svc_export *exp = exp_get(clp, ex_dev, nxp->ex_ino);
445                 if (exp) {
446                         exp_do_unexport(exp);
447                         err = 0;
448                 }
449         }
450
451         exp_writeunlock();
452         return err;
453 }
454
455 /*
456  * Obtain the root fh on behalf of a client.
457  * This could be done in user space, but I feel that it adds some safety
458  * since its harder to fool a kernel module than a user space program.
459  */
460 int
461 exp_rootfh(struct svc_client *clp, char *path, struct knfsd_fh *f, int maxsize)
462 {
463         struct svc_export       *exp;
464         struct nameidata        nd;
465         struct inode            *inode;
466         struct svc_fh           fh;
467         int                     err;
468
469         err = -EPERM;
470         /* NB: we probably ought to check that it's NUL-terminated */
471         if (path_lookup(path, 0, &nd)) {
472                 printk("nfsd: exp_rootfh path not found %s", path);
473                 return err;
474         }
475         inode = nd.dentry->d_inode;
476
477         dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n",
478                  path, nd.dentry, clp->cl_ident,
479                  inode->i_sb->s_id, inode->i_ino);
480         exp = exp_parent(clp, inode->i_sb, nd.dentry);
481         if (!exp) {
482                 dprintk("nfsd: exp_rootfh export not found.\n");
483                 goto out;
484         }
485
486         /*
487          * fh must be initialized before calling fh_compose
488          */
489         fh_init(&fh, maxsize);
490         if (fh_compose(&fh, exp, dget(nd.dentry), NULL))
491                 err = -EINVAL;
492         else
493                 err = 0;
494         memcpy(f, &fh.fh_handle, sizeof(struct knfsd_fh));
495         fh_put(&fh);
496
497 out:
498         path_release(&nd);
499         return err;
500 }
501
502
503 /*
504  * Find a valid client given an inet address. We always move the most
505  * recently used client to the front of the hash chain to speed up
506  * future lookups.
507  * Locking against other processes is the responsibility of the caller.
508  */
509 struct svc_client *
510 exp_getclient(struct sockaddr_in *sin)
511 {
512         struct svc_clnthash     **hp, **head, *tmp;
513         unsigned long           addr = sin->sin_addr.s_addr;
514
515         head = &clnt_hash[CLIENT_HASH(addr)];
516
517         for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) {
518                 if (tmp->h_addr.s_addr == addr) {
519 #if 0
520 /* If we really want to do this, we need a spin
521 lock to protect against multiple access (as we only
522 have an exp_readlock) and need to protect
523 the code in e_show() that walks this list too.
524 */
525                         /* Move client to the front */
526                         if (head != hp) {
527                                 *hp = tmp->h_next;
528                                 tmp->h_next = *head;
529                                 *head = tmp;
530                         }
531 #endif
532                         return tmp->h_client;
533                 }
534         }
535
536         return NULL;
537 }
538
539 /*
540  * Find a client given its identifier.
541  */
542 static svc_client *
543 exp_getclientbyname(char *ident)
544 {
545         svc_client *    clp;
546
547         for (clp = clients; clp; clp = clp->cl_next) {
548                 if (!strcmp(clp->cl_ident, ident))
549                         return clp;
550         }
551         return NULL;
552 }
553
554 /* Iterator */
555
556 static void *e_start(struct seq_file *m, loff_t *pos)
557 {
558         loff_t n = *pos;
559         unsigned client, export;
560         svc_client *clp;
561         struct list_head *p;
562         
563         exp_readlock();
564         if (!n--)
565                 return (void *)1;
566         client = n >> 32;
567         export = n & ((1LL<<32) - 1);
568         for (clp = clients; client && clp; clp = clp->cl_next, client--)
569                 ;
570         if (!clp)
571                 return NULL;
572         list_for_each(p, &clp->cl_list)
573                 if (!export--)
574                         return list_entry(p, svc_export, ex_list);
575         n &= ~((1LL<<32) - 1);
576         do {
577                 clp = clp->cl_next;
578                 n += 1LL<<32;
579         } while(clp && list_empty(&clp->cl_list));
580         if (!clp)
581                 return NULL;
582         *pos = n+1;
583         return list_entry(clp->cl_list.next, svc_export, ex_list);
584 }
585
586 static void *e_next(struct seq_file *m, void *p, loff_t *pos)
587 {
588         svc_export *exp = p;
589         svc_client *clp;
590
591         if (p == (void *)1)
592                 clp = clients;
593         else if (exp->ex_list.next == &exp->ex_client->cl_list) {
594                 clp = exp->ex_client->cl_next;
595                 *pos += 1LL<<32;
596         } else {
597                 ++*pos;
598                 return list_entry(exp->ex_list.next, svc_export, ex_list);
599         }
600         *pos &= ~((1LL<<32) - 1);
601         while (clp && list_empty(&clp->cl_list)) {
602                 clp = clp->cl_next;
603                 *pos += 1LL<<32;
604         }
605         if (!clp)
606                 return NULL;
607         ++*pos;
608         return list_entry(clp->cl_list.next, svc_export, ex_list);
609 }
610
611 static void e_stop(struct seq_file *m, void *p)
612 {
613         exp_readunlock();
614 }
615
616 struct flags {
617         int flag;
618         char *name[2];
619 } expflags[] = {
620         { NFSEXP_READONLY, {"ro", "rw"}},
621         { NFSEXP_INSECURE_PORT, {"insecure", ""}},
622         { NFSEXP_ROOTSQUASH, {"root_squash", "no_root_squash"}},
623         { NFSEXP_ALLSQUASH, {"all_squash", ""}},
624         { NFSEXP_ASYNC, {"async", "sync"}},
625         { NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}},
626         { NFSEXP_UIDMAP, {"uidmap", ""}},
627         { NFSEXP_KERBEROS, { "kerberos", ""}},
628         { NFSEXP_SUNSECURE, { "sunsecure", ""}},
629         { NFSEXP_CROSSMNT, {"nohide", ""}},
630         { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
631         { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
632 #ifdef MSNFS
633         { NFSEXP_MSNFS, {"msnfs", ""}},
634 #endif
635         { 0, {"", ""}}
636 };
637
638 static void exp_flags(struct seq_file *m, int flag, int fsid)
639 {
640         int first = 0;
641         struct flags *flg;
642
643         for (flg = expflags; flg->flag; flg++) {
644                 int state = (flg->flag & flag)?0:1;
645                 if (*flg->name[state])
646                         seq_printf(m, "%s%s", first++?",":"", flg->name[state]);
647         }
648         if (flag & NFSEXP_FSID)
649                 seq_printf(m, "%sfsid=%d", first++?",":"", fsid);
650 }
651
652 static inline void mangle(struct seq_file *m, const char *s)
653 {
654         seq_escape(m, s, " \t\n\\");
655 }
656
657 static int e_show(struct seq_file *m, void *p)
658 {
659         struct svc_export *exp = p;
660         struct svc_client *clp;
661         int j, first = 0;
662
663         if (p == (void *)1) {
664                 seq_puts(m, "# Version 1.1\n");
665                 seq_puts(m, "# Path Client(Flags) # IPs\n");
666                 return 0;
667         }
668
669         clp = exp->ex_client;
670
671         mangle(m, exp->ex_path);
672         seq_putc(m, '\t');
673         mangle(m, clp->cl_ident);
674         seq_putc(m, '(');
675         exp_flags(m, exp->ex_flags, exp->ex_fsid);
676         seq_puts(m, ") # ");
677         for (j = 0; j < clp->cl_naddr; j++) {
678                 struct svc_clnthash **hp, **head, *tmp;
679                 struct in_addr addr = clp->cl_addr[j]; 
680
681                 head = &clnt_hash[CLIENT_HASH(addr.s_addr)];
682                 for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) {
683                         if (tmp->h_addr.s_addr == addr.s_addr)
684                                 break;
685                 }
686                 if (tmp) {
687                         if (first++)
688                                 seq_putc(m, ' ');
689                         if (tmp->h_client != clp)
690                                 seq_putc(m, '(');
691                         seq_printf(m, "%d.%d.%d.%d",
692                                 htonl(addr.s_addr) >> 24 & 0xff,
693                                 htonl(addr.s_addr) >> 16 & 0xff,
694                                 htonl(addr.s_addr) >>  8 & 0xff,
695                                 htonl(addr.s_addr) >>  0 & 0xff);
696                         if (tmp->h_client != clp)
697                                 seq_putc(m, ')');
698                 }
699         }
700         seq_putc(m, '\n');
701         return 0;
702 }
703
704 struct seq_operations nfs_exports_op = {
705         start:  e_start,
706         next:   e_next,
707         stop:   e_stop,
708         show:   e_show,
709 };
710
711 /*
712  * Add or modify a client.
713  * Change requests may involve the list of host addresses. The list of
714  * exports and possibly existing uid maps are left untouched.
715  */
716 int
717 exp_addclient(struct nfsctl_client *ncp)
718 {
719         struct svc_clnthash *   ch[NFSCLNT_ADDRMAX];
720         svc_client *            clp;
721         int                     i, err, change = 0, ilen;
722
723         /* First, consistency check. */
724         err = -EINVAL;
725         if (!(ilen = exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX)))
726                 goto out;
727         if (ncp->cl_naddr > NFSCLNT_ADDRMAX)
728                 goto out;
729
730         /* Lock the hashtable */
731         exp_writelock();
732
733         /* First check if this is a change request for a client. */
734         for (clp = clients; clp; clp = clp->cl_next)
735                 if (!strcmp(clp->cl_ident, ncp->cl_ident))
736                         break;
737
738         err = -ENOMEM;
739         if (clp) {
740                 change = 1;
741         } else {
742                 if (!(clp = kmalloc(sizeof(*clp), GFP_KERNEL)))
743                         goto out_unlock;
744                 memset(clp, 0, sizeof(*clp));
745                 for (i = 0; i < NFSCLNT_EXPMAX; i++) {
746                         INIT_LIST_HEAD(&clp->cl_export[i]);
747                         INIT_LIST_HEAD(&clp->cl_expfsid[i]);
748                 }
749                 INIT_LIST_HEAD(&clp->cl_list);
750
751                 dprintk("created client %s (%p)\n", ncp->cl_ident, clp);
752
753                 strcpy(clp->cl_ident, ncp->cl_ident);
754                 clp->cl_idlen = ilen;
755         }
756
757         /* Allocate hash buckets */
758         for (i = 0; i < ncp->cl_naddr; i++) {
759                 ch[i] = kmalloc(sizeof(struct svc_clnthash), GFP_KERNEL);
760                 if (!ch[i]) {
761                         while (i--)
762                                 kfree(ch[i]);
763                         if (!change)
764                                 kfree(clp);
765                         goto out_unlock;
766                 }
767         }
768
769         /* Copy addresses. */
770         for (i = 0; i < ncp->cl_naddr; i++) {
771                 clp->cl_addr[i] = ncp->cl_addrlist[i];
772         }
773         clp->cl_naddr = ncp->cl_naddr;
774
775         /* Remove old client hash entries. */
776         if (change)
777                 exp_unhashclient(clp);
778
779         /* Insert client into hashtable. */
780         for (i = 0; i < ncp->cl_naddr; i++) {
781                 struct in_addr  addr = clp->cl_addr[i];
782                 int             hash;
783
784                 hash = CLIENT_HASH(addr.s_addr);
785                 ch[i]->h_client = clp;
786                 ch[i]->h_addr = addr;
787                 ch[i]->h_next = clnt_hash[hash];
788                 clnt_hash[hash] = ch[i];
789         }
790
791         if (!change) {
792                 clp->cl_next = clients;
793                 clients = clp;
794         }
795         err = 0;
796
797 out_unlock:
798         exp_writeunlock();
799 out:
800         return err;
801 }
802
803 /*
804  * Delete a client given an identifier.
805  */
806 int
807 exp_delclient(struct nfsctl_client *ncp)
808 {
809         svc_client      **clpp, *clp;
810         int             err;
811
812         err = -EINVAL;
813         if (!exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX))
814                 goto out;
815
816         /* Lock the hashtable */
817         exp_writelock();
818
819         for (clpp = &clients; (clp = *clpp); clpp = &(clp->cl_next))
820                 if (!strcmp(ncp->cl_ident, clp->cl_ident))
821                         break;
822
823         if (clp) {
824                 *clpp = clp->cl_next;
825                 exp_freeclient(clp);
826                 err = 0;
827         }
828
829         exp_writeunlock();
830 out:
831         return err;
832 }
833
834 /*
835  * Free a client. The caller has already removed it from the client list.
836  */
837 static void
838 exp_freeclient(svc_client *clp)
839 {
840         exp_unhashclient(clp);
841
842         /* umap_free(&(clp->cl_umap)); */
843         exp_unexport_all(clp);
844         nfsd_lockd_unexport(clp);
845         kfree (clp);
846 }
847
848 /*
849  * Remove client from hashtable. We first collect all hashtable
850  * entries and free them in one go.
851  * The hash table must be writelocked by the caller.
852  */
853 static void
854 exp_unhashclient(svc_client *clp)
855 {
856         struct svc_clnthash     **hpp, *hp, *ch[NFSCLNT_ADDRMAX];
857         int                     i, count, err;
858
859 again:
860         err = 0;
861         for (i = 0, count = 0; i < CLIENT_HASHMAX && !err; i++) {
862                 hpp = clnt_hash + i;
863                 while ((hp = *hpp) && !err) {
864                         if (hp->h_client == clp) {
865                                 *hpp = hp->h_next;
866                                 ch[count++] = hp;
867                                 err = (count >= NFSCLNT_ADDRMAX);
868                         } else {
869                                 hpp = &(hp->h_next);
870                         }
871                 }
872         }
873         if (count != clp->cl_naddr)
874                 printk(KERN_WARNING "nfsd: bad address count in freeclient!\n");
875         if (err)
876                 goto again;
877         for (i = 0; i < count; i++)
878                 kfree (ch[i]);
879 }
880
881 /*
882  * Lockd is shutting down and tells us to unregister all clients
883  */
884 void
885 exp_nlmdetach(void)
886 {
887         struct svc_client       *clp;
888
889         for (clp = clients; clp; clp = clp->cl_next)
890                 nfsd_lockd_unexport(clp);
891 }
892
893 /*
894  * Verify that string is non-empty and does not exceed max length.
895  */
896 static int
897 exp_verify_string(char *cp, int max)
898 {
899         int     i;
900
901         for (i = 0; i < max; i++)
902                 if (!cp[i])
903                         return i;
904         cp[i] = 0;
905         printk(KERN_NOTICE "nfsd: couldn't validate string %s\n", cp);
906         return 0;
907 }
908
909 /*
910  * Initialize the exports module.
911  */
912 void
913 nfsd_export_init(void)
914 {
915         int             i;
916
917         dprintk("nfsd: initializing export module.\n");
918
919         for (i = 0; i < CLIENT_HASHMAX; i++)
920                 clnt_hash[i] = NULL;
921         clients = NULL;
922
923 }
924
925 /*
926  * Shutdown the exports module.
927  */
928 void
929 nfsd_export_shutdown(void)
930 {
931         int     i;
932
933         dprintk("nfsd: shutting down export module.\n");
934
935         exp_writelock();
936
937         for (i = 0; i < CLIENT_HASHMAX; i++) {
938                 while (clnt_hash[i])
939                         exp_freeclient(clnt_hash[i]->h_client);
940         }
941         clients = NULL; /* we may be restarted before the module unloads */
942         
943         exp_writeunlock();
944         dprintk("nfsd: export shutdown complete.\n");
945 }