vserver 1.9.5.x5
[linux-2.6.git] / ipc / sem.c
index b1bd0af..416d06a 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -71,8 +71,7 @@
 #include <linux/time.h>
 #include <linux/smp_lock.h>
 #include <linux/security.h>
-#include <linux/vs_base.h>
-
+#include <linux/syscalls.h>
 #include <asm/uaccess.h>
 #include "util.h"
 
@@ -177,7 +176,7 @@ static int newary (key_t key, int nsems, int semflg)
 
        sma->sem_perm.mode = (semflg & S_IRWXUGO);
        sma->sem_perm.key = key;
-       sma->sem_perm.xid = current->xid;
+       sma->sem_perm.xid = vx_current_xid();
 
        sma->sem_perm.security = NULL;
        retval = security_sem_alloc(sma);
@@ -360,8 +359,22 @@ static void update_queue (struct sem_array * sma)
                if (error <= 0) {
                        struct sem_queue *n;
                        remove_from_queue(sma,q);
-                       n = q->next;
                        q->status = IN_WAKEUP;
+                       /*
+                        * Continue scanning. The next operation
+                        * that must be checked depends on the type of the
+                        * completed operation:
+                        * - if the operation modified the array, then
+                        *   restart from the head of the queue and
+                        *   check for threads that might be waiting
+                        *   for semaphore values to become 0.
+                        * - if the operation didn't modify the array,
+                        *   then just continue.
+                        */
+                       if (q->alter)
+                               n = sma->sem_pending;
+                       else
+                               n = q->next;
                        wake_up_process(q->sleeper);
                        /* hands-off: q will disappear immediately after
                         * writing q->status.
@@ -526,7 +539,7 @@ static int semctl_nolock(int semid, int semnum, int cmd, int version, union semu
                struct semid64_ds tbuf;
                int id;
 
-               if(semid >= sem_ids.size)
+               if(semid >= sem_ids.entries->size)
                        return -EINVAL;
 
                memset(&tbuf,0,sizeof(tbuf));
@@ -1121,8 +1134,11 @@ retry_undos:
                goto out_unlock_free;
 
        error = try_atomic_semop (sma, sops, nsops, un, current->tgid);
-       if (error <= 0)
-               goto update;
+       if (error <= 0) {
+               if (alter && error == 0)
+                       update_queue (sma);
+               goto out_unlock_free;
+       }
 
        /* We need to sleep on this operation, so we put the current
         * task into the pending queue and go to sleep.
@@ -1134,6 +1150,7 @@ retry_undos:
        queue.undo = un;
        queue.pid = current->tgid;
        queue.id = semid;
+       queue.alter = alter;
        if (alter)
                append_to_queue(sma ,&queue);
        else
@@ -1185,9 +1202,6 @@ retry_undos:
        remove_from_queue(sma,&queue);
        goto out_unlock_free;
 
-update:
-       if (alter)
-               update_queue (sma);
 out_unlock_free:
        sem_unlock(sma);
 out_free: