4 * This is the central lockd service.
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?
10 * Authors: Olaf Kirch (okir@monad.swb.de)
12 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
15 #define __KERNEL_SYSCALLS__
16 #include <linux/config.h>
17 #include <linux/module.h>
18 #include <linux/init.h>
20 #include <linux/sched.h>
21 #include <linux/errno.h>
23 #include <linux/uio.h>
24 #include <linux/version.h>
25 #include <linux/unistd.h>
26 #include <linux/slab.h>
27 #include <linux/smp.h>
28 #include <linux/smp_lock.h>
30 #include <linux/sunrpc/types.h>
31 #include <linux/sunrpc/stats.h>
32 #include <linux/sunrpc/clnt.h>
33 #include <linux/sunrpc/svc.h>
34 #include <linux/sunrpc/svcsock.h>
35 #include <linux/lockd/lockd.h>
36 #include <linux/nfs.h>
38 #define NLMDBG_FACILITY NLMDBG_SVC
39 #define LOCKD_BUFSIZE (1024 + NLMSSVC_XDRSIZE)
40 #define ALLOWED_SIGS (sigmask(SIGKILL))
42 extern struct svc_program nlmsvc_program;
43 struct nlmsvc_binding * nlmsvc_ops;
44 static DECLARE_MUTEX(nlmsvc_sema);
45 static unsigned int nlmsvc_users;
46 static pid_t nlmsvc_pid;
47 int nlmsvc_grace_period;
48 unsigned long nlmsvc_timeout;
50 static DECLARE_MUTEX_LOCKED(lockd_start);
51 static DECLARE_WAIT_QUEUE_HEAD(lockd_exit);
54 * Currently the following can be set only at insmod time.
55 * Ideally, they would be accessible through the sysctl interface.
57 unsigned long nlm_grace_period;
58 unsigned long nlm_timeout = LOCKD_DFLT_TIMEO;
59 unsigned long nlm_udpport, nlm_tcpport;
61 static unsigned long set_grace_period(void)
63 unsigned long grace_period;
65 /* Note: nlm_timeout should always be nonzero */
67 grace_period = ((nlm_grace_period + nlm_timeout - 1)
68 / nlm_timeout) * nlm_timeout * HZ;
70 grace_period = nlm_timeout * 5 * HZ;
71 nlmsvc_grace_period = 1;
72 return grace_period + jiffies;
76 * This is the lockd kernel thread
79 lockd(struct svc_rqst *rqstp)
81 struct svc_serv *serv = rqstp->rq_server;
83 unsigned long grace_period_expire;
85 /* Lock module and set up kernel thread */
90 * Let our maker know we're running.
92 nlmsvc_pid = current->pid;
97 sprintf(current->comm, "lockd");
99 /* Process request with signals blocked. */
100 spin_lock_irq(¤t->sigmask_lock);
101 siginitsetinv(¤t->blocked, sigmask(SIGKILL));
102 recalc_sigpending(current);
103 spin_unlock_irq(¤t->sigmask_lock);
108 dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
111 nlm_timeout = LOCKD_DFLT_TIMEO;
112 nlmsvc_timeout = nlm_timeout * HZ;
114 grace_period_expire = set_grace_period();
117 * The main request loop. We don't terminate until the last
118 * NFS mount or NFS daemon has gone away, and we've been sent a
119 * signal, or else another process has taken over our job.
121 while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid)
123 long timeout = MAX_SCHEDULE_TIMEOUT;
125 spin_lock_irq(¤t->sigmask_lock);
126 flush_signals(current);
127 spin_unlock_irq(¤t->sigmask_lock);
129 nlmsvc_ops->detach();
130 grace_period_expire = set_grace_period();
135 * Retry any blocked locks that have been notified by
136 * the VFS. Don't do this during grace period.
137 * (Theoretically, there shouldn't even be blocked locks
138 * during grace period).
140 if (!nlmsvc_grace_period)
141 timeout = nlmsvc_retry_blocked();
144 * Find a socket with data available and call its
147 err = svc_recv(serv, rqstp, timeout);
148 if (err == -EAGAIN || err == -EINTR)
152 "lockd: terminating on error %d\n",
157 dprintk("lockd: request from %08x\n",
158 (unsigned)ntohl(rqstp->rq_addr.sin_addr.s_addr));
161 * Look up the NFS client handle. The handle is needed for
162 * all but the GRANTED callback RPCs.
164 rqstp->rq_client = NULL;
166 nlmsvc_ops->exp_readlock();
168 nlmsvc_ops->exp_getclient(&rqstp->rq_addr);
171 if (nlmsvc_grace_period &&
172 time_before(grace_period_expire, jiffies))
173 nlmsvc_grace_period = 0;
174 svc_process(serv, rqstp);
176 /* Unlock export hash tables */
178 nlmsvc_ops->exp_unlock();
182 * Check whether there's a new lockd process before
183 * shutting down the hosts and clearing the slot.
185 if (!nlmsvc_pid || current->pid == nlmsvc_pid) {
187 nlmsvc_ops->detach();
188 nlm_shutdown_hosts();
192 "lockd: new process, skipping host shutdown\n");
193 wake_up(&lockd_exit);
195 /* Exit the RPC thread */
196 svc_exit_thread(rqstp);
206 * Bring up the lockd process if it's not already up.
211 static int warned = 0;
212 struct svc_serv * serv;
217 * Unconditionally increment the user count ... this is
218 * the number of clients who _want_ a lockd process.
222 * Check whether we're already up and running.
228 * Sanity check: if there's no pid,
229 * we should be the first user ...
231 if (nlmsvc_users > 1)
233 "lockd_up: no pid, %d users??\n", nlmsvc_users);
236 serv = svc_create(&nlmsvc_program, 0, NLMSVC_XDRSIZE);
238 printk(KERN_WARNING "lockd_up: create service failed\n");
242 if ((error = svc_makesock(serv, IPPROTO_UDP, nlm_udpport)) < 0
243 #ifdef CONFIG_NFSD_TCP
244 || (error = svc_makesock(serv, IPPROTO_TCP, nlm_tcpport)) < 0
249 "lockd_up: makesock failed, error=%d\n", error);
250 goto destroy_and_out;
255 * Create the kernel thread and wait for it to start.
257 error = svc_create_thread(lockd, serv);
260 "lockd_up: create thread failed, error=%d\n", error);
261 goto destroy_and_out;
266 * Note: svc_serv structures have an initial use count of 1,
267 * so we exit through here on both success and failure.
277 * Decrement the user count and bring down lockd if we're the last.
282 static int warned = 0;
289 printk(KERN_WARNING "lockd_down: no users! pid=%d\n", nlmsvc_pid);
293 printk(KERN_WARNING "lockd_down: no lockd running.\n");
298 kill_proc(nlmsvc_pid, SIGKILL, 1);
300 * Wait for the lockd process to exit, but since we're holding
301 * the lockd semaphore, we can't wait around forever ...
303 current->sigpending = 0;
304 interruptible_sleep_on_timeout(&lockd_exit, HZ);
307 "lockd_down: lockd failed to exit, clearing pid\n");
310 spin_lock_irq(¤t->sigmask_lock);
311 recalc_sigpending(current);
312 spin_unlock_irq(¤t->sigmask_lock);
318 /* New module support in 2.1.18 */
320 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
321 MODULE_DESCRIPTION("NFS file locking service version " LOCKD_VERSION ".");
322 MODULE_LICENSE("GPL");
323 MODULE_PARM(nlm_grace_period, "10-240l");
324 MODULE_PARM(nlm_timeout, "3-20l");
325 MODULE_PARM(nlm_udpport, "0-65535l");
326 MODULE_PARM(nlm_tcpport, "0-65535l");
331 /* Init the static variables */
332 init_MUTEX(&nlmsvc_sema);
341 /* FIXME: delete all NLM clients */
342 nlm_shutdown_hosts();
345 /* not a module, so process bootargs
346 * lockd.udpport and lockd.tcpport
349 static int __init udpport_set(char *str)
351 nlm_udpport = simple_strtoul(str, NULL, 0);
354 static int __init tcpport_set(char *str)
356 nlm_tcpport = simple_strtoul(str, NULL, 0);
359 __setup("lockd.udpport=", udpport_set);
360 __setup("lockd.tcpport=", tcpport_set);
365 * Define NLM program and procedures
367 static struct svc_version nlmsvc_version1 = {
368 1, 17, nlmsvc_procedures, NULL
370 static struct svc_version nlmsvc_version3 = {
371 3, 24, nlmsvc_procedures, NULL
373 #ifdef CONFIG_LOCKD_V4
374 static struct svc_version nlmsvc_version4 = {
375 4, 24, nlmsvc_procedures4, NULL
378 static struct svc_version * nlmsvc_version[] = {
383 #ifdef CONFIG_LOCKD_V4
388 static struct svc_stat nlmsvc_stats;
390 #define NLM_NRVERS (sizeof(nlmsvc_version)/sizeof(nlmsvc_version[0]))
391 struct svc_program nlmsvc_program = {
392 NLM_PROGRAM, /* program number */
393 1, NLM_NRVERS-1, /* version range */
394 NLM_NRVERS, /* number of entries in nlmsvc_version */
395 nlmsvc_version, /* version table */
396 "lockd", /* service name */
397 &nlmsvc_stats, /* stats table */