aboutsummaryrefslogtreecommitdiffstats
path: root/lib/rwsem.c
diff options
context:
space:
mode:
authorMichel Lespinasse <walken@google.com>2013-05-07 09:45:53 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-05-07 10:20:16 -0400
commit023fe4f712028d25b42d31984abae1f3d3f0e3e2 (patch)
tree59d1f890bfd4047c36808f7f7313bb2e0f39503c /lib/rwsem.c
parentda16922cc031b9c0221c836994276ab193b31de8 (diff)
rwsem: simplify rwsem_down_write_failed
When waking writers, we never grant them the lock - instead, they have to acquire it themselves when they run, and remove themselves from the wait_list when they succeed. As a result, we can do a few simplifications in rwsem_down_write_failed(): - We don't need to check for !waiter.task since __rwsem_do_wake() doesn't remove writers from the wait_list - There is no point releaseing the wait_lock before entering the wait loop, as we will need to reacquire it immediately. We can change the loop so that the lock is always held at the start of each loop iteration. - We don't need to get a reference on the task structure, since the task is responsible for removing itself from the wait_list. There is no risk, like in the rwsem_down_read_failed() case, that a task would wake up and exit (thus destroying its task structure) while __rwsem_do_wake() is still running - wait_lock protects against that. Signed-off-by: Michel Lespinasse <walken@google.com> Reviewed-by: Rik van Riel <riel@redhat.com> Reviewed-by: Peter Hurley <peter@hurleysoftware.com> Acked-by: Davidlohr Bueso <davidlohr.bueso@hp.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib/rwsem.c')
-rw-r--r--lib/rwsem.c33
1 files changed, 9 insertions, 24 deletions
diff --git a/lib/rwsem.c b/lib/rwsem.c
index 66f307e90761..c73bd96dc30c 100644
--- a/lib/rwsem.c
+++ b/lib/rwsem.c
@@ -161,16 +161,8 @@ static int try_get_writer_sem(struct rw_semaphore *sem,
161 161
162try_again_write: 162try_again_write:
163 oldcount = rwsem_atomic_update(adjustment, sem) - adjustment; 163 oldcount = rwsem_atomic_update(adjustment, sem) - adjustment;
164 if (!(oldcount & RWSEM_ACTIVE_MASK)) { 164 if (!(oldcount & RWSEM_ACTIVE_MASK))
165 /* No active lock: */
166 struct task_struct *tsk = waiter->task;
167
168 list_del(&waiter->list);
169 smp_mb();
170 put_task_struct(tsk);
171 tsk->state = TASK_RUNNING;
172 return 1; 165 return 1;
173 }
174 /* some one grabbed the sem already */ 166 /* some one grabbed the sem already */
175 if (rwsem_atomic_update(-adjustment, sem) & RWSEM_ACTIVE_MASK) 167 if (rwsem_atomic_update(-adjustment, sem) & RWSEM_ACTIVE_MASK)
176 return 0; 168 return 0;
@@ -220,11 +212,10 @@ struct rw_semaphore __sched *rwsem_down_read_failed(struct rw_semaphore *sem)
220} 212}
221 213
222/* 214/*
223 * wait for the write lock to be granted 215 * wait until we successfully acquire the write lock
224 */ 216 */
225struct rw_semaphore __sched *rwsem_down_write_failed(struct rw_semaphore *sem) 217struct rw_semaphore __sched *rwsem_down_write_failed(struct rw_semaphore *sem)
226{ 218{
227 enum rwsem_waiter_type type = RWSEM_WAITING_FOR_WRITE;
228 signed long adjustment = -RWSEM_ACTIVE_WRITE_BIAS; 219 signed long adjustment = -RWSEM_ACTIVE_WRITE_BIAS;
229 struct rwsem_waiter waiter; 220 struct rwsem_waiter waiter;
230 struct task_struct *tsk = current; 221 struct task_struct *tsk = current;
@@ -232,8 +223,7 @@ struct rw_semaphore __sched *rwsem_down_write_failed(struct rw_semaphore *sem)
232 223
233 /* set up my own style of waitqueue */ 224 /* set up my own style of waitqueue */
234 waiter.task = tsk; 225 waiter.task = tsk;
235 waiter.type = type; 226 waiter.type = RWSEM_WAITING_FOR_WRITE;
236 get_task_struct(tsk);
237 227
238 raw_spin_lock_irq(&sem->wait_lock); 228 raw_spin_lock_irq(&sem->wait_lock);
239 if (list_empty(&sem->wait_list)) 229 if (list_empty(&sem->wait_list))
@@ -255,25 +245,20 @@ struct rw_semaphore __sched *rwsem_down_write_failed(struct rw_semaphore *sem)
255 adjustment == -RWSEM_ACTIVE_WRITE_BIAS) 245 adjustment == -RWSEM_ACTIVE_WRITE_BIAS)
256 sem = __rwsem_do_wake(sem, RWSEM_WAKE_READ_OWNED); 246 sem = __rwsem_do_wake(sem, RWSEM_WAKE_READ_OWNED);
257 247
258 raw_spin_unlock_irq(&sem->wait_lock); 248 /* wait until we successfully acquire the lock */
259
260 /* wait to be given the lock */
261 while (true) { 249 while (true) {
262 set_task_state(tsk, TASK_UNINTERRUPTIBLE); 250 set_task_state(tsk, TASK_UNINTERRUPTIBLE);
263 if (!waiter.task) 251
252 if (try_get_writer_sem(sem, &waiter))
264 break; 253 break;
265 254
266 raw_spin_lock_irq(&sem->wait_lock);
267 /* Try to get the writer sem, may steal from the head writer: */
268 if (type == RWSEM_WAITING_FOR_WRITE)
269 if (try_get_writer_sem(sem, &waiter)) {
270 raw_spin_unlock_irq(&sem->wait_lock);
271 return sem;
272 }
273 raw_spin_unlock_irq(&sem->wait_lock); 255 raw_spin_unlock_irq(&sem->wait_lock);
274 schedule(); 256 schedule();
257 raw_spin_lock_irq(&sem->wait_lock);
275 } 258 }
276 259
260 list_del(&waiter.list);
261 raw_spin_unlock_irq(&sem->wait_lock);
277 tsk->state = TASK_RUNNING; 262 tsk->state = TASK_RUNNING;
278 263
279 return sem; 264 return sem;