aboutsummaryrefslogtreecommitdiffstats
path: root/fs/lockd/svc.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-04-24 14:45:00 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-24 14:45:00 -0400
commit10c993a6b5418cb1026775765ba4c70ffb70853d (patch)
tree717deba79b938c2f3f786ff6fe908d30582f06f8 /fs/lockd/svc.c
parentc328d54cd4ad120d76284e46dcca6c6cf996154a (diff)
parentca456252db0521e5e88024fa2b67535e9739e030 (diff)
Merge branch 'for-linus' of git://linux-nfs.org/~bfields/linux
* 'for-linus' of git://linux-nfs.org/~bfields/linux: (52 commits) knfsd: clear both setuid and setgid whenever a chown is done knfsd: get rid of imode variable in nfsd_setattr SUNRPC: Use unsigned loop and array index in svc_init_buffer() SUNRPC: Use unsigned index when looping over arrays SUNRPC: Update RPC server's TCP record marker decoder SUNRPC: RPC server still uses 2.4 method for disabling TCP Nagle NLM: don't let lockd exit on unexpected svc_recv errors (try #2) NFS: don't let nfs_callback_svc exit on unexpected svc_recv errors (try #2) Use a zero sized array for raw field in struct fid nfsd: use static memory for callback program and stats SUNRPC: remove svc_create_thread() nfsd: fix comment lockd: Fix stale nlmsvc_unlink_block comment NFSD: Strip __KERNEL__ testing from unexported header files. sunrpc: make token header values less confusing gss_krb5: consistently use unsigned for seqnum NFSD: Remove NFSv4 dependency on NFSv3 SUNRPC: Remove PROC_FS dependency NFSD: Use "depends on" for PROC_FS dependency nfsd: move most of fh_verify to separate function ...
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 1ed8bd4de941..cf977bbcf303 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
@@ -111,35 +109,30 @@ static inline void clear_grace_period(void)
111/* 109/*
112 * This is the lockd kernel thread 110 * This is the lockd kernel thread
113 */ 111 */
114static void 112static int
115lockd(struct svc_rqst *rqstp) 113lockd(void *vrqstp)
116{ 114{
117 int err = 0; 115 int err = 0, preverr = 0;
116 struct svc_rqst *rqstp = vrqstp;
118 unsigned long grace_period_expire; 117 unsigned long grace_period_expire;
119 118
120 /* Lock module and set up kernel thread */ 119 /* try_to_freeze() is called from svc_recv() */
121 /* lockd_up is waiting for us to startup, so will
122 * be holding a reference to this module, so it
123 * is safe to just claim another reference
124 */
125 __module_get(THIS_MODULE);
126 lock_kernel();
127
128 /*
129 * Let our maker know we're running.
130 */
131 nlmsvc_pid = current->pid;
132 nlmsvc_serv = rqstp->rq_server;
133 complete(&lockd_start_done);
134
135 daemonize("lockd");
136 set_freezable(); 120 set_freezable();
137 121
138 /* Process request with signals blocked, but allow SIGKILL. */ 122 /* Allow SIGKILL to tell lockd to drop all of its locks */
139 allow_signal(SIGKILL); 123 allow_signal(SIGKILL);
140 124
141 dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); 125 dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
142 126
127 /*
128 * FIXME: it would be nice if lockd didn't spend its entire life
129 * running under the BKL. At the very least, it would be good to
130 * have someone clarify what it's intended to protect here. I've
131 * seen some handwavy posts about posix locking needing to be
132 * done under the BKL, but it's far from clear.
133 */
134 lock_kernel();
135
143 if (!nlm_timeout) 136 if (!nlm_timeout)
144 nlm_timeout = LOCKD_DFLT_TIMEO; 137 nlm_timeout = LOCKD_DFLT_TIMEO;
145 nlmsvc_timeout = nlm_timeout * HZ; 138 nlmsvc_timeout = nlm_timeout * HZ;
@@ -148,10 +141,9 @@ lockd(struct svc_rqst *rqstp)
148 141
149 /* 142 /*
150 * The main request loop. We don't terminate until the last 143 * The main request loop. We don't terminate until the last
151 * NFS mount or NFS daemon has gone away, and we've been sent a 144 * NFS mount or NFS daemon has gone away.
152 * signal, or else another process has taken over our job.
153 */ 145 */
154 while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) { 146 while (!kthread_should_stop()) {
155 long timeout = MAX_SCHEDULE_TIMEOUT; 147 long timeout = MAX_SCHEDULE_TIMEOUT;
156 RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); 148 RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
157 149
@@ -161,6 +153,7 @@ lockd(struct svc_rqst *rqstp)
161 nlmsvc_invalidate_all(); 153 nlmsvc_invalidate_all();
162 grace_period_expire = set_grace_period(); 154 grace_period_expire = set_grace_period();
163 } 155 }
156 continue;
164 } 157 }
165 158
166 /* 159 /*
@@ -179,14 +172,20 @@ lockd(struct svc_rqst *rqstp)
179 * recvfrom routine. 172 * recvfrom routine.
180 */ 173 */
181 err = svc_recv(rqstp, timeout); 174 err = svc_recv(rqstp, timeout);
182 if (err == -EAGAIN || err == -EINTR) 175 if (err == -EAGAIN || err == -EINTR) {
176 preverr = err;
183 continue; 177 continue;
178 }
184 if (err < 0) { 179 if (err < 0) {
185 printk(KERN_WARNING 180 if (err != preverr) {
186 "lockd: terminating on error %d\n", 181 printk(KERN_WARNING "%s: unexpected error "
187 -err); 182 "from svc_recv (%d)\n", __func__, err);
188 break; 183 preverr = err;
184 }
185 schedule_timeout_interruptible(HZ);
186 continue;
189 } 187 }
188 preverr = err;
190 189
191 dprintk("lockd: request from %s\n", 190 dprintk("lockd: request from %s\n",
192 svc_print_addr(rqstp, buf, sizeof(buf))); 191 svc_print_addr(rqstp, buf, sizeof(buf)));
@@ -195,28 +194,19 @@ lockd(struct svc_rqst *rqstp)
195 } 194 }
196 195
197 flush_signals(current); 196 flush_signals(current);
197 if (nlmsvc_ops)
198 nlmsvc_invalidate_all();
199 nlm_shutdown_hosts();
198 200
199 /* 201 unlock_kernel();
200 * Check whether there's a new lockd process before 202
201 * shutting down the hosts and clearing the slot. 203 nlmsvc_task = NULL;
202 */ 204 nlmsvc_serv = NULL;
203 if (!nlmsvc_pid || current->pid == nlmsvc_pid) {
204 if (nlmsvc_ops)
205 nlmsvc_invalidate_all();
206 nlm_shutdown_hosts();
207 nlmsvc_pid = 0;
208 nlmsvc_serv = NULL;
209 } else
210 printk(KERN_DEBUG
211 "lockd: new process, skipping host shutdown\n");
212 wake_up(&lockd_exit);
213 205
214 /* Exit the RPC thread */ 206 /* Exit the RPC thread */
215 svc_exit_thread(rqstp); 207 svc_exit_thread(rqstp);
216 208
217 /* Release module */ 209 return 0;
218 unlock_kernel();
219 module_put_and_exit(0);
220} 210}
221 211
222/* 212/*
@@ -261,14 +251,15 @@ static int make_socks(struct svc_serv *serv, int proto)
261int 251int
262lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ 252lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
263{ 253{
264 struct svc_serv * serv; 254 struct svc_serv *serv;
265 int error = 0; 255 struct svc_rqst *rqstp;
256 int error = 0;
266 257
267 mutex_lock(&nlmsvc_mutex); 258 mutex_lock(&nlmsvc_mutex);
268 /* 259 /*
269 * Check whether we're already up and running. 260 * Check whether we're already up and running.
270 */ 261 */
271 if (nlmsvc_pid) { 262 if (nlmsvc_serv) {
272 if (proto) 263 if (proto)
273 error = make_socks(nlmsvc_serv, proto); 264 error = make_socks(nlmsvc_serv, proto);
274 goto out; 265 goto out;
@@ -295,13 +286,28 @@ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
295 /* 286 /*
296 * Create the kernel thread and wait for it to start. 287 * Create the kernel thread and wait for it to start.
297 */ 288 */
298 error = svc_create_thread(lockd, serv); 289 rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]);
299 if (error) { 290 if (IS_ERR(rqstp)) {
291 error = PTR_ERR(rqstp);
292 printk(KERN_WARNING
293 "lockd_up: svc_rqst allocation failed, error=%d\n",
294 error);
295 goto destroy_and_out;
296 }
297
298 svc_sock_update_bufs(serv);
299 nlmsvc_serv = rqstp->rq_server;
300
301 nlmsvc_task = kthread_run(lockd, rqstp, serv->sv_name);
302 if (IS_ERR(nlmsvc_task)) {
303 error = PTR_ERR(nlmsvc_task);
304 nlmsvc_task = NULL;
305 nlmsvc_serv = NULL;
300 printk(KERN_WARNING 306 printk(KERN_WARNING
301 "lockd_up: create thread failed, error=%d\n", error); 307 "lockd_up: kthread_run failed, error=%d\n", error);
308 svc_exit_thread(rqstp);
302 goto destroy_and_out; 309 goto destroy_and_out;
303 } 310 }
304 wait_for_completion(&lockd_start_done);
305 311
306 /* 312 /*
307 * Note: svc_serv structures have an initial use count of 1, 313 * Note: svc_serv structures have an initial use count of 1,
@@ -323,37 +329,21 @@ EXPORT_SYMBOL(lockd_up);
323void 329void
324lockd_down(void) 330lockd_down(void)
325{ 331{
326 static int warned;
327
328 mutex_lock(&nlmsvc_mutex); 332 mutex_lock(&nlmsvc_mutex);
329 if (nlmsvc_users) { 333 if (nlmsvc_users) {
330 if (--nlmsvc_users) 334 if (--nlmsvc_users)
331 goto out; 335 goto out;
332 } else 336 } else {
333 printk(KERN_WARNING "lockd_down: no users! pid=%d\n", nlmsvc_pid); 337 printk(KERN_ERR "lockd_down: no users! task=%p\n",
334 338 nlmsvc_task);
335 if (!nlmsvc_pid) { 339 BUG();
336 if (warned++ == 0)
337 printk(KERN_WARNING "lockd_down: no lockd running.\n");
338 goto out;
339 } 340 }
340 warned = 0;
341 341
342 kill_proc(nlmsvc_pid, SIGKILL, 1); 342 if (!nlmsvc_task) {
343 /* 343 printk(KERN_ERR "lockd_down: no lockd running.\n");
344 * Wait for the lockd process to exit, but since we're holding 344 BUG();
345 * the lockd semaphore, we can't wait around forever ...
346 */
347 clear_thread_flag(TIF_SIGPENDING);
348 interruptible_sleep_on_timeout(&lockd_exit, HZ);
349 if (nlmsvc_pid) {
350 printk(KERN_WARNING
351 "lockd_down: lockd failed to exit, clearing pid\n");
352 nlmsvc_pid = 0;
353 } 345 }
354 spin_lock_irq(&current->sighand->siglock); 346 kthread_stop(nlmsvc_task);
355 recalc_sigpending();
356 spin_unlock_irq(&current->sighand->siglock);
357out: 347out:
358 mutex_unlock(&nlmsvc_mutex); 348 mutex_unlock(&nlmsvc_mutex);
359} 349}