1 /*
2  * NFS exporting and validation.
3  *
4  * We maintain a list of clients, each of which has a list of
5  * exports. To export an fs to a given client, you first have
6  * to create the client entry with NFSCTL_ADDCLIENT, which
7  * creates a client control block and adds it to the hash
8  * table. Then, you call NFSCTL_EXPORT for each fs.
9  *
10  *
11  * Copyright (C) 1995, 1996 Olaf Kirch, <okir@monad.swb.de>
12  */
13 
14 #include <linux/slab.h>
15 #include <linux/namei.h>
16 #include <linux/module.h>
17 #include <linux/exportfs.h>
18 
19 #include <net/ipv6.h>
20 
21 #include "nfsd.h"
22 #include "nfsfh.h"
23 
24 #define NFSDDBG_FACILITY	NFSDDBG_EXPORT
25 
26 typedef struct auth_domain	svc_client;
27 typedef struct svc_export	svc_export;
28 
29 /*
30  * We have two caches.
31  * One maps client+vfsmnt+dentry to export options - the export map
32  * The other maps client+filehandle-fragment to export options. - the expkey map
33  *
34  * The export options are actually stored in the first map, and the
35  * second map contains a reference to the entry in the first map.
36  */
37 
38 #define	EXPKEY_HASHBITS		8
39 #define	EXPKEY_HASHMAX		(1 << EXPKEY_HASHBITS)
40 #define	EXPKEY_HASHMASK		(EXPKEY_HASHMAX -1)
41 static struct cache_head *expkey_table[EXPKEY_HASHMAX];
42 
expkey_put(struct kref * ref)43 static void expkey_put(struct kref *ref)
44 {
45 	struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref);
46 
47 	if (test_bit(CACHE_VALID, &key->h.flags) &&
48 	    !test_bit(CACHE_NEGATIVE, &key->h.flags))
49 		path_put(&key->ek_path);
50 	auth_domain_put(key->ek_client);
51 	kfree(key);
52 }
53 
expkey_request(struct cache_detail * cd,struct cache_head * h,char ** bpp,int * blen)54 static void expkey_request(struct cache_detail *cd,
55 			   struct cache_head *h,
56 			   char **bpp, int *blen)
57 {
58 	/* client fsidtype \xfsid */
59 	struct svc_expkey *ek = container_of(h, struct svc_expkey, h);
60 	char type[5];
61 
62 	qword_add(bpp, blen, ek->ek_client->name);
63 	snprintf(type, 5, "%d", ek->ek_fsidtype);
64 	qword_add(bpp, blen, type);
65 	qword_addhex(bpp, blen, (char*)ek->ek_fsid, key_len(ek->ek_fsidtype));
66 	(*bpp)[-1] = '\n';
67 }
68 
expkey_upcall(struct cache_detail * cd,struct cache_head * h)69 static int expkey_upcall(struct cache_detail *cd, struct cache_head *h)
70 {
71 	return sunrpc_cache_pipe_upcall(cd, h, expkey_request);
72 }
73 
74 static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old);
75 static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *);
76 static struct cache_detail svc_expkey_cache;
77 
expkey_parse(struct cache_detail * cd,char * mesg,int mlen)78 static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
79 {
80 	/* client fsidtype fsid [path] */
81 	char *buf;
82 	int len;
83 	struct auth_domain *dom = NULL;
84 	int err;
85 	int fsidtype;
86 	char *ep;
87 	struct svc_expkey key;
88 	struct svc_expkey *ek = NULL;
89 
90 	if (mesg[mlen - 1] != '\n')
91 		return -EINVAL;
92 	mesg[mlen-1] = 0;
93 
94 	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
95 	err = -ENOMEM;
96 	if (!buf)
97 		goto out;
98 
99 	err = -EINVAL;
100 	if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
101 		goto out;
102 
103 	err = -ENOENT;
104 	dom = auth_domain_find(buf);
105 	if (!dom)
106 		goto out;
107 	dprintk("found domain %s\n", buf);
108 
109 	err = -EINVAL;
110 	if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
111 		goto out;
112 	fsidtype = simple_strtoul(buf, &ep, 10);
113 	if (*ep)
114 		goto out;
115 	dprintk("found fsidtype %d\n", fsidtype);
116 	if (key_len(fsidtype)==0) /* invalid type */
117 		goto out;
118 	if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
119 		goto out;
120 	dprintk("found fsid length %d\n", len);
121 	if (len != key_len(fsidtype))
122 		goto out;
123 
124 	/* OK, we seem to have a valid key */
125 	key.h.flags = 0;
126 	key.h.expiry_time = get_expiry(&mesg);
127 	if (key.h.expiry_time == 0)
128 		goto out;
129 
130 	key.ek_client = dom;
131 	key.ek_fsidtype = fsidtype;
132 	memcpy(key.ek_fsid, buf, len);
133 
134 	ek = svc_expkey_lookup(&key);
135 	err = -ENOMEM;
136 	if (!ek)
137 		goto out;
138 
139 	/* now we want a pathname, or empty meaning NEGATIVE  */
140 	err = -EINVAL;
141 	len = qword_get(&mesg, buf, PAGE_SIZE);
142 	if (len < 0)
143 		goto out;
144 	dprintk("Path seems to be <%s>\n", buf);
145 	err = 0;
146 	if (len == 0) {
147 		set_bit(CACHE_NEGATIVE, &key.h.flags);
148 		ek = svc_expkey_update(&key, ek);
149 		if (!ek)
150 			err = -ENOMEM;
151 	} else {
152 		err = kern_path(buf, 0, &key.ek_path);
153 		if (err)
154 			goto out;
155 
156 		dprintk("Found the path %s\n", buf);
157 
158 		ek = svc_expkey_update(&key, ek);
159 		if (!ek)
160 			err = -ENOMEM;
161 		path_put(&key.ek_path);
162 	}
163 	cache_flush();
164  out:
165 	if (ek)
166 		cache_put(&ek->h, &svc_expkey_cache);
167 	if (dom)
168 		auth_domain_put(dom);
169 	kfree(buf);
170 	return err;
171 }
172 
expkey_show(struct seq_file * m,struct cache_detail * cd,struct cache_head * h)173 static int expkey_show(struct seq_file *m,
174 		       struct cache_detail *cd,
175 		       struct cache_head *h)
176 {
177 	struct svc_expkey *ek ;
178 	int i;
179 
180 	if (h ==NULL) {
181 		seq_puts(m, "#domain fsidtype fsid [path]\n");
182 		return 0;
183 	}
184 	ek = container_of(h, struct svc_expkey, h);
185 	seq_printf(m, "%s %d 0x", ek->ek_client->name,
186 		   ek->ek_fsidtype);
187 	for (i=0; i < key_len(ek->ek_fsidtype)/4; i++)
188 		seq_printf(m, "%08x", ek->ek_fsid[i]);
189 	if (test_bit(CACHE_VALID, &h->flags) &&
190 	    !test_bit(CACHE_NEGATIVE, &h->flags)) {
191 		seq_printf(m, " ");
192 		seq_path(m, &ek->ek_path, "\\ \t\n");
193 	}
194 	seq_printf(m, "\n");
195 	return 0;
196 }
197 
expkey_match(struct cache_head * a,struct cache_head * b)198 static inline int expkey_match (struct cache_head *a, struct cache_head *b)
199 {
200 	struct svc_expkey *orig = container_of(a, struct svc_expkey, h);
201 	struct svc_expkey *new = container_of(b, struct svc_expkey, h);
202 
203 	if (orig->ek_fsidtype != new->ek_fsidtype ||
204 	    orig->ek_client != new->ek_client ||
205 	    memcmp(orig->ek_fsid, new->ek_fsid, key_len(orig->ek_fsidtype)) != 0)
206 		return 0;
207 	return 1;
208 }
209 
expkey_init(struct cache_head * cnew,struct cache_head * citem)210 static inline void expkey_init(struct cache_head *cnew,
211 				   struct cache_head *citem)
212 {
213 	struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);
214 	struct svc_expkey *item = container_of(citem, struct svc_expkey, h);
215 
216 	kref_get(&item->ek_client->ref);
217 	new->ek_client = item->ek_client;
218 	new->ek_fsidtype = item->ek_fsidtype;
219 
220 	memcpy(new->ek_fsid, item->ek_fsid, sizeof(new->ek_fsid));
221 }
222 
expkey_update(struct cache_head * cnew,struct cache_head * citem)223 static inline void expkey_update(struct cache_head *cnew,
224 				   struct cache_head *citem)
225 {
226 	struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);
227 	struct svc_expkey *item = container_of(citem, struct svc_expkey, h);
228 
229 	new->ek_path = item->ek_path;
230 	path_get(&item->ek_path);
231 }
232 
expkey_alloc(void)233 static struct cache_head *expkey_alloc(void)
234 {
235 	struct svc_expkey *i = kmalloc(sizeof(*i), GFP_KERNEL);
236 	if (i)
237 		return &i->h;
238 	else
239 		return NULL;
240 }
241 
242 static struct cache_detail svc_expkey_cache = {
243 	.owner		= THIS_MODULE,
244 	.hash_size	= EXPKEY_HASHMAX,
245 	.hash_table	= expkey_table,
246 	.name		= "nfsd.fh",
247 	.cache_put	= expkey_put,
248 	.cache_upcall	= expkey_upcall,
249 	.cache_parse	= expkey_parse,
250 	.cache_show	= expkey_show,
251 	.match		= expkey_match,
252 	.init		= expkey_init,
253 	.update       	= expkey_update,
254 	.alloc		= expkey_alloc,
255 };
256 
257 static int
svc_expkey_hash(struct svc_expkey * item)258 svc_expkey_hash(struct svc_expkey *item)
259 {
260 	int hash = item->ek_fsidtype;
261 	char * cp = (char*)item->ek_fsid;
262 	int len = key_len(item->ek_fsidtype);
263 
264 	hash ^= hash_mem(cp, len, EXPKEY_HASHBITS);
265 	hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS);
266 	hash &= EXPKEY_HASHMASK;
267 	return hash;
268 }
269 
270 static struct svc_expkey *
svc_expkey_lookup(struct svc_expkey * item)271 svc_expkey_lookup(struct svc_expkey *item)
272 {
273 	struct cache_head *ch;
274 	int hash = svc_expkey_hash(item);
275 
276 	ch = sunrpc_cache_lookup(&svc_expkey_cache, &item->h,
277 				 hash);
278 	if (ch)
279 		return container_of(ch, struct svc_expkey, h);
280 	else
281 		return NULL;
282 }
283 
284 static struct svc_expkey *
svc_expkey_update(struct svc_expkey * new,struct svc_expkey * old)285 svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old)
286 {
287 	struct cache_head *ch;
288 	int hash = svc_expkey_hash(new);
289 
290 	ch = sunrpc_cache_update(&svc_expkey_cache, &new->h,
291 				 &old->h, hash);
292 	if (ch)
293 		return container_of(ch, struct svc_expkey, h);
294 	else
295 		return NULL;
296 }
297 
298 
299 #define	EXPORT_HASHBITS		8
300 #define	EXPORT_HASHMAX		(1<< EXPORT_HASHBITS)
301 
302 static struct cache_head *export_table[EXPORT_HASHMAX];
303 
nfsd4_fslocs_free(struct nfsd4_fs_locations * fsloc)304 static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc)
305 {
306 	int i;
307 
308 	for (i = 0; i < fsloc->locations_count; i++) {
309 		kfree(fsloc->locations[i].path);
310 		kfree(fsloc->locations[i].hosts);
311 	}
312 	kfree(fsloc->locations);
313 }
314 
svc_export_put(struct kref * ref)315 static void svc_export_put(struct kref *ref)
316 {
317 	struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
318 	path_put(&exp->ex_path);
319 	auth_domain_put(exp->ex_client);
320 	nfsd4_fslocs_free(&exp->ex_fslocs);
321 	kfree(exp);
322 }
323 
svc_export_request(struct cache_detail * cd,struct cache_head * h,char ** bpp,int * blen)324 static void svc_export_request(struct cache_detail *cd,
325 			       struct cache_head *h,
326 			       char **bpp, int *blen)
327 {
328 	/*  client path */
329 	struct svc_export *exp = container_of(h, struct svc_export, h);
330 	char *pth;
331 
332 	qword_add(bpp, blen, exp->ex_client->name);
333 	pth = d_path(&exp->ex_path, *bpp, *blen);
334 	if (IS_ERR(pth)) {
335 		/* is this correct? */
336 		(*bpp)[0] = '\n';
337 		return;
338 	}
339 	qword_add(bpp, blen, pth);
340 	(*bpp)[-1] = '\n';
341 }
342 
svc_export_upcall(struct cache_detail * cd,struct cache_head * h)343 static int svc_export_upcall(struct cache_detail *cd, struct cache_head *h)
344 {
345 	return sunrpc_cache_pipe_upcall(cd, h, svc_export_request);
346 }
347 
348 static struct svc_export *svc_export_update(struct svc_export *new,
349 					    struct svc_export *old);
350 static struct svc_export *svc_export_lookup(struct svc_export *);
351 
check_export(struct inode * inode,int * flags,unsigned char * uuid)352 static int check_export(struct inode *inode, int *flags, unsigned char *uuid)
353 {
354 
355 	/*
356 	 * We currently export only dirs, regular files, and (for v4
357 	 * pseudoroot) symlinks.
358 	 */
359 	if (!S_ISDIR(inode->i_mode) &&
360 	    !S_ISLNK(inode->i_mode) &&
361 	    !S_ISREG(inode->i_mode))
362 		return -ENOTDIR;
363 
364 	/*
365 	 * Mountd should never pass down a writeable V4ROOT export, but,
366 	 * just to make sure:
367 	 */
368 	if (*flags & NFSEXP_V4ROOT)
369 		*flags |= NFSEXP_READONLY;
370 
371 	/* There are two requirements on a filesystem to be exportable.
372 	 * 1:  We must be able to identify the filesystem from a number.
373 	 *       either a device number (so FS_REQUIRES_DEV needed)
374 	 *       or an FSID number (so NFSEXP_FSID or ->uuid is needed).
375 	 * 2:  We must be able to find an inode from a filehandle.
376 	 *       This means that s_export_op must be set.
377 	 */
378 	if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) &&
379 	    !(*flags & NFSEXP_FSID) &&
380 	    uuid == NULL) {
381 		dprintk("exp_export: export of non-dev fs without fsid\n");
382 		return -EINVAL;
383 	}
384 
385 	if (!inode->i_sb->s_export_op ||
386 	    !inode->i_sb->s_export_op->fh_to_dentry) {
387 		dprintk("exp_export: export of invalid fs type.\n");
388 		return -EINVAL;
389 	}
390 
391 	return 0;
392 
393 }
394 
395 #ifdef CONFIG_NFSD_V4
396 
397 static int
fsloc_parse(char ** mesg,char * buf,struct nfsd4_fs_locations * fsloc)398 fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc)
399 {
400 	int len;
401 	int migrated, i, err;
402 
403 	/* listsize */
404 	err = get_uint(mesg, &fsloc->locations_count);
405 	if (err)
406 		return err;
407 	if (fsloc->locations_count > MAX_FS_LOCATIONS)
408 		return -EINVAL;
409 	if (fsloc->locations_count == 0)
410 		return 0;
411 
412 	fsloc->locations = kzalloc(fsloc->locations_count
413 			* sizeof(struct nfsd4_fs_location), GFP_KERNEL);
414 	if (!fsloc->locations)
415 		return -ENOMEM;
416 	for (i=0; i < fsloc->locations_count; i++) {
417 		/* colon separated host list */
418 		err = -EINVAL;
419 		len = qword_get(mesg, buf, PAGE_SIZE);
420 		if (len <= 0)
421 			goto out_free_all;
422 		err = -ENOMEM;
423 		fsloc->locations[i].hosts = kstrdup(buf, GFP_KERNEL);
424 		if (!fsloc->locations[i].hosts)
425 			goto out_free_all;
426 		err = -EINVAL;
427 		/* slash separated path component list */
428 		len = qword_get(mesg, buf, PAGE_SIZE);
429 		if (len <= 0)
430 			goto out_free_all;
431 		err = -ENOMEM;
432 		fsloc->locations[i].path = kstrdup(buf, GFP_KERNEL);
433 		if (!fsloc->locations[i].path)
434 			goto out_free_all;
435 	}
436 	/* migrated */
437 	err = get_int(mesg, &migrated);
438 	if (err)
439 		goto out_free_all;
440 	err = -EINVAL;
441 	if (migrated < 0 || migrated > 1)
442 		goto out_free_all;
443 	fsloc->migrated = migrated;
444 	return 0;
445 out_free_all:
446 	nfsd4_fslocs_free(fsloc);
447 	return err;
448 }
449 
secinfo_parse(char ** mesg,char * buf,struct svc_export * exp)450 static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp)
451 {
452 	int listsize, err;
453 	struct exp_flavor_info *f;
454 
455 	err = get_int(mesg, &listsize);
456 	if (err)
457 		return err;
458 	if (listsize < 0 || listsize > MAX_SECINFO_LIST)
459 		return -EINVAL;
460 
461 	for (f = exp->ex_flavors; f < exp->ex_flavors + listsize; f++) {
462 		err = get_uint(mesg, &f->pseudoflavor);
463 		if (err)
464 			return err;
465 		/*
466 		 * XXX: It would be nice to also check whether this
467 		 * pseudoflavor is supported, so we can discover the
468 		 * problem at export time instead of when a client fails
469 		 * to authenticate.
470 		 */
471 		err = get_uint(mesg, &f->flags);
472 		if (err)
473 			return err;
474 		/* Only some flags are allowed to differ between flavors: */
475 		if (~NFSEXP_SECINFO_FLAGS & (f->flags ^ exp->ex_flags))
476 			return -EINVAL;
477 	}
478 	exp->ex_nflavors = listsize;
479 	return 0;
480 }
481 
482 #else /* CONFIG_NFSD_V4 */
483 static inline int
fsloc_parse(char ** mesg,char * buf,struct nfsd4_fs_locations * fsloc)484 fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc){return 0;}
485 static inline int
secinfo_parse(char ** mesg,char * buf,struct svc_export * exp)486 secinfo_parse(char **mesg, char *buf, struct svc_export *exp) { return 0; }
487 #endif
488 
svc_export_parse(struct cache_detail * cd,char * mesg,int mlen)489 static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
490 {
491 	/* client path expiry [flags anonuid anongid fsid] */
492 	char *buf;
493 	int len;
494 	int err;
495 	struct auth_domain *dom = NULL;
496 	struct svc_export exp = {}, *expp;
497 	int an_int;
498 
499 	if (mesg[mlen-1] != '\n')
500 		return -EINVAL;
501 	mesg[mlen-1] = 0;
502 
503 	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
504 	if (!buf)
505 		return -ENOMEM;
506 
507 	/* client */
508 	err = -EINVAL;
509 	len = qword_get(&mesg, buf, PAGE_SIZE);
510 	if (len <= 0)
511 		goto out;
512 
513 	err = -ENOENT;
514 	dom = auth_domain_find(buf);
515 	if (!dom)
516 		goto out;
517 
518 	/* path */
519 	err = -EINVAL;
520 	if ((len = qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
521 		goto out1;
522 
523 	err = kern_path(buf, 0, &exp.ex_path);
524 	if (err)
525 		goto out1;
526 
527 	exp.ex_client = dom;
528 
529 	/* expiry */
530 	err = -EINVAL;
531 	exp.h.expiry_time = get_expiry(&mesg);
532 	if (exp.h.expiry_time == 0)
533 		goto out3;
534 
535 	/* flags */
536 	err = get_int(&mesg, &an_int);
537 	if (err == -ENOENT) {
538 		err = 0;
539 		set_bit(CACHE_NEGATIVE, &exp.h.flags);
540 	} else {
541 		if (err || an_int < 0)
542 			goto out3;
543 		exp.ex_flags= an_int;
544 
545 		/* anon uid */
546 		err = get_int(&mesg, &an_int);
547 		if (err)
548 			goto out3;
549 		exp.ex_anon_uid= an_int;
550 
551 		/* anon gid */
552 		err = get_int(&mesg, &an_int);
553 		if (err)
554 			goto out3;
555 		exp.ex_anon_gid= an_int;
556 
557 		/* fsid */
558 		err = get_int(&mesg, &an_int);
559 		if (err)
560 			goto out3;
561 		exp.ex_fsid = an_int;
562 
563 		while ((len = qword_get(&mesg, buf, PAGE_SIZE)) > 0) {
564 			if (strcmp(buf, "fsloc") == 0)
565 				err = fsloc_parse(&mesg, buf, &exp.ex_fslocs);
566 			else if (strcmp(buf, "uuid") == 0) {
567 				/* expect a 16 byte uuid encoded as \xXXXX... */
568 				len = qword_get(&mesg, buf, PAGE_SIZE);
569 				if (len != 16)
570 					err  = -EINVAL;
571 				else {
572 					exp.ex_uuid =
573 						kmemdup(buf, 16, GFP_KERNEL);
574 					if (exp.ex_uuid == NULL)
575 						err = -ENOMEM;
576 				}
577 			} else if (strcmp(buf, "secinfo") == 0)
578 				err = secinfo_parse(&mesg, buf, &exp);
579 			else
580 				/* quietly ignore unknown words and anything
581 				 * following. Newer user-space can try to set
582 				 * new values, then see what the result was.
583 				 */
584 				break;
585 			if (err)
586 				goto out4;
587 		}
588 
589 		err = check_export(exp.ex_path.dentry->d_inode, &exp.ex_flags,
590 				   exp.ex_uuid);
591 		if (err)
592 			goto out4;
593 	}
594 
595 	expp = svc_export_lookup(&exp);
596 	if (expp)
597 		expp = svc_export_update(&exp, expp);
598 	else
599 		err = -ENOMEM;
600 	cache_flush();
601 	if (expp == NULL)
602 		err = -ENOMEM;
603 	else
604 		exp_put(expp);
605 out4:
606 	nfsd4_fslocs_free(&exp.ex_fslocs);
607 	kfree(exp.ex_uuid);
608 out3:
609 	path_put(&exp.ex_path);
610 out1:
611 	auth_domain_put(dom);
612 out:
613 	kfree(buf);
614 	return err;
615 }
616 
617 static void exp_flags(struct seq_file *m, int flag, int fsid,
618 		uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs);
619 static void show_secinfo(struct seq_file *m, struct svc_export *exp);
620 
svc_export_show(struct seq_file * m,struct cache_detail * cd,struct cache_head * h)621 static int svc_export_show(struct seq_file *m,
622 			   struct cache_detail *cd,
623 			   struct cache_head *h)
624 {
625 	struct svc_export *exp ;
626 
627 	if (h ==NULL) {
628 		seq_puts(m, "#path domain(flags)\n");
629 		return 0;
630 	}
631 	exp = container_of(h, struct svc_export, h);
632 	seq_path(m, &exp->ex_path, " \t\n\\");
633 	seq_putc(m, '\t');
634 	seq_escape(m, exp->ex_client->name, " \t\n\\");
635 	seq_putc(m, '(');
636 	if (test_bit(CACHE_VALID, &h->flags) &&
637 	    !test_bit(CACHE_NEGATIVE, &h->flags)) {
638 		exp_flags(m, exp->ex_flags, exp->ex_fsid,
639 			  exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs);
640 		if (exp->ex_uuid) {
641 			int i;
642 			seq_puts(m, ",uuid=");
643 			for (i=0; i<16; i++) {
644 				if ((i&3) == 0 && i)
645 					seq_putc(m, ':');
646 				seq_printf(m, "%02x", exp->ex_uuid[i]);
647 			}
648 		}
649 		show_secinfo(m, exp);
650 	}
651 	seq_puts(m, ")\n");
652 	return 0;
653 }
svc_export_match(struct cache_head * a,struct cache_head * b)654 static int svc_export_match(struct cache_head *a, struct cache_head *b)
655 {
656 	struct svc_export *orig = container_of(a, struct svc_export, h);
657 	struct svc_export *new = container_of(b, struct svc_export, h);
658 	return orig->ex_client == new->ex_client &&
659 		orig->ex_path.dentry == new->ex_path.dentry &&
660 		orig->ex_path.mnt == new->ex_path.mnt;
661 }
662 
svc_export_init(struct cache_head * cnew,struct cache_head * citem)663 static void svc_export_init(struct cache_head *cnew, struct cache_head *citem)
664 {
665 	struct svc_export *new = container_of(cnew, struct svc_export, h);
666 	struct svc_export *item = container_of(citem, struct svc_export, h);
667 
668 	kref_get(&item->ex_client->ref);
669 	new->ex_client = item->ex_client;
670 	new->ex_path.dentry = dget(item->ex_path.dentry);
671 	new->ex_path.mnt = mntget(item->ex_path.mnt);
672 	new->ex_fslocs.locations = NULL;
673 	new->ex_fslocs.locations_count = 0;
674 	new->ex_fslocs.migrated = 0;
675 }
676 
export_update(struct cache_head * cnew,struct cache_head * citem)677 static void export_update(struct cache_head *cnew, struct cache_head *citem)
678 {
679 	struct svc_export *new = container_of(cnew, struct svc_export, h);
680 	struct svc_export *item = container_of(citem, struct svc_export, h);
681 	int i;
682 
683 	new->ex_flags = item->ex_flags;
684 	new->ex_anon_uid = item->ex_anon_uid;
685 	new->ex_anon_gid = item->ex_anon_gid;
686 	new->ex_fsid = item->ex_fsid;
687 	new->ex_uuid = item->ex_uuid;
688 	item->ex_uuid = NULL;
689 	new->ex_fslocs.locations = item->ex_fslocs.locations;
690 	item->ex_fslocs.locations = NULL;
691 	new->ex_fslocs.locations_count = item->ex_fslocs.locations_count;
692 	item->ex_fslocs.locations_count = 0;
693 	new->ex_fslocs.migrated = item->ex_fslocs.migrated;
694 	item->ex_fslocs.migrated = 0;
695 	new->ex_nflavors = item->ex_nflavors;
696 	for (i = 0; i < MAX_SECINFO_LIST; i++) {
697 		new->ex_flavors[i] = item->ex_flavors[i];
698 	}
699 }
700 
svc_export_alloc(void)701 static struct cache_head *svc_export_alloc(void)
702 {
703 	struct svc_export *i = kmalloc(sizeof(*i), GFP_KERNEL);
704 	if (i)
705 		return &i->h;
706 	else
707 		return NULL;
708 }
709 
710 struct cache_detail svc_export_cache = {
711 	.owner		= THIS_MODULE,
712 	.hash_size	= EXPORT_HASHMAX,
713 	.hash_table	= export_table,
714 	.name		= "nfsd.export",
715 	.cache_put	= svc_export_put,
716 	.cache_upcall	= svc_export_upcall,
717 	.cache_parse	= svc_export_parse,
718 	.cache_show	= svc_export_show,
719 	.match		= svc_export_match,
720 	.init		= svc_export_init,
721 	.update		= export_update,
722 	.alloc		= svc_export_alloc,
723 };
724 
725 static int
svc_export_hash(struct svc_export * exp)726 svc_export_hash(struct svc_export *exp)
727 {
728 	int hash;
729 
730 	hash = hash_ptr(exp->ex_client, EXPORT_HASHBITS);
731 	hash ^= hash_ptr(exp->ex_path.dentry, EXPORT_HASHBITS);
732 	hash ^= hash_ptr(exp->ex_path.mnt, EXPORT_HASHBITS);
733 	return hash;
734 }
735 
736 static struct svc_export *
svc_export_lookup(struct svc_export * exp)737 svc_export_lookup(struct svc_export *exp)
738 {
739 	struct cache_head *ch;
740 	int hash = svc_export_hash(exp);
741 
742 	ch = sunrpc_cache_lookup(&svc_export_cache, &exp->h,
743 				 hash);
744 	if (ch)
745 		return container_of(ch, struct svc_export, h);
746 	else
747 		return NULL;
748 }
749 
750 static struct svc_export *
svc_export_update(struct svc_export * new,struct svc_export * old)751 svc_export_update(struct svc_export *new, struct svc_export *old)
752 {
753 	struct cache_head *ch;
754 	int hash = svc_export_hash(old);
755 
756 	ch = sunrpc_cache_update(&svc_export_cache, &new->h,
757 				 &old->h,
758 				 hash);
759 	if (ch)
760 		return container_of(ch, struct svc_export, h);
761 	else
762 		return NULL;
763 }
764 
765 
766 static struct svc_expkey *
exp_find_key(svc_client * clp,int fsid_type,u32 * fsidv,struct cache_req * reqp)767 exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
768 {
769 	struct svc_expkey key, *ek;
770 	int err;
771 
772 	if (!clp)
773 		return ERR_PTR(-ENOENT);
774 
775 	key.ek_client = clp;
776 	key.ek_fsidtype = fsid_type;
777 	memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
778 
779 	ek = svc_expkey_lookup(&key);
780 	if (ek == NULL)
781 		return ERR_PTR(-ENOMEM);
782 	err = cache_check(&svc_expkey_cache, &ek->h, reqp);
783 	if (err)
784 		return ERR_PTR(err);
785 	return ek;
786 }
787 
788 
exp_get_by_name(svc_client * clp,const struct path * path,struct cache_req * reqp)789 static svc_export *exp_get_by_name(svc_client *clp, const struct path *path,
790 				     struct cache_req *reqp)
791 {
792 	struct svc_export *exp, key;
793 	int err;
794 
795 	if (!clp)
796 		return ERR_PTR(-ENOENT);
797 
798 	key.ex_client = clp;
799 	key.ex_path = *path;
800 
801 	exp = svc_export_lookup(&key);
802 	if (exp == NULL)
803 		return ERR_PTR(-ENOMEM);
804 	err = cache_check(&svc_export_cache, &exp->h, reqp);
805 	if (err)
806 		return ERR_PTR(err);
807 	return exp;
808 }
809 
810 /*
811  * Find the export entry for a given dentry.
812  */
exp_parent(svc_client * clp,struct path * path)813 static struct svc_export *exp_parent(svc_client *clp, struct path *path)
814 {
815 	struct dentry *saved = dget(path->dentry);
816 	svc_export *exp = exp_get_by_name(clp, path, NULL);
817 
818 	while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
819 		struct dentry *parent = dget_parent(path->dentry);
820 		dput(path->dentry);
821 		path->dentry = parent;
822 		exp = exp_get_by_name(clp, path, NULL);
823 	}
824 	dput(path->dentry);
825 	path->dentry = saved;
826 	return exp;
827 }
828 
829 
830 
831 /*
832  * Obtain the root fh on behalf of a client.
833  * This could be done in user space, but I feel that it adds some safety
834  * since its harder to fool a kernel module than a user space program.
835  */
836 int
exp_rootfh(svc_client * clp,char * name,struct knfsd_fh * f,int maxsize)837 exp_rootfh(svc_client *clp, char *name, struct knfsd_fh *f, int maxsize)
838 {
839 	struct svc_export	*exp;
840 	struct path		path;
841 	struct inode		*inode;
842 	struct svc_fh		fh;
843 	int			err;
844 
845 	err = -EPERM;
846 	/* NB: we probably ought to check that it's NUL-terminated */
847 	if (kern_path(name, 0, &path)) {
848 		printk("nfsd: exp_rootfh path not found %s", name);
849 		return err;
850 	}
851 	inode = path.dentry->d_inode;
852 
853 	dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n",
854 		 name, path.dentry, clp->name,
855 		 inode->i_sb->s_id, inode->i_ino);
856 	exp = exp_parent(clp, &path);
857 	if (IS_ERR(exp)) {
858 		err = PTR_ERR(exp);
859 		goto out;
860 	}
861 
862 	/*
863 	 * fh must be initialized before calling fh_compose
864 	 */
865 	fh_init(&fh, maxsize);
866 	if (fh_compose(&fh, exp, path.dentry, NULL))
867 		err = -EINVAL;
868 	else
869 		err = 0;
870 	memcpy(f, &fh.fh_handle, sizeof(struct knfsd_fh));
871 	fh_put(&fh);
872 	exp_put(exp);
873 out:
874 	path_put(&path);
875 	return err;
876 }
877 
exp_find(struct auth_domain * clp,int fsid_type,u32 * fsidv,struct cache_req * reqp)878 static struct svc_export *exp_find(struct auth_domain *clp, int fsid_type,
879 				   u32 *fsidv, struct cache_req *reqp)
880 {
881 	struct svc_export *exp;
882 	struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);
883 	if (IS_ERR(ek))
884 		return ERR_CAST(ek);
885 
886 	exp = exp_get_by_name(clp, &ek->ek_path, reqp);
887 	cache_put(&ek->h, &svc_expkey_cache);
888 
889 	if (IS_ERR(exp))
890 		return ERR_CAST(exp);
891 	return exp;
892 }
893 
check_nfsd_access(struct svc_export * exp,struct svc_rqst * rqstp)894 __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
895 {
896 	struct exp_flavor_info *f;
897 	struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
898 
899 	/* legacy gss-only clients are always OK: */
900 	if (exp->ex_client == rqstp->rq_gssclient)
901 		return 0;
902 	/* ip-address based client; check sec= export option: */
903 	for (f = exp->ex_flavors; f < end; f++) {
904 		if (f->pseudoflavor == rqstp->rq_flavor)
905 			return 0;
906 	}
907 	/* defaults in absence of sec= options: */
908 	if (exp->ex_nflavors == 0) {
909 		if (rqstp->rq_flavor == RPC_AUTH_NULL ||
910 		    rqstp->rq_flavor == RPC_AUTH_UNIX)
911 			return 0;
912 	}
913 	return nfserr_wrongsec;
914 }
915 
916 /*
917  * Uses rq_client and rq_gssclient to find an export; uses rq_client (an
918  * auth_unix client) if it's available and has secinfo information;
919  * otherwise, will try to use rq_gssclient.
920  *
921  * Called from functions that handle requests; functions that do work on
922  * behalf of mountd are passed a single client name to use, and should
923  * use exp_get_by_name() or exp_find().
924  */
925 struct svc_export *
rqst_exp_get_by_name(struct svc_rqst * rqstp,struct path * path)926 rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path)
927 {
928 	struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
929 
930 	if (rqstp->rq_client == NULL)
931 		goto gss;
932 
933 	/* First try the auth_unix client: */
934 	exp = exp_get_by_name(rqstp->rq_client, path, &rqstp->rq_chandle);
935 	if (PTR_ERR(exp) == -ENOENT)
936 		goto gss;
937 	if (IS_ERR(exp))
938 		return exp;
939 	/* If it has secinfo, assume there are no gss/... clients */
940 	if (exp->ex_nflavors > 0)
941 		return exp;
942 gss:
943 	/* Otherwise, try falling back on gss client */
944 	if (rqstp->rq_gssclient == NULL)
945 		return exp;
946 	gssexp = exp_get_by_name(rqstp->rq_gssclient, path, &rqstp->rq_chandle);
947 	if (PTR_ERR(gssexp) == -ENOENT)
948 		return exp;
949 	if (!IS_ERR(exp))
950 		exp_put(exp);
951 	return gssexp;
952 }
953 
954 struct svc_export *
rqst_exp_find(struct svc_rqst * rqstp,int fsid_type,u32 * fsidv)955 rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv)
956 {
957 	struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
958 
959 	if (rqstp->rq_client == NULL)
960 		goto gss;
961 
962 	/* First try the auth_unix client: */
963 	exp = exp_find(rqstp->rq_client, fsid_type, fsidv, &rqstp->rq_chandle);
964 	if (PTR_ERR(exp) == -ENOENT)
965 		goto gss;
966 	if (IS_ERR(exp))
967 		return exp;
968 	/* If it has secinfo, assume there are no gss/... clients */
969 	if (exp->ex_nflavors > 0)
970 		return exp;
971 gss:
972 	/* Otherwise, try falling back on gss client */
973 	if (rqstp->rq_gssclient == NULL)
974 		return exp;
975 	gssexp = exp_find(rqstp->rq_gssclient, fsid_type, fsidv,
976 						&rqstp->rq_chandle);
977 	if (PTR_ERR(gssexp) == -ENOENT)
978 		return exp;
979 	if (!IS_ERR(exp))
980 		exp_put(exp);
981 	return gssexp;
982 }
983 
984 struct svc_export *
rqst_exp_parent(struct svc_rqst * rqstp,struct path * path)985 rqst_exp_parent(struct svc_rqst *rqstp, struct path *path)
986 {
987 	struct dentry *saved = dget(path->dentry);
988 	struct svc_export *exp = rqst_exp_get_by_name(rqstp, path);
989 
990 	while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
991 		struct dentry *parent = dget_parent(path->dentry);
992 		dput(path->dentry);
993 		path->dentry = parent;
994 		exp = rqst_exp_get_by_name(rqstp, path);
995 	}
996 	dput(path->dentry);
997 	path->dentry = saved;
998 	return exp;
999 }
1000 
rqst_find_fsidzero_export(struct svc_rqst * rqstp)1001 struct svc_export *rqst_find_fsidzero_export(struct svc_rqst *rqstp)
1002 {
1003 	u32 fsidv[2];
1004 
1005 	mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
1006 
1007 	return rqst_exp_find(rqstp, FSID_NUM, fsidv);
1008 }
1009 
1010 /*
1011  * Called when we need the filehandle for the root of the pseudofs,
1012  * for a given NFSv4 client.   The root is defined to be the
1013  * export point with fsid==0
1014  */
1015 __be32
exp_pseudoroot(struct svc_rqst * rqstp,struct svc_fh * fhp)1016 exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
1017 {
1018 	struct svc_export *exp;
1019 	__be32 rv;
1020 
1021 	exp = rqst_find_fsidzero_export(rqstp);
1022 	if (IS_ERR(exp))
1023 		return nfserrno(PTR_ERR(exp));
1024 	rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL);
1025 	exp_put(exp);
1026 	return rv;
1027 }
1028 
1029 /* Iterator */
1030 
e_start(struct seq_file * m,loff_t * pos)1031 static void *e_start(struct seq_file *m, loff_t *pos)
1032 	__acquires(svc_export_cache.hash_lock)
1033 {
1034 	loff_t n = *pos;
1035 	unsigned hash, export;
1036 	struct cache_head *ch;
1037 
1038 	read_lock(&svc_export_cache.hash_lock);
1039 	if (!n--)
1040 		return SEQ_START_TOKEN;
1041 	hash = n >> 32;
1042 	export = n & ((1LL<<32) - 1);
1043 
1044 
1045 	for (ch=export_table[hash]; ch; ch=ch->next)
1046 		if (!export--)
1047 			return ch;
1048 	n &= ~((1LL<<32) - 1);
1049 	do {
1050 		hash++;
1051 		n += 1LL<<32;
1052 	} while(hash < EXPORT_HASHMAX && export_table[hash]==NULL);
1053 	if (hash >= EXPORT_HASHMAX)
1054 		return NULL;
1055 	*pos = n+1;
1056 	return export_table[hash];
1057 }
1058 
e_next(struct seq_file * m,void * p,loff_t * pos)1059 static void *e_next(struct seq_file *m, void *p, loff_t *pos)
1060 {
1061 	struct cache_head *ch = p;
1062 	int hash = (*pos >> 32);
1063 
1064 	if (p == SEQ_START_TOKEN)
1065 		hash = 0;
1066 	else if (ch->next == NULL) {
1067 		hash++;
1068 		*pos += 1LL<<32;
1069 	} else {
1070 		++*pos;
1071 		return ch->next;
1072 	}
1073 	*pos &= ~((1LL<<32) - 1);
1074 	while (hash < EXPORT_HASHMAX && export_table[hash] == NULL) {
1075 		hash++;
1076 		*pos += 1LL<<32;
1077 	}
1078 	if (hash >= EXPORT_HASHMAX)
1079 		return NULL;
1080 	++*pos;
1081 	return export_table[hash];
1082 }
1083 
e_stop(struct seq_file * m,void * p)1084 static void e_stop(struct seq_file *m, void *p)
1085 	__releases(svc_export_cache.hash_lock)
1086 {
1087 	read_unlock(&svc_export_cache.hash_lock);
1088 }
1089 
1090 static struct flags {
1091 	int flag;
1092 	char *name[2];
1093 } expflags[] = {
1094 	{ NFSEXP_READONLY, {"ro", "rw"}},
1095 	{ NFSEXP_INSECURE_PORT, {"insecure", ""}},
1096 	{ NFSEXP_ROOTSQUASH, {"root_squash", "no_root_squash"}},
1097 	{ NFSEXP_ALLSQUASH, {"all_squash", ""}},
1098 	{ NFSEXP_ASYNC, {"async", "sync"}},
1099 	{ NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}},
1100 	{ NFSEXP_NOHIDE, {"nohide", ""}},
1101 	{ NFSEXP_CROSSMOUNT, {"crossmnt", ""}},
1102 	{ NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
1103 	{ NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
1104 	{ NFSEXP_V4ROOT, {"v4root", ""}},
1105 	{ 0, {"", ""}}
1106 };
1107 
show_expflags(struct seq_file * m,int flags,int mask)1108 static void show_expflags(struct seq_file *m, int flags, int mask)
1109 {
1110 	struct flags *flg;
1111 	int state, first = 0;
1112 
1113 	for (flg = expflags; flg->flag; flg++) {
1114 		if (flg->flag & ~mask)
1115 			continue;
1116 		state = (flg->flag & flags) ? 0 : 1;
1117 		if (*flg->name[state])
1118 			seq_printf(m, "%s%s", first++?",":"", flg->name[state]);
1119 	}
1120 }
1121 
show_secinfo_flags(struct seq_file * m,int flags)1122 static void show_secinfo_flags(struct seq_file *m, int flags)
1123 {
1124 	seq_printf(m, ",");
1125 	show_expflags(m, flags, NFSEXP_SECINFO_FLAGS);
1126 }
1127 
secinfo_flags_equal(int f,int g)1128 static bool secinfo_flags_equal(int f, int g)
1129 {
1130 	f &= NFSEXP_SECINFO_FLAGS;
1131 	g &= NFSEXP_SECINFO_FLAGS;
1132 	return f == g;
1133 }
1134 
show_secinfo_run(struct seq_file * m,struct exp_flavor_info ** fp,struct exp_flavor_info * end)1135 static int show_secinfo_run(struct seq_file *m, struct exp_flavor_info **fp, struct exp_flavor_info *end)
1136 {
1137 	int flags;
1138 
1139 	flags = (*fp)->flags;
1140 	seq_printf(m, ",sec=%d", (*fp)->pseudoflavor);
1141 	(*fp)++;
1142 	while (*fp != end && secinfo_flags_equal(flags, (*fp)->flags)) {
1143 		seq_printf(m, ":%d", (*fp)->pseudoflavor);
1144 		(*fp)++;
1145 	}
1146 	return flags;
1147 }
1148 
show_secinfo(struct seq_file * m,struct svc_export * exp)1149 static void show_secinfo(struct seq_file *m, struct svc_export *exp)
1150 {
1151 	struct exp_flavor_info *f;
1152 	struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
1153 	int flags;
1154 
1155 	if (exp->ex_nflavors == 0)
1156 		return;
1157 	f = exp->ex_flavors;
1158 	flags = show_secinfo_run(m, &f, end);
1159 	if (!secinfo_flags_equal(flags, exp->ex_flags))
1160 		show_secinfo_flags(m, flags);
1161 	while (f != end) {
1162 		flags = show_secinfo_run(m, &f, end);
1163 		show_secinfo_flags(m, flags);
1164 	}
1165 }
1166 
exp_flags(struct seq_file * m,int flag,int fsid,uid_t anonu,uid_t anong,struct nfsd4_fs_locations * fsloc)1167 static void exp_flags(struct seq_file *m, int flag, int fsid,
1168 		uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc)
1169 {
1170 	show_expflags(m, flag, NFSEXP_ALLFLAGS);
1171 	if (flag & NFSEXP_FSID)
1172 		seq_printf(m, ",fsid=%d", fsid);
1173 	if (anonu != (uid_t)-2 && anonu != (0x10000-2))
1174 		seq_printf(m, ",anonuid=%u", anonu);
1175 	if (anong != (gid_t)-2 && anong != (0x10000-2))
1176 		seq_printf(m, ",anongid=%u", anong);
1177 	if (fsloc && fsloc->locations_count > 0) {
1178 		char *loctype = (fsloc->migrated) ? "refer" : "replicas";
1179 		int i;
1180 
1181 		seq_printf(m, ",%s=", loctype);
1182 		seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\");
1183 		seq_putc(m, '@');
1184 		seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\");
1185 		for (i = 1; i < fsloc->locations_count; i++) {
1186 			seq_putc(m, ';');
1187 			seq_escape(m, fsloc->locations[i].path, ",;@ \t\n\\");
1188 			seq_putc(m, '@');
1189 			seq_escape(m, fsloc->locations[i].hosts, ",;@ \t\n\\");
1190 		}
1191 	}
1192 }
1193 
e_show(struct seq_file * m,void * p)1194 static int e_show(struct seq_file *m, void *p)
1195 {
1196 	struct cache_head *cp = p;
1197 	struct svc_export *exp = container_of(cp, struct svc_export, h);
1198 
1199 	if (p == SEQ_START_TOKEN) {
1200 		seq_puts(m, "# Version 1.1\n");
1201 		seq_puts(m, "# Path Client(Flags) # IPs\n");
1202 		return 0;
1203 	}
1204 
1205 	cache_get(&exp->h);
1206 	if (cache_check(&svc_export_cache, &exp->h, NULL))
1207 		return 0;
1208 	cache_put(&exp->h, &svc_export_cache);
1209 	return svc_export_show(m, &svc_export_cache, cp);
1210 }
1211 
1212 const struct seq_operations nfs_exports_op = {
1213 	.start	= e_start,
1214 	.next	= e_next,
1215 	.stop	= e_stop,
1216 	.show	= e_show,
1217 };
1218 
1219 
1220 /*
1221  * Initialize the exports module.
1222  */
1223 int
nfsd_export_init(void)1224 nfsd_export_init(void)
1225 {
1226 	int rv;
1227 	dprintk("nfsd: initializing export module.\n");
1228 
1229 	rv = cache_register_net(&svc_export_cache, &init_net);
1230 	if (rv)
1231 		return rv;
1232 	rv = cache_register_net(&svc_expkey_cache, &init_net);
1233 	if (rv)
1234 		cache_unregister_net(&svc_export_cache, &init_net);
1235 	return rv;
1236 
1237 }
1238 
1239 /*
1240  * Flush exports table - called when last nfsd thread is killed
1241  */
1242 void
nfsd_export_flush(void)1243 nfsd_export_flush(void)
1244 {
1245 	cache_purge(&svc_expkey_cache);
1246 	cache_purge(&svc_export_cache);
1247 }
1248 
1249 /*
1250  * Shutdown the exports module.
1251  */
1252 void
nfsd_export_shutdown(void)1253 nfsd_export_shutdown(void)
1254 {
1255 
1256 	dprintk("nfsd: shutting down export module.\n");
1257 
1258 	cache_unregister_net(&svc_expkey_cache, &init_net);
1259 	cache_unregister_net(&svc_export_cache, &init_net);
1260 	svcauth_unix_purge();
1261 
1262 	dprintk("nfsd: export shutdown complete.\n");
1263 }
1264