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