diff options
author | Jiri Kosina <jkosina@suse.cz> | 2010-08-04 15:14:38 +0200 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2010-08-04 15:14:38 +0200 |
commit | d790d4d583aeaed9fc6f8a9f4d9f8ce6b1c15c7f (patch) | |
tree | 854ab394486288d40fa8179cbfaf66e8bdc44b0f /ipc/sem.c | |
parent | 73b2c7165b76b20eb1290e7efebc33cfd21db1ca (diff) | |
parent | 3a09b1be53d23df780a0cd0e4087a05e2ca4a00c (diff) |
Merge branch 'master' into for-next
Diffstat (limited to 'ipc/sem.c')
-rw-r--r-- | ipc/sem.c | 46 |
1 files changed, 39 insertions, 7 deletions
diff --git a/ipc/sem.c b/ipc/sem.c index 506c8491a8d..40a8f462a82 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -1256,6 +1256,33 @@ out: 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; } |