Ok. I didn't make 2.4.0 in 2000. Tough. I tried, but we had some
[davej-history.git] / fs / lockd / svc.c
blob924741f9e96bb5b4e2ba6f0b4d712f05664565a8
1 /*
2 * linux/fs/lockd/svc.c
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>
21 #include <linux/in.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;
43 static DECLARE_MUTEX(nlmsvc_sema);
44 static unsigned int nlmsvc_users;
45 static pid_t nlmsvc_pid;
46 unsigned long nlmsvc_grace_period;
47 unsigned long nlmsvc_timeout;
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;
57 unsigned long nlm_timeout = LOCKD_DFLT_TIMEO;
60 * This is the lockd kernel thread
62 static void
63 lockd(struct svc_rqst *rqstp)
65 struct svc_serv *serv = rqstp->rq_server;
66 int err = 0;
67 unsigned long grace_period_expire;
69 /* Lock module and set up kernel thread */
70 MOD_INC_USE_COUNT;
71 lock_kernel();
74 * Let our maker know we're running.
76 nlmsvc_pid = current->pid;
77 up(&lockd_start);
79 exit_mm(current);
80 current->session = 1;
81 current->pgrp = 1;
82 sprintf(current->comm, "lockd");
84 /* Process request with signals blocked. */
85 spin_lock_irq(&current->sigmask_lock);
86 siginitsetinv(&current->blocked, sigmask(SIGKILL));
87 recalc_sigpending(current);
88 spin_unlock_irq(&current->sigmask_lock);
90 /* kick rpciod */
91 rpciod_up();
94 * N.B. current do_fork() doesn't like NULL task->files,
95 * so we defer closing files until forking rpciod.
97 exit_files(current);
99 dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
101 if (!nlm_timeout)
102 nlm_timeout = LOCKD_DFLT_TIMEO;
104 #ifdef RPC_DEBUG
105 nlmsvc_grace_period = 10 * HZ;
106 #else
107 if (nlm_grace_period) {
108 nlmsvc_grace_period += (1 + nlm_grace_period / nlm_timeout)
109 * nlm_timeout * HZ;
110 } else {
111 nlmsvc_grace_period += 5 * nlm_timeout * HZ;
113 #endif
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;
126 if (signalled()) {
127 spin_lock_irq(&current->sigmask_lock);
128 flush_signals(current);
129 spin_unlock_irq(&current->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
145 * recvfrom routine.
147 if ((err = svc_recv(serv, rqstp, timeout)) == -EAGAIN)
148 continue;
149 if (err < 0) {
150 if (err != -EINTR)
151 printk(KERN_WARNING
152 "lockd: terminating on error %d\n",
153 -err);
154 break;
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;
165 if (nlmsvc_ops) {
166 nlmsvc_ops->exp_readlock();
167 rqstp->rq_client =
168 nlmsvc_ops->exp_getclient(&rqstp->rq_addr);
171 svc_process(serv, rqstp);
173 /* Unlock export hash tables */
174 if (nlmsvc_ops)
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();
184 nlmsvc_pid = 0;
185 } else
186 printk(KERN_DEBUG
187 "lockd: new process, skipping host shutdown\n");
188 wake_up(&lockd_exit);
190 /* Exit the RPC thread */
191 svc_exit_thread(rqstp);
193 /* release rpciod */
194 rpciod_down();
196 /* Release module */
197 MOD_DEC_USE_COUNT;
201 * Bring up the lockd process if it's not already up.
204 lockd_up(void)
206 static int warned = 0;
207 struct svc_serv * serv;
208 int error = 0;
210 down(&nlmsvc_sema);
212 * Unconditionally increment the user count ... this is
213 * the number of clients who _want_ a lockd process.
215 nlmsvc_users++;
217 * Check whether we're already up and running.
219 if (nlmsvc_pid)
220 goto out;
223 * Sanity check: if there's no pid,
224 * we should be the first user ...
226 if (nlmsvc_users > 1)
227 printk(KERN_WARNING
228 "lockd_up: no pid, %d users??\n", nlmsvc_users);
230 error = -ENOMEM;
231 serv = svc_create(&nlmsvc_program, 0, NLMSVC_XDRSIZE);
232 if (!serv) {
233 printk(KERN_WARNING "lockd_up: create service failed\n");
234 goto out;
237 if ((error = svc_makesock(serv, IPPROTO_UDP, 0)) < 0
238 #ifdef CONFIG_NFSD_TCP
239 || (error = svc_makesock(serv, IPPROTO_TCP, 0)) < 0
240 #endif
242 if (warned++ == 0)
243 printk(KERN_WARNING
244 "lockd_up: makesock failed, error=%d\n", error);
245 goto destroy_and_out;
247 warned = 0;
250 * Create the kernel thread and wait for it to start.
252 error = svc_create_thread(lockd, serv);
253 if (error) {
254 printk(KERN_WARNING
255 "lockd_up: create thread failed, error=%d\n", error);
256 goto destroy_and_out;
258 down(&lockd_start);
261 * Note: svc_serv structures have an initial use count of 1,
262 * so we exit through here on both success and failure.
264 destroy_and_out:
265 svc_destroy(serv);
266 out:
267 up(&nlmsvc_sema);
268 return error;
272 * Decrement the user count and bring down lockd if we're the last.
274 void
275 lockd_down(void)
277 static int warned = 0;
279 down(&nlmsvc_sema);
280 if (nlmsvc_users) {
281 if (--nlmsvc_users)
282 goto out;
283 } else
284 printk(KERN_WARNING "lockd_down: no users! pid=%d\n", nlmsvc_pid);
286 if (!nlmsvc_pid) {
287 if (warned++ == 0)
288 printk(KERN_WARNING "lockd_down: no lockd running.\n");
289 goto out;
291 warned = 0;
293 kill_proc(nlmsvc_pid, SIGKILL, 1);
295 * Wait for the lockd process to exit, but since we're holding
296 * the lockd semaphore, we can't wait around forever ...
298 current->sigpending = 0;
299 interruptible_sleep_on_timeout(&lockd_exit, HZ);
300 if (nlmsvc_pid) {
301 printk(KERN_WARNING
302 "lockd_down: lockd failed to exit, clearing pid\n");
303 nlmsvc_pid = 0;
305 spin_lock_irq(&current->sigmask_lock);
306 recalc_sigpending(current);
307 spin_unlock_irq(&current->sigmask_lock);
308 out:
309 up(&nlmsvc_sema);
312 #ifdef MODULE
313 /* New module support in 2.1.18 */
315 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
316 MODULE_DESCRIPTION("NFS file locking service version " LOCKD_VERSION ".");
317 MODULE_PARM(nlm_grace_period, "10-240l");
318 MODULE_PARM(nlm_timeout, "3-20l");
321 init_module(void)
323 /* Init the static variables */
324 init_MUTEX(&nlmsvc_sema);
325 nlmsvc_users = 0;
326 nlmsvc_pid = 0;
327 return 0;
330 void
331 cleanup_module(void)
333 /* FIXME: delete all NLM clients */
334 nlm_shutdown_hosts();
336 #endif
339 * Define NLM program and procedures
341 static struct svc_version nlmsvc_version1 = {
342 1, 16, nlmsvc_procedures, NULL
344 static struct svc_version nlmsvc_version3 = {
345 3, 24, nlmsvc_procedures, NULL
347 #ifdef CONFIG_LOCKD_V4
348 static struct svc_version nlmsvc_version4 = {
349 4, 24, nlmsvc_procedures4, NULL
351 #endif
352 static struct svc_version * nlmsvc_version[] = {
353 NULL,
354 &nlmsvc_version1,
355 NULL,
356 &nlmsvc_version3,
357 #ifdef CONFIG_LOCKD_V4
358 &nlmsvc_version4,
359 #endif
362 static struct svc_stat nlmsvc_stats;
364 #define NLM_NRVERS (sizeof(nlmsvc_version)/sizeof(nlmsvc_version[0]))
365 struct svc_program nlmsvc_program = {
366 NLM_PROGRAM, /* program number */
367 1, NLM_NRVERS-1, /* version range */
368 NLM_NRVERS, /* number of entries in nlmsvc_version */
369 nlmsvc_version, /* version table */
370 "lockd", /* service name */
371 &nlmsvc_stats, /* stats table */