Commit 76621ec6 authored by Andrew Morton's avatar Andrew Morton Committed by Ben Collins

[PATCH] remove 16-bit pid assumption from ipc/sem.c

From: Manfred Spraul <manfred@colorfullife.com>

SysV sem operations that involve multiple semaphores can fail in the
middle, and then sempid (pid of the last successful operation) must be
restored.  This happens with "sempid >>= 16" - broken due to the 32-bit pid
values.  The attached patch fixes that by reordering the updates of the
semaphore fields.

Additionally, the patch fixes the corruption of the sempid value that occurs
if a wait-for-zero operation fails.

The patch is more than two years old, and was in -dj and -ak kernels.
parent 9243548a
...@@ -268,38 +268,38 @@ static int try_atomic_semop (struct sem_array * sma, struct sembuf * sops, ...@@ -268,38 +268,38 @@ static int try_atomic_semop (struct sem_array * sma, struct sembuf * sops,
for (sop = sops; sop < sops + nsops; sop++) { for (sop = sops; sop < sops + nsops; sop++) {
curr = sma->sem_base + sop->sem_num; curr = sma->sem_base + sop->sem_num;
sem_op = sop->sem_op; sem_op = sop->sem_op;
result = curr->semval;
if (!sem_op && curr->semval) if (!sem_op && result)
goto would_block; goto would_block;
curr->sempid = (curr->sempid << 16) | pid; result += sem_op;
curr->semval += sem_op; if (result < 0)
if (sop->sem_flg & SEM_UNDO) goto would_block;
{ if (result > SEMVMX)
goto out_of_range;
if (sop->sem_flg & SEM_UNDO) {
int undo = un->semadj[sop->sem_num] - sem_op; int undo = un->semadj[sop->sem_num] - sem_op;
/* /*
* Exceeding the undo range is an error. * Exceeding the undo range is an error.
*/ */
if (undo < (-SEMAEM - 1) || undo > SEMAEM) if (undo < (-SEMAEM - 1) || undo > SEMAEM)
{
/* Don't undo the undo */
sop->sem_flg &= ~SEM_UNDO;
goto out_of_range; goto out_of_range;
} }
un->semadj[sop->sem_num] = undo; curr->semval = result;
}
if (curr->semval < 0)
goto would_block;
if (curr->semval > SEMVMX)
goto out_of_range;
} }
if (do_undo) if (do_undo) {
{
sop--;
result = 0; result = 0;
goto undo; goto undo;
} }
sop--;
while (sop >= sops) {
sma->sem_base[sop->sem_num].sempid = pid;
if (sop->sem_flg & SEM_UNDO)
un->semadj[sop->sem_num] -= sop->sem_op;
sop--;
}
sma->sem_otime = get_seconds(); sma->sem_otime = get_seconds();
return 0; return 0;
...@@ -315,13 +315,9 @@ static int try_atomic_semop (struct sem_array * sma, struct sembuf * sops, ...@@ -315,13 +315,9 @@ static int try_atomic_semop (struct sem_array * sma, struct sembuf * sops,
result = 1; result = 1;
undo: undo:
sop--;
while (sop >= sops) { while (sop >= sops) {
curr = sma->sem_base + sop->sem_num; sma->sem_base[sop->sem_num].semval -= sop->sem_op;
curr->semval -= sop->sem_op;
curr->sempid >>= 16;
if (sop->sem_flg & SEM_UNDO)
un->semadj[sop->sem_num] += sop->sem_op;
sop--; sop--;
} }
...@@ -659,7 +655,7 @@ static int semctl_main(int semid, int semnum, int cmd, int version, union semun ...@@ -659,7 +655,7 @@ static int semctl_main(int semid, int semnum, int cmd, int version, union semun
err = curr->semval; err = curr->semval;
goto out_unlock; goto out_unlock;
case GETPID: case GETPID:
err = curr->sempid & 0xffff; err = curr->sempid;
goto out_unlock; goto out_unlock;
case GETNCNT: case GETNCNT:
err = count_semncnt(sma,semnum); err = count_semncnt(sma,semnum);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment