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