aboutsummaryrefslogtreecommitdiffstats
path: root/fs/lockd
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
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')
-rw-r--r--fs/lockd/host.c73
-rw-r--r--fs/lockd/svc.c150
-rw-r--r--fs/lockd/svclock.c6
-rw-r--r--fs/lockd/svcshare.c3
4 files changed, 111 insertions, 121 deletions
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index f1ef49fff118..c7854791898f 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -19,12 +19,11 @@
19 19
20 20
21#define NLMDBG_FACILITY NLMDBG_HOSTCACHE 21#define NLMDBG_FACILITY NLMDBG_HOSTCACHE
22#define NLM_HOST_MAX 64
23#define NLM_HOST_NRHASH 32 22#define NLM_HOST_NRHASH 32
24#define NLM_ADDRHASH(addr) (ntohl(addr) & (NLM_HOST_NRHASH-1)) 23#define NLM_ADDRHASH(addr) (ntohl(addr) & (NLM_HOST_NRHASH-1))
25#define NLM_HOST_REBIND (60 * HZ) 24#define NLM_HOST_REBIND (60 * HZ)
26#define NLM_HOST_EXPIRE ((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ) 25#define NLM_HOST_EXPIRE (300 * HZ)
27#define NLM_HOST_COLLECT ((nrhosts > NLM_HOST_MAX)? 120 * HZ : 60 * HZ) 26#define NLM_HOST_COLLECT (120 * HZ)
28 27
29static struct hlist_head nlm_hosts[NLM_HOST_NRHASH]; 28static struct hlist_head nlm_hosts[NLM_HOST_NRHASH];
30static unsigned long next_gc; 29static unsigned long next_gc;
@@ -142,9 +141,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin,
142 INIT_LIST_HEAD(&host->h_granted); 141 INIT_LIST_HEAD(&host->h_granted);
143 INIT_LIST_HEAD(&host->h_reclaim); 142 INIT_LIST_HEAD(&host->h_reclaim);
144 143
145 if (++nrhosts > NLM_HOST_MAX) 144 nrhosts++;
146 next_gc = 0;
147
148out: 145out:
149 mutex_unlock(&nlm_host_mutex); 146 mutex_unlock(&nlm_host_mutex);
150 return host; 147 return host;
@@ -460,7 +457,7 @@ nlm_gc_hosts(void)
460 * Manage NSM handles 457 * Manage NSM handles
461 */ 458 */
462static LIST_HEAD(nsm_handles); 459static LIST_HEAD(nsm_handles);
463static DEFINE_MUTEX(nsm_mutex); 460static DEFINE_SPINLOCK(nsm_lock);
464 461
465static struct nsm_handle * 462static struct nsm_handle *
466__nsm_find(const struct sockaddr_in *sin, 463__nsm_find(const struct sockaddr_in *sin,
@@ -468,7 +465,7 @@ __nsm_find(const struct sockaddr_in *sin,
468 int create) 465 int create)
469{ 466{
470 struct nsm_handle *nsm = NULL; 467 struct nsm_handle *nsm = NULL;
471 struct list_head *pos; 468 struct nsm_handle *pos;
472 469
473 if (!sin) 470 if (!sin)
474 return NULL; 471 return NULL;
@@ -482,38 +479,43 @@ __nsm_find(const struct sockaddr_in *sin,
482 return NULL; 479 return NULL;
483 } 480 }
484 481
485 mutex_lock(&nsm_mutex); 482retry:
486 list_for_each(pos, &nsm_handles) { 483 spin_lock(&nsm_lock);
487 nsm = list_entry(pos, struct nsm_handle, sm_link); 484 list_for_each_entry(pos, &nsm_handles, sm_link) {
488 485
489 if (hostname && nsm_use_hostnames) { 486 if (hostname && nsm_use_hostnames) {
490 if (strlen(nsm->sm_name) != hostname_len 487 if (strlen(pos->sm_name) != hostname_len
491 || memcmp(nsm->sm_name, hostname, hostname_len)) 488 || memcmp(pos->sm_name, hostname, hostname_len))
492 continue; 489 continue;
493 } else if (!nlm_cmp_addr(&nsm->sm_addr, sin)) 490 } else if (!nlm_cmp_addr(&pos->sm_addr, sin))
494 continue; 491 continue;
495 atomic_inc(&nsm->sm_count); 492 atomic_inc(&pos->sm_count);
496 goto out; 493 kfree(nsm);
494 nsm = pos;
495 goto found;
497 } 496 }
498 497 if (nsm) {
499 if (!create) { 498 list_add(&nsm->sm_link, &nsm_handles);
500 nsm = NULL; 499 goto found;
501 goto out;
502 } 500 }
501 spin_unlock(&nsm_lock);
502
503 if (!create)
504 return NULL;
503 505
504 nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL); 506 nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL);
505 if (nsm != NULL) { 507 if (nsm == NULL)
506 nsm->sm_addr = *sin; 508 return NULL;
507 nsm->sm_name = (char *) (nsm + 1);
508 memcpy(nsm->sm_name, hostname, hostname_len);
509 nsm->sm_name[hostname_len] = '\0';
510 atomic_set(&nsm->sm_count, 1);
511 509
512 list_add(&nsm->sm_link, &nsm_handles); 510 nsm->sm_addr = *sin;
513 } 511 nsm->sm_name = (char *) (nsm + 1);
512 memcpy(nsm->sm_name, hostname, hostname_len);
513 nsm->sm_name[hostname_len] = '\0';
514 atomic_set(&nsm->sm_count, 1);
515 goto retry;
514 516
515out: 517found:
516 mutex_unlock(&nsm_mutex); 518 spin_unlock(&nsm_lock);
517 return nsm; 519 return nsm;
518} 520}
519 521
@@ -532,12 +534,9 @@ nsm_release(struct nsm_handle *nsm)
532{ 534{
533 if (!nsm) 535 if (!nsm)
534 return; 536 return;
535 if (atomic_dec_and_test(&nsm->sm_count)) { 537 if (atomic_dec_and_lock(&nsm->sm_count, &nsm_lock)) {
536 mutex_lock(&nsm_mutex); 538 list_del(&nsm->sm_link);
537 if (atomic_read(&nsm->sm_count) == 0) { 539 spin_unlock(&nsm_lock);
538 list_del(&nsm->sm_link); 540 kfree(nsm);
539 kfree(nsm);
540 }
541 mutex_unlock(&nsm_mutex);
542 } 541 }
543} 542}
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}
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index fe9bdb4a220c..1f122c1940af 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -29,6 +29,7 @@
29#include <linux/sunrpc/svc.h> 29#include <linux/sunrpc/svc.h>
30#include <linux/lockd/nlm.h> 30#include <linux/lockd/nlm.h>
31#include <linux/lockd/lockd.h> 31#include <linux/lockd/lockd.h>
32#include <linux/kthread.h>
32 33
33#define NLMDBG_FACILITY NLMDBG_SVCLOCK 34#define NLMDBG_FACILITY NLMDBG_SVCLOCK
34 35
@@ -226,8 +227,7 @@ failed:
226} 227}
227 228
228/* 229/*
229 * Delete a block. If the lock was cancelled or the grant callback 230 * Delete a block.
230 * failed, unlock is set to 1.
231 * It is the caller's responsibility to check whether the file 231 * It is the caller's responsibility to check whether the file
232 * can be closed hereafter. 232 * can be closed hereafter.
233 */ 233 */
@@ -887,7 +887,7 @@ nlmsvc_retry_blocked(void)
887 unsigned long timeout = MAX_SCHEDULE_TIMEOUT; 887 unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
888 struct nlm_block *block; 888 struct nlm_block *block;
889 889
890 while (!list_empty(&nlm_blocked)) { 890 while (!list_empty(&nlm_blocked) && !kthread_should_stop()) {
891 block = list_entry(nlm_blocked.next, struct nlm_block, b_list); 891 block = list_entry(nlm_blocked.next, struct nlm_block, b_list);
892 892
893 if (block->b_when == NLM_NEVER) 893 if (block->b_when == NLM_NEVER)
diff --git a/fs/lockd/svcshare.c b/fs/lockd/svcshare.c
index 068886de4dda..b0ae07008700 100644
--- a/fs/lockd/svcshare.c
+++ b/fs/lockd/svcshare.c
@@ -71,7 +71,8 @@ nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file,
71 struct nlm_share *share, **shpp; 71 struct nlm_share *share, **shpp;
72 struct xdr_netobj *oh = &argp->lock.oh; 72 struct xdr_netobj *oh = &argp->lock.oh;
73 73
74 for (shpp = &file->f_shares; (share = *shpp) != 0; shpp = &share->s_next) { 74 for (shpp = &file->f_shares; (share = *shpp) != NULL;
75 shpp = &share->s_next) {
75 if (share->s_host == host && nlm_cmp_owner(share, oh)) { 76 if (share->s_host == host && nlm_cmp_owner(share, oh)) {
76 *shpp = share->s_next; 77 *shpp = share->s_next;
77 kfree(share); 78 kfree(share);