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