]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - ipc/sem.c
firmware: fix batched requests - send wake up on failure on direct lookups
[karo-tx-linux.git] / ipc / sem.c
index 484ccf83cf856469e0f0bfb610a3d0564b0e4e6e..9e70cd7a17da7e74e915ce7f4061aa99aea66b89 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -264,7 +264,7 @@ static void sem_rcu_free(struct rcu_head *head)
        struct sem_array *sma = container_of(p, struct sem_array, sem_perm);
 
        security_sem_free(sma);
-       ipc_rcu_free(head);
+       kvfree(sma);
 }
 
 /*
@@ -446,6 +446,24 @@ static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
        ipc_rmid(&sem_ids(ns), &s->sem_perm);
 }
 
+static struct sem_array *sem_alloc(size_t nsems)
+{
+       struct sem_array *sma;
+       size_t size;
+
+       if (nsems > (INT_MAX - sizeof(*sma)) / sizeof(sma->sems[0]))
+               return NULL;
+
+       size = sizeof(*sma) + nsems * sizeof(sma->sems[0]);
+       sma = kvmalloc(size, GFP_KERNEL);
+       if (unlikely(!sma))
+               return NULL;
+
+       memset(sma, 0, size);
+
+       return sma;
+}
+
 /**
  * newary - Create a new semaphore set
  * @ns: namespace
@@ -455,10 +473,8 @@ static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
  */
 static int newary(struct ipc_namespace *ns, struct ipc_params *params)
 {
-       int id;
        int retval;
        struct sem_array *sma;
-       int size;
        key_t key = params->key;
        int nsems = params->u.nsems;
        int semflg = params->flg;
@@ -469,10 +485,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
        if (ns->used_sems + nsems > ns->sc_semmns)
                return -ENOSPC;
 
-       BUILD_BUG_ON(offsetof(struct sem_array, sem_perm) != 0);
-
-       size = sizeof(*sma) + nsems * sizeof(sma->sems[0]);
-       sma = container_of(ipc_rcu_alloc(size), struct sem_array, sem_perm);
+       sma = sem_alloc(nsems);
        if (!sma)
                return -ENOMEM;
 
@@ -482,7 +495,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
        sma->sem_perm.security = NULL;
        retval = security_sem_alloc(sma);
        if (retval) {
-               ipc_rcu_putref(&sma->sem_perm, ipc_rcu_free);
+               kvfree(sma);
                return retval;
        }
 
@@ -500,10 +513,10 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
        sma->sem_nsems = nsems;
        sma->sem_ctime = get_seconds();
 
-       id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
-       if (id < 0) {
-               ipc_rcu_putref(&sma->sem_perm, sem_rcu_free);
-               return id;
+       retval = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
+       if (retval < 0) {
+               call_rcu(&sma->sem_perm.rcu, sem_rcu_free);
+               return retval;
        }
        ns->used_sems += nsems;