aboutsummaryrefslogtreecommitdiffstats
path: root/fs/lockd/svc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/lockd/svc.c')
-rw-r--r--fs/lockd/svc.c150
1 files changed, 70 insertions, 80 deletions
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 38c2f0b1dd7d..2169af4d5455 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -25,6 +25,7 @@
25#include <linux/smp.h> 25#include <linux/smp.h>
26#include <linux/smp_lock.h> 26#include <linux/smp_lock.h>
27#include <linux/mutex.h> 27#include <linux/mutex.h>
28#include <linux/kthread.h>
28#include <linux/freezer.h> 29#include <linux/freezer.h>
29 30
30#include <linux/sunrpc/types.h> 31#include <linux/sunrpc/types.h>
@@ -48,14 +49,11 @@ EXPORT_SYMBOL(nlmsvc_ops);
48 49
49static DEFINE_MUTEX(nlmsvc_mutex); 50static DEFINE_MUTEX(nlmsvc_mutex);
50static unsigned int nlmsvc_users; 51static unsigned int nlmsvc_users;
51static pid_t nlmsvc_pid; 52static struct task_struct *nlmsvc_task;
52static struct svc_serv *nlmsvc_serv; 53static struct svc_serv *nlmsvc_serv;
53int nlmsvc_grace_period; 54int nlmsvc_grace_period;
54unsigned long nlmsvc_timeout; 55unsigned long nlmsvc_timeout;
55 56
56static DECLARE_COMPLETION(lockd_start_done);
57static DECLARE_WAIT_QUEUE_HEAD(lockd_exit);
58
59/* 57/*
60 * These can be set at insmod time (useful for NFS as root filesystem), 58 * These can be set at insmod time (useful for NFS as root filesystem),
61 * and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003 59 * and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003
@@ -113,35 +111,30 @@ static inline void clear_grace_period(void)
113/* 111/*
114 * This is the lockd kernel thread 112 * This is the lockd kernel thread
115 */ 113 */
116static void 114static int
117lockd(struct svc_rqst *rqstp) 115lockd(void *vrqstp)
118{ 116{
119 int err = 0; 117 int err = 0, preverr = 0;
118 struct svc_rqst *rqstp = vrqstp;
120 unsigned long grace_period_expire; 119 unsigned long grace_period_expire;
121 120
122 /* Lock module and set up kernel thread */ 121 /* try_to_freeze() is called from svc_recv() */
123 /* lockd_up is waiting for us to startup, so will
124 * be holding a reference to this module, so it
125 * is safe to just claim another reference
126 */
127 __module_get(THIS_MODULE);
128 lock_kernel();
129
130 /*
131 * Let our maker know we're running.
132 */
133 nlmsvc_pid = current->pid;
134 nlmsvc_serv = rqstp->rq_server;
135 complete(&lockd_start_done);
136
137 daemonize("lockd");
138 set_freezable(); 122 set_freezable();
139 123
140 /* Process request with signals blocked, but allow SIGKILL. */ 124 /* Allow SIGKILL to tell lockd to drop all of its locks */
141 allow_signal(SIGKILL); 125 allow_signal(SIGKILL);
142 126
143 dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); 127 dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
144 128
129 /*
130 * FIXME: it would be nice if lockd didn't spend its entire life
131 * running under the BKL. At the very least, it would be good to
132 * have someone clarify what it's intended to protect here. I've
133 * seen some handwavy posts about posix locking needing to be
134 * done under the BKL, but it's far from clear.
135 */
136 lock_kernel();
137
145 if (!nlm_timeout) 138 if (!nlm_timeout)
146 nlm_timeout = LOCKD_DFLT_TIMEO; 139 nlm_timeout = LOCKD_DFLT_TIMEO;
147 nlmsvc_timeout = nlm_timeout * HZ; 140 nlmsvc_timeout = nlm_timeout * HZ;
@@ -150,10 +143,9 @@ lockd(struct svc_rqst *rqstp)
150 143
151 /* 144 /*
152 * The main request loop. We don't terminate until the last 145 * The main request loop. We don't terminate until the last
153 * NFS mount or NFS daemon has gone away, and we've been sent a 146 * NFS mount or NFS daemon has gone away.
154 * signal, or else another process has taken over our job.
155 */ 147 */
156 while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) { 148 while (!kthread_should_stop()) {
157 long timeout = MAX_SCHEDULE_TIMEOUT; 149 long timeout = MAX_SCHEDULE_TIMEOUT;
158 RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); 150 RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
159 151
@@ -163,6 +155,7 @@ lockd(struct svc_rqst *rqstp)
163 nlmsvc_invalidate_all(); 155 nlmsvc_invalidate_all();
164 grace_period_expire = set_grace_period(); 156 grace_period_expire = set_grace_period();
165 } 157 }
158 continue;
166 } 159 }
167 160
168 /* 161 /*
@@ -181,14 +174,20 @@ lockd(struct svc_rqst *rqstp)
181 * recvfrom routine. 174 * recvfrom routine.
182 */ 175 */
183 err = svc_recv(rqstp, timeout); 176 err = svc_recv(rqstp, timeout);
184 if (err == -EAGAIN || err == -EINTR) 177 if (err == -EAGAIN || err == -EINTR) {
178 preverr = err;
185 continue; 179 continue;
180 }
186 if (err < 0) { 181 if (err < 0) {
187 printk(KERN_WARNING 182 if (err != preverr) {
188 "lockd: terminating on error %d\n", 183 printk(KERN_WARNING "%s: unexpected error "
189 -err); 184 "from svc_recv (%d)\n", __func__, err);
190 break; 185 preverr = err;
186 }
187 schedule_timeout_interruptible(HZ);
188 continue;
191 } 189 }
190 preverr = err;
192 191
193 dprintk("lockd: request from %s\n", 192 dprintk("lockd: request from %s\n",
194 svc_print_addr(rqstp, buf, sizeof(buf))); 193 svc_print_addr(rqstp, buf, sizeof(buf)));
@@ -197,28 +196,19 @@ lockd(struct svc_rqst *rqstp)
197 } 196 }
198 197
199 flush_signals(current); 198 flush_signals(current);
199 if (nlmsvc_ops)
200 nlmsvc_invalidate_all();
201 nlm_shutdown_hosts();
200 202
201 /* 203 unlock_kernel();
202 * Check whether there's a new lockd process before 204
203 * shutting down the hosts and clearing the slot. 205 nlmsvc_task = NULL;
204 */ 206 nlmsvc_serv = NULL;
205 if (!nlmsvc_pid || current->pid == nlmsvc_pid) {
206 if (nlmsvc_ops)
207 nlmsvc_invalidate_all();
208 nlm_shutdown_hosts();
209 nlmsvc_pid = 0;
210 nlmsvc_serv = NULL;
211 } else
212 printk(KERN_DEBUG
213 "lockd: new process, skipping host shutdown\n");
214 wake_up(&lockd_exit);
215 207
216 /* Exit the RPC thread */ 208 /* Exit the RPC thread */
217 svc_exit_thread(rqstp); 209 svc_exit_thread(rqstp);
218 210
219 /* Release module */ 211 return 0;
220 unlock_kernel();
221 module_put_and_exit(0);
222} 212}
223 213
224/* 214/*
@@ -263,14 +253,15 @@ static int make_socks(struct svc_serv *serv, int proto)
263int 253int
264lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ 254lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
265{ 255{
266 struct svc_serv * serv; 256 struct svc_serv *serv;
267 int error = 0; 257 struct svc_rqst *rqstp;
258 int error = 0;
268 259
269 mutex_lock(&nlmsvc_mutex); 260 mutex_lock(&nlmsvc_mutex);
270 /* 261 /*
271 * Check whether we're already up and running. 262 * Check whether we're already up and running.
272 */ 263 */
273 if (nlmsvc_pid) { 264 if (nlmsvc_serv) {
274 if (proto) 265 if (proto)
275 error = make_socks(nlmsvc_serv, proto); 266 error = make_socks(nlmsvc_serv, proto);
276 goto out; 267 goto out;
@@ -297,13 +288,28 @@ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
297 /* 288 /*
298 * Create the kernel thread and wait for it to start. 289 * Create the kernel thread and wait for it to start.
299 */ 290 */
300 error = svc_create_thread(lockd, serv); 291 rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]);
301 if (error) { 292 if (IS_ERR(rqstp)) {
293 error = PTR_ERR(rqstp);
302 printk(KERN_WARNING 294 printk(KERN_WARNING
303 "lockd_up: create thread failed, error=%d\n", error); 295 "lockd_up: svc_rqst allocation failed, error=%d\n",
296 error);
297 goto destroy_and_out;
298 }
299
300 svc_sock_update_bufs(serv);
301 nlmsvc_serv = rqstp->rq_server;
302
303 nlmsvc_task = kthread_run(lockd, rqstp, serv->sv_name);
304 if (IS_ERR(nlmsvc_task)) {
305 error = PTR_ERR(nlmsvc_task);
306 nlmsvc_task = NULL;
307 nlmsvc_serv = NULL;
308 printk(KERN_WARNING
309 "lockd_up: kthread_run failed, error=%d\n", error);
310 svc_exit_thread(rqstp);
304 goto destroy_and_out; 311 goto destroy_and_out;
305 } 312 }
306 wait_for_completion(&lockd_start_done);
307 313
308 /* 314 /*
309 * Note: svc_serv structures have an initial use count of 1, 315 * Note: svc_serv structures have an initial use count of 1,
@@ -325,37 +331,21 @@ EXPORT_SYMBOL(lockd_up);
325void 331void
326lockd_down(void) 332lockd_down(void)
327{ 333{
328 static int warned;
329
330 mutex_lock(&nlmsvc_mutex); 334 mutex_lock(&nlmsvc_mutex);
331 if (nlmsvc_users) { 335 if (nlmsvc_users) {
332 if (--nlmsvc_users) 336 if (--nlmsvc_users)
333 goto out; 337 goto out;
334 } else 338 } else {
335 printk(KERN_WARNING "lockd_down: no users! pid=%d\n", nlmsvc_pid); 339 printk(KERN_ERR "lockd_down: no users! task=%p\n",
336 340 nlmsvc_task);
337 if (!nlmsvc_pid) { 341 BUG();
338 if (warned++ == 0)
339 printk(KERN_WARNING "lockd_down: no lockd running.\n");
340 goto out;
341 } 342 }
342 warned = 0;
343 343
344 kill_proc(nlmsvc_pid, SIGKILL, 1); 344 if (!nlmsvc_task) {
345 /* 345 printk(KERN_ERR "lockd_down: no lockd running.\n");
346 * Wait for the lockd process to exit, but since we're holding 346 BUG();
347 * the lockd semaphore, we can't wait around forever ...
348 */
349 clear_thread_flag(TIF_SIGPENDING);
350 interruptible_sleep_on_timeout(&lockd_exit, HZ);
351 if (nlmsvc_pid) {
352 printk(KERN_WARNING
353 "lockd_down: lockd failed to exit, clearing pid\n");
354 nlmsvc_pid = 0;
355 } 347 }
356 spin_lock_irq(&current->sighand->siglock); 348 kthread_stop(nlmsvc_task);
357 recalc_sigpending();
358 spin_unlock_irq(&current->sighand->siglock);
359out: 349out:
360 mutex_unlock(&nlmsvc_mutex); 350 mutex_unlock(&nlmsvc_mutex);
361} 351}