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