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