Import 2.3.26pre2
[davej-history.git] / fs / lockd / svc.c
blob878797b8adaa9952860c3670d28b8374f486efd0
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 = 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
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 || (error = svc_makesock(serv, IPPROTO_TCP, 0)) < 0) {
239 if (warned++ == 0)
240 printk(KERN_WARNING
241 "lockd_up: makesock failed, error=%d\n", error);
242 goto destroy_and_out;
244 warned = 0;
247 * Create the kernel thread and wait for it to start.
249 error = svc_create_thread(lockd, serv);
250 if (error) {
251 printk(KERN_WARNING
252 "lockd_up: create thread failed, error=%d\n", error);
253 goto destroy_and_out;
255 down(&lockd_start);
258 * Note: svc_serv structures have an initial use count of 1,
259 * so we exit through here on both success and failure.
261 destroy_and_out:
262 svc_destroy(serv);
263 out:
264 up(&nlmsvc_sema);
265 return error;
269 * Decrement the user count and bring down lockd if we're the last.
271 void
272 lockd_down(void)
274 static int warned = 0;
276 down(&nlmsvc_sema);
277 if (nlmsvc_users) {
278 if (--nlmsvc_users)
279 goto out;
280 } else
281 printk(KERN_WARNING "lockd_down: no users! pid=%d\n", nlmsvc_pid);
283 if (!nlmsvc_pid) {
284 if (warned++ == 0)
285 printk(KERN_WARNING "lockd_down: no lockd running.\n");
286 goto out;
288 warned = 0;
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);
297 if (nlmsvc_pid) {
298 printk(KERN_WARNING
299 "lockd_down: lockd failed to exit, clearing pid\n");
300 nlmsvc_pid = 0;
302 spin_lock_irq(&current->sigmask_lock);
303 recalc_sigpending(current);
304 spin_unlock_irq(&current->sigmask_lock);
305 out:
306 up(&nlmsvc_sema);
309 #ifdef MODULE
310 /* New module support in 2.1.18 */
311 #if LINUX_VERSION_CODE >= 0x020112
312 EXPORT_NO_SYMBOLS;
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");
317 #endif
319 init_module(void)
321 /* Init the static variables */
322 init_MUTEX(&nlmsvc_sema);
323 nlmsvc_users = 0;
324 nlmsvc_pid = 0;
325 nlmxdr_init();
326 return 0;
329 void
330 cleanup_module(void)
332 /* FIXME: delete all NLM clients */
333 nlm_shutdown_hosts();
335 #endif
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
350 #endif
351 static struct svc_version * nlmsvc_version[] = {
352 NULL,
353 &nlmsvc_version1,
354 NULL,
355 &nlmsvc_version3,
356 #ifdef CONFIG_NFSD_NFS3
357 &nlmsvc_version4,
358 #endif
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 */