Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

Advertisement
[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Advertisement

Kernel v2.6.26 /ipc/sem.c

Filename:/ipc/sem.c
Lines Added:56
Lines Deleted:103
Also changed in: (Previous) 2.6.26-rc9  2.6.26-rc8  2.6.26-rc7  2.6.26-rc6  2.6.26-rc5  2.6.26-rc4 
(Following) 2.6.26-git13  2.6.26-git14  2.6.26-git15  2.6.26-git16  2.6.26-git17  2.6.26-git18 

Location
[  2.6.26
  [  ipc
     o  sem.c

Patch

diff --git a/ipc/sem.c b/ipc/sem.c
index 0b45a4d..e9418df 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -91,7 +91,6 @@
 
 #define sem_unlock(sma)      ipc_unlock(&(sma)->sem_perm)
 #define sem_checkid(sma, semid)   ipc_checkid(&sma->sem_perm, semid)
-#define sem_buildid(id, seq)   ipc_buildid(id, seq)
 
 static int newary(struct ipc_namespace *, struct ipc_params *);
 static void freeary(struct ipc_namespace *, struct kern_ipc_perm *);
@@ -142,21 +141,6 @@ void __init sem_init (void)
 }
 
 /*
- * This routine is called in the paths where the rw_mutex is held to protect
- * access to the idr tree.
- */
-static inline struct sem_array *sem_lock_check_down(struct ipc_namespace *ns,
-                  int id)
-{
-   struct kern_ipc_perm *ipcp = ipc_lock_check_down(&sem_ids(ns), id);
-
-   if (IS_ERR(ipcp))
-      return (struct sem_array *)ipcp;
-
-   return container_of(ipcp, struct sem_array, sem_perm);
-}
-
-/*
  * sem_lock_(check_) routines are called in the paths where the rw_mutex
  * is not held.
  */
@@ -181,6 +165,25 @@ static inline struct sem_array *sem_lock_check(struct ipc_namespace *ns,
    return container_of(ipcp, struct sem_array, sem_perm);
 }
 
+static inline void sem_lock_and_putref(struct sem_array *sma)
+{
+   ipc_lock_by_ptr(&sma->sem_perm);
+   ipc_rcu_putref(sma);
+}
+
+static inline void sem_getref_and_unlock(struct sem_array *sma)
+{
+   ipc_rcu_getref(sma);
+   ipc_unlock(&(sma)->sem_perm);
+}
+
+static inline void sem_putref(struct sem_array *sma)
+{
+   ipc_lock_by_ptr(&sma->sem_perm);
+   ipc_rcu_putref(sma);
+   ipc_unlock(&(sma)->sem_perm);
+}
+
 static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
 {
    ipc_rmid(&sem_ids(ns), &s->sem_perm);
@@ -268,7 +271,6 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
    }
    ns->used_sems += nsems;
 
-   sma->sem_perm.id = sem_buildid(id, sma->sem_perm.seq);
    sma->sem_base = (struct sem *) &sma[1];
    /* sma->sem_pending = NULL; */
    sma->sem_pending_last = &sma->sem_pending;
@@ -700,19 +702,15 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
       int i;
 
       if(nsems > SEMMSL_FAST) {
-         ipc_rcu_getref(sma);
-         sem_unlock(sma);         
+         sem_getref_and_unlock(sma);
 
          sem_io = ipc_alloc(sizeof(ushort)*nsems);
          if(sem_io == NULL) {
-            ipc_lock_by_ptr(&sma->sem_perm);
-            ipc_rcu_putref(sma);
-            sem_unlock(sma);
+            sem_putref(sma);
             return -ENOMEM;
          }
 
-         ipc_lock_by_ptr(&sma->sem_perm);
-         ipc_rcu_putref(sma);
+         sem_lock_and_putref(sma);
          if (sma->sem_perm.deleted) {
             sem_unlock(sma);
             err = -EIDRM;
@@ -733,38 +731,30 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
       int i;
       struct sem_undo *un;
 
-      ipc_rcu_getref(sma);
-      sem_unlock(sma);
+      sem_getref_and_unlock(sma);
 
       if(nsems > SEMMSL_FAST) {
          sem_io = ipc_alloc(sizeof(ushort)*nsems);
          if(sem_io == NULL) {
-            ipc_lock_by_ptr(&sma->sem_perm);
-            ipc_rcu_putref(sma);
-            sem_unlock(sma);
+            sem_putref(sma);
             return -ENOMEM;
          }
       }
 
       if (copy_from_user (sem_io, arg.array, nsems*sizeof(ushort))) {
-         ipc_lock_by_ptr(&sma->sem_perm);
-         ipc_rcu_putref(sma);
-         sem_unlock(sma);
+         sem_putref(sma);
          err = -EFAULT;
          goto out_free;
       }
 
       for (i = 0; i < nsems; i++) {
          if (sem_io[i] > SEMVMX) {
-            ipc_lock_by_ptr(&sma->sem_perm);
-            ipc_rcu_putref(sma);
-            sem_unlock(sma);
+            sem_putref(sma);
             err = -ERANGE;
             goto out_free;
          }
       }
-      ipc_lock_by_ptr(&sma->sem_perm);
-      ipc_rcu_putref(sma);
+      sem_lock_and_putref(sma);
       if (sma->sem_perm.deleted) {
          sem_unlock(sma);
          err = -EIDRM;
@@ -830,28 +820,14 @@ out_free:
    return err;
 }
 
-struct sem_setbuf {
-   uid_t   uid;
-   gid_t   gid;
-   mode_t   mode;
-};
-
-static inline unsigned long copy_semid_from_user(struct sem_setbuf *out, void __user *buf, int version)
+static inline unsigned long
+copy_semid_from_user(struct semid64_ds *out, void __user *buf, int version)
 {
    switch(version) {
    case IPC_64:
-       {
-      struct semid64_ds tbuf;
-
-      if(copy_from_user(&tbuf, buf, sizeof(tbuf)))
+      if (copy_from_user(out, buf, sizeof(*out)))
          return -EFAULT;
-
-      out->uid   = tbuf.sem_perm.uid;
-      out->gid   = tbuf.sem_perm.gid;
-      out->mode   = tbuf.sem_perm.mode;
-
       return 0;
-       }
    case IPC_OLD:
        {
       struct semid_ds tbuf_old;
@@ -859,9 +835,9 @@ static inline unsigned long copy_semid_from_user(struct sem_setbuf *out, void __
       if(copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
          return -EFAULT;
 
-      out->uid   = tbuf_old.sem_perm.uid;
-      out->gid   = tbuf_old.sem_perm.gid;
-      out->mode   = tbuf_old.sem_perm.mode;
+      out->sem_perm.uid   = tbuf_old.sem_perm.uid;
+      out->sem_perm.gid   = tbuf_old.sem_perm.gid;
+      out->sem_perm.mode   = tbuf_old.sem_perm.mode;
 
       return 0;
        }
@@ -870,38 +846,29 @@ static inline unsigned long copy_semid_from_user(struct sem_setbuf *out, void __
    }
 }
 
-static int semctl_down(struct ipc_namespace *ns, int semid, int semnum,
-      int cmd, int version, union semun arg)
+/*
+ * This function handles some semctl commands which require the rw_mutex
+ * to be held in write mode.
+ * NOTE: no locks must be held, the rw_mutex is taken inside this function.
+ */
+static int semctl_down(struct ipc_namespace *ns, int semid,
+             int cmd, int version, union semun arg)
 {
    struct sem_array *sma;
    int err;
-   struct sem_setbuf uninitialized_var(setbuf);
+   struct semid64_ds semid64;
    struct kern_ipc_perm *ipcp;
 
    if(cmd == IPC_SET) {
-      if(copy_semid_from_user (&setbuf, arg.buf, version))
+      if (copy_semid_from_user(&semid64, arg.buf, version))
          return -EFAULT;
    }
-   sma = sem_lock_check_down(ns, semid);
-   if (IS_ERR(sma))
-      return PTR_ERR(sma);
 
-   ipcp = &sma->sem_perm;
-
-   err = audit_ipc_obj(ipcp);
-   if (err)
-      goto out_unlock;
+   ipcp = ipcctl_pre_down(&sem_ids(ns), semid, cmd, &semid64.sem_perm, 0);
+   if (IS_ERR(ipcp))
+      return PTR_ERR(ipcp);
 
-   if (cmd == IPC_SET) {
-      err = audit_ipc_set_perm(0, setbuf.uid, setbuf.gid, setbuf.mode);
-      if (err)
-         goto out_unlock;
-   }
-   if (current->euid != ipcp->cuid && 
-       current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) {
-          err=-EPERM;
-      goto out_unlock;
-   }
+   sma = container_of(ipcp, struct sem_array, sem_perm);
 
    err = security_sem_semctl(sma, cmd);
    if (err)
@@ -910,26 +877,19 @@ static int semctl_down(struct ipc_namespace *ns, int semid, int semnum,
    switch(cmd){
    case IPC_RMID:
       freeary(ns, ipcp);
-      err = 0;
-      break;
+      goto out_up;
    case IPC_SET:
-      ipcp->uid = setbuf.uid;
-      ipcp->gid = setbuf.gid;
-      ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
-            | (setbuf.mode & S_IRWXUGO);
+      ipc_update_perm(&semid64.sem_perm, ipcp);
       sma->sem_ctime = get_seconds();
-      sem_unlock(sma);
-      err = 0;
       break;
    default:
-      sem_unlock(sma);
       err = -EINVAL;
-      break;
    }
-   return err;
 
 out_unlock:
    sem_unlock(sma);
+out_up:
+   up_write(&sem_ids(ns).rw_mutex);
    return err;
 }
 
@@ -963,9 +923,7 @@ asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
       return err;
    case IPC_RMID:
    case IPC_SET:
-      down_write(&sem_ids(ns).rw_mutex);
-      err = semctl_down(ns,semid,semnum,cmd,version,arg);
-      up_write(&sem_ids(ns).rw_mutex);
+      err = semctl_down(ns, semid, cmd, version, arg);
       return err;
    default:
       return -EINVAL;
@@ -1044,14 +1002,11 @@ static struct sem_undo *find_undo(struct ipc_namespace *ns, int semid)
       return ERR_PTR(PTR_ERR(sma));
 
    nsems = sma->sem_nsems;
-   ipc_rcu_getref(sma);
-   sem_unlock(sma);
+   sem_getref_and_unlock(sma);
 
    new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL);
    if (!new) {
-      ipc_lock_by_ptr(&sma->sem_perm);
-      ipc_rcu_putref(sma);
-      sem_unlock(sma);
+      sem_putref(sma);
       return ERR_PTR(-ENOMEM);
    }
    new->semadj = (short *) &new[1];
@@ -1062,13 +1017,10 @@ static struct sem_undo *find_undo(struct ipc_namespace *ns, int semid)
    if (un) {
       spin_unlock(&ulp->lock);
       kfree(new);
-      ipc_lock_by_ptr(&sma->sem_perm);
-      ipc_rcu_putref(sma);
-      sem_unlock(sma);
+      sem_putref(sma);
       goto out;
    }
-   ipc_lock_by_ptr(&sma->sem_perm);
-   ipc_rcu_putref(sma);
+   sem_lock_and_putref(sma);
    if (sma->sem_perm.deleted) {
       sem_unlock(sma);
       spin_unlock(&ulp->lock);
@@ -1298,6 +1250,7 @@ void exit_sem(struct task_struct *tsk)
    undo_list = tsk->sysvsem.undo_list;
    if (!undo_list)
       return;
+   tsk->sysvsem.undo_list = NULL;
 
    if (!atomic_dec_and_test(&undo_list->refcnt))
       return;


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.