aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/rwsem-spinlock.c23
-rw-r--r--lib/rwsem.c26
2 files changed, 19 insertions, 30 deletions
diff --git a/lib/rwsem-spinlock.c b/lib/rwsem-spinlock.c
index 5f117f37ac0a..9be8a9144978 100644
--- a/lib/rwsem-spinlock.c
+++ b/lib/rwsem-spinlock.c
@@ -70,26 +70,17 @@ __rwsem_do_wake(struct rw_semaphore *sem, int wakewrite)
70 70
71 waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list); 71 waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list);
72 72
73 if (!wakewrite) {
74 if (waiter->type == RWSEM_WAITING_FOR_WRITE)
75 goto out;
76 goto dont_wake_writers;
77 }
78
79 /*
80 * as we support write lock stealing, we can't set sem->activity
81 * to -1 here to indicate we get the lock. Instead, we wake it up
82 * to let it go get it again.
83 */
84 if (waiter->type == RWSEM_WAITING_FOR_WRITE) { 73 if (waiter->type == RWSEM_WAITING_FOR_WRITE) {
85 wake_up_process(waiter->task); 74 if (wakewrite)
75 /* Wake up a writer. Note that we do not grant it the
76 * lock - it will have to acquire it when it runs. */
77 wake_up_process(waiter->task);
86 goto out; 78 goto out;
87 } 79 }
88 80
89 /* grant an infinite number of read locks to the front of the queue */ 81 /* grant an infinite number of read locks to the front of the queue */
90 dont_wake_writers:
91 woken = 0; 82 woken = 0;
92 while (waiter->type == RWSEM_WAITING_FOR_READ) { 83 do {
93 struct list_head *next = waiter->list.next; 84 struct list_head *next = waiter->list.next;
94 85
95 list_del(&waiter->list); 86 list_del(&waiter->list);
@@ -99,10 +90,10 @@ __rwsem_do_wake(struct rw_semaphore *sem, int wakewrite)
99 wake_up_process(tsk); 90 wake_up_process(tsk);
100 put_task_struct(tsk); 91 put_task_struct(tsk);
101 woken++; 92 woken++;
102 if (list_empty(&sem->wait_list)) 93 if (next == &sem->wait_list)
103 break; 94 break;
104 waiter = list_entry(next, struct rwsem_waiter, list); 95 waiter = list_entry(next, struct rwsem_waiter, list);
105 } 96 } while (waiter->type != RWSEM_WAITING_FOR_WRITE);
106 97
107 sem->activity += woken; 98 sem->activity += woken;
108 99
diff --git a/lib/rwsem.c b/lib/rwsem.c
index 0d50e46d5b0c..9a675fa9d78e 100644
--- a/lib/rwsem.c
+++ b/lib/rwsem.c
@@ -68,20 +68,17 @@ __rwsem_do_wake(struct rw_semaphore *sem, int wake_type)
68 signed long woken, loop, adjustment; 68 signed long woken, loop, adjustment;
69 69
70 waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list); 70 waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list);
71 if (waiter->type != RWSEM_WAITING_FOR_WRITE) 71 if (waiter->type == RWSEM_WAITING_FOR_WRITE) {
72 goto readers_only; 72 if (wake_type != RWSEM_WAKE_READ_OWNED)
73 73 /* Wake writer at the front of the queue, but do not
74 if (wake_type == RWSEM_WAKE_READ_OWNED) 74 * grant it the lock yet as we want other writers
75 /* Another active reader was observed, so wakeup is not 75 * to be able to steal it. Readers, on the other hand,
76 * likely to succeed. Save the atomic op. 76 * will block as they will notice the queued writer.
77 */ 77 */
78 wake_up_process(waiter->task);
78 goto out; 79 goto out;
80 }
79 81
80 /* Wake up the writing waiter and let the task grab the sem: */
81 wake_up_process(waiter->task);
82 goto out;
83
84 readers_only:
85 /* If we come here from up_xxxx(), another thread might have reached 82 /* If we come here from up_xxxx(), another thread might have reached
86 * rwsem_down_failed_common() before we acquired the spinlock and 83 * rwsem_down_failed_common() before we acquired the spinlock and
87 * woken up a waiter, making it now active. We prefer to check for 84 * woken up a waiter, making it now active. We prefer to check for
@@ -125,7 +122,8 @@ __rwsem_do_wake(struct rw_semaphore *sem, int wake_type)
125 rwsem_atomic_add(adjustment, sem); 122 rwsem_atomic_add(adjustment, sem);
126 123
127 next = sem->wait_list.next; 124 next = sem->wait_list.next;
128 for (loop = woken; loop > 0; loop--) { 125 loop = woken;
126 do {
129 waiter = list_entry(next, struct rwsem_waiter, list); 127 waiter = list_entry(next, struct rwsem_waiter, list);
130 next = waiter->list.next; 128 next = waiter->list.next;
131 tsk = waiter->task; 129 tsk = waiter->task;
@@ -133,7 +131,7 @@ __rwsem_do_wake(struct rw_semaphore *sem, int wake_type)
133 waiter->task = NULL; 131 waiter->task = NULL;
134 wake_up_process(tsk); 132 wake_up_process(tsk);
135 put_task_struct(tsk); 133 put_task_struct(tsk);
136 } 134 } while (--loop);
137 135
138 sem->wait_list.next = next; 136 sem->wait_list.next = next;
139 next->prev = &sem->wait_list; 137 next->prev = &sem->wait_list;