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