diff --git a/ipc/msg.c b/ipc/msg.c
index ccf5f495db7b851cb4ae92d40acad93919b25a49..fdf3db5731ce8df2cfd038f40c69710243d85338 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -203,10 +203,10 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params)
 	 * ipc_addid() locks msq
 	 */
 	id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
-	if (id == -1) {
+	if (id < 0) {
 		security_msg_queue_free(msq);
 		ipc_rcu_putref(msq);
-		return -ENOSPC;
+		return id;
 	}
 
 	msq->q_perm.id = msg_buildid(id, msq->q_perm.seq);
diff --git a/ipc/sem.c b/ipc/sem.c
index 7617f4f34edc4f914541c4b3d6fa2ce5f2c66e7e..35952c0bae4629cac017c4c62623c91a022ebee5 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -283,10 +283,10 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
 	}
 
 	id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
-	if(id == -1) {
+	if (id < 0) {
 		security_sem_free(sma);
 		ipc_rcu_putref(sma);
-		return -ENOSPC;
+		return id;
 	}
 	ns->used_sems += nsems;
 
diff --git a/ipc/shm.c b/ipc/shm.c
index 05c97c7513c2671b06523dd986b2cc4774dd8345..3818fae625c5252363380fa9c7a521e8b5c1a7d1 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -433,10 +433,11 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
 	if (IS_ERR(file))
 		goto no_file;
 
-	error = -ENOSPC;
 	id = shm_addid(ns, shp);
-	if(id == -1) 
+	if (id < 0) {
+		error = id;
 		goto no_id;
+	}
 
 	shp->shm_cprid = task_tgid_vnr(current);
 	shp->shm_lprid = 0;
diff --git a/ipc/util.c b/ipc/util.c
index b42fbd58973a02f2d59a29204a23c5323bcd960c..1aa0ebf71bac7e5c30559eb0f60a89bdc6688efb 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -262,7 +262,7 @@ int ipc_get_maxid(struct ipc_ids *ids)
  *	Add an entry 'new' to the IPC ids idr. The permissions object is
  *	initialised and the first free entry is set up and the id assigned
  *	is returned. The 'new' entry is returned in a locked state on success.
- *	On failure the entry is not locked and -1 is returned.
+ *	On failure the entry is not locked and a negative err-code is returned.
  *
  *	Called with ipc_ids.rw_mutex held as a writer.
  */
@@ -275,11 +275,11 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
 		size = IPCMNI;
 
 	if (ids->in_use >= size)
-		return -1;
+		return -ENOSPC;
 
 	err = idr_get_new(&ids->ipcs_idr, new, &id);
 	if (err)
-		return -1;
+		return err;
 
 	ids->in_use++;
 
@@ -311,7 +311,7 @@ int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids,
 		struct ipc_ops *ops, struct ipc_params *params)
 {
 	int err;
-
+retry:
 	err = idr_pre_get(&ids->ipcs_idr, GFP_KERNEL);
 
 	if (!err)
@@ -321,6 +321,9 @@ int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids,
 	err = ops->getnew(ns, params);
 	up_write(&ids->rw_mutex);
 
+	if (err == -EAGAIN)
+		goto retry;
+
 	return err;
 }
 
@@ -374,7 +377,7 @@ int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids,
 	struct kern_ipc_perm *ipcp;
 	int flg = params->flg;
 	int err;
-
+retry:
 	err = idr_pre_get(&ids->ipcs_idr, GFP_KERNEL);
 
 	/*
@@ -411,6 +414,9 @@ int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids,
 	}
 	up_write(&ids->rw_mutex);
 
+	if (err == -EAGAIN)
+		goto retry;
+
 	return err;
 }