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 #define __KERNEL_SYSCALLS__
16 #include <linux/config.h>
17 #include <linux/module.h>
18
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>
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 <linux/lockd/lockd.h>
35 #include <linux/nfs.h>
36
37 #define NLMDBG_FACILITY NLMDBG_SVC
38 #define LOCKD_BUFSIZE (1024 + NLMSSVC_XDRSIZE)
39 #define ALLOWED_SIGS (sigmask(SIGKILL))
40
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;
48
49 static DECLARE_MUTEX_LOCKED(lockd_start);
50 static DECLARE_WAIT_QUEUE_HEAD(lockd_exit);
51
52 /*
53 * Currently the following can be set only at insmod time.
54 * Ideally, they would be accessible through the sysctl interface.
55 */
56 unsigned long nlm_grace_period;
57 unsigned long nlm_timeout = LOCKD_DFLT_TIMEO;
58
59 /*
60 * This is the lockd kernel thread
61 */
62 static void
63 lockd(struct svc_rqst *rqstp)
64 {
65 struct svc_serv *serv = rqstp->rq_server;
66 int err = 0;
67 unsigned long grace_period_expire;
68
69 /* Lock module and set up kernel thread */
70 MOD_INC_USE_COUNT;
71 lock_kernel();
72
73 /*
74 * Let our maker know we're running.
75 */
76 nlmsvc_pid = current->pid;
77 up(&lockd_start);
78
79 exit_mm(current);
80 current->session = 1;
81 current->pgrp = 1;
82 sprintf(current->comm, "lockd");
83
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);
89
90 /* kick rpciod */
91 rpciod_up();
92
93 /*
94 * N.B. current do_fork() doesn't like NULL task->files,
95 * so we defer closing files until forking rpciod.
96 */
97 exit_files(current);
98
99 dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
100
101 if (!nlm_timeout)
102 nlm_timeout = LOCKD_DFLT_TIMEO;
103
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;
112 }
113 #endif
114
115 grace_period_expire = nlmsvc_grace_period + jiffies;
116 nlmsvc_timeout = nlm_timeout * HZ;
117
118 /*
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.
122 */
123 while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid)
124 {
125 long timeout = MAX_SCHEDULE_TIMEOUT;
126 if (signalled()) {
127 spin_lock_irq(¤t->sigmask_lock);
128 flush_signals(current);
129 spin_unlock_irq(¤t->sigmask_lock);
130 }
131
132 /*
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).
137 */
138 if (!nlmsvc_grace_period) {
139 timeout = nlmsvc_retry_blocked();
140 } else if (time_before(nlmsvc_grace_period, jiffies))
141 nlmsvc_grace_period = 0;
142
143 /*
144 * Find a socket with data available and call its
145 * recvfrom routine.
146 */
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;
155 }
156
157 dprintk("lockd: request from %08x\n",
158 (unsigned)ntohl(rqstp->rq_addr.sin_addr.s_addr));
159
160 /*
161 * Look up the NFS client handle. The handle is needed for
162 * all but the GRANTED callback RPCs.
163 */
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);
169 }
170
171 svc_process(serv, rqstp);
172
173 /* Unlock export hash tables */
174 if (nlmsvc_ops)
175 nlmsvc_ops->exp_unlock();
176 }
177
178 /*
179 * Check whether there's a new lockd process before
180 * shutting down the hosts and clearing the slot.
181 */
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);
189
190 /* Exit the RPC thread */
191 svc_exit_thread(rqstp);
192
193 /* release rpciod */
194 rpciod_down();
195
196 /* Release module */
197 MOD_DEC_USE_COUNT;
198 }
199
200 /*
201 * Bring up the lockd process if it's not already up.
202 */
203 int
204 lockd_up(void)
205 {
206 static int warned = 0;
207 struct svc_serv * serv;
208 int error = 0;
209
210 down(&nlmsvc_sema);
211 /*
212 * Unconditionally increment the user count ... this is
213 * the number of clients who _want_ a lockd process.
214 */
215 nlmsvc_users++;
216 /*
217 * Check whether we're already up and running.
218 */
219 if (nlmsvc_pid)
220 goto out;
221
222 /*
223 * Sanity check: if there's no pid,
224 * we should be the first user ...
225 */
226 if (nlmsvc_users > 1)
227 printk(KERN_WARNING
228 "lockd_up: no pid, %d users??\n", nlmsvc_users);
229
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;
235 }
236
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
241 ) {
242 if (warned++ == 0)
243 printk(KERN_WARNING
244 "lockd_up: makesock failed, error=%d\n", error);
245 goto destroy_and_out;
246 }
247 warned = 0;
248
249 /*
250 * Create the kernel thread and wait for it to start.
251 */
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;
257 }
258 down(&lockd_start);
259
260 /*
261 * Note: svc_serv structures have an initial use count of 1,
262 * so we exit through here on both success and failure.
263 */
264 destroy_and_out:
265 svc_destroy(serv);
266 out:
267 up(&nlmsvc_sema);
268 return error;
269 }
270
271 /*
272 * Decrement the user count and bring down lockd if we're the last.
273 */
274 void
275 lockd_down(void)
276 {
277 static int warned = 0;
278
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);
285
286 if (!nlmsvc_pid) {
287 if (warned++ == 0)
288 printk(KERN_WARNING "lockd_down: no lockd running.\n");
289 goto out;
290 }
291 warned = 0;
292
293 kill_proc(nlmsvc_pid, SIGKILL, 1);
294 /*
295 * Wait for the lockd process to exit, but since we're holding
296 * the lockd semaphore, we can't wait around forever ...
297 */
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;
304 }
305 spin_lock_irq(¤t->sigmask_lock);
306 recalc_sigpending(current);
307 spin_unlock_irq(¤t->sigmask_lock);
308 out:
309 up(&nlmsvc_sema);
310 }
311
312 #ifdef MODULE
313 /* New module support in 2.1.18 */
314
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");
319
320 int
321 init_module(void)
322 {
323 /* Init the static variables */
324 init_MUTEX(&nlmsvc_sema);
325 nlmsvc_users = 0;
326 nlmsvc_pid = 0;
327 return 0;
328 }
329
330 void
331 cleanup_module(void)
332 {
333 /* FIXME: delete all NLM clients */
334 nlm_shutdown_hosts();
335 }
336 #endif
337
338 /*
339 * Define NLM program and procedures
340 */
341 static struct svc_version nlmsvc_version1 = {
342 1, 16, nlmsvc_procedures, NULL
343 };
344 static struct svc_version nlmsvc_version3 = {
345 3, 24, nlmsvc_procedures, NULL
346 };
347 #ifdef CONFIG_LOCKD_V4
348 static struct svc_version nlmsvc_version4 = {
349 4, 24, nlmsvc_procedures4, NULL
350 };
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
360 };
361
362 static struct svc_stat nlmsvc_stats;
363
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 */
372 };
373
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.