Merge with Linux 2.3.99-pre4.
[linux-2.6/linux-mips.git] / fs / nfsd / export.c
blob53bfa0beaef79d93406d228393e5e1f56b2ba8b2
1 /*
2 * linux/fs/nfsd/export.c
4 * NFS exporting and validation.
6 * We maintain a list of clients, each of which has a list of
7 * exports. To export an fs to a given client, you first have
8 * to create the client entry with NFSCTL_ADDCLIENT, which
9 * creates a client control block and adds it to the hash
10 * table. Then, you call NFSCTL_EXPORT for each fs.
12 * You cannot currently read the export information from the
13 * kernel. It would be nice to have a /proc file though.
15 * Copyright (C) 1995, 1996 Olaf Kirch, <okir@monad.swb.de>
18 #include <linux/unistd.h>
19 #include <linux/malloc.h>
20 #include <linux/stat.h>
21 #include <linux/in.h>
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>
29 #define NFSDDBG_FACILITY NFSDDBG_EXPORT
30 #define NFSD_PARANOIA 1
32 typedef struct svc_client svc_client;
33 typedef struct svc_export svc_export;
35 static svc_export * exp_find(svc_client *clp, kdev_t dev);
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);
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))
55 struct svc_clnthash {
56 struct svc_clnthash * h_next;
57 struct in_addr h_addr;
58 struct svc_client * h_client;
60 static struct svc_clnthash * clnt_hash[CLIENT_HASHMAX];
61 static svc_client * clients = NULL;
62 static int initialized = 0;
64 static int hash_lock = 0;
65 static int want_lock = 0;
66 static int hash_count = 0;
67 static DECLARE_WAIT_QUEUE_HEAD( hash_wait );
71 * Find a client's export for a device.
73 static inline svc_export *
74 exp_find(svc_client *clp, kdev_t dev)
76 svc_export * exp;
78 exp = clp->cl_export[EXPORT_HASH(dev)];
79 while (exp && exp->ex_dev != dev)
80 exp = exp->ex_next;
81 return exp;
85 * Find the client's export entry matching xdev/xino.
87 svc_export *
88 exp_get(svc_client *clp, kdev_t dev, ino_t ino)
90 svc_export * exp;
92 if (!clp)
93 return NULL;
95 exp = clp->cl_export[EXPORT_HASH(dev)];
96 if (exp)
97 do {
98 if (exp->ex_ino == ino && exp->ex_dev == dev)
99 goto out;
100 } while (NULL != (exp = exp->ex_next));
101 exp = NULL;
102 out:
103 return exp;
108 * Look up the device of the parent fs.
110 static inline int
111 nfsd_parentdev(kdev_t *devp)
113 struct super_block *sb;
115 if (!(sb = get_super(*devp)) || !sb->s_root->d_covers)
116 return 0;
117 if (*devp == sb->s_root->d_covers->d_inode->i_dev)
118 return 0;
119 *devp = sb->s_root->d_covers->d_inode->i_dev;
120 return 1;
124 * Find the export entry for a given dentry. <gam3@acm.org>
126 static svc_export *
127 exp_parent(svc_client *clp, kdev_t dev, struct dentry *dentry)
129 svc_export *exp;
130 kdev_t xdev = dev;
131 struct dentry *xdentry = dentry;
132 struct dentry *ndentry = NULL;
134 if (clp == NULL || dentry == NULL)
135 return NULL;
137 do {
138 xdev = dev;
139 do {
140 exp = clp->cl_export[EXPORT_HASH(xdev)];
141 if (exp)
142 do {
143 ndentry = exp->ex_dentry;
144 if (ndentry == xdentry) {
145 #ifdef NFSD_PARANOIA
146 if (dev == xdev)
147 dprintk("nfsd: exp_parent submount over mount.\n");
148 else
149 dprintk("nfsd: exp_parent found.\n");
150 #endif
151 goto out;
153 } while (NULL != (exp = exp->ex_next));
154 } while (nfsd_parentdev(&xdev));
155 if (IS_ROOT(xdentry))
156 break;
157 } while ((xdentry = xdentry->d_parent));
158 exp = NULL;
159 out:
160 return exp;
164 * Find the child export entry for a given fs. This function is used
165 * only by the export syscall to keep the export tree consistent.
166 * <gam3@acm.org>
168 static svc_export *
169 exp_child(svc_client *clp, kdev_t dev, struct dentry *dentry)
171 svc_export *exp;
172 struct dentry *xdentry = dentry;
173 struct dentry *ndentry = NULL;
175 if (clp == NULL || dentry == NULL)
176 return NULL;
178 exp = clp->cl_export[EXPORT_HASH(dev)];
179 if (exp)
180 do {
181 ndentry = exp->ex_dentry;
182 if (ndentry)
183 while ((ndentry = ndentry->d_parent)) {
184 if (ndentry == xdentry) {
185 #ifdef NFSD_PARANOIA
186 dprintk("nfsd: exp_child mount under submount.\n");
187 #endif
188 goto out;
190 if (IS_ROOT(ndentry))
191 break;
193 } while (NULL != (exp = exp->ex_next));
194 exp = NULL;
195 out:
196 return exp;
200 * Export a file system.
203 exp_export(struct nfsctl_export *nxp)
205 svc_client *clp;
206 svc_export *exp, *parent;
207 svc_export **head;
208 struct dentry *dentry = NULL;
209 struct inode *inode = NULL;
210 int i, err;
211 kdev_t dev;
212 ino_t ino;
214 /* Consistency check */
215 err = -EINVAL;
216 if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) ||
217 !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
218 goto out;
220 dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n",
221 nxp->ex_client, nxp->ex_path,
222 nxp->ex_dev, (long) nxp->ex_ino, nxp->ex_flags);
223 dev = to_kdev_t(nxp->ex_dev);
224 ino = nxp->ex_ino;
226 /* Try to lock the export table for update */
227 if ((err = exp_writelock()) < 0)
228 goto out;
230 /* Look up client info */
231 err = -EINVAL;
232 if (!(clp = exp_getclientbyname(nxp->ex_client)))
233 goto out_unlock;
236 * If there's already an export for this file, assume this
237 * is just a flag update.
239 if ((exp = exp_get(clp, dev, ino)) != NULL) {
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 err = 0;
244 goto out_unlock;
247 /* Look up the dentry */
248 err = -EINVAL;
249 dentry = lookup_dentry(nxp->ex_path, LOOKUP_POSITIVE);
250 if (IS_ERR(dentry))
251 goto out_unlock;
253 inode = dentry->d_inode;
254 err = -EINVAL;
255 if (inode->i_dev != dev || inode->i_ino != nxp->ex_ino) {
256 printk(KERN_DEBUG "exp_export: i_dev = %x, dev = %x\n",
257 inode->i_dev, dev);
258 /* I'm just being paranoid... */
259 goto finish;
262 /* We currently export only dirs and regular files.
263 * This is what umountd does.
265 err = -ENOTDIR;
266 if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode))
267 goto finish;
269 err = -EINVAL;
270 if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) ||
271 inode->i_sb->s_op->read_inode == NULL) {
272 dprintk("exp_export: export of invalid fs type.\n");
273 goto finish;
276 if ((parent = exp_child(clp, dev, dentry)) != NULL) {
277 dprintk("exp_export: export not valid (Rule 3).\n");
278 goto finish;
280 /* Is this is a sub-export, must be a proper subset of FS */
281 if ((parent = exp_parent(clp, dev, dentry)) != NULL) {
282 if (dev == parent->ex_dev) {
283 dprintk("exp_export: sub-export not valid (Rule 2).\n");
284 goto finish;
288 err = -ENOMEM;
289 if (!(exp = kmalloc(sizeof(*exp), GFP_USER)))
290 goto finish;
291 dprintk("nfsd: created export entry %p for client %p\n", exp, clp);
293 strcpy(exp->ex_path, nxp->ex_path);
294 exp->ex_client = clp;
295 exp->ex_parent = parent;
296 exp->ex_dentry = dentry;
297 exp->ex_flags = nxp->ex_flags;
298 exp->ex_dev = dev;
299 exp->ex_ino = ino;
300 exp->ex_anon_uid = nxp->ex_anon_uid;
301 exp->ex_anon_gid = nxp->ex_anon_gid;
303 /* Update parent pointers of all exports */
304 if (parent) {
305 for (i = 0; i < NFSCLNT_EXPMAX; i++) {
306 svc_export *temp = clp->cl_export[i];
308 while (temp) {
309 if (temp->ex_parent == parent)
310 temp->ex_parent = exp;
311 temp = temp->ex_next;
316 head = clp->cl_export + EXPORT_HASH(dev);
317 exp->ex_next = *head;
318 *head = exp;
320 err = 0;
322 /* Unlock hashtable */
323 out_unlock:
324 exp_unlock();
325 out:
326 return err;
328 /* Release the dentry */
329 finish:
330 dput(dentry);
331 goto out_unlock;
335 * Unexport a file system. The export entry has already
336 * been removed from the client's list of exported fs's.
338 static void
339 exp_do_unexport(svc_export *unexp)
341 svc_export *exp;
342 svc_client *clp;
343 struct dentry *dentry;
344 struct inode *inode;
345 int i;
347 /* Update parent pointers. */
348 clp = unexp->ex_client;
349 for (i = 0; i < NFSCLNT_EXPMAX; i++) {
350 for (exp = clp->cl_export[i]; exp; exp = exp->ex_next)
351 if (exp->ex_parent == unexp)
352 exp->ex_parent = unexp->ex_parent;
355 dentry = unexp->ex_dentry;
356 inode = dentry->d_inode;
357 if (unexp->ex_dev != inode->i_dev || unexp->ex_ino != inode->i_ino)
358 printk(KERN_WARNING "nfsd: bad dentry in unexport!\n");
359 dput(dentry);
361 kfree(unexp);
365 * Revoke all exports for a given client.
366 * This may look very awkward, but we have to do it this way in order
367 * to avoid race conditions (aka mind the parent pointer).
369 static void
370 exp_unexport_all(svc_client *clp)
372 svc_export *exp;
373 int i;
375 dprintk("unexporting all fs's for clnt %p\n", clp);
376 for (i = 0; i < NFSCLNT_EXPMAX; i++) {
377 exp = clp->cl_export[i];
378 clp->cl_export[i] = NULL;
379 while (exp) {
380 svc_export *next = exp->ex_next;
381 exp_do_unexport(exp);
382 exp = next;
388 * unexport syscall.
391 exp_unexport(struct nfsctl_export *nxp)
393 svc_client *clp;
394 svc_export **expp, *exp = NULL;
395 int err;
397 /* Consistency check */
398 if (!exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
399 return -EINVAL;
401 if ((err = exp_writelock()) < 0)
402 goto out;
404 err = -EINVAL;
405 clp = exp_getclientbyname(nxp->ex_client);
406 if (clp) {
407 expp = clp->cl_export + EXPORT_HASH(nxp->ex_dev);
408 while ((exp = *expp) != NULL) {
409 if (exp->ex_dev == nxp->ex_dev) {
410 if (exp->ex_ino == nxp->ex_ino) {
411 *expp = exp->ex_next;
412 exp_do_unexport(exp);
413 err = 0;
414 break;
417 expp = &(exp->ex_next);
421 exp_unlock();
422 out:
423 return err;
427 * Obtain the root fh on behalf of a client.
428 * This could be done in user space, but I feel that it adds some safety
429 * since its harder to fool a kernel module than a user space program.
432 exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino,
433 char *path, struct knfsd_fh *f, int maxsize)
435 struct svc_export *exp;
436 struct dentry *dentry = NULL;
437 struct inode *inode;
438 struct svc_fh fh;
439 int err;
441 err = -EPERM;
442 if (path) {
443 if (!(dentry = lookup_dentry(path, 0))) {
444 printk("nfsd: exp_rootfh path not found %s", path);
445 return -EPERM;
447 dev = dentry->d_inode->i_dev;
448 ino = dentry->d_inode->i_ino;
450 dprintk("nfsd: exp_rootfh(%s [%p] %s:%x/%ld)\n",
451 path, dentry, clp->cl_ident, dev, (long) ino);
452 exp = exp_parent(clp, dev, dentry);
453 } else {
454 dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n",
455 clp->cl_ident, dev, (long) ino);
456 if ((exp = exp_get(clp, dev, ino)))
457 if (!(dentry = dget(exp->ex_dentry))) {
458 printk("exp_rootfh: Aieee, NULL dentry\n");
459 return -EPERM;
462 if (!exp) {
463 dprintk("nfsd: exp_rootfh export not found.\n");
464 goto out;
467 inode = dentry->d_inode;
468 if (!inode) {
469 printk("exp_rootfh: Aieee, NULL d_inode\n");
470 goto out;
472 if (inode->i_dev != dev || inode->i_ino != ino) {
473 printk("exp_rootfh: Aieee, ino/dev mismatch\n");
474 printk("exp_rootfh: arg[dev(%x):ino(%ld)]"
475 " inode[dev(%x):ino(%ld)]\n",
476 dev, (long) ino, inode->i_dev, (long) inode->i_ino);
480 * fh must be initialized before calling fh_compose
482 fh_init(&fh, maxsize);
483 if (fh_compose(&fh, exp, dentry))
484 err = -EINVAL;
485 else
486 err = 0;
487 memcpy(f, &fh.fh_handle, sizeof(struct knfsd_fh));
488 fh_put(&fh);
489 return err;
491 out:
492 dput(dentry);
493 return err;
497 * Hashtable locking. Write locks are placed only by user processes
498 * wanting to modify export information.
500 void
501 exp_readlock(void)
503 while (hash_lock || want_lock)
504 sleep_on(&hash_wait);
505 hash_count++;
509 exp_writelock(void)
511 /* fast track */
512 if (!hash_count && !hash_lock) {
513 lock_it:
514 hash_lock = 1;
515 return 0;
518 current->sigpending = 0;
519 want_lock++;
520 while (hash_count || hash_lock) {
521 interruptible_sleep_on(&hash_wait);
522 if (signal_pending(current))
523 break;
525 want_lock--;
527 /* restore the task's signals */
528 spin_lock_irq(&current->sigmask_lock);
529 recalc_sigpending(current);
530 spin_unlock_irq(&current->sigmask_lock);
532 if (!hash_count && !hash_lock)
533 goto lock_it;
534 return -EINTR;
537 void
538 exp_unlock(void)
540 if (!hash_count && !hash_lock)
541 printk(KERN_WARNING "exp_unlock: not locked!\n");
542 if (hash_count)
543 hash_count--;
544 else
545 hash_lock = 0;
546 wake_up(&hash_wait);
550 * Find a valid client given an inet address. We always move the most
551 * recently used client to the front of the hash chain to speed up
552 * future lookups.
553 * Locking against other processes is the responsibility of the caller.
555 struct svc_client *
556 exp_getclient(struct sockaddr_in *sin)
558 struct svc_clnthash **hp, **head, *tmp;
559 unsigned long addr = sin->sin_addr.s_addr;
561 if (!initialized)
562 return NULL;
564 head = &clnt_hash[CLIENT_HASH(addr)];
566 for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) {
567 if (tmp->h_addr.s_addr == addr) {
568 /* Move client to the front */
569 if (head != hp) {
570 *hp = tmp->h_next;
571 tmp->h_next = *head;
572 *head = tmp;
575 return tmp->h_client;
579 return NULL;
583 * Find a client given its identifier.
585 static svc_client *
586 exp_getclientbyname(char *ident)
588 svc_client * clp;
590 for (clp = clients; clp; clp = clp->cl_next) {
591 if (!strcmp(clp->cl_ident, ident))
592 return clp;
594 return NULL;
597 struct flags {
598 int flag;
599 char *name[2];
600 } expflags[] = {
601 { NFSEXP_READONLY, {"ro", "rw"}},
602 { NFSEXP_INSECURE_PORT, {"insecure", ""}},
603 { NFSEXP_ROOTSQUASH, {"root_squash", "no_root_squash"}},
604 { NFSEXP_ALLSQUASH, {"all_squash", ""}},
605 { NFSEXP_ASYNC, {"async", ""}},
606 { NFSEXP_GATHERED_WRITES, {"wdelay", ""}},
607 { NFSEXP_UIDMAP, {"uidmap", ""}},
608 { NFSEXP_KERBEROS, { "kerberos", ""}},
609 { NFSEXP_SUNSECURE, { "sunsecure", ""}},
610 { NFSEXP_CROSSMNT, {"nohide", ""}},
611 { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
612 { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
613 { 0, {"", ""}}
616 static int
617 exp_flags(char *buffer, int flag)
619 int len = 0, first = 0;
620 struct flags *flg = expflags;
622 for (;flg->flag;flg++) {
623 int state = (flg->flag & flag)?0:1;
624 if (!flg->flag)
625 break;
626 if (*flg->name[state]) {
627 len += sprintf(buffer + len, "%s%s",
628 first++?",":"", flg->name[state]);
631 return len;
635 exp_procfs_exports(char *buffer, char **start, off_t offset,
636 int length, int *eof, void *data)
638 struct svc_clnthash **hp, **head, *tmp;
639 struct svc_client *clp;
640 svc_export *exp;
641 off_t pos = 0;
642 off_t begin = 0;
643 int len = 0;
644 int i,j;
646 len += sprintf(buffer, "# Version 1.0\n");
647 len += sprintf(buffer+len, "# Path Client(Flags) # IPs\n");
649 for (clp = clients; clp; clp = clp->cl_next) {
650 for (i = 0; i < NFSCLNT_EXPMAX; i++) {
651 exp = clp->cl_export[i];
652 while (exp) {
653 int first = 0;
654 len += sprintf(buffer+len, "%s\t", exp->ex_path);
655 len += sprintf(buffer+len, "%s", clp->cl_ident);
656 len += sprintf(buffer+len, "(");
658 len += exp_flags(buffer+len, exp->ex_flags);
659 len += sprintf(buffer+len, ") # ");
660 for (j = 0; j < clp->cl_naddr; j++) {
661 struct in_addr addr = clp->cl_addr[j];
663 head = &clnt_hash[CLIENT_HASH(addr.s_addr)];
664 for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) {
665 if (tmp->h_addr.s_addr == addr.s_addr) {
666 if (first++) len += sprintf(buffer+len, "%s", " ");
667 if (tmp->h_client != clp)
668 len += sprintf(buffer+len, "(");
669 len += sprintf(buffer+len, "%d.%d.%d.%d",
670 htonl(addr.s_addr) >> 24 & 0xff,
671 htonl(addr.s_addr) >> 16 & 0xff,
672 htonl(addr.s_addr) >> 8 & 0xff,
673 htonl(addr.s_addr) >> 0 & 0xff);
674 if (tmp->h_client != clp)
675 len += sprintf(buffer+len, ")");
676 break;
680 exp = exp->ex_next;
682 buffer[len++]='\n';
684 pos=begin+len;
685 if(pos<offset) {
686 len=0;
687 begin=pos;
689 if (pos > offset + length)
690 goto done;
695 *eof = 1;
697 done:
698 *start = buffer + (offset - begin);
699 len -= (offset - begin);
700 if ( len > length )
701 len = length;
702 return len;
706 * Add or modify a client.
707 * Change requests may involve the list of host addresses. The list of
708 * exports and possibly existing uid maps are left untouched.
711 exp_addclient(struct nfsctl_client *ncp)
713 struct svc_clnthash * ch[NFSCLNT_ADDRMAX];
714 svc_client * clp;
715 int i, err, change = 0, ilen;
717 /* First, consistency check. */
718 err = -EINVAL;
719 if (!(ilen = exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX)))
720 goto out;
721 if (ncp->cl_naddr > NFSCLNT_ADDRMAX)
722 goto out;
724 /* Lock the hashtable */
725 if ((err = exp_writelock()) < 0)
726 goto out;
728 /* First check if this is a change request for a client. */
729 for (clp = clients; clp; clp = clp->cl_next)
730 if (!strcmp(clp->cl_ident, ncp->cl_ident))
731 break;
733 err = -ENOMEM;
734 if (clp) {
735 change = 1;
736 } else {
737 if (!(clp = kmalloc(sizeof(*clp), GFP_KERNEL)))
738 goto out_unlock;
739 memset(clp, 0, sizeof(*clp));
741 dprintk("created client %s (%p)\n", ncp->cl_ident, clp);
743 strcpy(clp->cl_ident, ncp->cl_ident);
744 clp->cl_idlen = ilen;
747 /* Allocate hash buckets */
748 for (i = 0; i < ncp->cl_naddr; i++) {
749 ch[i] = kmalloc(sizeof(struct svc_clnthash), GFP_KERNEL);
750 if (!ch[i]) {
751 while (i--)
752 kfree(ch[i]);
753 if (!change)
754 kfree(clp);
755 goto out_unlock;
759 /* Copy addresses. */
760 for (i = 0; i < ncp->cl_naddr; i++) {
761 clp->cl_addr[i] = ncp->cl_addrlist[i];
763 clp->cl_naddr = ncp->cl_naddr;
765 /* Remove old client hash entries. */
766 if (change)
767 exp_unhashclient(clp);
769 /* Insert client into hashtable. */
770 for (i = 0; i < ncp->cl_naddr; i++) {
771 struct in_addr addr = clp->cl_addr[i];
772 int hash;
774 hash = CLIENT_HASH(addr.s_addr);
775 ch[i]->h_client = clp;
776 ch[i]->h_addr = addr;
777 ch[i]->h_next = clnt_hash[hash];
778 clnt_hash[hash] = ch[i];
781 if (!change) {
782 clp->cl_next = clients;
783 clients = clp;
785 err = 0;
787 out_unlock:
788 exp_unlock();
789 out:
790 return err;
794 * Delete a client given an identifier.
797 exp_delclient(struct nfsctl_client *ncp)
799 svc_client **clpp, *clp;
800 int err;
802 err = -EINVAL;
803 if (!exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX))
804 goto out;
806 /* Lock the hashtable */
807 if ((err = exp_writelock()) < 0)
808 goto out;
810 err = -EINVAL;
811 for (clpp = &clients; (clp = *clpp); clpp = &(clp->cl_next))
812 if (!strcmp(ncp->cl_ident, clp->cl_ident))
813 break;
815 if (clp) {
816 *clpp = clp->cl_next;
817 exp_freeclient(clp);
818 err = 0;
821 exp_unlock();
822 out:
823 return err;
827 * Free a client. The caller has already removed it from the client list.
829 static void
830 exp_freeclient(svc_client *clp)
832 exp_unhashclient(clp);
834 /* umap_free(&(clp->cl_umap)); */
835 exp_unexport_all(clp);
836 nfsd_lockd_unexport(clp);
837 kfree (clp);
841 * Remove client from hashtable. We first collect all hashtable
842 * entries and free them in one go.
843 * The hash table must be writelocked by the caller.
845 static void
846 exp_unhashclient(svc_client *clp)
848 struct svc_clnthash **hpp, *hp, *ch[NFSCLNT_ADDRMAX];
849 int i, count, err;
851 again:
852 err = 0;
853 for (i = 0, count = 0; i < CLIENT_HASHMAX && !err; i++) {
854 hpp = clnt_hash + i;
855 while ((hp = *hpp) && !err) {
856 if (hp->h_client == clp) {
857 *hpp = hp->h_next;
858 ch[count++] = hp;
859 err = (count >= NFSCLNT_ADDRMAX);
860 } else {
861 hpp = &(hp->h_next);
865 if (count != clp->cl_naddr)
866 printk(KERN_WARNING "nfsd: bad address count in freeclient!\n");
867 if (err)
868 goto again;
869 for (i = 0; i < count; i++)
870 kfree (ch[i]);
874 * Lockd is shutting down and tells us to unregister all clients
876 void
877 exp_nlmdetach(void)
879 struct svc_client *clp;
881 for (clp = clients; clp; clp = clp->cl_next)
882 nfsd_lockd_unexport(clp);
886 * Verify that string is non-empty and does not exceed max length.
888 static int
889 exp_verify_string(char *cp, int max)
891 int i;
893 for (i = 0; i < max; i++)
894 if (!cp[i])
895 return i;
896 cp[i] = 0;
897 printk(KERN_NOTICE "nfsd: couldn't validate string %s\n", cp);
898 return 0;
902 * Initialize the exports module.
904 void
905 nfsd_export_init(void)
907 int i;
909 dprintk("nfsd: initializing export module.\n");
910 if (initialized)
911 return;
912 for (i = 0; i < CLIENT_HASHMAX; i++)
913 clnt_hash[i] = NULL;
914 clients = NULL;
916 initialized = 1;
920 * Shutdown the exports module.
922 void
923 nfsd_export_shutdown(void)
925 int i;
927 dprintk("nfsd: shutting down export module.\n");
928 if (!initialized)
929 return;
930 if (exp_writelock() < 0) {
931 printk(KERN_WARNING "Weird: hashtable locked in exp_shutdown");
932 return;
934 for (i = 0; i < CLIENT_HASHMAX; i++) {
935 while (clnt_hash[i])
936 exp_freeclient(clnt_hash[i]->h_client);
938 clients = NULL; /* we may be restarted before the module unloads */
940 exp_unlock();
941 dprintk("nfsd: export shutdown complete.\n");