import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / fs / lockd / svc.c
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 #include <linux/init.h>
19
20 #include <linux/sched.h>
21 #include <linux/errno.h>
22 #include <linux/in.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>
29
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>
37
38 #define NLMDBG_FACILITY         NLMDBG_SVC
39 #define LOCKD_BUFSIZE           (1024 + NLMSSVC_XDRSIZE)
40 #define ALLOWED_SIGS            (sigmask(SIGKILL))
41
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;
49
50 static DECLARE_MUTEX_LOCKED(lockd_start);
51 static DECLARE_WAIT_QUEUE_HEAD(lockd_exit);
52
53 /*
54  * Currently the following can be set only at insmod time.
55  * Ideally, they would be accessible through the sysctl interface.
56  */
57 unsigned long                   nlm_grace_period;
58 unsigned long                   nlm_timeout = LOCKD_DFLT_TIMEO;
59 unsigned long                   nlm_udpport, nlm_tcpport;
60
61 static unsigned long set_grace_period(void)
62 {
63         unsigned long grace_period;
64
65         /* Note: nlm_timeout should always be nonzero */
66         if (nlm_grace_period)
67                 grace_period = ((nlm_grace_period + nlm_timeout - 1)
68                                 / nlm_timeout) * nlm_timeout * HZ;
69         else
70                 grace_period = nlm_timeout * 5 * HZ;
71         nlmsvc_grace_period = 1;
72         return grace_period + jiffies;
73 }
74
75 /*
76  * This is the lockd kernel thread
77  */
78 static void
79 lockd(struct svc_rqst *rqstp)
80 {
81         struct svc_serv *serv = rqstp->rq_server;
82         int             err = 0;
83         unsigned long grace_period_expire;
84
85         /* Lock module and set up kernel thread */
86         MOD_INC_USE_COUNT;
87         lock_kernel();
88
89         /*
90          * Let our maker know we're running.
91          */
92         nlmsvc_pid = current->pid;
93         up(&lockd_start);
94
95         daemonize();
96         reparent_to_init();
97         sprintf(current->comm, "lockd");
98
99         /* Process request with signals blocked.  */
100         spin_lock_irq(&current->sigmask_lock);
101         siginitsetinv(&current->blocked, sigmask(SIGKILL));
102         recalc_sigpending(current);
103         spin_unlock_irq(&current->sigmask_lock);
104
105         /* kick rpciod */
106         rpciod_up();
107
108         dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
109
110         if (!nlm_timeout)
111                 nlm_timeout = LOCKD_DFLT_TIMEO;
112         nlmsvc_timeout = nlm_timeout * HZ;
113
114         grace_period_expire = set_grace_period();
115
116         /*
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.
120          */
121         while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid)
122         {
123                 long timeout = MAX_SCHEDULE_TIMEOUT;
124                 if (signalled()) {
125                         spin_lock_irq(&current->sigmask_lock);
126                         flush_signals(current);
127                         spin_unlock_irq(&current->sigmask_lock);
128                         if (nlmsvc_ops) {
129                                 nlmsvc_ops->detach();
130                                 grace_period_expire = set_grace_period();
131                         }
132                 }
133
134                 /*
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).
139                  */
140                 if (!nlmsvc_grace_period)
141                         timeout = nlmsvc_retry_blocked();
142
143                 /*
144                  * Find a socket with data available and call its
145                  * recvfrom routine.
146                  */
147                 err = svc_recv(serv, rqstp, timeout);
148                 if (err == -EAGAIN || err == -EINTR)
149                         continue;
150                 if (err < 0) {
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                 if (nlmsvc_grace_period &&
172                     time_before(grace_period_expire, jiffies))
173                         nlmsvc_grace_period = 0;
174                 svc_process(serv, rqstp);
175
176                 /* Unlock export hash tables */
177                 if (nlmsvc_ops)
178                         nlmsvc_ops->exp_unlock();
179         }
180
181         /*
182          * Check whether there's a new lockd process before
183          * shutting down the hosts and clearing the slot.
184          */
185         if (!nlmsvc_pid || current->pid == nlmsvc_pid) {
186                 if (nlmsvc_ops)
187                         nlmsvc_ops->detach();
188                 nlm_shutdown_hosts();
189                 nlmsvc_pid = 0;
190         } else
191                 printk(KERN_DEBUG
192                         "lockd: new process, skipping host shutdown\n");
193         wake_up(&lockd_exit);
194                 
195         /* Exit the RPC thread */
196         svc_exit_thread(rqstp);
197
198         /* release rpciod */
199         rpciod_down();
200
201         /* Release module */
202         MOD_DEC_USE_COUNT;
203 }
204
205 /*
206  * Bring up the lockd process if it's not already up.
207  */
208 int
209 lockd_up(void)
210 {
211         static int              warned = 0; 
212         struct svc_serv *       serv;
213         int                     error = 0;
214
215         down(&nlmsvc_sema);
216         /*
217          * Unconditionally increment the user count ... this is
218          * the number of clients who _want_ a lockd process.
219          */
220         nlmsvc_users++; 
221         /*
222          * Check whether we're already up and running.
223          */
224         if (nlmsvc_pid)
225                 goto out;
226
227         /*
228          * Sanity check: if there's no pid,
229          * we should be the first user ...
230          */
231         if (nlmsvc_users > 1)
232                 printk(KERN_WARNING
233                         "lockd_up: no pid, %d users??\n", nlmsvc_users);
234
235         error = -ENOMEM;
236         serv = svc_create(&nlmsvc_program, 0, NLMSVC_XDRSIZE);
237         if (!serv) {
238                 printk(KERN_WARNING "lockd_up: create service failed\n");
239                 goto out;
240         }
241
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
245 #endif
246                 ) {
247                 if (warned++ == 0) 
248                         printk(KERN_WARNING
249                                 "lockd_up: makesock failed, error=%d\n", error);
250                 goto destroy_and_out;
251         } 
252         warned = 0;
253
254         /*
255          * Create the kernel thread and wait for it to start.
256          */
257         error = svc_create_thread(lockd, serv);
258         if (error) {
259                 printk(KERN_WARNING
260                         "lockd_up: create thread failed, error=%d\n", error);
261                 goto destroy_and_out;
262         }
263         down(&lockd_start);
264
265         /*
266          * Note: svc_serv structures have an initial use count of 1,
267          * so we exit through here on both success and failure.
268          */
269 destroy_and_out:
270         svc_destroy(serv);
271 out:
272         up(&nlmsvc_sema);
273         return error;
274 }
275
276 /*
277  * Decrement the user count and bring down lockd if we're the last.
278  */
279 void
280 lockd_down(void)
281 {
282         static int warned = 0; 
283
284         down(&nlmsvc_sema);
285         if (nlmsvc_users) {
286                 if (--nlmsvc_users)
287                         goto out;
288         } else
289                 printk(KERN_WARNING "lockd_down: no users! pid=%d\n", nlmsvc_pid);
290
291         if (!nlmsvc_pid) {
292                 if (warned++ == 0)
293                         printk(KERN_WARNING "lockd_down: no lockd running.\n"); 
294                 goto out;
295         }
296         warned = 0;
297
298         kill_proc(nlmsvc_pid, SIGKILL, 1);
299         /*
300          * Wait for the lockd process to exit, but since we're holding
301          * the lockd semaphore, we can't wait around forever ...
302          */
303         current->sigpending = 0;
304         interruptible_sleep_on_timeout(&lockd_exit, HZ);
305         if (nlmsvc_pid) {
306                 printk(KERN_WARNING 
307                         "lockd_down: lockd failed to exit, clearing pid\n");
308                 nlmsvc_pid = 0;
309         }
310         spin_lock_irq(&current->sigmask_lock);
311         recalc_sigpending(current);
312         spin_unlock_irq(&current->sigmask_lock);
313 out:
314         up(&nlmsvc_sema);
315 }
316
317 #ifdef MODULE
318 /* New module support in 2.1.18 */
319
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");
327
328 int
329 init_module(void)
330 {
331         /* Init the static variables */
332         init_MUTEX(&nlmsvc_sema);
333         nlmsvc_users = 0;
334         nlmsvc_pid = 0;
335         return 0;
336 }
337
338 void
339 cleanup_module(void)
340 {
341         /* FIXME: delete all NLM clients */
342         nlm_shutdown_hosts();
343 }
344 #else
345 /* not a module, so process bootargs
346  * lockd.udpport and lockd.tcpport
347  */
348
349 static int __init udpport_set(char *str)
350 {
351         nlm_udpport = simple_strtoul(str, NULL, 0);
352         return 1;
353 }
354 static int __init tcpport_set(char *str)
355 {
356         nlm_tcpport = simple_strtoul(str, NULL, 0);
357         return 1;
358 }
359 __setup("lockd.udpport=", udpport_set);
360 __setup("lockd.tcpport=", tcpport_set);
361
362 #endif
363
364 /*
365  * Define NLM program and procedures
366  */
367 static struct svc_version       nlmsvc_version1 = {
368         1, 17, nlmsvc_procedures, NULL
369 };
370 static struct svc_version       nlmsvc_version3 = {
371         3, 24, nlmsvc_procedures, NULL
372 };
373 #ifdef CONFIG_LOCKD_V4
374 static struct svc_version       nlmsvc_version4 = {
375         4, 24, nlmsvc_procedures4, NULL
376 };
377 #endif
378 static struct svc_version *     nlmsvc_version[] = {
379         NULL,
380         &nlmsvc_version1,
381         NULL,
382         &nlmsvc_version3,
383 #ifdef CONFIG_LOCKD_V4
384         &nlmsvc_version4,
385 #endif
386 };
387
388 static struct svc_stat          nlmsvc_stats;
389
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 */
398 };