aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ipc/sem.c51
1 files changed, 40 insertions, 11 deletions
diff --git a/ipc/sem.c b/ipc/sem.c
index 4252a8eb77e2..7eb6f049dd7c 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -434,17 +434,45 @@ static void unlink_queue(struct sem_array *sma, struct sem_queue *q)
434 sma->complex_count--; 434 sma->complex_count--;
435} 435}
436 436
437/* Go through the pending queue for the indicated semaphore 437
438 * looking for tasks that can be completed. 438/**
439 * update_queue(sma, semnum): Look for tasks that can be completed.
440 * @sma: semaphore array.
441 * @semnum: semaphore that was modified.
442 *
443 * update_queue must be called after a semaphore in a semaphore array
444 * was modified. If multiple semaphore were modified, then @semnum
445 * must be set to -1.
439 */ 446 */
440static void update_queue (struct sem_array * sma) 447static void update_queue(struct sem_array *sma, int semnum)
441{ 448{
442 struct sem_queue *q, *tq; 449 struct sem_queue *q;
450 struct list_head *walk;
451 struct list_head *pending_list;
452 int offset;
453
454 /* if there are complex operations around, then knowing the semaphore
455 * that was modified doesn't help us. Assume that multiple semaphores
456 * were modified.
457 */
458 if (sma->complex_count)
459 semnum = -1;
460
461 if (semnum == -1) {
462 pending_list = &sma->sem_pending;
463 offset = offsetof(struct sem_queue, list);
464 } else {
465 pending_list = &sma->sem_base[semnum].sem_pending;
466 offset = offsetof(struct sem_queue, simple_list);
467 }
443 468
444again: 469again:
445 list_for_each_entry_safe(q, tq, &sma->sem_pending, list) { 470 walk = pending_list->next;
446 int error; 471 while (walk != pending_list) {
447 int alter; 472 int error, alter;
473
474 q = (struct sem_queue *)((char *)walk - offset);
475 walk = walk->next;
448 476
449 error = try_atomic_semop(sma, q->sops, q->nsops, 477 error = try_atomic_semop(sma, q->sops, q->nsops,
450 q->undo, q->pid); 478 q->undo, q->pid);
@@ -769,7 +797,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
769 } 797 }
770 sma->sem_ctime = get_seconds(); 798 sma->sem_ctime = get_seconds();
771 /* maybe some queued-up processes were waiting for this */ 799 /* maybe some queued-up processes were waiting for this */
772 update_queue(sma); 800 update_queue(sma, -1);
773 err = 0; 801 err = 0;
774 goto out_unlock; 802 goto out_unlock;
775 } 803 }
@@ -811,7 +839,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
811 curr->sempid = task_tgid_vnr(current); 839 curr->sempid = task_tgid_vnr(current);
812 sma->sem_ctime = get_seconds(); 840 sma->sem_ctime = get_seconds();
813 /* maybe some queued-up processes were waiting for this */ 841 /* maybe some queued-up processes were waiting for this */
814 update_queue(sma); 842 update_queue(sma, semnum);
815 err = 0; 843 err = 0;
816 goto out_unlock; 844 goto out_unlock;
817 } 845 }
@@ -1187,7 +1215,8 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
1187 error = try_atomic_semop (sma, sops, nsops, un, task_tgid_vnr(current)); 1215 error = try_atomic_semop (sma, sops, nsops, un, task_tgid_vnr(current));
1188 if (error <= 0) { 1216 if (error <= 0) {
1189 if (alter && error == 0) 1217 if (alter && error == 0)
1190 update_queue (sma); 1218 update_queue(sma, (nsops == 1) ? sops[0].sem_num : -1);
1219
1191 goto out_unlock_free; 1220 goto out_unlock_free;
1192 } 1221 }
1193 1222
@@ -1388,7 +1417,7 @@ void exit_sem(struct task_struct *tsk)
1388 } 1417 }
1389 sma->sem_otime = get_seconds(); 1418 sma->sem_otime = get_seconds();
1390 /* maybe some queued-up processes were waiting for this */ 1419 /* maybe some queued-up processes were waiting for this */
1391 update_queue(sma); 1420 update_queue(sma, -1);
1392 sem_unlock(sma); 1421 sem_unlock(sma);
1393 1422
1394 call_rcu(&un->rcu, free_un); 1423 call_rcu(&un->rcu, free_un);