[PATCH] lockd

From: Steve Dickson
Date: Mon Oct 04 2004 - 11:25:07 EST


Hey Neil,

Attached is a patch that fixes some potential SMP races
in the lockd code that were identified by the SLEEP_ON_BKLCHECK
that was (at one time) in the -mm tree...

Signed-Off-By: Steve Dickson <SteveD@xxxxxxxxxx>


--- 2.6.9-rc3-mm2/fs/lockd/clntlock.c.old 2004-10-04 09:32:20.404018000 -0400
+++ 2.6.9-rc3-mm2/fs/lockd/clntlock.c 2004-10-04 11:29:38.940621000 -0400
@@ -50,14 +50,19 @@ nlmclnt_block(struct nlm_host *host, str
struct nlm_wait block, **head;
int err;
u32 pstate;
+ wait_queue_t __wait;

block.b_host = host;
block.b_lock = fl;
- init_waitqueue_head(&block.b_wait);
block.b_status = NLM_LCK_BLOCKED;
+ init_waitqueue_entry(&__wait, current);
+ init_waitqueue_head(&block.b_wait);
+ add_wait_queue(&block.b_wait, &__wait);
+
block.b_next = nlm_blocked;
nlm_blocked = &block;

+
/* Remember pseudo nsm state */
pstate = host->h_state;

@@ -69,7 +74,7 @@ nlmclnt_block(struct nlm_host *host, str
* a 1 minute timeout would do. See the comment before
* nlmclnt_lock for an explanation.
*/
- sleep_on_timeout(&block.b_wait, 30*HZ);
+ schedule_timeout(30*HZ);

for (head = &nlm_blocked; *head; head = &(*head)->b_next) {
if (*head == &block) {
@@ -77,6 +82,7 @@ nlmclnt_block(struct nlm_host *host, str
break;
}
}
+ remove_wait_queue(&block.b_wait, &__wait);

if (!signalled()) {
*statp = block.b_status;
--- 2.6.9-rc3-mm2/fs/lockd/svc.c.old 2004-10-04 09:32:20.417019000 -0400
+++ 2.6.9-rc3-mm2/fs/lockd/svc.c 2004-10-04 11:27:54.868205000 -0400
@@ -278,6 +278,8 @@ void
lockd_down(void)
{
static int warned;
+ wait_queue_t __wait;
+ int retries=0;

down(&nlmsvc_sema);
if (nlmsvc_users) {
@@ -294,20 +296,33 @@ lockd_down(void)
warned = 0;

kill_proc(nlmsvc_pid, SIGKILL, 1);
+
+ init_waitqueue_entry(&__wait, current);
+ add_wait_queue(&lockd_exit, &__wait);
+
/*
* Wait for the lockd process to exit, but since we're holding
* the lockd semaphore, we can't wait around forever ...
*/
clear_thread_flag(TIF_SIGPENDING);
- interruptible_sleep_on_timeout(&lockd_exit, HZ);
- if (nlmsvc_pid) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ while (nlmsvc_pid) {
+
+ schedule_timeout(HZ);
+ if (retries++ < 3)
+ continue;
+
printk(KERN_WARNING
"lockd_down: lockd failed to exit, clearing pid\n");
nlmsvc_pid = 0;
}
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&lockd_exit, &__wait);
+
spin_lock_irq(&current->sighand->siglock);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
+
out:
up(&nlmsvc_sema);
}