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 *
exp_get(svc_client * clp,kdev_t dev,ino_t ino)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 *
exp_get_fsid(svc_client * clp,int fsid)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 *
exp_parent(svc_client * clp,kdev_t dev,struct dentry * dentry)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 *
exp_child(svc_client * clp,kdev_t dev,struct dentry * dentry)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 */
exp_change_parents(svc_client * clp,svc_export * old,svc_export * new)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 
exp_fsid_unhash(struct svc_export * exp)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 
exp_fsid_hash(struct svc_client * clp,struct svc_export * exp)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
exp_export(struct nfsctl_export * nxp)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
exp_do_unexport(svc_export * unexp)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
exp_unexport_all(svc_client * clp)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
exp_unexport(struct nfsctl_export * nxp)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
exp_rootfh(struct svc_client * clp,kdev_t dev,ino_t ino,char * path,struct knfsd_fh * f,int maxsize)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
exp_readlock(void)473 exp_readlock(void)
474 {
475 	while (hash_lock || want_lock)
476 		sleep_on(&hash_wait);
477 	hash_count++;
478 }
479 
480 int
exp_writelock(void)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
exp_unlock(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 *
exp_getclient(struct sockaddr_in * sin)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 *
exp_getclientbyname(char * ident)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 
e_start(struct seq_file * m,loff_t * pos)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 
e_next(struct seq_file * m,void * p,loff_t * pos)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 
e_stop(struct seq_file * m,void * p)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 
exp_flags(struct seq_file * m,int flag,int fsid)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 
mangle(struct seq_file * m,const char * s)666 static inline void mangle(struct seq_file *m, const char *s)
667 {
668 	seq_escape(m, s, " \t\n\\");
669 }
670 
e_show(struct seq_file * m,void * p)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
exp_addclient(struct nfsctl_client * ncp)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
exp_delclient(struct nfsctl_client * ncp)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
exp_freeclient(svc_client * clp)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
exp_unhashclient(svc_client * clp)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
exp_nlmdetach(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
exp_verify_string(char * cp,int max)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
nfsd_export_init(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
nfsd_export_shutdown(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 }
967