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