From 5a556848b3104073f0d4fe7691c16fe9c123f9bd Mon Sep 17 00:00:00 2001 From: Manfred Spraul Date: Tue, 20 Jul 2010 13:24:23 -0700 Subject: [PATCH] --- yaml --- r: 201062 b: refs/heads/master c: c61284e99191b2284fb74dae6961d4d09e4e59e8 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/ipc/sem.c | 46 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/[refs] b/[refs] index c47a3904f285..f919fd9d2af4 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 19f0f0af097ba3138ae2780b471180512763a78f +refs/heads/master: c61284e99191b2284fb74dae6961d4d09e4e59e8 diff --git a/trunk/ipc/sem.c b/trunk/ipc/sem.c index 506c8491a8d1..40a8f462a822 100644 --- a/trunk/ipc/sem.c +++ b/trunk/ipc/sem.c @@ -1256,6 +1256,33 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid) return un; } + +/** + * get_queue_result - Retrieve the result code from sem_queue + * @q: Pointer to queue structure + * + * Retrieve the return code from the pending queue. If IN_WAKEUP is found in + * q->status, then we must loop until the value is replaced with the final + * value: This may happen if a task is woken up by an unrelated event (e.g. + * signal) and in parallel the task is woken up by another task because it got + * the requested semaphores. + * + * The function can be called with or without holding the semaphore spinlock. + */ +static int get_queue_result(struct sem_queue *q) +{ + int error; + + error = q->status; + while (unlikely(error == IN_WAKEUP)) { + cpu_relax(); + error = q->status; + } + + return error; +} + + SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, unsigned, nsops, const struct timespec __user *, timeout) { @@ -1409,15 +1436,18 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, else schedule(); - error = queue.status; - while(unlikely(error == IN_WAKEUP)) { - cpu_relax(); - error = queue.status; - } + error = get_queue_result(&queue); if (error != -EINTR) { /* fast path: update_queue already obtained all requested - * resources */ + * resources. + * Perform a smp_mb(): User space could assume that semop() + * is a memory barrier: Without the mb(), the cpu could + * speculatively read in user space stale data that was + * overwritten by the previous owner of the semaphore. + */ + smp_mb(); + goto out_free; } @@ -1427,10 +1457,12 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, goto out_free; } + error = get_queue_result(&queue); + /* * If queue.status != -EINTR we are woken up by another process */ - error = queue.status; + if (error != -EINTR) { goto out_unlock_free; }