Import 2.3.1pre2
[davej-history.git] / fs / nfsd / export.c
blobf7d2cc551b65bd0120f3d9d4fa7f5bdb98f9cfa2
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 );
69 #define READLOCK 0
70 #define WRITELOCK 1
73 * Find a client's export for a device.
75 static inline svc_export *
76 exp_find(svc_client *clp, kdev_t dev)
78 svc_export * exp;
80 exp = clp->cl_export[EXPORT_HASH(dev)];
81 while (exp && exp->ex_dev != dev)
82 exp = exp->ex_next;
83 return exp;
87 * Find the client's export entry matching xdev/xino.
89 svc_export *
90 exp_get(svc_client *clp, kdev_t dev, ino_t ino)
92 svc_export * exp;
94 if (!clp)
95 return NULL;
97 exp = clp->cl_export[EXPORT_HASH(dev)];
98 if (exp)
99 do {
100 if (exp->ex_ino == ino && exp->ex_dev == dev)
101 goto out;
102 } while (NULL != (exp = exp->ex_next));
103 exp = NULL;
104 out:
105 return exp;
109 * Check whether there are any exports for a device.
111 static int
112 exp_device_in_use(kdev_t dev)
114 struct svc_client *clp;
116 for (clp = clients; clp; clp = clp->cl_next) {
117 if (exp_find(clp, dev))
118 return 1;
120 return 0;
124 * Look up the device of the parent fs.
126 static inline int
127 nfsd_parentdev(kdev_t *devp)
129 struct super_block *sb;
131 if (!(sb = get_super(*devp)) || !sb->s_root->d_covers)
132 return 0;
133 if (*devp == sb->s_root->d_covers->d_inode->i_dev)
134 return 0;
135 *devp = sb->s_root->d_covers->d_inode->i_dev;
136 return 1;
140 * Find the export entry for a given dentry. <gam3@acm.org>
142 static svc_export *
143 exp_parent(svc_client *clp, kdev_t dev, struct dentry *dentry)
145 svc_export *exp;
146 kdev_t xdev = dev;
147 struct dentry *xdentry = dentry;
148 struct dentry *ndentry = NULL;
150 if (clp == NULL || dentry == NULL)
151 return NULL;
153 do {
154 xdev = dev;
155 do {
156 exp = clp->cl_export[EXPORT_HASH(xdev)];
157 if (exp)
158 do {
159 ndentry = exp->ex_dentry;
160 if (ndentry == xdentry) {
161 #ifdef NFSD_PARANOIA
162 if (dev == xdev)
163 dprintk("nfsd: exp_parent submount over mount.\n");
164 else
165 dprintk("nfsd: exp_parent found.\n");
166 #endif
167 goto out;
169 } while (NULL != (exp = exp->ex_next));
170 } while (nfsd_parentdev(&xdev));
171 if (xdentry == xdentry->d_parent) {
172 break;
174 } while ((xdentry = xdentry->d_parent));
175 exp = NULL;
176 out:
177 return exp;
181 * Find the child export entry for a given fs. This function is used
182 * only by the export syscall to keep the export tree consistent.
183 * <gam3@acm.org>
185 static svc_export *
186 exp_child(svc_client *clp, kdev_t dev, struct dentry *dentry)
188 svc_export *exp;
189 struct dentry *xdentry = dentry;
190 struct dentry *ndentry = NULL;
192 if (clp == NULL || dentry == NULL)
193 return NULL;
195 exp = clp->cl_export[EXPORT_HASH(dev)];
196 if (exp)
197 do {
198 ndentry = exp->ex_dentry;
199 if (ndentry)
200 while ((ndentry = ndentry->d_parent)) {
201 if (ndentry == xdentry) {
202 #ifdef NFSD_PARANOIA
203 dprintk("nfsd: exp_child mount under submount.\n");
204 #endif
205 goto out;
207 if (ndentry == ndentry->d_parent)
208 break;
210 } while (NULL != (exp = exp->ex_next));
211 exp = NULL;
212 out:
213 return exp;
217 * Export a file system.
220 exp_export(struct nfsctl_export *nxp)
222 svc_client *clp;
223 svc_export *exp, *parent;
224 svc_export **head;
225 struct dentry *dentry = NULL;
226 struct inode *inode = NULL;
227 int i, err;
228 kdev_t dev;
229 ino_t ino;
231 /* Consistency check */
232 err = -EINVAL;
233 if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) ||
234 !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
235 goto out;
237 dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n",
238 nxp->ex_client, nxp->ex_path,
239 nxp->ex_dev, nxp->ex_ino, nxp->ex_flags);
240 dev = to_kdev_t(nxp->ex_dev);
241 ino = nxp->ex_ino;
243 /* Try to lock the export table for update */
244 if ((err = exp_writelock()) < 0)
245 goto out;
247 /* Look up client info */
248 err = -EINVAL;
249 if (!(clp = exp_getclientbyname(nxp->ex_client)))
250 goto out_unlock;
253 * If there's already an export for this file, assume this
254 * is just a flag update.
256 if ((exp = exp_get(clp, dev, ino)) != NULL) {
257 exp->ex_flags = nxp->ex_flags;
258 exp->ex_anon_uid = nxp->ex_anon_uid;
259 exp->ex_anon_gid = nxp->ex_anon_gid;
260 err = 0;
261 goto out_unlock;
264 /* Look up the dentry */
265 err = -EINVAL;
266 dentry = lookup_dentry(nxp->ex_path, NULL, 0);
267 if (IS_ERR(dentry))
268 goto out_unlock;
270 err = -ENOENT;
271 inode = dentry->d_inode;
272 if (!inode)
273 goto finish;
274 err = -EINVAL;
275 if (inode->i_dev != dev || inode->i_ino != nxp->ex_ino) {
276 printk(KERN_DEBUG "exp_export: i_dev = %x, dev = %x\n",
277 inode->i_dev, dev);
278 /* I'm just being paranoid... */
279 goto finish;
282 /* We currently export only dirs and regular files.
283 * This is what umountd does.
285 err = -ENOTDIR;
286 if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode))
287 goto finish;
289 err = -EINVAL;
290 if ((parent = exp_child(clp, dev, dentry)) != NULL) {
291 dprintk("exp_export: export not valid (Rule 3).\n");
292 goto finish;
294 /* Is this is a sub-export, must be a proper subset of FS */
295 if ((parent = exp_parent(clp, dev, dentry)) != NULL) {
296 if (dev == parent->ex_dev) {
297 dprintk("exp_export: sub-export not valid (Rule 2).\n");
298 goto finish;
302 err = -ENOMEM;
303 if (!(exp = kmalloc(sizeof(*exp), GFP_USER)))
304 goto finish;
305 dprintk("nfsd: created export entry %p for client %p\n", exp, clp);
307 strcpy(exp->ex_path, nxp->ex_path);
308 exp->ex_client = clp;
309 exp->ex_parent = parent;
310 exp->ex_dentry = dentry;
311 exp->ex_flags = nxp->ex_flags;
312 exp->ex_dev = dev;
313 exp->ex_ino = ino;
314 exp->ex_anon_uid = nxp->ex_anon_uid;
315 exp->ex_anon_gid = nxp->ex_anon_gid;
317 /* Update parent pointers of all exports */
318 if (parent) {
319 for (i = 0; i < NFSCLNT_EXPMAX; i++) {
320 svc_export *temp = clp->cl_export[i];
322 while (temp) {
323 if (temp->ex_parent == parent)
324 temp->ex_parent = exp;
325 temp = temp->ex_next;
330 head = clp->cl_export + EXPORT_HASH(dev);
331 exp->ex_next = *head;
332 *head = exp;
334 err = 0;
336 /* Unlock hashtable */
337 out_unlock:
338 exp_unlock();
339 out:
340 return err;
342 /* Release the dentry */
343 finish:
344 dput(dentry);
345 goto out_unlock;
349 * Unexport a file system. The export entry has already
350 * been removed from the client's list of exported fs's.
352 static void
353 exp_do_unexport(svc_export *unexp)
355 svc_export *exp;
356 svc_client *clp;
357 struct dentry *dentry;
358 struct inode *inode;
359 int i;
361 /* Update parent pointers. */
362 clp = unexp->ex_client;
363 for (i = 0; i < NFSCLNT_EXPMAX; i++) {
364 for (exp = clp->cl_export[i]; exp; exp = exp->ex_next)
365 if (exp->ex_parent == unexp)
366 exp->ex_parent = unexp->ex_parent;
370 * Check whether this is the last export for this device,
371 * and if so flush any cached dentries.
373 if (!exp_device_in_use(unexp->ex_dev)) {
374 printk("exp_do_unexport: %s last use, flushing cache\n",
375 kdevname(unexp->ex_dev));
376 nfsd_fh_flush(unexp->ex_dev);
379 dentry = unexp->ex_dentry;
380 inode = dentry->d_inode;
381 if (unexp->ex_dev != inode->i_dev || unexp->ex_ino != inode->i_ino)
382 printk(KERN_WARNING "nfsd: bad dentry in unexport!\n");
383 dput(dentry);
385 kfree(unexp);
389 * Revoke all exports for a given client.
390 * This may look very awkward, but we have to do it this way in order
391 * to avoid race conditions (aka mind the parent pointer).
393 static void
394 exp_unexport_all(svc_client *clp)
396 svc_export *exp;
397 int i;
399 dprintk("unexporting all fs's for clnt %p\n", clp);
400 for (i = 0; i < NFSCLNT_EXPMAX; i++) {
401 exp = clp->cl_export[i];
402 clp->cl_export[i] = NULL;
403 while (exp) {
404 svc_export *next = exp->ex_next;
405 exp_do_unexport(exp);
406 exp = next;
412 * unexport syscall.
415 exp_unexport(struct nfsctl_export *nxp)
417 svc_client *clp;
418 svc_export **expp, *exp = NULL;
419 int err;
421 /* Consistency check */
422 if (!exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
423 return -EINVAL;
425 if ((err = exp_writelock()) < 0)
426 goto out;
428 err = -EINVAL;
429 clp = exp_getclientbyname(nxp->ex_client);
430 if (clp) {
431 expp = clp->cl_export + EXPORT_HASH(nxp->ex_dev);
432 while ((exp = *expp) != NULL) {
433 if (exp->ex_dev == nxp->ex_dev) {
434 if (exp->ex_ino == nxp->ex_ino) {
435 *expp = exp->ex_next;
436 exp_do_unexport(exp);
437 err = 0;
438 break;
441 expp = &(exp->ex_next);
445 exp_unlock();
446 out:
447 return err;
451 * Obtain the root fh on behalf of a client.
452 * This could be done in user space, but I feel that it adds some safety
453 * since its harder to fool a kernel module than a user space program.
456 exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino,
457 char *path, struct knfs_fh *f)
459 struct svc_export *exp;
460 struct dentry *dentry = NULL;
461 struct inode *inode;
462 struct svc_fh fh;
463 int err;
465 err = -EPERM;
466 if (path) {
467 if (!(dentry = lookup_dentry(path, NULL, 0))) {
468 printk("nfsd: exp_rootfh path not found %s", path);
469 return -EPERM;
471 dev = dentry->d_inode->i_dev;
472 ino = dentry->d_inode->i_ino;
474 dprintk("nfsd: exp_rootfh(%s [%p] %s:%x/%ld)\n",
475 path, dentry, clp->cl_ident, dev, ino);
476 exp = exp_parent(clp, dev, dentry);
477 } else {
478 dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n",
479 clp->cl_ident, dev, ino);
480 if ((exp = exp_get(clp, dev, ino)))
481 if (!(dentry = dget(exp->ex_dentry))) {
482 printk("exp_rootfh: Aieee, NULL dentry\n");
483 return -EPERM;
486 if (!exp) {
487 dprintk("nfsd: exp_rootfh export not found.\n");
488 goto out;
491 inode = dentry->d_inode;
492 if (!inode) {
493 printk("exp_rootfh: Aieee, NULL d_inode\n");
494 goto out;
496 if (inode->i_dev != dev || inode->i_ino != ino) {
497 printk("exp_rootfh: Aieee, ino/dev mismatch\n");
498 printk("exp_rootfh: arg[dev(%x):ino(%ld)]"
499 " inode[dev(%x):ino(%ld)]\n",
500 dev, ino, inode->i_dev, inode->i_ino);
504 * fh must be initialized before calling fh_compose
506 fh_init(&fh);
507 fh_compose(&fh, exp, dentry);
508 memcpy(f, &fh.fh_handle, sizeof(struct knfs_fh));
509 fh_put(&fh);
510 return 0;
512 out:
513 dput(dentry);
514 return err;
518 * Hashtable locking. Write locks are placed only by user processes
519 * wanting to modify export information.
521 void
522 exp_readlock(void)
524 while (hash_lock || want_lock)
525 sleep_on(&hash_wait);
526 hash_count++;
530 exp_writelock(void)
532 /* fast track */
533 if (!hash_count && !hash_lock) {
534 lock_it:
535 hash_lock = 1;
536 return 0;
539 current->sigpending = 0;
540 want_lock++;
541 while (hash_count || hash_lock) {
542 interruptible_sleep_on(&hash_wait);
543 if (signal_pending(current))
544 break;
546 want_lock--;
548 /* restore the task's signals */
549 spin_lock_irq(&current->sigmask_lock);
550 recalc_sigpending(current);
551 spin_unlock_irq(&current->sigmask_lock);
553 if (!hash_count && !hash_lock)
554 goto lock_it;
555 return -EINTR;
558 void
559 exp_unlock(void)
561 if (!hash_count && !hash_lock)
562 printk(KERN_WARNING "exp_unlock: not locked!\n");
563 if (hash_count)
564 hash_count--;
565 else
566 hash_lock = 0;
567 wake_up(&hash_wait);
571 * Find a valid client given an inet address. We always move the most
572 * recently used client to the front of the hash chain to speed up
573 * future lookups.
574 * Locking against other processes is the responsibility of the caller.
576 struct svc_client *
577 exp_getclient(struct sockaddr_in *sin)
579 struct svc_clnthash **hp, **head, *tmp;
580 unsigned long addr = sin->sin_addr.s_addr;
582 if (!initialized)
583 return NULL;
585 head = &clnt_hash[CLIENT_HASH(addr)];
587 for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) {
588 if (tmp->h_addr.s_addr == addr) {
589 /* Move client to the front */
590 if (head != hp) {
591 *hp = tmp->h_next;
592 tmp->h_next = *head;
593 *head = tmp;
596 return tmp->h_client;
600 return NULL;
604 * Find a client given its identifier.
606 static svc_client *
607 exp_getclientbyname(char *ident)
609 svc_client * clp;
611 for (clp = clients; clp; clp = clp->cl_next) {
612 if (!strcmp(clp->cl_ident, ident))
613 return clp;
615 return NULL;
618 struct flags {
619 int flag;
620 char *name[2];
621 } expflags[] = {
622 { NFSEXP_READONLY, {"ro", "rw"}},
623 { NFSEXP_INSECURE_PORT, {"insecure", ""}},
624 { NFSEXP_ROOTSQUASH, {"root_squash", "no_root_squash"}},
625 { NFSEXP_ALLSQUASH, {"all_squash", ""}},
626 { NFSEXP_ASYNC, {"async", ""}},
627 { NFSEXP_GATHERED_WRITES, {"wdelay", ""}},
628 { NFSEXP_UIDMAP, {"uidmap", ""}},
629 { NFSEXP_KERBEROS, { "kerberos", ""}},
630 { NFSEXP_SUNSECURE, { "sunsecure", ""}},
631 { NFSEXP_CROSSMNT, {"crossmnt", ""}},
632 { 0, {"", ""}}
635 static int
636 exp_flags(char *buffer, int flag)
638 int len = 0, first = 0;
639 struct flags *flg = expflags;
641 for (;flg->flag;flg++) {
642 int state = (flg->flag & flag)?0:1;
643 if (!flg->flag)
644 break;
645 if (*flg->name[state]) {
646 len += sprintf(buffer + len, "%s%s",
647 first++?",":"", flg->name[state]);
650 return len;
654 exp_procfs_exports(char *buffer, char **start, off_t offset,
655 int length, int *eof, void *data)
657 struct svc_clnthash **hp, **head, *tmp;
658 struct svc_client *clp;
659 svc_export *exp;
660 off_t pos = 0;
661 off_t begin = 0;
662 int len = 0;
663 int i,j;
665 len += sprintf(buffer, "# Version 1.0\n");
666 len += sprintf(buffer+len, "# Path Client(Flags) # IPs\n");
668 for (clp = clients; clp; clp = clp->cl_next) {
669 for (i = 0; i < NFSCLNT_EXPMAX; i++) {
670 exp = clp->cl_export[i];
671 while (exp) {
672 int first = 0;
673 len += sprintf(buffer+len, "%s\t", exp->ex_path);
674 len += sprintf(buffer+len, "%s", clp->cl_ident);
675 len += sprintf(buffer+len, "(");
677 len += exp_flags(buffer+len, exp->ex_flags);
678 len += sprintf(buffer+len, ") # ");
679 for (j = 0; j < clp->cl_naddr; j++) {
680 struct in_addr addr = clp->cl_addr[j];
682 head = &clnt_hash[CLIENT_HASH(addr.s_addr)];
683 for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) {
684 if (tmp->h_addr.s_addr == addr.s_addr) {
685 if (first++) len += sprintf(buffer+len, "%s", " ");
686 if (tmp->h_client != clp)
687 len += sprintf(buffer+len, "(");
688 len += sprintf(buffer+len, "%ld.%ld.%ld.%ld",
689 htonl(addr.s_addr) >> 24 & 0xff,
690 htonl(addr.s_addr) >> 16 & 0xff,
691 htonl(addr.s_addr) >> 8 & 0xff,
692 htonl(addr.s_addr) >> 0 & 0xff);
693 if (tmp->h_client != clp)
694 len += sprintf(buffer+len, ")");
695 break;
699 exp = exp->ex_next;
701 buffer[len++]='\n';
703 pos=begin+len;
704 if(pos<offset) {
705 len=0;
706 begin=pos;
708 if (pos > offset + length)
709 goto done;
714 *eof = 1;
716 done:
717 *start = buffer + (offset - begin);
718 len -= (offset - begin);
719 if ( len > length )
720 len = length;
721 return len;
725 * Add or modify a client.
726 * Change requests may involve the list of host addresses. The list of
727 * exports and possibly existing uid maps are left untouched.
730 exp_addclient(struct nfsctl_client *ncp)
732 struct svc_clnthash * ch[NFSCLNT_ADDRMAX];
733 svc_client * clp;
734 int i, err, change = 0, ilen;
736 /* First, consistency check. */
737 err = -EINVAL;
738 if (!(ilen = exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX)))
739 goto out;
740 if (ncp->cl_naddr > NFSCLNT_ADDRMAX)
741 goto out;
743 /* Lock the hashtable */
744 if ((err = exp_writelock()) < 0)
745 goto out;
747 /* First check if this is a change request for a client. */
748 for (clp = clients; clp; clp = clp->cl_next)
749 if (!strcmp(clp->cl_ident, ncp->cl_ident))
750 break;
752 err = -ENOMEM;
753 if (clp) {
754 change = 1;
755 } else {
756 if (!(clp = kmalloc(sizeof(*clp), GFP_KERNEL)))
757 goto out_unlock;
758 memset(clp, 0, sizeof(*clp));
760 dprintk("created client %s (%p)\n", ncp->cl_ident, clp);
762 strcpy(clp->cl_ident, ncp->cl_ident);
763 clp->cl_idlen = ilen;
766 /* Allocate hash buckets */
767 for (i = 0; i < ncp->cl_naddr; i++) {
768 ch[i] = kmalloc(sizeof(struct svc_clnthash), GFP_KERNEL);
769 if (!ch[i]) {
770 while (i--)
771 kfree(ch[i]);
772 if (!change)
773 kfree(clp);
774 goto out_unlock;
778 /* Copy addresses. */
779 for (i = 0; i < ncp->cl_naddr; i++) {
780 clp->cl_addr[i] = ncp->cl_addrlist[i];
782 clp->cl_naddr = ncp->cl_naddr;
784 /* Remove old client hash entries. */
785 if (change)
786 exp_unhashclient(clp);
788 /* Insert client into hashtable. */
789 for (i = 0; i < ncp->cl_naddr; i++) {
790 struct in_addr addr = clp->cl_addr[i];
791 int hash;
793 hash = CLIENT_HASH(addr.s_addr);
794 ch[i]->h_client = clp;
795 ch[i]->h_addr = addr;
796 ch[i]->h_next = clnt_hash[hash];
797 clnt_hash[hash] = ch[i];
800 if (!change) {
801 clp->cl_next = clients;
802 clients = clp;
804 err = 0;
806 out_unlock:
807 exp_unlock();
808 out:
809 return err;
813 * Delete a client given an identifier.
816 exp_delclient(struct nfsctl_client *ncp)
818 svc_client **clpp, *clp;
819 int err;
821 err = -EINVAL;
822 if (!exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX))
823 goto out;
825 /* Lock the hashtable */
826 if ((err = exp_writelock()) < 0)
827 goto out;
829 err = -EINVAL;
830 for (clpp = &clients; (clp = *clpp); clpp = &(clp->cl_next))
831 if (!strcmp(ncp->cl_ident, clp->cl_ident))
832 break;
834 if (clp) {
835 *clpp = clp->cl_next;
836 exp_freeclient(clp);
837 err = 0;
840 exp_unlock();
841 out:
842 return err;
846 * Free a client. The caller has already removed it from the client list.
848 static void
849 exp_freeclient(svc_client *clp)
851 exp_unhashclient(clp);
853 /* umap_free(&(clp->cl_umap)); */
854 exp_unexport_all(clp);
855 nfsd_lockd_unexport(clp);
856 kfree (clp);
860 * Remove client from hashtable. We first collect all hashtable
861 * entries and free them in one go.
862 * The hash table must be writelocked by the caller.
864 static void
865 exp_unhashclient(svc_client *clp)
867 struct svc_clnthash **hpp, *hp, *ch[NFSCLNT_ADDRMAX];
868 int i, count, err;
870 again:
871 err = 0;
872 for (i = 0, count = 0; i < CLIENT_HASHMAX && !err; i++) {
873 hpp = clnt_hash + i;
874 while ((hp = *hpp) && !err) {
875 if (hp->h_client == clp) {
876 *hpp = hp->h_next;
877 ch[count++] = hp;
878 err = (count >= NFSCLNT_ADDRMAX);
879 } else {
880 hpp = &(hp->h_next);
884 if (count != clp->cl_naddr)
885 printk(KERN_WARNING "nfsd: bad address count in freeclient!\n");
886 if (err)
887 goto again;
888 for (i = 0; i < count; i++)
889 kfree (ch[i]);
893 * Lockd is shutting down and tells us to unregister all clients
895 void
896 exp_nlmdetach(void)
898 struct svc_client *clp;
900 for (clp = clients; clp; clp = clp->cl_next)
901 nfsd_lockd_unexport(clp);
905 * Verify that string is non-empty and does not exceed max length.
907 static int
908 exp_verify_string(char *cp, int max)
910 int i;
912 for (i = 0; i < max; i++)
913 if (!cp[i])
914 return i;
915 cp[i] = 0;
916 printk(KERN_NOTICE "nfsd: couldn't validate string %s\n", cp);
917 return 0;
921 * Initialize the exports module.
923 void
924 nfsd_export_init(void)
926 int i;
928 dprintk("nfsd: initializing export module.\n");
929 if (initialized)
930 return;
931 for (i = 0; i < CLIENT_HASHMAX; i++)
932 clnt_hash[i] = NULL;
933 clients = NULL;
935 initialized = 1;
939 * Shutdown the exports module.
941 void
942 nfsd_export_shutdown(void)
944 int i;
946 dprintk("nfsd: shutting down export module.\n");
947 if (!initialized)
948 return;
949 if (exp_writelock() < 0) {
950 printk(KERN_WARNING "Weird: hashtable locked in exp_shutdown");
951 return;
953 for (i = 0; i < CLIENT_HASHMAX; i++) {
954 while (clnt_hash[i])
955 exp_freeclient(clnt_hash[i]->h_client);
957 clients = NULL; /* we may be restarted before the module unloads */
959 exp_unlock();
960 dprintk("nfsd: export shutdown complete.\n");