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