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