~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/lockd/svc.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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(&current->sigmask_lock);
 86         siginitsetinv(&current->blocked, sigmask(SIGKILL));
 87         recalc_sigpending(current);
 88         spin_unlock_irq(&current->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(&current->sigmask_lock);
128                         flush_signals(current);
129                         spin_unlock_irq(&current->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(&current->sigmask_lock);
306         recalc_sigpending(current);
307         spin_unlock_irq(&current->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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.