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

Archive Download this file



interactive