Root/fs/lockd/svc.c

1/*
2 * linux/fs/lockd/svc.c
3 *
4 * This is the central lockd service.
5 *
6 * FIXME: Separate the lockd NFS server functionality from the lockd NFS
7 * client functionality. Oh why didn't Sun create two separate
8 * services in the first place?
9 *
10 * Authors: Olaf Kirch (okir@monad.swb.de)
11 *
12 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
13 */
14
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/sysctl.h>
18#include <linux/moduleparam.h>
19
20#include <linux/sched.h>
21#include <linux/errno.h>
22#include <linux/in.h>
23#include <linux/uio.h>
24#include <linux/smp.h>
25#include <linux/mutex.h>
26#include <linux/kthread.h>
27#include <linux/freezer.h>
28
29#include <linux/sunrpc/types.h>
30#include <linux/sunrpc/stats.h>
31#include <linux/sunrpc/clnt.h>
32#include <linux/sunrpc/svc.h>
33#include <linux/sunrpc/svcsock.h>
34#include <net/ip.h>
35#include <linux/lockd/lockd.h>
36#include <linux/nfs.h>
37
38#define NLMDBG_FACILITY NLMDBG_SVC
39#define LOCKD_BUFSIZE (1024 + NLMSVC_XDRSIZE)
40#define ALLOWED_SIGS (sigmask(SIGKILL))
41
42static struct svc_program nlmsvc_program;
43
44struct nlmsvc_binding * nlmsvc_ops;
45EXPORT_SYMBOL_GPL(nlmsvc_ops);
46
47static DEFINE_MUTEX(nlmsvc_mutex);
48static unsigned int nlmsvc_users;
49static struct task_struct *nlmsvc_task;
50static struct svc_rqst *nlmsvc_rqst;
51unsigned long nlmsvc_timeout;
52
53/*
54 * These can be set at insmod time (useful for NFS as root filesystem),
55 * and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003
56 */
57static unsigned long nlm_grace_period;
58static unsigned long nlm_timeout = LOCKD_DFLT_TIMEO;
59static int nlm_udpport, nlm_tcpport;
60
61/* RLIM_NOFILE defaults to 1024. That seems like a reasonable default here. */
62static unsigned int nlm_max_connections = 1024;
63
64/*
65 * Constants needed for the sysctl interface.
66 */
67static const unsigned long nlm_grace_period_min = 0;
68static const unsigned long nlm_grace_period_max = 240;
69static const unsigned long nlm_timeout_min = 3;
70static const unsigned long nlm_timeout_max = 20;
71static const int nlm_port_min = 0, nlm_port_max = 65535;
72
73#ifdef CONFIG_SYSCTL
74static struct ctl_table_header * nlm_sysctl_table;
75#endif
76
77static unsigned long get_lockd_grace_period(void)
78{
79    /* Note: nlm_timeout should always be nonzero */
80    if (nlm_grace_period)
81        return roundup(nlm_grace_period, nlm_timeout) * HZ;
82    else
83        return nlm_timeout * 5 * HZ;
84}
85
86static struct lock_manager lockd_manager = {
87};
88
89static void grace_ender(struct work_struct *not_used)
90{
91    locks_end_grace(&lockd_manager);
92}
93
94static DECLARE_DELAYED_WORK(grace_period_end, grace_ender);
95
96static void set_grace_period(void)
97{
98    unsigned long grace_period = get_lockd_grace_period();
99
100    locks_start_grace(&lockd_manager);
101    cancel_delayed_work_sync(&grace_period_end);
102    schedule_delayed_work(&grace_period_end, grace_period);
103}
104
105static void restart_grace(void)
106{
107    if (nlmsvc_ops) {
108        cancel_delayed_work_sync(&grace_period_end);
109        locks_end_grace(&lockd_manager);
110        nlmsvc_invalidate_all();
111        set_grace_period();
112    }
113}
114
115/*
116 * This is the lockd kernel thread
117 */
118static int
119lockd(void *vrqstp)
120{
121    int err = 0, preverr = 0;
122    struct svc_rqst *rqstp = vrqstp;
123
124    /* try_to_freeze() is called from svc_recv() */
125    set_freezable();
126
127    /* Allow SIGKILL to tell lockd to drop all of its locks */
128    allow_signal(SIGKILL);
129
130    dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
131
132    if (!nlm_timeout)
133        nlm_timeout = LOCKD_DFLT_TIMEO;
134    nlmsvc_timeout = nlm_timeout * HZ;
135
136    set_grace_period();
137
138    /*
139     * The main request loop. We don't terminate until the last
140     * NFS mount or NFS daemon has gone away.
141     */
142    while (!kthread_should_stop()) {
143        long timeout = MAX_SCHEDULE_TIMEOUT;
144        RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
145
146        /* update sv_maxconn if it has changed */
147        rqstp->rq_server->sv_maxconn = nlm_max_connections;
148
149        if (signalled()) {
150            flush_signals(current);
151            restart_grace();
152            continue;
153        }
154
155        timeout = nlmsvc_retry_blocked();
156
157        /*
158         * Find a socket with data available and call its
159         * recvfrom routine.
160         */
161        err = svc_recv(rqstp, timeout);
162        if (err == -EAGAIN || err == -EINTR) {
163            preverr = err;
164            continue;
165        }
166        if (err < 0) {
167            if (err != preverr) {
168                printk(KERN_WARNING "%s: unexpected error "
169                    "from svc_recv (%d)\n", __func__, err);
170                preverr = err;
171            }
172            schedule_timeout_interruptible(HZ);
173            continue;
174        }
175        preverr = err;
176
177        dprintk("lockd: request from %s\n",
178                svc_print_addr(rqstp, buf, sizeof(buf)));
179
180        svc_process(rqstp);
181    }
182    flush_signals(current);
183    cancel_delayed_work_sync(&grace_period_end);
184    locks_end_grace(&lockd_manager);
185    if (nlmsvc_ops)
186        nlmsvc_invalidate_all();
187    nlm_shutdown_hosts();
188    return 0;
189}
190
191static int create_lockd_listener(struct svc_serv *serv, const char *name,
192                 const int family, const unsigned short port)
193{
194    struct svc_xprt *xprt;
195
196    xprt = svc_find_xprt(serv, name, family, 0);
197    if (xprt == NULL)
198        return svc_create_xprt(serv, name, &init_net, family, port,
199                        SVC_SOCK_DEFAULTS);
200    svc_xprt_put(xprt);
201    return 0;
202}
203
204static int create_lockd_family(struct svc_serv *serv, const int family)
205{
206    int err;
207
208    err = create_lockd_listener(serv, "udp", family, nlm_udpport);
209    if (err < 0)
210        return err;
211
212    return create_lockd_listener(serv, "tcp", family, nlm_tcpport);
213}
214
215/*
216 * Ensure there are active UDP and TCP listeners for lockd.
217 *
218 * Even if we have only TCP NFS mounts and/or TCP NFSDs, some
219 * local services (such as rpc.statd) still require UDP, and
220 * some NFS servers do not yet support NLM over TCP.
221 *
222 * Returns zero if all listeners are available; otherwise a
223 * negative errno value is returned.
224 */
225static int make_socks(struct svc_serv *serv)
226{
227    static int warned;
228    int err;
229
230    err = create_lockd_family(serv, PF_INET);
231    if (err < 0)
232        goto out_err;
233
234    err = create_lockd_family(serv, PF_INET6);
235    if (err < 0 && err != -EAFNOSUPPORT)
236        goto out_err;
237
238    warned = 0;
239    return 0;
240
241out_err:
242    if (warned++ == 0)
243        printk(KERN_WARNING
244            "lockd_up: makesock failed, error=%d\n", err);
245    return err;
246}
247
248/*
249 * Bring up the lockd process if it's not already up.
250 */
251int lockd_up(void)
252{
253    struct svc_serv *serv;
254    int error = 0;
255
256    mutex_lock(&nlmsvc_mutex);
257    /*
258     * Check whether we're already up and running.
259     */
260    if (nlmsvc_rqst)
261        goto out;
262
263    /*
264     * Sanity check: if there's no pid,
265     * we should be the first user ...
266     */
267    if (nlmsvc_users)
268        printk(KERN_WARNING
269            "lockd_up: no pid, %d users??\n", nlmsvc_users);
270
271    error = -ENOMEM;
272    serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, NULL);
273    if (!serv) {
274        printk(KERN_WARNING "lockd_up: create service failed\n");
275        goto out;
276    }
277
278    error = make_socks(serv);
279    if (error < 0)
280        goto destroy_and_out;
281
282    /*
283     * Create the kernel thread and wait for it to start.
284     */
285    nlmsvc_rqst = svc_prepare_thread(serv, &serv->sv_pools[0]);
286    if (IS_ERR(nlmsvc_rqst)) {
287        error = PTR_ERR(nlmsvc_rqst);
288        nlmsvc_rqst = NULL;
289        printk(KERN_WARNING
290            "lockd_up: svc_rqst allocation failed, error=%d\n",
291            error);
292        goto destroy_and_out;
293    }
294
295    svc_sock_update_bufs(serv);
296    serv->sv_maxconn = nlm_max_connections;
297
298    nlmsvc_task = kthread_run(lockd, nlmsvc_rqst, serv->sv_name);
299    if (IS_ERR(nlmsvc_task)) {
300        error = PTR_ERR(nlmsvc_task);
301        svc_exit_thread(nlmsvc_rqst);
302        nlmsvc_task = NULL;
303        nlmsvc_rqst = NULL;
304        printk(KERN_WARNING
305            "lockd_up: kthread_run failed, error=%d\n", error);
306        goto destroy_and_out;
307    }
308
309    /*
310     * Note: svc_serv structures have an initial use count of 1,
311     * so we exit through here on both success and failure.
312     */
313destroy_and_out:
314    svc_destroy(serv);
315out:
316    if (!error)
317        nlmsvc_users++;
318    mutex_unlock(&nlmsvc_mutex);
319    return error;
320}
321EXPORT_SYMBOL_GPL(lockd_up);
322
323/*
324 * Decrement the user count and bring down lockd if we're the last.
325 */
326void
327lockd_down(void)
328{
329    mutex_lock(&nlmsvc_mutex);
330    if (nlmsvc_users) {
331        if (--nlmsvc_users)
332            goto out;
333    } else {
334        printk(KERN_ERR "lockd_down: no users! task=%p\n",
335            nlmsvc_task);
336        BUG();
337    }
338
339    if (!nlmsvc_task) {
340        printk(KERN_ERR "lockd_down: no lockd running.\n");
341        BUG();
342    }
343    kthread_stop(nlmsvc_task);
344    svc_exit_thread(nlmsvc_rqst);
345    nlmsvc_task = NULL;
346    nlmsvc_rqst = NULL;
347out:
348    mutex_unlock(&nlmsvc_mutex);
349}
350EXPORT_SYMBOL_GPL(lockd_down);
351
352#ifdef CONFIG_SYSCTL
353
354/*
355 * Sysctl parameters (same as module parameters, different interface).
356 */
357
358static ctl_table nlm_sysctls[] = {
359    {
360        .procname = "nlm_grace_period",
361        .data = &nlm_grace_period,
362        .maxlen = sizeof(unsigned long),
363        .mode = 0644,
364        .proc_handler = proc_doulongvec_minmax,
365        .extra1 = (unsigned long *) &nlm_grace_period_min,
366        .extra2 = (unsigned long *) &nlm_grace_period_max,
367    },
368    {
369        .procname = "nlm_timeout",
370        .data = &nlm_timeout,
371        .maxlen = sizeof(unsigned long),
372        .mode = 0644,
373        .proc_handler = proc_doulongvec_minmax,
374        .extra1 = (unsigned long *) &nlm_timeout_min,
375        .extra2 = (unsigned long *) &nlm_timeout_max,
376    },
377    {
378        .procname = "nlm_udpport",
379        .data = &nlm_udpport,
380        .maxlen = sizeof(int),
381        .mode = 0644,
382        .proc_handler = proc_dointvec_minmax,
383        .extra1 = (int *) &nlm_port_min,
384        .extra2 = (int *) &nlm_port_max,
385    },
386    {
387        .procname = "nlm_tcpport",
388        .data = &nlm_tcpport,
389        .maxlen = sizeof(int),
390        .mode = 0644,
391        .proc_handler = proc_dointvec_minmax,
392        .extra1 = (int *) &nlm_port_min,
393        .extra2 = (int *) &nlm_port_max,
394    },
395    {
396        .procname = "nsm_use_hostnames",
397        .data = &nsm_use_hostnames,
398        .maxlen = sizeof(int),
399        .mode = 0644,
400        .proc_handler = proc_dointvec,
401    },
402    {
403        .procname = "nsm_local_state",
404        .data = &nsm_local_state,
405        .maxlen = sizeof(int),
406        .mode = 0644,
407        .proc_handler = proc_dointvec,
408    },
409    { }
410};
411
412static ctl_table nlm_sysctl_dir[] = {
413    {
414        .procname = "nfs",
415        .mode = 0555,
416        .child = nlm_sysctls,
417    },
418    { }
419};
420
421static ctl_table nlm_sysctl_root[] = {
422    {
423        .procname = "fs",
424        .mode = 0555,
425        .child = nlm_sysctl_dir,
426    },
427    { }
428};
429
430#endif /* CONFIG_SYSCTL */
431
432/*
433 * Module (and sysfs) parameters.
434 */
435
436#define param_set_min_max(name, type, which_strtol, min, max) \
437static int param_set_##name(const char *val, struct kernel_param *kp) \
438{ \
439    char *endp; \
440    __typeof__(type) num = which_strtol(val, &endp, 0); \
441    if (endp == val || *endp || num < (min) || num > (max)) \
442        return -EINVAL; \
443    *((int *) kp->arg) = num; \
444    return 0; \
445}
446
447static inline int is_callback(u32 proc)
448{
449    return proc == NLMPROC_GRANTED
450        || proc == NLMPROC_GRANTED_MSG
451        || proc == NLMPROC_TEST_RES
452        || proc == NLMPROC_LOCK_RES
453        || proc == NLMPROC_CANCEL_RES
454        || proc == NLMPROC_UNLOCK_RES
455        || proc == NLMPROC_NSM_NOTIFY;
456}
457
458
459static int lockd_authenticate(struct svc_rqst *rqstp)
460{
461    rqstp->rq_client = NULL;
462    switch (rqstp->rq_authop->flavour) {
463        case RPC_AUTH_NULL:
464        case RPC_AUTH_UNIX:
465            if (rqstp->rq_proc == 0)
466                return SVC_OK;
467            if (is_callback(rqstp->rq_proc)) {
468                /* Leave it to individual procedures to
469                 * call nlmsvc_lookup_host(rqstp)
470                 */
471                return SVC_OK;
472            }
473            return svc_set_client(rqstp);
474    }
475    return SVC_DENIED;
476}
477
478
479param_set_min_max(port, int, simple_strtol, 0, 65535)
480param_set_min_max(grace_period, unsigned long, simple_strtoul,
481          nlm_grace_period_min, nlm_grace_period_max)
482param_set_min_max(timeout, unsigned long, simple_strtoul,
483          nlm_timeout_min, nlm_timeout_max)
484
485MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
486MODULE_DESCRIPTION("NFS file locking service version " LOCKD_VERSION ".");
487MODULE_LICENSE("GPL");
488
489module_param_call(nlm_grace_period, param_set_grace_period, param_get_ulong,
490          &nlm_grace_period, 0644);
491module_param_call(nlm_timeout, param_set_timeout, param_get_ulong,
492          &nlm_timeout, 0644);
493module_param_call(nlm_udpport, param_set_port, param_get_int,
494          &nlm_udpport, 0644);
495module_param_call(nlm_tcpport, param_set_port, param_get_int,
496          &nlm_tcpport, 0644);
497module_param(nsm_use_hostnames, bool, 0644);
498module_param(nlm_max_connections, uint, 0644);
499
500/*
501 * Initialising and terminating the module.
502 */
503
504static int __init init_nlm(void)
505{
506#ifdef CONFIG_SYSCTL
507    nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root);
508    return nlm_sysctl_table ? 0 : -ENOMEM;
509#else
510    return 0;
511#endif
512}
513
514static void __exit exit_nlm(void)
515{
516    /* FIXME: delete all NLM clients */
517    nlm_shutdown_hosts();
518#ifdef CONFIG_SYSCTL
519    unregister_sysctl_table(nlm_sysctl_table);
520#endif
521}
522
523module_init(init_nlm);
524module_exit(exit_nlm);
525
526/*
527 * Define NLM program and procedures
528 */
529static struct svc_version nlmsvc_version1 = {
530        .vs_vers = 1,
531        .vs_nproc = 17,
532        .vs_proc = nlmsvc_procedures,
533        .vs_xdrsize = NLMSVC_XDRSIZE,
534};
535static struct svc_version nlmsvc_version3 = {
536        .vs_vers = 3,
537        .vs_nproc = 24,
538        .vs_proc = nlmsvc_procedures,
539        .vs_xdrsize = NLMSVC_XDRSIZE,
540};
541#ifdef CONFIG_LOCKD_V4
542static struct svc_version nlmsvc_version4 = {
543        .vs_vers = 4,
544        .vs_nproc = 24,
545        .vs_proc = nlmsvc_procedures4,
546        .vs_xdrsize = NLMSVC_XDRSIZE,
547};
548#endif
549static struct svc_version * nlmsvc_version[] = {
550    [1] = &nlmsvc_version1,
551    [3] = &nlmsvc_version3,
552#ifdef CONFIG_LOCKD_V4
553    [4] = &nlmsvc_version4,
554#endif
555};
556
557static struct svc_stat nlmsvc_stats;
558
559#define NLM_NRVERS ARRAY_SIZE(nlmsvc_version)
560static struct svc_program nlmsvc_program = {
561    .pg_prog = NLM_PROGRAM, /* program number */
562    .pg_nvers = NLM_NRVERS, /* number of entries in nlmsvc_version */
563    .pg_vers = nlmsvc_version, /* version table */
564    .pg_name = "lockd", /* service name */
565    .pg_class = "nfsd", /* share authentication with nfsd */
566    .pg_stats = &nlmsvc_stats, /* stats table */
567    .pg_authenticate = &lockd_authenticate /* export authentication */
568};
569

Archive Download this file



interactive