xref: /openbmc/linux/fs/nfsd/nfsctl.c (revision e8e0929d)
1 /*
2  * linux/fs/nfsd/nfsctl.c
3  *
4  * Syscall interface to knfsd.
5  *
6  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7  */
8 
9 #include <linux/module.h>
10 
11 #include <linux/linkage.h>
12 #include <linux/time.h>
13 #include <linux/errno.h>
14 #include <linux/fs.h>
15 #include <linux/namei.h>
16 #include <linux/fcntl.h>
17 #include <linux/net.h>
18 #include <linux/in.h>
19 #include <linux/syscalls.h>
20 #include <linux/unistd.h>
21 #include <linux/slab.h>
22 #include <linux/proc_fs.h>
23 #include <linux/seq_file.h>
24 #include <linux/pagemap.h>
25 #include <linux/init.h>
26 #include <linux/inet.h>
27 #include <linux/string.h>
28 #include <linux/ctype.h>
29 
30 #include <linux/nfs.h>
31 #include <linux/nfsd_idmap.h>
32 #include <linux/lockd/bind.h>
33 #include <linux/sunrpc/svc.h>
34 #include <linux/sunrpc/svcsock.h>
35 #include <linux/nfsd/nfsd.h>
36 #include <linux/nfsd/cache.h>
37 #include <linux/nfsd/xdr.h>
38 #include <linux/nfsd/syscall.h>
39 #include <linux/lockd/lockd.h>
40 #include <linux/sunrpc/clnt.h>
41 
42 #include <asm/uaccess.h>
43 #include <net/ipv6.h>
44 
45 /*
46  *	We have a single directory with 9 nodes in it.
47  */
48 enum {
49 	NFSD_Root = 1,
50 	NFSD_Svc,
51 	NFSD_Add,
52 	NFSD_Del,
53 	NFSD_Export,
54 	NFSD_Unexport,
55 	NFSD_Getfd,
56 	NFSD_Getfs,
57 	NFSD_List,
58 	NFSD_Fh,
59 	NFSD_FO_UnlockIP,
60 	NFSD_FO_UnlockFS,
61 	NFSD_Threads,
62 	NFSD_Pool_Threads,
63 	NFSD_Pool_Stats,
64 	NFSD_Versions,
65 	NFSD_Ports,
66 	NFSD_MaxBlkSize,
67 	/*
68 	 * The below MUST come last.  Otherwise we leave a hole in nfsd_files[]
69 	 * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops
70 	 */
71 #ifdef CONFIG_NFSD_V4
72 	NFSD_Leasetime,
73 	NFSD_RecoveryDir,
74 #endif
75 };
76 
77 /*
78  * write() for these nodes.
79  */
80 static ssize_t write_svc(struct file *file, char *buf, size_t size);
81 static ssize_t write_add(struct file *file, char *buf, size_t size);
82 static ssize_t write_del(struct file *file, char *buf, size_t size);
83 static ssize_t write_export(struct file *file, char *buf, size_t size);
84 static ssize_t write_unexport(struct file *file, char *buf, size_t size);
85 static ssize_t write_getfd(struct file *file, char *buf, size_t size);
86 static ssize_t write_getfs(struct file *file, char *buf, size_t size);
87 static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
88 static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size);
89 static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size);
90 static ssize_t write_threads(struct file *file, char *buf, size_t size);
91 static ssize_t write_pool_threads(struct file *file, char *buf, size_t size);
92 static ssize_t write_versions(struct file *file, char *buf, size_t size);
93 static ssize_t write_ports(struct file *file, char *buf, size_t size);
94 static ssize_t write_maxblksize(struct file *file, char *buf, size_t size);
95 #ifdef CONFIG_NFSD_V4
96 static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
97 static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
98 #endif
99 
100 static ssize_t (*write_op[])(struct file *, char *, size_t) = {
101 	[NFSD_Svc] = write_svc,
102 	[NFSD_Add] = write_add,
103 	[NFSD_Del] = write_del,
104 	[NFSD_Export] = write_export,
105 	[NFSD_Unexport] = write_unexport,
106 	[NFSD_Getfd] = write_getfd,
107 	[NFSD_Getfs] = write_getfs,
108 	[NFSD_Fh] = write_filehandle,
109 	[NFSD_FO_UnlockIP] = write_unlock_ip,
110 	[NFSD_FO_UnlockFS] = write_unlock_fs,
111 	[NFSD_Threads] = write_threads,
112 	[NFSD_Pool_Threads] = write_pool_threads,
113 	[NFSD_Versions] = write_versions,
114 	[NFSD_Ports] = write_ports,
115 	[NFSD_MaxBlkSize] = write_maxblksize,
116 #ifdef CONFIG_NFSD_V4
117 	[NFSD_Leasetime] = write_leasetime,
118 	[NFSD_RecoveryDir] = write_recoverydir,
119 #endif
120 };
121 
122 static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
123 {
124 	ino_t ino =  file->f_path.dentry->d_inode->i_ino;
125 	char *data;
126 	ssize_t rv;
127 
128 	if (ino >= ARRAY_SIZE(write_op) || !write_op[ino])
129 		return -EINVAL;
130 
131 	data = simple_transaction_get(file, buf, size);
132 	if (IS_ERR(data))
133 		return PTR_ERR(data);
134 
135 	rv =  write_op[ino](file, data, size);
136 	if (rv >= 0) {
137 		simple_transaction_set(file, rv);
138 		rv = size;
139 	}
140 	return rv;
141 }
142 
143 static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
144 {
145 	if (! file->private_data) {
146 		/* An attempt to read a transaction file without writing
147 		 * causes a 0-byte write so that the file can return
148 		 * state information
149 		 */
150 		ssize_t rv = nfsctl_transaction_write(file, buf, 0, pos);
151 		if (rv < 0)
152 			return rv;
153 	}
154 	return simple_transaction_read(file, buf, size, pos);
155 }
156 
157 static const struct file_operations transaction_ops = {
158 	.write		= nfsctl_transaction_write,
159 	.read		= nfsctl_transaction_read,
160 	.release	= simple_transaction_release,
161 };
162 
163 static int exports_open(struct inode *inode, struct file *file)
164 {
165 	return seq_open(file, &nfs_exports_op);
166 }
167 
168 static const struct file_operations exports_operations = {
169 	.open		= exports_open,
170 	.read		= seq_read,
171 	.llseek		= seq_lseek,
172 	.release	= seq_release,
173 	.owner		= THIS_MODULE,
174 };
175 
176 extern int nfsd_pool_stats_open(struct inode *inode, struct file *file);
177 extern int nfsd_pool_stats_release(struct inode *inode, struct file *file);
178 
179 static const struct file_operations pool_stats_operations = {
180 	.open		= nfsd_pool_stats_open,
181 	.read		= seq_read,
182 	.llseek		= seq_lseek,
183 	.release	= nfsd_pool_stats_release,
184 	.owner		= THIS_MODULE,
185 };
186 
187 /*----------------------------------------------------------------------------*/
188 /*
189  * payload - write methods
190  */
191 
192 /**
193  * write_svc - Start kernel's NFSD server
194  *
195  * Deprecated.  /proc/fs/nfsd/threads is preferred.
196  * Function remains to support old versions of nfs-utils.
197  *
198  * Input:
199  *			buf:	struct nfsctl_svc
200  *				svc_port:	port number of this
201  *						server's listener
202  *				svc_nthreads:	number of threads to start
203  *			size:	size in bytes of passed in nfsctl_svc
204  * Output:
205  *	On success:	returns zero
206  *	On error:	return code is negative errno value
207  */
208 static ssize_t write_svc(struct file *file, char *buf, size_t size)
209 {
210 	struct nfsctl_svc *data;
211 	int err;
212 	if (size < sizeof(*data))
213 		return -EINVAL;
214 	data = (struct nfsctl_svc*) buf;
215 	err = nfsd_svc(data->svc_port, data->svc_nthreads);
216 	if (err < 0)
217 		return err;
218 	return 0;
219 }
220 
221 /**
222  * write_add - Add or modify client entry in auth unix cache
223  *
224  * Deprecated.  /proc/net/rpc/auth.unix.ip is preferred.
225  * Function remains to support old versions of nfs-utils.
226  *
227  * Input:
228  *			buf:	struct nfsctl_client
229  *				cl_ident:	'\0'-terminated C string
230  *						containing domain name
231  *						of client
232  *				cl_naddr:	no. of items in cl_addrlist
233  *				cl_addrlist:	array of client addresses
234  *				cl_fhkeytype:	ignored
235  *				cl_fhkeylen:	ignored
236  *				cl_fhkey:	ignored
237  *			size:	size in bytes of passed in nfsctl_client
238  * Output:
239  *	On success:	returns zero
240  *	On error:	return code is negative errno value
241  *
242  * Note: Only AF_INET client addresses are passed in, since
243  * nfsctl_client.cl_addrlist contains only in_addr fields for addresses.
244  */
245 static ssize_t write_add(struct file *file, char *buf, size_t size)
246 {
247 	struct nfsctl_client *data;
248 	if (size < sizeof(*data))
249 		return -EINVAL;
250 	data = (struct nfsctl_client *)buf;
251 	return exp_addclient(data);
252 }
253 
254 /**
255  * write_del - Remove client from auth unix cache
256  *
257  * Deprecated.  /proc/net/rpc/auth.unix.ip is preferred.
258  * Function remains to support old versions of nfs-utils.
259  *
260  * Input:
261  *			buf:	struct nfsctl_client
262  *				cl_ident:	'\0'-terminated C string
263  *						containing domain name
264  *						of client
265  *				cl_naddr:	ignored
266  *				cl_addrlist:	ignored
267  *				cl_fhkeytype:	ignored
268  *				cl_fhkeylen:	ignored
269  *				cl_fhkey:	ignored
270  *			size:	size in bytes of passed in nfsctl_client
271  * Output:
272  *	On success:	returns zero
273  *	On error:	return code is negative errno value
274  *
275  * Note: Only AF_INET client addresses are passed in, since
276  * nfsctl_client.cl_addrlist contains only in_addr fields for addresses.
277  */
278 static ssize_t write_del(struct file *file, char *buf, size_t size)
279 {
280 	struct nfsctl_client *data;
281 	if (size < sizeof(*data))
282 		return -EINVAL;
283 	data = (struct nfsctl_client *)buf;
284 	return exp_delclient(data);
285 }
286 
287 /**
288  * write_export - Export part or all of a local file system
289  *
290  * Deprecated.  /proc/net/rpc/{nfsd.export,nfsd.fh} are preferred.
291  * Function remains to support old versions of nfs-utils.
292  *
293  * Input:
294  *			buf:	struct nfsctl_export
295  *				ex_client:	'\0'-terminated C string
296  *						containing domain name
297  *						of client allowed to access
298  *						this export
299  *				ex_path:	'\0'-terminated C string
300  *						containing pathname of
301  *						directory in local file system
302  *				ex_dev:		fsid to use for this export
303  *				ex_ino:		ignored
304  *				ex_flags:	export flags for this export
305  *				ex_anon_uid:	UID to use for anonymous
306  *						requests
307  *				ex_anon_gid:	GID to use for anonymous
308  *						requests
309  *			size:	size in bytes of passed in nfsctl_export
310  * Output:
311  *	On success:	returns zero
312  *	On error:	return code is negative errno value
313  */
314 static ssize_t write_export(struct file *file, char *buf, size_t size)
315 {
316 	struct nfsctl_export *data;
317 	if (size < sizeof(*data))
318 		return -EINVAL;
319 	data = (struct nfsctl_export*)buf;
320 	return exp_export(data);
321 }
322 
323 /**
324  * write_unexport - Unexport a previously exported file system
325  *
326  * Deprecated.  /proc/net/rpc/{nfsd.export,nfsd.fh} are preferred.
327  * Function remains to support old versions of nfs-utils.
328  *
329  * Input:
330  *			buf:	struct nfsctl_export
331  *				ex_client:	'\0'-terminated C string
332  *						containing domain name
333  *						of client no longer allowed
334  *						to access this export
335  *				ex_path:	'\0'-terminated C string
336  *						containing pathname of
337  *						directory in local file system
338  *				ex_dev:		ignored
339  *				ex_ino:		ignored
340  *				ex_flags:	ignored
341  *				ex_anon_uid:	ignored
342  *				ex_anon_gid:	ignored
343  *			size:	size in bytes of passed in nfsctl_export
344  * Output:
345  *	On success:	returns zero
346  *	On error:	return code is negative errno value
347  */
348 static ssize_t write_unexport(struct file *file, char *buf, size_t size)
349 {
350 	struct nfsctl_export *data;
351 
352 	if (size < sizeof(*data))
353 		return -EINVAL;
354 	data = (struct nfsctl_export*)buf;
355 	return exp_unexport(data);
356 }
357 
358 /**
359  * write_getfs - Get a variable-length NFS file handle by path
360  *
361  * Deprecated.  /proc/fs/nfsd/filehandle is preferred.
362  * Function remains to support old versions of nfs-utils.
363  *
364  * Input:
365  *			buf:	struct nfsctl_fsparm
366  *				gd_addr:	socket address of client
367  *				gd_path:	'\0'-terminated C string
368  *						containing pathname of
369  *						directory in local file system
370  *				gd_maxlen:	maximum size of returned file
371  *						handle
372  *			size:	size in bytes of passed in nfsctl_fsparm
373  * Output:
374  *	On success:	passed-in buffer filled with a knfsd_fh structure
375  *			(a variable-length raw NFS file handle);
376  *			return code is the size in bytes of the file handle
377  *	On error:	return code is negative errno value
378  *
379  * Note: Only AF_INET client addresses are passed in, since gd_addr
380  * is the same size as a struct sockaddr_in.
381  */
382 static ssize_t write_getfs(struct file *file, char *buf, size_t size)
383 {
384 	struct nfsctl_fsparm *data;
385 	struct sockaddr_in *sin;
386 	struct auth_domain *clp;
387 	int err = 0;
388 	struct knfsd_fh *res;
389 	struct in6_addr in6;
390 
391 	if (size < sizeof(*data))
392 		return -EINVAL;
393 	data = (struct nfsctl_fsparm*)buf;
394 	err = -EPROTONOSUPPORT;
395 	if (data->gd_addr.sa_family != AF_INET)
396 		goto out;
397 	sin = (struct sockaddr_in *)&data->gd_addr;
398 	if (data->gd_maxlen > NFS3_FHSIZE)
399 		data->gd_maxlen = NFS3_FHSIZE;
400 
401 	res = (struct knfsd_fh*)buf;
402 
403 	exp_readlock();
404 
405 	ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
406 
407 	clp = auth_unix_lookup(&in6);
408 	if (!clp)
409 		err = -EPERM;
410 	else {
411 		err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
412 		auth_domain_put(clp);
413 	}
414 	exp_readunlock();
415 	if (err == 0)
416 		err = res->fh_size + offsetof(struct knfsd_fh, fh_base);
417  out:
418 	return err;
419 }
420 
421 /**
422  * write_getfd - Get a fixed-length NFS file handle by path (used by mountd)
423  *
424  * Deprecated.  /proc/fs/nfsd/filehandle is preferred.
425  * Function remains to support old versions of nfs-utils.
426  *
427  * Input:
428  *			buf:	struct nfsctl_fdparm
429  *				gd_addr:	socket address of client
430  *				gd_path:	'\0'-terminated C string
431  *						containing pathname of
432  *						directory in local file system
433  *				gd_version:	fdparm structure version
434  *			size:	size in bytes of passed in nfsctl_fdparm
435  * Output:
436  *	On success:	passed-in buffer filled with nfsctl_res
437  *			(a fixed-length raw NFS file handle);
438  *			return code is the size in bytes of the file handle
439  *	On error:	return code is negative errno value
440  *
441  * Note: Only AF_INET client addresses are passed in, since gd_addr
442  * is the same size as a struct sockaddr_in.
443  */
444 static ssize_t write_getfd(struct file *file, char *buf, size_t size)
445 {
446 	struct nfsctl_fdparm *data;
447 	struct sockaddr_in *sin;
448 	struct auth_domain *clp;
449 	int err = 0;
450 	struct knfsd_fh fh;
451 	char *res;
452 	struct in6_addr in6;
453 
454 	if (size < sizeof(*data))
455 		return -EINVAL;
456 	data = (struct nfsctl_fdparm*)buf;
457 	err = -EPROTONOSUPPORT;
458 	if (data->gd_addr.sa_family != AF_INET)
459 		goto out;
460 	err = -EINVAL;
461 	if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS)
462 		goto out;
463 
464 	res = buf;
465 	sin = (struct sockaddr_in *)&data->gd_addr;
466 	exp_readlock();
467 
468 	ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
469 
470 	clp = auth_unix_lookup(&in6);
471 	if (!clp)
472 		err = -EPERM;
473 	else {
474 		err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
475 		auth_domain_put(clp);
476 	}
477 	exp_readunlock();
478 
479 	if (err == 0) {
480 		memset(res,0, NFS_FHSIZE);
481 		memcpy(res, &fh.fh_base, fh.fh_size);
482 		err = NFS_FHSIZE;
483 	}
484  out:
485 	return err;
486 }
487 
488 /**
489  * write_unlock_ip - Release all locks used by a client
490  *
491  * Experimental.
492  *
493  * Input:
494  *			buf:	'\n'-terminated C string containing a
495  *				presentation format IP address
496  *			size:	length of C string in @buf
497  * Output:
498  *	On success:	returns zero if all specified locks were released;
499  *			returns one if one or more locks were not released
500  *	On error:	return code is negative errno value
501  */
502 static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
503 {
504 	struct sockaddr_storage address;
505 	struct sockaddr *sap = (struct sockaddr *)&address;
506 	size_t salen = sizeof(address);
507 	char *fo_path;
508 
509 	/* sanity check */
510 	if (size == 0)
511 		return -EINVAL;
512 
513 	if (buf[size-1] != '\n')
514 		return -EINVAL;
515 
516 	fo_path = buf;
517 	if (qword_get(&buf, fo_path, size) < 0)
518 		return -EINVAL;
519 
520 	if (rpc_pton(fo_path, size, sap, salen) == 0)
521 		return -EINVAL;
522 
523 	return nlmsvc_unlock_all_by_ip(sap);
524 }
525 
526 /**
527  * write_unlock_fs - Release all locks on a local file system
528  *
529  * Experimental.
530  *
531  * Input:
532  *			buf:	'\n'-terminated C string containing the
533  *				absolute pathname of a local file system
534  *			size:	length of C string in @buf
535  * Output:
536  *	On success:	returns zero if all specified locks were released;
537  *			returns one if one or more locks were not released
538  *	On error:	return code is negative errno value
539  */
540 static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size)
541 {
542 	struct path path;
543 	char *fo_path;
544 	int error;
545 
546 	/* sanity check */
547 	if (size == 0)
548 		return -EINVAL;
549 
550 	if (buf[size-1] != '\n')
551 		return -EINVAL;
552 
553 	fo_path = buf;
554 	if (qword_get(&buf, fo_path, size) < 0)
555 		return -EINVAL;
556 
557 	error = kern_path(fo_path, 0, &path);
558 	if (error)
559 		return error;
560 
561 	/*
562 	 * XXX: Needs better sanity checking.  Otherwise we could end up
563 	 * releasing locks on the wrong file system.
564 	 *
565 	 * For example:
566 	 * 1.  Does the path refer to a directory?
567 	 * 2.  Is that directory a mount point, or
568 	 * 3.  Is that directory the root of an exported file system?
569 	 */
570 	error = nlmsvc_unlock_all_by_sb(path.mnt->mnt_sb);
571 
572 	path_put(&path);
573 	return error;
574 }
575 
576 /**
577  * write_filehandle - Get a variable-length NFS file handle by path
578  *
579  * On input, the buffer contains a '\n'-terminated C string comprised of
580  * three alphanumeric words separated by whitespace.  The string may
581  * contain escape sequences.
582  *
583  * Input:
584  *			buf:
585  *				domain:		client domain name
586  *				path:		export pathname
587  *				maxsize:	numeric maximum size of
588  *						@buf
589  *			size:	length of C string in @buf
590  * Output:
591  *	On success:	passed-in buffer filled with '\n'-terminated C
592  *			string containing a ASCII hex text version
593  *			of the NFS file handle;
594  *			return code is the size in bytes of the string
595  *	On error:	return code is negative errno value
596  */
597 static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
598 {
599 	char *dname, *path;
600 	int uninitialized_var(maxsize);
601 	char *mesg = buf;
602 	int len;
603 	struct auth_domain *dom;
604 	struct knfsd_fh fh;
605 
606 	if (size == 0)
607 		return -EINVAL;
608 
609 	if (buf[size-1] != '\n')
610 		return -EINVAL;
611 	buf[size-1] = 0;
612 
613 	dname = mesg;
614 	len = qword_get(&mesg, dname, size);
615 	if (len <= 0)
616 		return -EINVAL;
617 
618 	path = dname+len+1;
619 	len = qword_get(&mesg, path, size);
620 	if (len <= 0)
621 		return -EINVAL;
622 
623 	len = get_int(&mesg, &maxsize);
624 	if (len)
625 		return len;
626 
627 	if (maxsize < NFS_FHSIZE)
628 		return -EINVAL;
629 	if (maxsize > NFS3_FHSIZE)
630 		maxsize = NFS3_FHSIZE;
631 
632 	if (qword_get(&mesg, mesg, size)>0)
633 		return -EINVAL;
634 
635 	/* we have all the words, they are in buf.. */
636 	dom = unix_domain_find(dname);
637 	if (!dom)
638 		return -ENOMEM;
639 
640 	len = exp_rootfh(dom, path, &fh,  maxsize);
641 	auth_domain_put(dom);
642 	if (len)
643 		return len;
644 
645 	mesg = buf;
646 	len = SIMPLE_TRANSACTION_LIMIT;
647 	qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size);
648 	mesg[-1] = '\n';
649 	return mesg - buf;
650 }
651 
652 /**
653  * write_threads - Start NFSD, or report the current number of running threads
654  *
655  * Input:
656  *			buf:		ignored
657  *			size:		zero
658  * Output:
659  *	On success:	passed-in buffer filled with '\n'-terminated C
660  *			string numeric value representing the number of
661  *			running NFSD threads;
662  *			return code is the size in bytes of the string
663  *	On error:	return code is zero
664  *
665  * OR
666  *
667  * Input:
668  *			buf:		C string containing an unsigned
669  *					integer value representing the
670  *					number of NFSD threads to start
671  *			size:		non-zero length of C string in @buf
672  * Output:
673  *	On success:	NFS service is started;
674  *			passed-in buffer filled with '\n'-terminated C
675  *			string numeric value representing the number of
676  *			running NFSD threads;
677  *			return code is the size in bytes of the string
678  *	On error:	return code is zero or a negative errno value
679  */
680 static ssize_t write_threads(struct file *file, char *buf, size_t size)
681 {
682 	char *mesg = buf;
683 	int rv;
684 	if (size > 0) {
685 		int newthreads;
686 		rv = get_int(&mesg, &newthreads);
687 		if (rv)
688 			return rv;
689 		if (newthreads < 0)
690 			return -EINVAL;
691 		rv = nfsd_svc(NFS_PORT, newthreads);
692 		if (rv < 0)
693 			return rv;
694 	} else
695 		rv = nfsd_nrthreads();
696 
697 	return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv);
698 }
699 
700 /**
701  * write_pool_threads - Set or report the current number of threads per pool
702  *
703  * Input:
704  *			buf:		ignored
705  *			size:		zero
706  *
707  * OR
708  *
709  * Input:
710  * 			buf:		C string containing whitespace-
711  * 					separated unsigned integer values
712  *					representing the number of NFSD
713  *					threads to start in each pool
714  *			size:		non-zero length of C string in @buf
715  * Output:
716  *	On success:	passed-in buffer filled with '\n'-terminated C
717  *			string containing integer values representing the
718  *			number of NFSD threads in each pool;
719  *			return code is the size in bytes of the string
720  *	On error:	return code is zero or a negative errno value
721  */
722 static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
723 {
724 	/* if size > 0, look for an array of number of threads per node
725 	 * and apply them  then write out number of threads per node as reply
726 	 */
727 	char *mesg = buf;
728 	int i;
729 	int rv;
730 	int len;
731 	int npools;
732 	int *nthreads;
733 
734 	mutex_lock(&nfsd_mutex);
735 	npools = nfsd_nrpools();
736 	if (npools == 0) {
737 		/*
738 		 * NFS is shut down.  The admin can start it by
739 		 * writing to the threads file but NOT the pool_threads
740 		 * file, sorry.  Report zero threads.
741 		 */
742 		mutex_unlock(&nfsd_mutex);
743 		strcpy(buf, "0\n");
744 		return strlen(buf);
745 	}
746 
747 	nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL);
748 	rv = -ENOMEM;
749 	if (nthreads == NULL)
750 		goto out_free;
751 
752 	if (size > 0) {
753 		for (i = 0; i < npools; i++) {
754 			rv = get_int(&mesg, &nthreads[i]);
755 			if (rv == -ENOENT)
756 				break;		/* fewer numbers than pools */
757 			if (rv)
758 				goto out_free;	/* syntax error */
759 			rv = -EINVAL;
760 			if (nthreads[i] < 0)
761 				goto out_free;
762 		}
763 		rv = nfsd_set_nrthreads(i, nthreads);
764 		if (rv)
765 			goto out_free;
766 	}
767 
768 	rv = nfsd_get_nrthreads(npools, nthreads);
769 	if (rv)
770 		goto out_free;
771 
772 	mesg = buf;
773 	size = SIMPLE_TRANSACTION_LIMIT;
774 	for (i = 0; i < npools && size > 0; i++) {
775 		snprintf(mesg, size, "%d%c", nthreads[i], (i == npools-1 ? '\n' : ' '));
776 		len = strlen(mesg);
777 		size -= len;
778 		mesg += len;
779 	}
780 	rv = mesg - buf;
781 out_free:
782 	kfree(nthreads);
783 	mutex_unlock(&nfsd_mutex);
784 	return rv;
785 }
786 
787 static ssize_t __write_versions(struct file *file, char *buf, size_t size)
788 {
789 	char *mesg = buf;
790 	char *vers, *minorp, sign;
791 	int len, num, remaining;
792 	unsigned minor;
793 	ssize_t tlen = 0;
794 	char *sep;
795 
796 	if (size>0) {
797 		if (nfsd_serv)
798 			/* Cannot change versions without updating
799 			 * nfsd_serv->sv_xdrsize, and reallocing
800 			 * rq_argp and rq_resp
801 			 */
802 			return -EBUSY;
803 		if (buf[size-1] != '\n')
804 			return -EINVAL;
805 		buf[size-1] = 0;
806 
807 		vers = mesg;
808 		len = qword_get(&mesg, vers, size);
809 		if (len <= 0) return -EINVAL;
810 		do {
811 			sign = *vers;
812 			if (sign == '+' || sign == '-')
813 				num = simple_strtol((vers+1), &minorp, 0);
814 			else
815 				num = simple_strtol(vers, &minorp, 0);
816 			if (*minorp == '.') {
817 				if (num < 4)
818 					return -EINVAL;
819 				minor = simple_strtoul(minorp+1, NULL, 0);
820 				if (minor == 0)
821 					return -EINVAL;
822 				if (nfsd_minorversion(minor, sign == '-' ?
823 						     NFSD_CLEAR : NFSD_SET) < 0)
824 					return -EINVAL;
825 				goto next;
826 			}
827 			switch(num) {
828 			case 2:
829 			case 3:
830 			case 4:
831 				nfsd_vers(num, sign == '-' ? NFSD_CLEAR : NFSD_SET);
832 				break;
833 			default:
834 				return -EINVAL;
835 			}
836 		next:
837 			vers += len + 1;
838 		} while ((len = qword_get(&mesg, vers, size)) > 0);
839 		/* If all get turned off, turn them back on, as
840 		 * having no versions is BAD
841 		 */
842 		nfsd_reset_versions();
843 	}
844 
845 	/* Now write current state into reply buffer */
846 	len = 0;
847 	sep = "";
848 	remaining = SIMPLE_TRANSACTION_LIMIT;
849 	for (num=2 ; num <= 4 ; num++)
850 		if (nfsd_vers(num, NFSD_AVAIL)) {
851 			len = snprintf(buf, remaining, "%s%c%d", sep,
852 				       nfsd_vers(num, NFSD_TEST)?'+':'-',
853 				       num);
854 			sep = " ";
855 
856 			if (len > remaining)
857 				break;
858 			remaining -= len;
859 			buf += len;
860 			tlen += len;
861 		}
862 	if (nfsd_vers(4, NFSD_AVAIL))
863 		for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION;
864 		     minor++) {
865 			len = snprintf(buf, remaining, " %c4.%u",
866 					(nfsd_vers(4, NFSD_TEST) &&
867 					 nfsd_minorversion(minor, NFSD_TEST)) ?
868 						'+' : '-',
869 					minor);
870 
871 			if (len > remaining)
872 				break;
873 			remaining -= len;
874 			buf += len;
875 			tlen += len;
876 		}
877 
878 	len = snprintf(buf, remaining, "\n");
879 	if (len > remaining)
880 		return -EINVAL;
881 	return tlen + len;
882 }
883 
884 /**
885  * write_versions - Set or report the available NFS protocol versions
886  *
887  * Input:
888  *			buf:		ignored
889  *			size:		zero
890  * Output:
891  *	On success:	passed-in buffer filled with '\n'-terminated C
892  *			string containing positive or negative integer
893  *			values representing the current status of each
894  *			protocol version;
895  *			return code is the size in bytes of the string
896  *	On error:	return code is zero or a negative errno value
897  *
898  * OR
899  *
900  * Input:
901  * 			buf:		C string containing whitespace-
902  * 					separated positive or negative
903  * 					integer values representing NFS
904  * 					protocol versions to enable ("+n")
905  * 					or disable ("-n")
906  *			size:		non-zero length of C string in @buf
907  * Output:
908  *	On success:	status of zero or more protocol versions has
909  *			been updated; passed-in buffer filled with
910  *			'\n'-terminated C string containing positive
911  *			or negative integer values representing the
912  *			current status of each protocol version;
913  *			return code is the size in bytes of the string
914  *	On error:	return code is zero or a negative errno value
915  */
916 static ssize_t write_versions(struct file *file, char *buf, size_t size)
917 {
918 	ssize_t rv;
919 
920 	mutex_lock(&nfsd_mutex);
921 	rv = __write_versions(file, buf, size);
922 	mutex_unlock(&nfsd_mutex);
923 	return rv;
924 }
925 
926 /*
927  * Zero-length write.  Return a list of NFSD's current listener
928  * transports.
929  */
930 static ssize_t __write_ports_names(char *buf)
931 {
932 	if (nfsd_serv == NULL)
933 		return 0;
934 	return svc_xprt_names(nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT);
935 }
936 
937 /*
938  * A single 'fd' number was written, in which case it must be for
939  * a socket of a supported family/protocol, and we use it as an
940  * nfsd listener.
941  */
942 static ssize_t __write_ports_addfd(char *buf)
943 {
944 	char *mesg = buf;
945 	int fd, err;
946 
947 	err = get_int(&mesg, &fd);
948 	if (err != 0 || fd < 0)
949 		return -EINVAL;
950 
951 	err = nfsd_create_serv();
952 	if (err != 0)
953 		return err;
954 
955 	err = lockd_up();
956 	if (err != 0)
957 		goto out;
958 
959 	err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
960 	if (err < 0)
961 		lockd_down();
962 
963 out:
964 	/* Decrease the count, but don't shut down the service */
965 	nfsd_serv->sv_nrthreads--;
966 	return err;
967 }
968 
969 /*
970  * A '-' followed by the 'name' of a socket means we close the socket.
971  */
972 static ssize_t __write_ports_delfd(char *buf)
973 {
974 	char *toclose;
975 	int len = 0;
976 
977 	toclose = kstrdup(buf + 1, GFP_KERNEL);
978 	if (toclose == NULL)
979 		return -ENOMEM;
980 
981 	if (nfsd_serv != NULL)
982 		len = svc_sock_names(nfsd_serv, buf,
983 					SIMPLE_TRANSACTION_LIMIT, toclose);
984 	if (len >= 0)
985 		lockd_down();
986 
987 	kfree(toclose);
988 	return len;
989 }
990 
991 /*
992  * A transport listener is added by writing it's transport name and
993  * a port number.
994  */
995 static ssize_t __write_ports_addxprt(char *buf)
996 {
997 	char transport[16];
998 	int port, err;
999 
1000 	if (sscanf(buf, "%15s %4u", transport, &port) != 2)
1001 		return -EINVAL;
1002 
1003 	if (port < 1 || port > USHORT_MAX)
1004 		return -EINVAL;
1005 
1006 	err = nfsd_create_serv();
1007 	if (err != 0)
1008 		return err;
1009 
1010 	err = svc_create_xprt(nfsd_serv, transport,
1011 				PF_INET, port, SVC_SOCK_ANONYMOUS);
1012 	if (err < 0) {
1013 		/* Give a reasonable perror msg for bad transport string */
1014 		if (err == -ENOENT)
1015 			err = -EPROTONOSUPPORT;
1016 		return err;
1017 	}
1018 	return 0;
1019 }
1020 
1021 /*
1022  * A transport listener is removed by writing a "-", it's transport
1023  * name, and it's port number.
1024  */
1025 static ssize_t __write_ports_delxprt(char *buf)
1026 {
1027 	struct svc_xprt *xprt;
1028 	char transport[16];
1029 	int port;
1030 
1031 	if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2)
1032 		return -EINVAL;
1033 
1034 	if (port < 1 || port > USHORT_MAX || nfsd_serv == NULL)
1035 		return -EINVAL;
1036 
1037 	xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port);
1038 	if (xprt == NULL)
1039 		return -ENOTCONN;
1040 
1041 	svc_close_xprt(xprt);
1042 	svc_xprt_put(xprt);
1043 	return 0;
1044 }
1045 
1046 static ssize_t __write_ports(struct file *file, char *buf, size_t size)
1047 {
1048 	if (size == 0)
1049 		return __write_ports_names(buf);
1050 
1051 	if (isdigit(buf[0]))
1052 		return __write_ports_addfd(buf);
1053 
1054 	if (buf[0] == '-' && isdigit(buf[1]))
1055 		return __write_ports_delfd(buf);
1056 
1057 	if (isalpha(buf[0]))
1058 		return __write_ports_addxprt(buf);
1059 
1060 	if (buf[0] == '-' && isalpha(buf[1]))
1061 		return __write_ports_delxprt(buf);
1062 
1063 	return -EINVAL;
1064 }
1065 
1066 /**
1067  * write_ports - Pass a socket file descriptor or transport name to listen on
1068  *
1069  * Input:
1070  *			buf:		ignored
1071  *			size:		zero
1072  * Output:
1073  *	On success:	passed-in buffer filled with a '\n'-terminated C
1074  *			string containing a whitespace-separated list of
1075  *			named NFSD listeners;
1076  *			return code is the size in bytes of the string
1077  *	On error:	return code is zero or a negative errno value
1078  *
1079  * OR
1080  *
1081  * Input:
1082  *			buf:		C string containing an unsigned
1083  *					integer value representing a bound
1084  *					but unconnected socket that is to be
1085  *					used as an NFSD listener; listen(3)
1086  *					must be called for a SOCK_STREAM
1087  *					socket, otherwise it is ignored
1088  *			size:		non-zero length of C string in @buf
1089  * Output:
1090  *	On success:	NFS service is started;
1091  *			passed-in buffer filled with a '\n'-terminated C
1092  *			string containing a unique alphanumeric name of
1093  *			the listener;
1094  *			return code is the size in bytes of the string
1095  *	On error:	return code is a negative errno value
1096  *
1097  * OR
1098  *
1099  * Input:
1100  *			buf:		C string containing a "-" followed
1101  *					by an integer value representing a
1102  *					previously passed in socket file
1103  *					descriptor
1104  *			size:		non-zero length of C string in @buf
1105  * Output:
1106  *	On success:	NFS service no longer listens on that socket;
1107  *			passed-in buffer filled with a '\n'-terminated C
1108  *			string containing a unique name of the listener;
1109  *			return code is the size in bytes of the string
1110  *	On error:	return code is a negative errno value
1111  *
1112  * OR
1113  *
1114  * Input:
1115  *			buf:		C string containing a transport
1116  *					name and an unsigned integer value
1117  *					representing the port to listen on,
1118  *					separated by whitespace
1119  *			size:		non-zero length of C string in @buf
1120  * Output:
1121  *	On success:	returns zero; NFS service is started
1122  *	On error:	return code is a negative errno value
1123  *
1124  * OR
1125  *
1126  * Input:
1127  *			buf:		C string containing a "-" followed
1128  *					by a transport name and an unsigned
1129  *					integer value representing the port
1130  *					to listen on, separated by whitespace
1131  *			size:		non-zero length of C string in @buf
1132  * Output:
1133  *	On success:	returns zero; NFS service no longer listens
1134  *			on that transport
1135  *	On error:	return code is a negative errno value
1136  */
1137 static ssize_t write_ports(struct file *file, char *buf, size_t size)
1138 {
1139 	ssize_t rv;
1140 
1141 	mutex_lock(&nfsd_mutex);
1142 	rv = __write_ports(file, buf, size);
1143 	mutex_unlock(&nfsd_mutex);
1144 	return rv;
1145 }
1146 
1147 
1148 int nfsd_max_blksize;
1149 
1150 /**
1151  * write_maxblksize - Set or report the current NFS blksize
1152  *
1153  * Input:
1154  *			buf:		ignored
1155  *			size:		zero
1156  *
1157  * OR
1158  *
1159  * Input:
1160  * 			buf:		C string containing an unsigned
1161  * 					integer value representing the new
1162  * 					NFS blksize
1163  *			size:		non-zero length of C string in @buf
1164  * Output:
1165  *	On success:	passed-in buffer filled with '\n'-terminated C string
1166  *			containing numeric value of the current NFS blksize
1167  *			setting;
1168  *			return code is the size in bytes of the string
1169  *	On error:	return code is zero or a negative errno value
1170  */
1171 static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
1172 {
1173 	char *mesg = buf;
1174 	if (size > 0) {
1175 		int bsize;
1176 		int rv = get_int(&mesg, &bsize);
1177 		if (rv)
1178 			return rv;
1179 		/* force bsize into allowed range and
1180 		 * required alignment.
1181 		 */
1182 		if (bsize < 1024)
1183 			bsize = 1024;
1184 		if (bsize > NFSSVC_MAXBLKSIZE)
1185 			bsize = NFSSVC_MAXBLKSIZE;
1186 		bsize &= ~(1024-1);
1187 		mutex_lock(&nfsd_mutex);
1188 		if (nfsd_serv && nfsd_serv->sv_nrthreads) {
1189 			mutex_unlock(&nfsd_mutex);
1190 			return -EBUSY;
1191 		}
1192 		nfsd_max_blksize = bsize;
1193 		mutex_unlock(&nfsd_mutex);
1194 	}
1195 
1196 	return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n",
1197 							nfsd_max_blksize);
1198 }
1199 
1200 #ifdef CONFIG_NFSD_V4
1201 extern time_t nfs4_leasetime(void);
1202 
1203 static ssize_t __write_leasetime(struct file *file, char *buf, size_t size)
1204 {
1205 	/* if size > 10 seconds, call
1206 	 * nfs4_reset_lease() then write out the new lease (seconds) as reply
1207 	 */
1208 	char *mesg = buf;
1209 	int rv, lease;
1210 
1211 	if (size > 0) {
1212 		if (nfsd_serv)
1213 			return -EBUSY;
1214 		rv = get_int(&mesg, &lease);
1215 		if (rv)
1216 			return rv;
1217 		if (lease < 10 || lease > 3600)
1218 			return -EINVAL;
1219 		nfs4_reset_lease(lease);
1220 	}
1221 
1222 	return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n",
1223 							nfs4_lease_time());
1224 }
1225 
1226 /**
1227  * write_leasetime - Set or report the current NFSv4 lease time
1228  *
1229  * Input:
1230  *			buf:		ignored
1231  *			size:		zero
1232  *
1233  * OR
1234  *
1235  * Input:
1236  *			buf:		C string containing an unsigned
1237  *					integer value representing the new
1238  *					NFSv4 lease expiry time
1239  *			size:		non-zero length of C string in @buf
1240  * Output:
1241  *	On success:	passed-in buffer filled with '\n'-terminated C
1242  *			string containing unsigned integer value of the
1243  *			current lease expiry time;
1244  *			return code is the size in bytes of the string
1245  *	On error:	return code is zero or a negative errno value
1246  */
1247 static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
1248 {
1249 	ssize_t rv;
1250 
1251 	mutex_lock(&nfsd_mutex);
1252 	rv = __write_leasetime(file, buf, size);
1253 	mutex_unlock(&nfsd_mutex);
1254 	return rv;
1255 }
1256 
1257 extern char *nfs4_recoverydir(void);
1258 
1259 static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)
1260 {
1261 	char *mesg = buf;
1262 	char *recdir;
1263 	int len, status;
1264 
1265 	if (size > 0) {
1266 		if (nfsd_serv)
1267 			return -EBUSY;
1268 		if (size > PATH_MAX || buf[size-1] != '\n')
1269 			return -EINVAL;
1270 		buf[size-1] = 0;
1271 
1272 		recdir = mesg;
1273 		len = qword_get(&mesg, recdir, size);
1274 		if (len <= 0)
1275 			return -EINVAL;
1276 
1277 		status = nfs4_reset_recoverydir(recdir);
1278 	}
1279 
1280 	return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n",
1281 							nfs4_recoverydir());
1282 }
1283 
1284 /**
1285  * write_recoverydir - Set or report the pathname of the recovery directory
1286  *
1287  * Input:
1288  *			buf:		ignored
1289  *			size:		zero
1290  *
1291  * OR
1292  *
1293  * Input:
1294  *			buf:		C string containing the pathname
1295  *					of the directory on a local file
1296  *					system containing permanent NFSv4
1297  *					recovery data
1298  *			size:		non-zero length of C string in @buf
1299  * Output:
1300  *	On success:	passed-in buffer filled with '\n'-terminated C string
1301  *			containing the current recovery pathname setting;
1302  *			return code is the size in bytes of the string
1303  *	On error:	return code is zero or a negative errno value
1304  */
1305 static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
1306 {
1307 	ssize_t rv;
1308 
1309 	mutex_lock(&nfsd_mutex);
1310 	rv = __write_recoverydir(file, buf, size);
1311 	mutex_unlock(&nfsd_mutex);
1312 	return rv;
1313 }
1314 
1315 #endif
1316 
1317 /*----------------------------------------------------------------------------*/
1318 /*
1319  *	populating the filesystem.
1320  */
1321 
1322 static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
1323 {
1324 	static struct tree_descr nfsd_files[] = {
1325 		[NFSD_Svc] = {".svc", &transaction_ops, S_IWUSR},
1326 		[NFSD_Add] = {".add", &transaction_ops, S_IWUSR},
1327 		[NFSD_Del] = {".del", &transaction_ops, S_IWUSR},
1328 		[NFSD_Export] = {".export", &transaction_ops, S_IWUSR},
1329 		[NFSD_Unexport] = {".unexport", &transaction_ops, S_IWUSR},
1330 		[NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR},
1331 		[NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR},
1332 		[NFSD_List] = {"exports", &exports_operations, S_IRUGO},
1333 		[NFSD_FO_UnlockIP] = {"unlock_ip",
1334 					&transaction_ops, S_IWUSR|S_IRUSR},
1335 		[NFSD_FO_UnlockFS] = {"unlock_filesystem",
1336 					&transaction_ops, S_IWUSR|S_IRUSR},
1337 		[NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
1338 		[NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
1339 		[NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},
1340 		[NFSD_Pool_Stats] = {"pool_stats", &pool_stats_operations, S_IRUGO},
1341 		[NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
1342 		[NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
1343 		[NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
1344 #ifdef CONFIG_NFSD_V4
1345 		[NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
1346 		[NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
1347 #endif
1348 		/* last one */ {""}
1349 	};
1350 	return simple_fill_super(sb, 0x6e667364, nfsd_files);
1351 }
1352 
1353 static int nfsd_get_sb(struct file_system_type *fs_type,
1354 	int flags, const char *dev_name, void *data, struct vfsmount *mnt)
1355 {
1356 	return get_sb_single(fs_type, flags, data, nfsd_fill_super, mnt);
1357 }
1358 
1359 static struct file_system_type nfsd_fs_type = {
1360 	.owner		= THIS_MODULE,
1361 	.name		= "nfsd",
1362 	.get_sb		= nfsd_get_sb,
1363 	.kill_sb	= kill_litter_super,
1364 };
1365 
1366 #ifdef CONFIG_PROC_FS
1367 static int create_proc_exports_entry(void)
1368 {
1369 	struct proc_dir_entry *entry;
1370 
1371 	entry = proc_mkdir("fs/nfs", NULL);
1372 	if (!entry)
1373 		return -ENOMEM;
1374 	entry = proc_create("exports", 0, entry, &exports_operations);
1375 	if (!entry)
1376 		return -ENOMEM;
1377 	return 0;
1378 }
1379 #else /* CONFIG_PROC_FS */
1380 static int create_proc_exports_entry(void)
1381 {
1382 	return 0;
1383 }
1384 #endif
1385 
1386 static int __init init_nfsd(void)
1387 {
1388 	int retval;
1389 	printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
1390 
1391 	retval = nfs4_state_init(); /* nfs4 locking state */
1392 	if (retval)
1393 		return retval;
1394 	nfsd_stat_init();	/* Statistics */
1395 	retval = nfsd_reply_cache_init();
1396 	if (retval)
1397 		goto out_free_stat;
1398 	retval = nfsd_export_init();
1399 	if (retval)
1400 		goto out_free_cache;
1401 	nfsd_lockd_init();	/* lockd->nfsd callbacks */
1402 	retval = nfsd_idmap_init();
1403 	if (retval)
1404 		goto out_free_lockd;
1405 	retval = create_proc_exports_entry();
1406 	if (retval)
1407 		goto out_free_idmap;
1408 	retval = register_filesystem(&nfsd_fs_type);
1409 	if (retval)
1410 		goto out_free_all;
1411 	return 0;
1412 out_free_all:
1413 	remove_proc_entry("fs/nfs/exports", NULL);
1414 	remove_proc_entry("fs/nfs", NULL);
1415 out_free_idmap:
1416 	nfsd_idmap_shutdown();
1417 out_free_lockd:
1418 	nfsd_lockd_shutdown();
1419 	nfsd_export_shutdown();
1420 out_free_cache:
1421 	nfsd_reply_cache_shutdown();
1422 out_free_stat:
1423 	nfsd_stat_shutdown();
1424 	nfsd4_free_slabs();
1425 	return retval;
1426 }
1427 
1428 static void __exit exit_nfsd(void)
1429 {
1430 	nfsd_export_shutdown();
1431 	nfsd_reply_cache_shutdown();
1432 	remove_proc_entry("fs/nfs/exports", NULL);
1433 	remove_proc_entry("fs/nfs", NULL);
1434 	nfsd_stat_shutdown();
1435 	nfsd_lockd_shutdown();
1436 	nfsd_idmap_shutdown();
1437 	nfsd4_free_slabs();
1438 	unregister_filesystem(&nfsd_fs_type);
1439 }
1440 
1441 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
1442 MODULE_LICENSE("GPL");
1443 module_init(init_nfsd)
1444 module_exit(exit_nfsd)
1445