ipc: unify the syscalls code

This patch introduces a change into the sys_msgget(), sys_semget() and
sys_shmget() routines: they now share a common code, which is better for
maintainability.

Signed-off-by: Nadia Derbey <Nadia.Derbey@bull.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
diff --git a/ipc/shm.c b/ipc/shm.c
index dcc3332..d20cc25 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -68,8 +68,7 @@
 #define shm_buildid(ns, id, seq)	\
 	ipc_buildid(&shm_ids(ns), id, seq)
 
-static int newseg (struct ipc_namespace *ns, key_t key,
-		int shmflg, size_t size);
+static int newseg(struct ipc_namespace *, struct ipc_params *);
 static void shm_open(struct vm_area_struct *vma);
 static void shm_close(struct vm_area_struct *vma);
 static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp);
@@ -341,8 +340,11 @@
 #endif
 };
 
-static int newseg (struct ipc_namespace *ns, key_t key, int shmflg, size_t size)
+static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
 {
+	key_t key = params->key;
+	int shmflg = params->flg;
+	size_t size = params->u.size;
 	int error;
 	struct shmid_kernel *shp;
 	int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT;
@@ -423,57 +425,36 @@
 	return error;
 }
 
+static inline int shm_security(void *shp, int shmflg)
+{
+	return security_shm_associate((struct shmid_kernel *) shp, shmflg);
+}
+
+static inline int shm_more_checks(void *shp, struct ipc_params *params)
+{
+	if (((struct shmid_kernel *)shp)->shm_segsz < params->u.size)
+		return -EINVAL;
+
+	return 0;
+}
+
 asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
 {
-	struct shmid_kernel *shp;
-	int err;
 	struct ipc_namespace *ns;
+	struct ipc_ops shm_ops;
+	struct ipc_params shm_params;
 
 	ns = current->nsproxy->ipc_ns;
 
-	err = idr_pre_get(&shm_ids(ns).ipcs_idr, GFP_KERNEL);
+	shm_ops.getnew = newseg;
+	shm_ops.associate = shm_security;
+	shm_ops.more_checks = shm_more_checks;
 
-	if (key == IPC_PRIVATE) {
-		if (!err)
-			err = -ENOMEM;
-		else {
-			mutex_lock(&shm_ids(ns).mutex);
-			err = newseg(ns, key, shmflg, size);
-			mutex_unlock(&shm_ids(ns).mutex);
-		}
-	} else {
-		mutex_lock(&shm_ids(ns).mutex);
-		shp = (struct shmid_kernel *) ipc_findkey(&shm_ids(ns), key);
-		if (shp == NULL) {
-			if (!(shmflg & IPC_CREAT))
-				err = -ENOENT;
-			else if (!err)
-				err = -ENOMEM;
-			else
-				err = newseg(ns, key, shmflg, size);
-		} else {
-			/* shp has been locked by ipc_findkey() */
+	shm_params.key = key;
+	shm_params.flg = shmflg;
+	shm_params.u.size = size;
 
-			if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL))
-				err = -EEXIST;
-			else {
-				if (shp->shm_segsz < size)
-					err = -EINVAL;
-				else if (ipcperms(&shp->shm_perm, shmflg))
-					err = -EACCES;
-				else {
-					err = security_shm_associate(shp,
-								shmflg);
-					if (!err)
-						err = shp->shm_perm.id;
-				}
-			}
-			shm_unlock(shp);
-		}
-		mutex_unlock(&shm_ids(ns).mutex);
-	}
-
-	return err;
+	return ipcget(ns, &shm_ids(ns), &shm_ops, &shm_params);
 }
 
 static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ds *in, int version)