diff options
Diffstat (limited to 'fs/lockd/svc.c')
-rw-r--r-- | fs/lockd/svc.c | 150 |
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 | ||
49 | static DEFINE_MUTEX(nlmsvc_mutex); | 50 | static DEFINE_MUTEX(nlmsvc_mutex); |
50 | static unsigned int nlmsvc_users; | 51 | static unsigned int nlmsvc_users; |
51 | static pid_t nlmsvc_pid; | 52 | static struct task_struct *nlmsvc_task; |
52 | static struct svc_serv *nlmsvc_serv; | 53 | static struct svc_serv *nlmsvc_serv; |
53 | int nlmsvc_grace_period; | 54 | int nlmsvc_grace_period; |
54 | unsigned long nlmsvc_timeout; | 55 | unsigned long nlmsvc_timeout; |
55 | 56 | ||
56 | static DECLARE_COMPLETION(lockd_start_done); | ||
57 | static 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 | */ |
116 | static void | 114 | static int |
117 | lockd(struct svc_rqst *rqstp) | 115 | lockd(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) | |||
263 | int | 253 | int |
264 | lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ | 254 | lockd_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); | |||
325 | void | 331 | void |
326 | lockd_down(void) | 332 | lockd_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(¤t->sighand->siglock); | 348 | kthread_stop(nlmsvc_task); |
357 | recalc_sigpending(); | ||
358 | spin_unlock_irq(¤t->sighand->siglock); | ||
359 | out: | 349 | out: |
360 | mutex_unlock(&nlmsvc_mutex); | 350 | mutex_unlock(&nlmsvc_mutex); |
361 | } | 351 | } |