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