Commit 8aaac862 authored by Linus Torvalds's avatar Linus Torvalds

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>
parent 04e469df
...@@ -71,10 +71,11 @@ static inline struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem, int ...@@ -71,10 +71,11 @@ static inline struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem, int
if (waiter->flags & RWSEM_WAITING_FOR_WRITE) { if (waiter->flags & RWSEM_WAITING_FOR_WRITE) {
sem->activity = -1; sem->activity = -1;
list_del(&waiter->list); list_del(&waiter->list);
mb();
tsk = waiter->task; tsk = waiter->task;
mb();
waiter->task = NULL; waiter->task = NULL;
wake_up_process(tsk); wake_up_process(tsk);
put_task_struct(tsk);
goto out; goto out;
} }
...@@ -85,10 +86,11 @@ static inline struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem, int ...@@ -85,10 +86,11 @@ static inline struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem, int
struct list_head *next = waiter->list.next; struct list_head *next = waiter->list.next;
list_del(&waiter->list); list_del(&waiter->list);
mb();
tsk = waiter->task; tsk = waiter->task;
mb();
waiter->task = NULL; waiter->task = NULL;
wake_up_process(tsk); wake_up_process(tsk);
put_task_struct(tsk);
woken++; woken++;
if (list_empty(&sem->wait_list)) if (list_empty(&sem->wait_list))
break; break;
...@@ -115,10 +117,11 @@ static inline struct rw_semaphore *__rwsem_wake_one_writer(struct rw_semaphore * ...@@ -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); waiter = list_entry(sem->wait_list.next,struct rwsem_waiter,list);
list_del(&waiter->list); list_del(&waiter->list);
mb();
tsk = waiter->task; tsk = waiter->task;
mb();
waiter->task = NULL; waiter->task = NULL;
wake_up_process(tsk); wake_up_process(tsk);
put_task_struct(tsk);
return sem; return sem;
} }
...@@ -147,6 +150,7 @@ void fastcall __down_read(struct rw_semaphore *sem) ...@@ -147,6 +150,7 @@ void fastcall __down_read(struct rw_semaphore *sem)
/* set up my own style of waitqueue */ /* set up my own style of waitqueue */
waiter.task = tsk; waiter.task = tsk;
waiter.flags = RWSEM_WAITING_FOR_READ; waiter.flags = RWSEM_WAITING_FOR_READ;
get_task_struct(tsk);
list_add_tail(&waiter.list,&sem->wait_list); list_add_tail(&waiter.list,&sem->wait_list);
...@@ -215,6 +219,7 @@ void fastcall __down_write(struct rw_semaphore *sem) ...@@ -215,6 +219,7 @@ void fastcall __down_write(struct rw_semaphore *sem)
/* set up my own style of waitqueue */ /* set up my own style of waitqueue */
waiter.task = tsk; waiter.task = tsk;
waiter.flags = RWSEM_WAITING_FOR_WRITE; waiter.flags = RWSEM_WAITING_FOR_WRITE;
get_task_struct(tsk);
list_add_tail(&waiter.list,&sem->wait_list); list_add_tail(&waiter.list,&sem->wait_list);
......
...@@ -65,10 +65,11 @@ static inline struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem, int ...@@ -65,10 +65,11 @@ static inline struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem, int
goto readers_only; goto readers_only;
list_del(&waiter->list); list_del(&waiter->list);
mb();
tsk = waiter->task; tsk = waiter->task;
mb();
waiter->task = NULL; waiter->task = NULL;
wake_up_process(tsk); wake_up_process(tsk);
put_task_struct(tsk);
goto out; goto out;
/* don't want to wake any writers */ /* don't want to wake any writers */
...@@ -102,10 +103,11 @@ static inline struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem, int ...@@ -102,10 +103,11 @@ static inline struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem, int
for (; loop>0; loop--) { for (; loop>0; loop--) {
waiter = list_entry(next,struct rwsem_waiter,list); waiter = list_entry(next,struct rwsem_waiter,list);
next = waiter->list.next; next = waiter->list.next;
mb();
tsk = waiter->task; tsk = waiter->task;
mb();
waiter->task = NULL; waiter->task = NULL;
wake_up_process(tsk); wake_up_process(tsk);
put_task_struct(tsk);
} }
sem->wait_list.next = next; sem->wait_list.next = next;
...@@ -137,6 +139,7 @@ static inline struct rw_semaphore *rwsem_down_failed_common(struct rw_semaphore ...@@ -137,6 +139,7 @@ static inline struct rw_semaphore *rwsem_down_failed_common(struct rw_semaphore
/* set up my own style of waitqueue */ /* set up my own style of waitqueue */
spin_lock(&sem->wait_lock); spin_lock(&sem->wait_lock);
waiter->task = tsk; waiter->task = tsk;
get_task_struct(tsk);
list_add_tail(&waiter->list,&sem->wait_list); list_add_tail(&waiter->list,&sem->wait_list);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment