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