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