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>
19 #include <linux/sched.h>
20 #include <linux/errno.h>
22 #include <linux/uio.h>
23 #include <linux/version.h>
24 #include <linux/unistd.h>
25 #include <linux/malloc.h>
26 #include <linux/smp.h>
27 #include <linux/smp_lock.h>
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 <linux/lockd/lockd.h>
35 #include <linux/nfs.h>
37 #define NLMDBG_FACILITY NLMDBG_SVC
38 #define LOCKD_BUFSIZE (1024 + NLMSSVC_XDRSIZE)
39 #define ALLOWED_SIGS (sigmask(SIGKILL))
41 extern struct svc_program nlmsvc_program
;
42 struct nlmsvc_binding
* nlmsvc_ops
= NULL
;
43 static DECLARE_MUTEX(nlmsvc_sema
);
44 static unsigned int nlmsvc_users
= 0;
45 static pid_t nlmsvc_pid
= 0;
46 unsigned long nlmsvc_grace_period
= 0;
47 unsigned long nlmsvc_timeout
= 0;
49 static DECLARE_MUTEX_LOCKED(lockd_start
);
50 static DECLARE_WAIT_QUEUE_HEAD(lockd_exit
);
53 * Currently the following can be set only at insmod time.
54 * Ideally, they would be accessible through the sysctl interface.
56 unsigned long nlm_grace_period
= 0;
57 unsigned long nlm_timeout
= LOCKD_DFLT_TIMEO
;
60 * This is the lockd kernel thread
63 lockd(struct svc_rqst
*rqstp
)
65 struct svc_serv
*serv
= rqstp
->rq_server
;
67 unsigned long grace_period_expire
;
69 /* Lock module and set up kernel thread */
74 * Let our maker know we're running.
76 nlmsvc_pid
= current
->pid
;
82 sprintf(current
->comm
, "lockd");
84 /* Process request with signals blocked. */
85 spin_lock_irq(¤t
->sigmask_lock
);
86 siginitsetinv(¤t
->blocked
, sigmask(SIGKILL
));
87 recalc_sigpending(current
);
88 spin_unlock_irq(¤t
->sigmask_lock
);
94 * N.B. current do_fork() doesn't like NULL task->files,
95 * so we defer closing files until forking rpciod.
99 dprintk("NFS locking service started (ver " LOCKD_VERSION
").\n");
102 nlm_timeout
= LOCKD_DFLT_TIMEO
;
105 nlmsvc_grace_period
= 10 * HZ
;
107 if (nlm_grace_period
) {
108 nlmsvc_grace_period
+= (1 + nlm_grace_period
/ nlm_timeout
)
111 nlmsvc_grace_period
+= 5 * nlm_timeout
* HZ
;
115 grace_period_expire
= nlmsvc_grace_period
+ jiffies
;
116 nlmsvc_timeout
= nlm_timeout
* HZ
;
119 * The main request loop. We don't terminate until the last
120 * NFS mount or NFS daemon has gone away, and we've been sent a
121 * signal, or else another process has taken over our job.
123 while ((nlmsvc_users
|| !signalled()) && nlmsvc_pid
== current
->pid
)
125 long timeout
= MAX_SCHEDULE_TIMEOUT
;
127 spin_lock_irq(¤t
->sigmask_lock
);
128 flush_signals(current
);
129 spin_unlock_irq(¤t
->sigmask_lock
);
133 * Retry any blocked locks that have been notified by
134 * the VFS. Don't do this during grace period.
135 * (Theoretically, there shouldn't even be blocked locks
136 * during grace period).
138 if (!nlmsvc_grace_period
) {
139 timeout
= nlmsvc_retry_blocked();
140 } else if (time_before(nlmsvc_grace_period
, jiffies
))
141 nlmsvc_grace_period
= 0;
144 * Find a socket with data available and call its
147 if ((err
= svc_recv(serv
, rqstp
, timeout
)) == -EAGAIN
)
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 svc_process(serv
, rqstp
);
173 /* Unlock export hash tables */
175 nlmsvc_ops
->exp_unlock();
179 * Check whether there's a new lockd process before
180 * shutting down the hosts and clearing the slot.
182 if (!nlmsvc_pid
|| current
->pid
== nlmsvc_pid
) {
183 nlm_shutdown_hosts();
187 "lockd: new process, skipping host shutdown\n");
188 wake_up(&lockd_exit
);
190 /* Exit the RPC thread */
191 svc_exit_thread(rqstp
);
201 * Bring up the lockd process if it's not already up.
206 static int warned
= 0;
207 struct svc_serv
* serv
;
212 * Unconditionally increment the user count ... this is
213 * the number of clients who _want_ a lockd process.
217 * Check whether we're already up and running.
223 * Sanity check: if there's no pid,
224 * we should be the first user ...
226 if (nlmsvc_users
> 1)
228 "lockd_up: no pid, %d users??\n", nlmsvc_users
);
231 serv
= svc_create(&nlmsvc_program
, 0, NLMSVC_XDRSIZE
);
233 printk(KERN_WARNING
"lockd_up: create service failed\n");
237 if ((error
= svc_makesock(serv
, IPPROTO_UDP
, 0)) < 0
238 || (error
= svc_makesock(serv
, IPPROTO_TCP
, 0)) < 0) {
241 "lockd_up: makesock failed, error=%d\n", error
);
242 goto destroy_and_out
;
247 * Create the kernel thread and wait for it to start.
249 error
= svc_create_thread(lockd
, serv
);
252 "lockd_up: create thread failed, error=%d\n", error
);
253 goto destroy_and_out
;
258 * Note: svc_serv structures have an initial use count of 1,
259 * so we exit through here on both success and failure.
269 * Decrement the user count and bring down lockd if we're the last.
274 static int warned
= 0;
281 printk(KERN_WARNING
"lockd_down: no users! pid=%d\n", nlmsvc_pid
);
285 printk(KERN_WARNING
"lockd_down: no lockd running.\n");
290 kill_proc(nlmsvc_pid
, SIGKILL
, 1);
292 * Wait for the lockd process to exit, but since we're holding
293 * the lockd semaphore, we can't wait around forever ...
295 current
->sigpending
= 0;
296 interruptible_sleep_on_timeout(&lockd_exit
, HZ
);
299 "lockd_down: lockd failed to exit, clearing pid\n");
302 spin_lock_irq(¤t
->sigmask_lock
);
303 recalc_sigpending(current
);
304 spin_unlock_irq(¤t
->sigmask_lock
);
310 /* New module support in 2.1.18 */
311 #if LINUX_VERSION_CODE >= 0x020112
313 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
314 MODULE_DESCRIPTION("NFS file locking service version " LOCKD_VERSION
".");
315 MODULE_PARM(nlm_grace_period
, "10-240l");
316 MODULE_PARM(nlm_timeout
, "3-20l");
321 /* Init the static variables */
322 init_MUTEX(&nlmsvc_sema
);
332 /* FIXME: delete all NLM clients */
333 nlm_shutdown_hosts();
338 * Define NLM program and procedures
340 static struct svc_version nlmsvc_version1
= {
341 1, 16, nlmsvc_procedures
, NULL
343 static struct svc_version nlmsvc_version3
= {
344 3, 24, nlmsvc_procedures
, NULL
346 #ifdef CONFIG_NFSD_NFS3
347 static struct svc_version nlmsvc_version4
= {
348 4, 24, nlmsvc_procedures4
, NULL
351 static struct svc_version
* nlmsvc_version
[] = {
356 #ifdef CONFIG_NFSD_NFS3
361 static struct svc_stat nlmsvc_stats
;
363 #define NLM_NRVERS (sizeof(nlmsvc_version)/sizeof(nlmsvc_version[0]))
364 struct svc_program nlmsvc_program
= {
365 NLM_PROGRAM
, /* program number */
366 1, NLM_NRVERS
-1, /* version range */
367 NLM_NRVERS
, /* number of entries in nlmsvc_version */
368 nlmsvc_version
, /* version table */
369 "lockd", /* service name */
370 &nlmsvc_stats
, /* stats table */