diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-05-03 22:30:47 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-05-03 22:30:47 -0700 |
commit | 8aaac862603e2b493613bce18ecb5be285d64934 (patch) | |
tree | 339d3b2999ea7e8d03fdf51c4619aebcc3d4589e /lib | |
parent | 04e469df9896c834d5364f65780e70ffea417d5c (diff) | |
download | history-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.c | 11 | ||||
-rw-r--r-- | lib/rwsem.c | 7 |
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); |