aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2004-05-03 22:30:47 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-05-03 22:30:47 -0700
commit8aaac862603e2b493613bce18ecb5be285d64934 (patch)
tree339d3b2999ea7e8d03fdf51c4619aebcc3d4589e /lib
parent04e469df9896c834d5364f65780e70ffea417d5c (diff)
downloadhistory-8aaac862603e2b493613bce18ecb5be285d64934.tar.gz
Be more careful about waking up rwsem waiters
Get a reference count on the the sleeper, so that it can't possibly go away before we've sent it the wakeup event. Noted by Nick Piggin <nickpiggin@yahoo.com.au> David Howells <dhowells@redhat.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/rwsem-spinlock.c11
-rw-r--r--lib/rwsem.c7
2 files changed, 13 insertions, 5 deletions
diff --git a/lib/rwsem-spinlock.c b/lib/rwsem-spinlock.c
index d6c0e14c272961..a71152d550f015 100644
--- a/lib/rwsem-spinlock.c
+++ b/lib/rwsem-spinlock.c
@@ -71,10 +71,11 @@ static inline struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem, int
if (waiter->flags & RWSEM_WAITING_FOR_WRITE) {
sem->activity = -1;
list_del(&waiter->list);
- mb();
tsk = waiter->task;
+ mb();
waiter->task = NULL;
wake_up_process(tsk);
+ put_task_struct(tsk);
goto out;
}
@@ -85,10 +86,11 @@ static inline struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem, int
struct list_head *next = waiter->list.next;
list_del(&waiter->list);
- mb();
tsk = waiter->task;
+ mb();
waiter->task = NULL;
wake_up_process(tsk);
+ put_task_struct(tsk);
woken++;
if (list_empty(&sem->wait_list))
break;
@@ -115,10 +117,11 @@ static inline struct rw_semaphore *__rwsem_wake_one_writer(struct rw_semaphore *
waiter = list_entry(sem->wait_list.next,struct rwsem_waiter,list);
list_del(&waiter->list);
- mb();
tsk = waiter->task;
+ mb();
waiter->task = NULL;
wake_up_process(tsk);
+ put_task_struct(tsk);
return sem;
}
@@ -147,6 +150,7 @@ void fastcall __down_read(struct rw_semaphore *sem)
/* set up my own style of waitqueue */
waiter.task = tsk;
waiter.flags = RWSEM_WAITING_FOR_READ;
+ get_task_struct(tsk);
list_add_tail(&waiter.list,&sem->wait_list);
@@ -215,6 +219,7 @@ void fastcall __down_write(struct rw_semaphore *sem)
/* set up my own style of waitqueue */
waiter.task = tsk;
waiter.flags = RWSEM_WAITING_FOR_WRITE;
+ get_task_struct(tsk);
list_add_tail(&waiter.list,&sem->wait_list);
diff --git a/lib/rwsem.c b/lib/rwsem.c
index 7df79fdbe9ba75..ce15eb0137616d 100644
--- a/lib/rwsem.c
+++ b/lib/rwsem.c
@@ -65,10 +65,11 @@ static inline struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem, int
goto readers_only;
list_del(&waiter->list);
- mb();
tsk = waiter->task;
+ mb();
waiter->task = NULL;
wake_up_process(tsk);
+ put_task_struct(tsk);
goto out;
/* don't want to wake any writers */
@@ -102,10 +103,11 @@ static inline struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem, int
for (; loop>0; loop--) {
waiter = list_entry(next,struct rwsem_waiter,list);
next = waiter->list.next;
- mb();
tsk = waiter->task;
+ mb();
waiter->task = NULL;
wake_up_process(tsk);
+ put_task_struct(tsk);
}
sem->wait_list.next = next;
@@ -137,6 +139,7 @@ static inline struct rw_semaphore *rwsem_down_failed_common(struct rw_semaphore
/* set up my own style of waitqueue */
spin_lock(&sem->wait_lock);
waiter->task = tsk;
+ get_task_struct(tsk);
list_add_tail(&waiter->list,&sem->wait_list);