xref: /openbmc/linux/fs/nfsd/nfsctl.c (revision cff4fa84)
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 	NFSD_List,
28 	NFSD_Export_features,
29 	NFSD_Fh,
30 	NFSD_FO_UnlockIP,
31 	NFSD_FO_UnlockFS,
32 	NFSD_Threads,
33 	NFSD_Pool_Threads,
34 	NFSD_Pool_Stats,
35 	NFSD_Versions,
36 	NFSD_Ports,
37 	NFSD_MaxBlkSize,
38 	NFSD_SupportedEnctypes,
39 	/*
40 	 * The below MUST come last.  Otherwise we leave a hole in nfsd_files[]
41 	 * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops
42 	 */
43 #ifdef CONFIG_NFSD_V4
44 	NFSD_Leasetime,
45 	NFSD_Gracetime,
46 	NFSD_RecoveryDir,
47 #endif
48 };
49 
50 /*
51  * write() for these nodes.
52  */
53 static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
54 static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size);
55 static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size);
56 static ssize_t write_threads(struct file *file, char *buf, size_t size);
57 static ssize_t write_pool_threads(struct file *file, char *buf, size_t size);
58 static ssize_t write_versions(struct file *file, char *buf, size_t size);
59 static ssize_t write_ports(struct file *file, char *buf, size_t size);
60 static ssize_t write_maxblksize(struct file *file, char *buf, size_t size);
61 #ifdef CONFIG_NFSD_V4
62 static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
63 static ssize_t write_gracetime(struct file *file, char *buf, size_t size);
64 static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
65 #endif
66 
67 static ssize_t (*write_op[])(struct file *, char *, size_t) = {
68 	[NFSD_Fh] = write_filehandle,
69 	[NFSD_FO_UnlockIP] = write_unlock_ip,
70 	[NFSD_FO_UnlockFS] = write_unlock_fs,
71 	[NFSD_Threads] = write_threads,
72 	[NFSD_Pool_Threads] = write_pool_threads,
73 	[NFSD_Versions] = write_versions,
74 	[NFSD_Ports] = write_ports,
75 	[NFSD_MaxBlkSize] = write_maxblksize,
76 #ifdef CONFIG_NFSD_V4
77 	[NFSD_Leasetime] = write_leasetime,
78 	[NFSD_Gracetime] = write_gracetime,
79 	[NFSD_RecoveryDir] = write_recoverydir,
80 #endif
81 };
82 
83 static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
84 {
85 	ino_t ino =  file->f_path.dentry->d_inode->i_ino;
86 	char *data;
87 	ssize_t rv;
88 
89 	if (ino >= ARRAY_SIZE(write_op) || !write_op[ino])
90 		return -EINVAL;
91 
92 	data = simple_transaction_get(file, buf, size);
93 	if (IS_ERR(data))
94 		return PTR_ERR(data);
95 
96 	rv =  write_op[ino](file, data, size);
97 	if (rv >= 0) {
98 		simple_transaction_set(file, rv);
99 		rv = size;
100 	}
101 	return rv;
102 }
103 
104 static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
105 {
106 	if (! file->private_data) {
107 		/* An attempt to read a transaction file without writing
108 		 * causes a 0-byte write so that the file can return
109 		 * state information
110 		 */
111 		ssize_t rv = nfsctl_transaction_write(file, buf, 0, pos);
112 		if (rv < 0)
113 			return rv;
114 	}
115 	return simple_transaction_read(file, buf, size, pos);
116 }
117 
118 static const struct file_operations transaction_ops = {
119 	.write		= nfsctl_transaction_write,
120 	.read		= nfsctl_transaction_read,
121 	.release	= simple_transaction_release,
122 	.llseek		= default_llseek,
123 };
124 
125 static int exports_open(struct inode *inode, struct file *file)
126 {
127 	return seq_open(file, &nfs_exports_op);
128 }
129 
130 static const struct file_operations exports_operations = {
131 	.open		= exports_open,
132 	.read		= seq_read,
133 	.llseek		= seq_lseek,
134 	.release	= seq_release,
135 	.owner		= THIS_MODULE,
136 };
137 
138 static int export_features_show(struct seq_file *m, void *v)
139 {
140 	seq_printf(m, "0x%x 0x%x\n", NFSEXP_ALLFLAGS, NFSEXP_SECINFO_FLAGS);
141 	return 0;
142 }
143 
144 static int export_features_open(struct inode *inode, struct file *file)
145 {
146 	return single_open(file, export_features_show, NULL);
147 }
148 
149 static struct file_operations export_features_operations = {
150 	.open		= export_features_open,
151 	.read		= seq_read,
152 	.llseek		= seq_lseek,
153 	.release	= single_release,
154 };
155 
156 #if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE)
157 static int supported_enctypes_show(struct seq_file *m, void *v)
158 {
159 	seq_printf(m, KRB5_SUPPORTED_ENCTYPES);
160 	return 0;
161 }
162 
163 static int supported_enctypes_open(struct inode *inode, struct file *file)
164 {
165 	return single_open(file, supported_enctypes_show, NULL);
166 }
167 
168 static struct file_operations supported_enctypes_ops = {
169 	.open		= supported_enctypes_open,
170 	.read		= seq_read,
171 	.llseek		= seq_lseek,
172 	.release	= single_release,
173 };
174 #endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */
175 
176 extern int nfsd_pool_stats_open(struct inode *inode, struct file *file);
177 extern int nfsd_pool_stats_release(struct inode *inode, struct file *file);
178 
179 static const struct file_operations pool_stats_operations = {
180 	.open		= nfsd_pool_stats_open,
181 	.read		= seq_read,
182 	.llseek		= seq_lseek,
183 	.release	= nfsd_pool_stats_release,
184 	.owner		= THIS_MODULE,
185 };
186 
187 /*----------------------------------------------------------------------------*/
188 /*
189  * payload - write methods
190  */
191 
192 
193 /**
194  * write_unlock_ip - Release all locks used by a client
195  *
196  * Experimental.
197  *
198  * Input:
199  *			buf:	'\n'-terminated C string containing a
200  *				presentation format IP address
201  *			size:	length of C string in @buf
202  * Output:
203  *	On success:	returns zero if all specified locks were released;
204  *			returns one if one or more locks were not released
205  *	On error:	return code is negative errno value
206  */
207 static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
208 {
209 	struct sockaddr_storage address;
210 	struct sockaddr *sap = (struct sockaddr *)&address;
211 	size_t salen = sizeof(address);
212 	char *fo_path;
213 
214 	/* sanity check */
215 	if (size == 0)
216 		return -EINVAL;
217 
218 	if (buf[size-1] != '\n')
219 		return -EINVAL;
220 
221 	fo_path = buf;
222 	if (qword_get(&buf, fo_path, size) < 0)
223 		return -EINVAL;
224 
225 	if (rpc_pton(fo_path, size, sap, salen) == 0)
226 		return -EINVAL;
227 
228 	return nlmsvc_unlock_all_by_ip(sap);
229 }
230 
231 /**
232  * write_unlock_fs - Release all locks on a local file system
233  *
234  * Experimental.
235  *
236  * Input:
237  *			buf:	'\n'-terminated C string containing the
238  *				absolute pathname of a local file system
239  *			size:	length of C string in @buf
240  * Output:
241  *	On success:	returns zero if all specified locks were released;
242  *			returns one if one or more locks were not released
243  *	On error:	return code is negative errno value
244  */
245 static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size)
246 {
247 	struct path path;
248 	char *fo_path;
249 	int error;
250 
251 	/* sanity check */
252 	if (size == 0)
253 		return -EINVAL;
254 
255 	if (buf[size-1] != '\n')
256 		return -EINVAL;
257 
258 	fo_path = buf;
259 	if (qword_get(&buf, fo_path, size) < 0)
260 		return -EINVAL;
261 
262 	error = kern_path(fo_path, 0, &path);
263 	if (error)
264 		return error;
265 
266 	/*
267 	 * XXX: Needs better sanity checking.  Otherwise we could end up
268 	 * releasing locks on the wrong file system.
269 	 *
270 	 * For example:
271 	 * 1.  Does the path refer to a directory?
272 	 * 2.  Is that directory a mount point, or
273 	 * 3.  Is that directory the root of an exported file system?
274 	 */
275 	error = nlmsvc_unlock_all_by_sb(path.mnt->mnt_sb);
276 
277 	path_put(&path);
278 	return error;
279 }
280 
281 /**
282  * write_filehandle - Get a variable-length NFS file handle by path
283  *
284  * On input, the buffer contains a '\n'-terminated C string comprised of
285  * three alphanumeric words separated by whitespace.  The string may
286  * contain escape sequences.
287  *
288  * Input:
289  *			buf:
290  *				domain:		client domain name
291  *				path:		export pathname
292  *				maxsize:	numeric maximum size of
293  *						@buf
294  *			size:	length of C string in @buf
295  * Output:
296  *	On success:	passed-in buffer filled with '\n'-terminated C
297  *			string containing a ASCII hex text version
298  *			of the NFS file handle;
299  *			return code is the size in bytes of the string
300  *	On error:	return code is negative errno value
301  */
302 static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
303 {
304 	char *dname, *path;
305 	int uninitialized_var(maxsize);
306 	char *mesg = buf;
307 	int len;
308 	struct auth_domain *dom;
309 	struct knfsd_fh fh;
310 
311 	if (size == 0)
312 		return -EINVAL;
313 
314 	if (buf[size-1] != '\n')
315 		return -EINVAL;
316 	buf[size-1] = 0;
317 
318 	dname = mesg;
319 	len = qword_get(&mesg, dname, size);
320 	if (len <= 0)
321 		return -EINVAL;
322 
323 	path = dname+len+1;
324 	len = qword_get(&mesg, path, size);
325 	if (len <= 0)
326 		return -EINVAL;
327 
328 	len = get_int(&mesg, &maxsize);
329 	if (len)
330 		return len;
331 
332 	if (maxsize < NFS_FHSIZE)
333 		return -EINVAL;
334 	if (maxsize > NFS3_FHSIZE)
335 		maxsize = NFS3_FHSIZE;
336 
337 	if (qword_get(&mesg, mesg, size)>0)
338 		return -EINVAL;
339 
340 	/* we have all the words, they are in buf.. */
341 	dom = unix_domain_find(dname);
342 	if (!dom)
343 		return -ENOMEM;
344 
345 	len = exp_rootfh(dom, path, &fh,  maxsize);
346 	auth_domain_put(dom);
347 	if (len)
348 		return len;
349 
350 	mesg = buf;
351 	len = SIMPLE_TRANSACTION_LIMIT;
352 	qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size);
353 	mesg[-1] = '\n';
354 	return mesg - buf;
355 }
356 
357 /**
358  * write_threads - Start NFSD, or report the current number of running threads
359  *
360  * Input:
361  *			buf:		ignored
362  *			size:		zero
363  * Output:
364  *	On success:	passed-in buffer filled with '\n'-terminated C
365  *			string numeric value representing the number of
366  *			running NFSD threads;
367  *			return code is the size in bytes of the string
368  *	On error:	return code is zero
369  *
370  * OR
371  *
372  * Input:
373  *			buf:		C string containing an unsigned
374  *					integer value representing the
375  *					number of NFSD threads to start
376  *			size:		non-zero length of C string in @buf
377  * Output:
378  *	On success:	NFS service is started;
379  *			passed-in buffer filled with '\n'-terminated C
380  *			string numeric value representing the number of
381  *			running NFSD threads;
382  *			return code is the size in bytes of the string
383  *	On error:	return code is zero or a negative errno value
384  */
385 static ssize_t write_threads(struct file *file, char *buf, size_t size)
386 {
387 	char *mesg = buf;
388 	int rv;
389 	if (size > 0) {
390 		int newthreads;
391 		rv = get_int(&mesg, &newthreads);
392 		if (rv)
393 			return rv;
394 		if (newthreads < 0)
395 			return -EINVAL;
396 		rv = nfsd_svc(NFS_PORT, newthreads);
397 		if (rv < 0)
398 			return rv;
399 	} else
400 		rv = nfsd_nrthreads();
401 
402 	return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv);
403 }
404 
405 /**
406  * write_pool_threads - Set or report the current number of threads per pool
407  *
408  * Input:
409  *			buf:		ignored
410  *			size:		zero
411  *
412  * OR
413  *
414  * Input:
415  * 			buf:		C string containing whitespace-
416  * 					separated unsigned integer values
417  *					representing the number of NFSD
418  *					threads to start in each pool
419  *			size:		non-zero length of C string in @buf
420  * Output:
421  *	On success:	passed-in buffer filled with '\n'-terminated C
422  *			string containing integer values representing the
423  *			number of NFSD threads in each pool;
424  *			return code is the size in bytes of the string
425  *	On error:	return code is zero or a negative errno value
426  */
427 static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
428 {
429 	/* if size > 0, look for an array of number of threads per node
430 	 * and apply them  then write out number of threads per node as reply
431 	 */
432 	char *mesg = buf;
433 	int i;
434 	int rv;
435 	int len;
436 	int npools;
437 	int *nthreads;
438 
439 	mutex_lock(&nfsd_mutex);
440 	npools = nfsd_nrpools();
441 	if (npools == 0) {
442 		/*
443 		 * NFS is shut down.  The admin can start it by
444 		 * writing to the threads file but NOT the pool_threads
445 		 * file, sorry.  Report zero threads.
446 		 */
447 		mutex_unlock(&nfsd_mutex);
448 		strcpy(buf, "0\n");
449 		return strlen(buf);
450 	}
451 
452 	nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL);
453 	rv = -ENOMEM;
454 	if (nthreads == NULL)
455 		goto out_free;
456 
457 	if (size > 0) {
458 		for (i = 0; i < npools; i++) {
459 			rv = get_int(&mesg, &nthreads[i]);
460 			if (rv == -ENOENT)
461 				break;		/* fewer numbers than pools */
462 			if (rv)
463 				goto out_free;	/* syntax error */
464 			rv = -EINVAL;
465 			if (nthreads[i] < 0)
466 				goto out_free;
467 		}
468 		rv = nfsd_set_nrthreads(i, nthreads);
469 		if (rv)
470 			goto out_free;
471 	}
472 
473 	rv = nfsd_get_nrthreads(npools, nthreads);
474 	if (rv)
475 		goto out_free;
476 
477 	mesg = buf;
478 	size = SIMPLE_TRANSACTION_LIMIT;
479 	for (i = 0; i < npools && size > 0; i++) {
480 		snprintf(mesg, size, "%d%c", nthreads[i], (i == npools-1 ? '\n' : ' '));
481 		len = strlen(mesg);
482 		size -= len;
483 		mesg += len;
484 	}
485 	rv = mesg - buf;
486 out_free:
487 	kfree(nthreads);
488 	mutex_unlock(&nfsd_mutex);
489 	return rv;
490 }
491 
492 static ssize_t __write_versions(struct file *file, char *buf, size_t size)
493 {
494 	char *mesg = buf;
495 	char *vers, *minorp, sign;
496 	int len, num, remaining;
497 	unsigned minor;
498 	ssize_t tlen = 0;
499 	char *sep;
500 
501 	if (size>0) {
502 		if (nfsd_serv)
503 			/* Cannot change versions without updating
504 			 * nfsd_serv->sv_xdrsize, and reallocing
505 			 * rq_argp and rq_resp
506 			 */
507 			return -EBUSY;
508 		if (buf[size-1] != '\n')
509 			return -EINVAL;
510 		buf[size-1] = 0;
511 
512 		vers = mesg;
513 		len = qword_get(&mesg, vers, size);
514 		if (len <= 0) return -EINVAL;
515 		do {
516 			sign = *vers;
517 			if (sign == '+' || sign == '-')
518 				num = simple_strtol((vers+1), &minorp, 0);
519 			else
520 				num = simple_strtol(vers, &minorp, 0);
521 			if (*minorp == '.') {
522 				if (num < 4)
523 					return -EINVAL;
524 				minor = simple_strtoul(minorp+1, NULL, 0);
525 				if (minor == 0)
526 					return -EINVAL;
527 				if (nfsd_minorversion(minor, sign == '-' ?
528 						     NFSD_CLEAR : NFSD_SET) < 0)
529 					return -EINVAL;
530 				goto next;
531 			}
532 			switch(num) {
533 			case 2:
534 			case 3:
535 			case 4:
536 				nfsd_vers(num, sign == '-' ? NFSD_CLEAR : NFSD_SET);
537 				break;
538 			default:
539 				return -EINVAL;
540 			}
541 		next:
542 			vers += len + 1;
543 		} while ((len = qword_get(&mesg, vers, size)) > 0);
544 		/* If all get turned off, turn them back on, as
545 		 * having no versions is BAD
546 		 */
547 		nfsd_reset_versions();
548 	}
549 
550 	/* Now write current state into reply buffer */
551 	len = 0;
552 	sep = "";
553 	remaining = SIMPLE_TRANSACTION_LIMIT;
554 	for (num=2 ; num <= 4 ; num++)
555 		if (nfsd_vers(num, NFSD_AVAIL)) {
556 			len = snprintf(buf, remaining, "%s%c%d", sep,
557 				       nfsd_vers(num, NFSD_TEST)?'+':'-',
558 				       num);
559 			sep = " ";
560 
561 			if (len > remaining)
562 				break;
563 			remaining -= len;
564 			buf += len;
565 			tlen += len;
566 		}
567 	if (nfsd_vers(4, NFSD_AVAIL))
568 		for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION;
569 		     minor++) {
570 			len = snprintf(buf, remaining, " %c4.%u",
571 					(nfsd_vers(4, NFSD_TEST) &&
572 					 nfsd_minorversion(minor, NFSD_TEST)) ?
573 						'+' : '-',
574 					minor);
575 
576 			if (len > remaining)
577 				break;
578 			remaining -= len;
579 			buf += len;
580 			tlen += len;
581 		}
582 
583 	len = snprintf(buf, remaining, "\n");
584 	if (len > remaining)
585 		return -EINVAL;
586 	return tlen + len;
587 }
588 
589 /**
590  * write_versions - Set or report the available NFS protocol versions
591  *
592  * Input:
593  *			buf:		ignored
594  *			size:		zero
595  * Output:
596  *	On success:	passed-in buffer filled with '\n'-terminated C
597  *			string containing positive or negative integer
598  *			values representing the current status of each
599  *			protocol version;
600  *			return code is the size in bytes of the string
601  *	On error:	return code is zero or a negative errno value
602  *
603  * OR
604  *
605  * Input:
606  * 			buf:		C string containing whitespace-
607  * 					separated positive or negative
608  * 					integer values representing NFS
609  * 					protocol versions to enable ("+n")
610  * 					or disable ("-n")
611  *			size:		non-zero length of C string in @buf
612  * Output:
613  *	On success:	status of zero or more protocol versions has
614  *			been updated; passed-in buffer filled with
615  *			'\n'-terminated C string containing positive
616  *			or negative integer values representing the
617  *			current status of each protocol version;
618  *			return code is the size in bytes of the string
619  *	On error:	return code is zero or a negative errno value
620  */
621 static ssize_t write_versions(struct file *file, char *buf, size_t size)
622 {
623 	ssize_t rv;
624 
625 	mutex_lock(&nfsd_mutex);
626 	rv = __write_versions(file, buf, size);
627 	mutex_unlock(&nfsd_mutex);
628 	return rv;
629 }
630 
631 /*
632  * Zero-length write.  Return a list of NFSD's current listener
633  * transports.
634  */
635 static ssize_t __write_ports_names(char *buf)
636 {
637 	if (nfsd_serv == NULL)
638 		return 0;
639 	return svc_xprt_names(nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT);
640 }
641 
642 /*
643  * A single 'fd' number was written, in which case it must be for
644  * a socket of a supported family/protocol, and we use it as an
645  * nfsd listener.
646  */
647 static ssize_t __write_ports_addfd(char *buf)
648 {
649 	char *mesg = buf;
650 	int fd, err;
651 
652 	err = get_int(&mesg, &fd);
653 	if (err != 0 || fd < 0)
654 		return -EINVAL;
655 
656 	err = nfsd_create_serv();
657 	if (err != 0)
658 		return err;
659 
660 	err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
661 	if (err < 0) {
662 		svc_destroy(nfsd_serv);
663 		return err;
664 	}
665 
666 	/* Decrease the count, but don't shut down the service */
667 	nfsd_serv->sv_nrthreads--;
668 	return err;
669 }
670 
671 /*
672  * A '-' followed by the 'name' of a socket means we close the socket.
673  */
674 static ssize_t __write_ports_delfd(char *buf)
675 {
676 	char *toclose;
677 	int len = 0;
678 
679 	toclose = kstrdup(buf + 1, GFP_KERNEL);
680 	if (toclose == NULL)
681 		return -ENOMEM;
682 
683 	if (nfsd_serv != NULL)
684 		len = svc_sock_names(nfsd_serv, buf,
685 					SIMPLE_TRANSACTION_LIMIT, toclose);
686 	kfree(toclose);
687 	return len;
688 }
689 
690 /*
691  * A transport listener is added by writing it's transport name and
692  * a port number.
693  */
694 static ssize_t __write_ports_addxprt(char *buf)
695 {
696 	char transport[16];
697 	struct svc_xprt *xprt;
698 	int port, err;
699 
700 	if (sscanf(buf, "%15s %4u", transport, &port) != 2)
701 		return -EINVAL;
702 
703 	if (port < 1 || port > USHRT_MAX)
704 		return -EINVAL;
705 
706 	err = nfsd_create_serv();
707 	if (err != 0)
708 		return err;
709 
710 	err = svc_create_xprt(nfsd_serv, transport, &init_net,
711 				PF_INET, port, SVC_SOCK_ANONYMOUS);
712 	if (err < 0)
713 		goto out_err;
714 
715 	err = svc_create_xprt(nfsd_serv, transport, &init_net,
716 				PF_INET6, port, SVC_SOCK_ANONYMOUS);
717 	if (err < 0 && err != -EAFNOSUPPORT)
718 		goto out_close;
719 
720 	/* Decrease the count, but don't shut down the service */
721 	nfsd_serv->sv_nrthreads--;
722 	return 0;
723 out_close:
724 	xprt = svc_find_xprt(nfsd_serv, transport, PF_INET, port);
725 	if (xprt != NULL) {
726 		svc_close_xprt(xprt);
727 		svc_xprt_put(xprt);
728 	}
729 out_err:
730 	svc_destroy(nfsd_serv);
731 	return err;
732 }
733 
734 /*
735  * A transport listener is removed by writing a "-", it's transport
736  * name, and it's port number.
737  */
738 static ssize_t __write_ports_delxprt(char *buf)
739 {
740 	struct svc_xprt *xprt;
741 	char transport[16];
742 	int port;
743 
744 	if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2)
745 		return -EINVAL;
746 
747 	if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL)
748 		return -EINVAL;
749 
750 	xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port);
751 	if (xprt == NULL)
752 		return -ENOTCONN;
753 
754 	svc_close_xprt(xprt);
755 	svc_xprt_put(xprt);
756 	return 0;
757 }
758 
759 static ssize_t __write_ports(struct file *file, char *buf, size_t size)
760 {
761 	if (size == 0)
762 		return __write_ports_names(buf);
763 
764 	if (isdigit(buf[0]))
765 		return __write_ports_addfd(buf);
766 
767 	if (buf[0] == '-' && isdigit(buf[1]))
768 		return __write_ports_delfd(buf);
769 
770 	if (isalpha(buf[0]))
771 		return __write_ports_addxprt(buf);
772 
773 	if (buf[0] == '-' && isalpha(buf[1]))
774 		return __write_ports_delxprt(buf);
775 
776 	return -EINVAL;
777 }
778 
779 /**
780  * write_ports - Pass a socket file descriptor or transport name to listen on
781  *
782  * Input:
783  *			buf:		ignored
784  *			size:		zero
785  * Output:
786  *	On success:	passed-in buffer filled with a '\n'-terminated C
787  *			string containing a whitespace-separated list of
788  *			named NFSD listeners;
789  *			return code is the size in bytes of the string
790  *	On error:	return code is zero or a negative errno value
791  *
792  * OR
793  *
794  * Input:
795  *			buf:		C string containing an unsigned
796  *					integer value representing a bound
797  *					but unconnected socket that is to be
798  *					used as an NFSD listener; listen(3)
799  *					must be called for a SOCK_STREAM
800  *					socket, otherwise it is ignored
801  *			size:		non-zero length of C string in @buf
802  * Output:
803  *	On success:	NFS service is started;
804  *			passed-in buffer filled with a '\n'-terminated C
805  *			string containing a unique alphanumeric name of
806  *			the listener;
807  *			return code is the size in bytes of the string
808  *	On error:	return code is a negative errno value
809  *
810  * OR
811  *
812  * Input:
813  *			buf:		C string containing a "-" followed
814  *					by an integer value representing a
815  *					previously passed in socket file
816  *					descriptor
817  *			size:		non-zero length of C string in @buf
818  * Output:
819  *	On success:	NFS service no longer listens on that socket;
820  *			passed-in buffer filled with a '\n'-terminated C
821  *			string containing a unique name of the listener;
822  *			return code is the size in bytes of the string
823  *	On error:	return code is a negative errno value
824  *
825  * OR
826  *
827  * Input:
828  *			buf:		C string containing a transport
829  *					name and an unsigned integer value
830  *					representing the port to listen on,
831  *					separated by whitespace
832  *			size:		non-zero length of C string in @buf
833  * Output:
834  *	On success:	returns zero; NFS service is started
835  *	On error:	return code is a negative errno value
836  *
837  * OR
838  *
839  * Input:
840  *			buf:		C string containing a "-" followed
841  *					by a transport name and an unsigned
842  *					integer value representing the port
843  *					to listen on, separated by whitespace
844  *			size:		non-zero length of C string in @buf
845  * Output:
846  *	On success:	returns zero; NFS service no longer listens
847  *			on that transport
848  *	On error:	return code is a negative errno value
849  */
850 static ssize_t write_ports(struct file *file, char *buf, size_t size)
851 {
852 	ssize_t rv;
853 
854 	mutex_lock(&nfsd_mutex);
855 	rv = __write_ports(file, buf, size);
856 	mutex_unlock(&nfsd_mutex);
857 	return rv;
858 }
859 
860 
861 int nfsd_max_blksize;
862 
863 /**
864  * write_maxblksize - Set or report the current NFS blksize
865  *
866  * Input:
867  *			buf:		ignored
868  *			size:		zero
869  *
870  * OR
871  *
872  * Input:
873  * 			buf:		C string containing an unsigned
874  * 					integer value representing the new
875  * 					NFS blksize
876  *			size:		non-zero length of C string in @buf
877  * Output:
878  *	On success:	passed-in buffer filled with '\n'-terminated C string
879  *			containing numeric value of the current NFS blksize
880  *			setting;
881  *			return code is the size in bytes of the string
882  *	On error:	return code is zero or a negative errno value
883  */
884 static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
885 {
886 	char *mesg = buf;
887 	if (size > 0) {
888 		int bsize;
889 		int rv = get_int(&mesg, &bsize);
890 		if (rv)
891 			return rv;
892 		/* force bsize into allowed range and
893 		 * required alignment.
894 		 */
895 		if (bsize < 1024)
896 			bsize = 1024;
897 		if (bsize > NFSSVC_MAXBLKSIZE)
898 			bsize = NFSSVC_MAXBLKSIZE;
899 		bsize &= ~(1024-1);
900 		mutex_lock(&nfsd_mutex);
901 		if (nfsd_serv) {
902 			mutex_unlock(&nfsd_mutex);
903 			return -EBUSY;
904 		}
905 		nfsd_max_blksize = bsize;
906 		mutex_unlock(&nfsd_mutex);
907 	}
908 
909 	return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n",
910 							nfsd_max_blksize);
911 }
912 
913 #ifdef CONFIG_NFSD_V4
914 static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time)
915 {
916 	char *mesg = buf;
917 	int rv, i;
918 
919 	if (size > 0) {
920 		if (nfsd_serv)
921 			return -EBUSY;
922 		rv = get_int(&mesg, &i);
923 		if (rv)
924 			return rv;
925 		/*
926 		 * Some sanity checking.  We don't have a reason for
927 		 * these particular numbers, but problems with the
928 		 * extremes are:
929 		 *	- Too short: the briefest network outage may
930 		 *	  cause clients to lose all their locks.  Also,
931 		 *	  the frequent polling may be wasteful.
932 		 *	- Too long: do you really want reboot recovery
933 		 *	  to take more than an hour?  Or to make other
934 		 *	  clients wait an hour before being able to
935 		 *	  revoke a dead client's locks?
936 		 */
937 		if (i < 10 || i > 3600)
938 			return -EINVAL;
939 		*time = i;
940 	}
941 
942 	return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n", *time);
943 }
944 
945 static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time)
946 {
947 	ssize_t rv;
948 
949 	mutex_lock(&nfsd_mutex);
950 	rv = __nfsd4_write_time(file, buf, size, time);
951 	mutex_unlock(&nfsd_mutex);
952 	return rv;
953 }
954 
955 /**
956  * write_leasetime - Set or report the current NFSv4 lease time
957  *
958  * Input:
959  *			buf:		ignored
960  *			size:		zero
961  *
962  * OR
963  *
964  * Input:
965  *			buf:		C string containing an unsigned
966  *					integer value representing the new
967  *					NFSv4 lease expiry time
968  *			size:		non-zero length of C string in @buf
969  * Output:
970  *	On success:	passed-in buffer filled with '\n'-terminated C
971  *			string containing unsigned integer value of the
972  *			current lease expiry time;
973  *			return code is the size in bytes of the string
974  *	On error:	return code is zero or a negative errno value
975  */
976 static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
977 {
978 	return nfsd4_write_time(file, buf, size, &nfsd4_lease);
979 }
980 
981 /**
982  * write_gracetime - Set or report current NFSv4 grace period time
983  *
984  * As above, but sets the time of the NFSv4 grace period.
985  *
986  * Note this should never be set to less than the *previous*
987  * lease-period time, but we don't try to enforce this.  (In the common
988  * case (a new boot), we don't know what the previous lease time was
989  * anyway.)
990  */
991 static ssize_t write_gracetime(struct file *file, char *buf, size_t size)
992 {
993 	return nfsd4_write_time(file, buf, size, &nfsd4_grace);
994 }
995 
996 extern char *nfs4_recoverydir(void);
997 
998 static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)
999 {
1000 	char *mesg = buf;
1001 	char *recdir;
1002 	int len, status;
1003 
1004 	if (size > 0) {
1005 		if (nfsd_serv)
1006 			return -EBUSY;
1007 		if (size > PATH_MAX || buf[size-1] != '\n')
1008 			return -EINVAL;
1009 		buf[size-1] = 0;
1010 
1011 		recdir = mesg;
1012 		len = qword_get(&mesg, recdir, size);
1013 		if (len <= 0)
1014 			return -EINVAL;
1015 
1016 		status = nfs4_reset_recoverydir(recdir);
1017 		if (status)
1018 			return status;
1019 	}
1020 
1021 	return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n",
1022 							nfs4_recoverydir());
1023 }
1024 
1025 /**
1026  * write_recoverydir - Set or report the pathname of the recovery directory
1027  *
1028  * Input:
1029  *			buf:		ignored
1030  *			size:		zero
1031  *
1032  * OR
1033  *
1034  * Input:
1035  *			buf:		C string containing the pathname
1036  *					of the directory on a local file
1037  *					system containing permanent NFSv4
1038  *					recovery data
1039  *			size:		non-zero length of C string in @buf
1040  * Output:
1041  *	On success:	passed-in buffer filled with '\n'-terminated C string
1042  *			containing the current recovery pathname setting;
1043  *			return code is the size in bytes of the string
1044  *	On error:	return code is zero or a negative errno value
1045  */
1046 static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
1047 {
1048 	ssize_t rv;
1049 
1050 	mutex_lock(&nfsd_mutex);
1051 	rv = __write_recoverydir(file, buf, size);
1052 	mutex_unlock(&nfsd_mutex);
1053 	return rv;
1054 }
1055 
1056 #endif
1057 
1058 /*----------------------------------------------------------------------------*/
1059 /*
1060  *	populating the filesystem.
1061  */
1062 
1063 static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
1064 {
1065 	static struct tree_descr nfsd_files[] = {
1066 		[NFSD_List] = {"exports", &exports_operations, S_IRUGO},
1067 		[NFSD_Export_features] = {"export_features",
1068 					&export_features_operations, S_IRUGO},
1069 		[NFSD_FO_UnlockIP] = {"unlock_ip",
1070 					&transaction_ops, S_IWUSR|S_IRUSR},
1071 		[NFSD_FO_UnlockFS] = {"unlock_filesystem",
1072 					&transaction_ops, S_IWUSR|S_IRUSR},
1073 		[NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
1074 		[NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
1075 		[NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},
1076 		[NFSD_Pool_Stats] = {"pool_stats", &pool_stats_operations, S_IRUGO},
1077 		[NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
1078 		[NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
1079 		[NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
1080 #if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE)
1081 		[NFSD_SupportedEnctypes] = {"supported_krb5_enctypes", &supported_enctypes_ops, S_IRUGO},
1082 #endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */
1083 #ifdef CONFIG_NFSD_V4
1084 		[NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
1085 		[NFSD_Gracetime] = {"nfsv4gracetime", &transaction_ops, S_IWUSR|S_IRUSR},
1086 		[NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
1087 #endif
1088 		/* last one */ {""}
1089 	};
1090 	return simple_fill_super(sb, 0x6e667364, nfsd_files);
1091 }
1092 
1093 static struct dentry *nfsd_mount(struct file_system_type *fs_type,
1094 	int flags, const char *dev_name, void *data)
1095 {
1096 	return mount_single(fs_type, flags, data, nfsd_fill_super);
1097 }
1098 
1099 static struct file_system_type nfsd_fs_type = {
1100 	.owner		= THIS_MODULE,
1101 	.name		= "nfsd",
1102 	.mount		= nfsd_mount,
1103 	.kill_sb	= kill_litter_super,
1104 };
1105 
1106 #ifdef CONFIG_PROC_FS
1107 static int create_proc_exports_entry(void)
1108 {
1109 	struct proc_dir_entry *entry;
1110 
1111 	entry = proc_mkdir("fs/nfs", NULL);
1112 	if (!entry)
1113 		return -ENOMEM;
1114 	entry = proc_create("exports", 0, entry, &exports_operations);
1115 	if (!entry)
1116 		return -ENOMEM;
1117 	return 0;
1118 }
1119 #else /* CONFIG_PROC_FS */
1120 static int create_proc_exports_entry(void)
1121 {
1122 	return 0;
1123 }
1124 #endif
1125 
1126 static int __init init_nfsd(void)
1127 {
1128 	int retval;
1129 	printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
1130 
1131 	retval = nfs4_state_init(); /* nfs4 locking state */
1132 	if (retval)
1133 		return retval;
1134 	nfsd_stat_init();	/* Statistics */
1135 	retval = nfsd_reply_cache_init();
1136 	if (retval)
1137 		goto out_free_stat;
1138 	retval = nfsd_export_init();
1139 	if (retval)
1140 		goto out_free_cache;
1141 	nfsd_lockd_init();	/* lockd->nfsd callbacks */
1142 	retval = nfsd_idmap_init();
1143 	if (retval)
1144 		goto out_free_lockd;
1145 	retval = create_proc_exports_entry();
1146 	if (retval)
1147 		goto out_free_idmap;
1148 	retval = register_filesystem(&nfsd_fs_type);
1149 	if (retval)
1150 		goto out_free_all;
1151 	return 0;
1152 out_free_all:
1153 	remove_proc_entry("fs/nfs/exports", NULL);
1154 	remove_proc_entry("fs/nfs", NULL);
1155 out_free_idmap:
1156 	nfsd_idmap_shutdown();
1157 out_free_lockd:
1158 	nfsd_lockd_shutdown();
1159 	nfsd_export_shutdown();
1160 out_free_cache:
1161 	nfsd_reply_cache_shutdown();
1162 out_free_stat:
1163 	nfsd_stat_shutdown();
1164 	nfsd4_free_slabs();
1165 	return retval;
1166 }
1167 
1168 static void __exit exit_nfsd(void)
1169 {
1170 	nfsd_export_shutdown();
1171 	nfsd_reply_cache_shutdown();
1172 	remove_proc_entry("fs/nfs/exports", NULL);
1173 	remove_proc_entry("fs/nfs", NULL);
1174 	nfsd_stat_shutdown();
1175 	nfsd_lockd_shutdown();
1176 	nfsd_idmap_shutdown();
1177 	nfsd4_free_slabs();
1178 	unregister_filesystem(&nfsd_fs_type);
1179 }
1180 
1181 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
1182 MODULE_LICENSE("GPL");
1183 module_init(init_nfsd)
1184 module_exit(exit_nfsd)
1185