* [RFC][PATCH 1/6] Storing ipcs into IDRs
2007-08-31 11:24 [RFC][PATCH 0/6] An IPC implementation base on Linux IDRs Nadia.Derbey
@ 2007-08-31 11:24 ` Nadia.Derbey
2007-09-01 22:12 ` Andi Kleen
2007-09-10 20:08 ` Andrew Morton
2007-08-31 11:24 ` [RFC][PATCH 2/6] Unifying the syscalls code Nadia.Derbey
` (4 subsequent siblings)
5 siblings, 2 replies; 12+ messages in thread
From: Nadia.Derbey @ 2007-08-31 11:24 UTC (permalink / raw)
To: linux-kernel; +Cc: matthltc, Nadia Derbey
[-- Attachment #1: ipc_idr.patch --]
[-- Type: text/plain, Size: 36826 bytes --]
[PATCH 01/06]
This patch introduces ipcs storage into IDRs. The main changes are:
. This ipc_ids structure is changed: the entries array is changed into a
root idr structure.
. The grow_ary() routine is removed: it is not needed anymore when adding
an ipc structure, since we are now using the IDR facility.
. The ipc_rmid() routine interface is changed:
. there is no need for this routine to return the pointer passed in as
argument: it is now declared as a void
. since the id is now part of the kern_ipc_perm structure, no need to
have it as an argument to the routine
Signed-off-by: Nadia Derbey <Nadia.Derbey@bull.net>
---
include/linux/ipc.h | 1
include/linux/msg.h | 1
include/linux/sem.h | 1
include/linux/shm.h | 1
ipc/msg.c | 113 +++++++++++++---------
ipc/sem.c | 111 ++++++++++++---------
ipc/shm.c | 116 +++++++++++++---------
ipc/util.c | 264 +++++++++++++++++++++++-----------------------------
ipc/util.h | 32 +-----
9 files changed, 329 insertions(+), 311 deletions(-)
Index: linux-2.6.23-rc2/include/linux/ipc.h
===================================================================
--- linux-2.6.23-rc2.orig/include/linux/ipc.h 2007-08-31 07:49:01.000000000 +0200
+++ linux-2.6.23-rc2/include/linux/ipc.h 2007-08-31 08:05:36.000000000 +0200
@@ -61,6 +61,7 @@ struct kern_ipc_perm
{
spinlock_t lock;
int deleted;
+ int id;
key_t key;
uid_t uid;
gid_t gid;
Index: linux-2.6.23-rc2/include/linux/msg.h
===================================================================
--- linux-2.6.23-rc2.orig/include/linux/msg.h 2007-08-31 07:49:01.000000000 +0200
+++ linux-2.6.23-rc2/include/linux/msg.h 2007-08-31 08:06:24.000000000 +0200
@@ -77,7 +77,6 @@ struct msg_msg {
/* one msq_queue structure for each present queue on the system */
struct msg_queue {
struct kern_ipc_perm q_perm;
- int q_id;
time_t q_stime; /* last msgsnd time */
time_t q_rtime; /* last msgrcv time */
time_t q_ctime; /* last change time */
Index: linux-2.6.23-rc2/include/linux/sem.h
===================================================================
--- linux-2.6.23-rc2.orig/include/linux/sem.h 2007-08-31 07:49:01.000000000 +0200
+++ linux-2.6.23-rc2/include/linux/sem.h 2007-08-31 08:06:45.000000000 +0200
@@ -90,7 +90,6 @@ struct sem {
/* One sem_array data structure for each set of semaphores in the system. */
struct sem_array {
struct kern_ipc_perm sem_perm; /* permissions .. see ipc.h */
- int sem_id;
time_t sem_otime; /* last semop time */
time_t sem_ctime; /* last change time */
struct sem *sem_base; /* ptr to first semaphore in array */
Index: linux-2.6.23-rc2/include/linux/shm.h
===================================================================
--- linux-2.6.23-rc2.orig/include/linux/shm.h 2007-08-31 07:49:01.000000000 +0200
+++ linux-2.6.23-rc2/include/linux/shm.h 2007-08-31 08:07:07.000000000 +0200
@@ -77,7 +77,6 @@ struct shmid_kernel /* private to the ke
{
struct kern_ipc_perm shm_perm;
struct file * shm_file;
- int id;
unsigned long shm_nattch;
unsigned long shm_segsz;
time_t shm_atim;
Index: linux-2.6.23-rc2/ipc/util.h
===================================================================
--- linux-2.6.23-rc2.orig/ipc/util.h 2007-08-31 07:49:21.000000000 +0200
+++ linux-2.6.23-rc2/ipc/util.h 2007-08-31 11:29:21.000000000 +0200
@@ -10,6 +10,8 @@
#ifndef _IPC_UTIL_H
#define _IPC_UTIL_H
+#include <linux/idr.h>
+
#define USHRT_MAX 0xffff
#define SEQ_MULTIPLIER (IPCMNI)
@@ -25,24 +27,17 @@ void sem_exit_ns(struct ipc_namespace *n
void msg_exit_ns(struct ipc_namespace *ns);
void shm_exit_ns(struct ipc_namespace *ns);
-struct ipc_id_ary {
- int size;
- struct kern_ipc_perm *p[0];
-};
-
struct ipc_ids {
int in_use;
- int max_id;
unsigned short seq;
unsigned short seq_max;
struct mutex mutex;
- struct ipc_id_ary nullentry;
- struct ipc_id_ary* entries;
+ struct idr ipcs_idr;
};
struct seq_file;
-void ipc_init_ids(struct ipc_ids *ids, int size);
+void ipc_init_ids(struct ipc_ids *);
#ifdef CONFIG_PROC_FS
void __init ipc_init_proc_interface(const char *path, const char *header,
int ids, int (*show)(struct seq_file *, void *));
@@ -55,11 +50,12 @@ void __init ipc_init_proc_interface(cons
#define IPC_SHM_IDS 2
/* must be called with ids->mutex acquired.*/
-int ipc_findkey(struct ipc_ids* ids, key_t key);
-int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size);
+struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key);
+int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int);
+int ipc_get_maxid(struct ipc_ids *);
/* must be called with both locks acquired. */
-struct kern_ipc_perm* ipc_rmid(struct ipc_ids* ids, int id);
+void ipc_rmid(struct ipc_ids *, struct kern_ipc_perm *);
int ipcperms (struct kern_ipc_perm *ipcp, short flg);
@@ -79,18 +75,6 @@ void* ipc_rcu_alloc(int size);
void ipc_rcu_getref(void *ptr);
void ipc_rcu_putref(void *ptr);
-static inline void __ipc_fini_ids(struct ipc_ids *ids,
- struct ipc_id_ary *entries)
-{
- if (entries != &ids->nullentry)
- ipc_rcu_putref(entries);
-}
-
-static inline void ipc_fini_ids(struct ipc_ids *ids)
-{
- __ipc_fini_ids(ids, ids->entries);
-}
-
struct kern_ipc_perm* ipc_get(struct ipc_ids* ids, int id);
struct kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id);
void ipc_lock_by_ptr(struct kern_ipc_perm *ipcp);
Index: linux-2.6.23-rc2/ipc/util.c
===================================================================
--- linux-2.6.23-rc2.orig/ipc/util.c 2007-08-31 07:49:21.000000000 +0200
+++ linux-2.6.23-rc2/ipc/util.c 2007-08-31 11:34:17.000000000 +0200
@@ -129,23 +129,16 @@ __initcall(ipc_init);
/**
* ipc_init_ids - initialise IPC identifiers
* @ids: Identifier set
- * @size: Number of identifiers
*
- * Given a size for the ipc identifier range (limited below IPCMNI)
- * set up the sequence range to use then allocate and initialise the
- * array itself.
+ * Set up the sequence range to use for the ipc identifier range (limited
+ * below IPCMNI) then initialise the ids idr.
*/
-void ipc_init_ids(struct ipc_ids* ids, int size)
+void ipc_init_ids(struct ipc_ids *ids)
{
- int i;
-
mutex_init(&ids->mutex);
- if(size > IPCMNI)
- size = IPCMNI;
ids->in_use = 0;
- ids->max_id = -1;
ids->seq = 0;
{
int seq_limit = INT_MAX/SEQ_MULTIPLIER;
@@ -155,17 +148,7 @@ void ipc_init_ids(struct ipc_ids* ids, i
ids->seq_max = seq_limit;
}
- ids->entries = ipc_rcu_alloc(sizeof(struct kern_ipc_perm *)*size +
- sizeof(struct ipc_id_ary));
-
- if(ids->entries == NULL) {
- printk(KERN_ERR "ipc_init_ids() failed, ipc service disabled.\n");
- size = 0;
- ids->entries = &ids->nullentry;
- }
- ids->entries->size = size;
- for(i=0;i<size;i++)
- ids->entries->p[i] = NULL;
+ idr_init(&ids->ipcs_idr);
}
#ifdef CONFIG_PROC_FS
@@ -209,72 +192,73 @@ void __init ipc_init_proc_interface(cons
* @key: The key to find
*
* Requires ipc_ids.mutex locked.
- * Returns the identifier if found or -1 if not.
+ * Returns the LOCKED pointer to the ipc structure if found or NULL
+ * if not.
+ * If key is found ipc contains its ipc structure
*/
-int ipc_findkey(struct ipc_ids* ids, key_t key)
+struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
{
- int id;
- struct kern_ipc_perm* p;
- int max_id = ids->max_id;
+ struct kern_ipc_perm *ipc;
+ int next_id;
+ int total;
- /*
- * rcu_dereference() is not needed here
- * since ipc_ids.mutex is held
- */
- for (id = 0; id <= max_id; id++) {
- p = ids->entries->p[id];
- if(p==NULL)
+ for (total = 0, next_id = 0; total < ids->in_use; next_id++) {
+ ipc = idr_find(&ids->ipcs_idr, next_id);
+
+ if (ipc == NULL)
continue;
- if (key == p->key)
- return id;
+
+ if (ipc->key != key) {
+ total++;
+ continue;
+ }
+
+ ipc_lock_by_ptr(ipc);
+ return ipc;
}
- return -1;
+
+ return NULL;
}
-/*
- * Requires ipc_ids.mutex locked
+/**
+ * ipc_get_maxid - get the last assigned id
+ * @ids: IPC identifier set
+ *
+ * Called with ipc_ids.mutex held.
*/
-static int grow_ary(struct ipc_ids* ids, int newsize)
+
+int ipc_get_maxid(struct ipc_ids *ids)
{
- struct ipc_id_ary* new;
- struct ipc_id_ary* old;
- int i;
- int size = ids->entries->size;
-
- if(newsize > IPCMNI)
- newsize = IPCMNI;
- if(newsize <= size)
- return newsize;
-
- new = ipc_rcu_alloc(sizeof(struct kern_ipc_perm *)*newsize +
- sizeof(struct ipc_id_ary));
- if(new == NULL)
- return size;
- new->size = newsize;
- memcpy(new->p, ids->entries->p, sizeof(struct kern_ipc_perm *)*size);
- for(i=size;i<newsize;i++) {
- new->p[i] = NULL;
- }
- old = ids->entries;
+ struct kern_ipc_perm *ipc;
+ int max_id = -1;
+ int total, id;
- /*
- * Use rcu_assign_pointer() to make sure the memcpyed contents
- * of the new array are visible before the new array becomes visible.
- */
- rcu_assign_pointer(ids->entries, new);
+ if (ids->in_use == 0)
+ return -1;
+
+ if (ids->in_use == IPCMNI)
+ return IPCMNI - 1;
- __ipc_fini_ids(ids, old);
- return newsize;
+ /* Look for the last assigned id */
+ total = 0;
+ for (id = 0; id < IPCMNI && total < ids->in_use; id++) {
+ ipc = idr_find(&ids->ipcs_idr, id);
+ if (ipc != NULL) {
+ max_id = id;
+ total++;
+ }
+ }
+ return max_id;
}
/**
* ipc_addid - add an IPC identifier
* @ids: IPC identifier set
* @new: new IPC permission set
- * @size: new size limit for the id array
+ * @size: limit for the number of used ids
*
- * Add an entry 'new' to the IPC arrays. The permissions object is
+ * Add an entry 'new' to the IPC idr. The permissions object is
* initialised and the first free entry is set up and the id assigned
* is returned. The list is returned in a locked state on success.
* On failure the list is not locked and -1 is returned.
@@ -284,23 +268,23 @@ static int grow_ary(struct ipc_ids* ids,
int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
{
- int id;
-
- size = grow_ary(ids,size);
+ int id, err;
/*
* rcu_dereference()() is not needed here since
* ipc_ids.mutex is held
*/
- for (id = 0; id < size; id++) {
- if(ids->entries->p[id] == NULL)
- goto found;
- }
- return -1;
-found:
+ if (size > IPCMNI)
+ size = IPCMNI;
+
+ if (ids->in_use >= size)
+ return -1;
+
+ err = idr_get_new(&ids->ipcs_idr, new, &id);
+ if (err)
+ return -1;
+
ids->in_use++;
- if (id > ids->max_id)
- ids->max_id = id;
new->cuid = new->uid = current->euid;
new->gid = new->cgid = current->egid;
@@ -313,48 +297,32 @@ found:
new->deleted = 0;
rcu_read_lock();
spin_lock(&new->lock);
- ids->entries->p[id] = new;
return id;
}
/**
* ipc_rmid - remove an IPC identifier
* @ids: identifier set
- * @id: Identifier to remove
+ * @id: ipc perm structure containing the identifier to remove
*
* The identifier must be valid, and in use. The kernel will panic if
* fed an invalid identifier. The entry is removed and internal
- * variables recomputed. The object associated with the identifier
- * is returned.
- * ipc_ids.mutex and the spinlock for this ID is hold before this function
- * is called, and remain locked on the exit.
+ * variables recomputed.
+ * ipc_ids.mutex and the spinlock for this ID are held before this
+ * function is called, and remain locked on the exit.
*/
-struct kern_ipc_perm* ipc_rmid(struct ipc_ids* ids, int id)
+void ipc_rmid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)
{
- struct kern_ipc_perm* p;
- int lid = id % SEQ_MULTIPLIER;
- BUG_ON(lid >= ids->entries->size);
+ int lid = ipcp->id % SEQ_MULTIPLIER;
+
+ idr_remove(&ids->ipcs_idr, lid);
- /*
- * do not need a rcu_dereference()() here to force ordering
- * on Alpha, since the ipc_ids.mutex is held.
- */
- p = ids->entries->p[lid];
- ids->entries->p[lid] = NULL;
- BUG_ON(p==NULL);
ids->in_use--;
- if (lid == ids->max_id) {
- do {
- lid--;
- if(lid == -1)
- break;
- } while (ids->entries->p[lid] == NULL);
- ids->max_id = lid;
- }
- p->deleted = 1;
- return p;
+ ipcp->deleted = 1;
+
+ return;
}
/**
@@ -613,33 +581,26 @@ void ipc64_perm_to_ipc_perm (struct ipc6
* if in the future ipc_get() is used by other places without ipc_ids.mutex
* down, then ipc_get() needs read memery barriers as ipc_lock() does.
*/
-struct kern_ipc_perm* ipc_get(struct ipc_ids* ids, int id)
+struct kern_ipc_perm *ipc_get(struct ipc_ids *ids, int id)
{
- struct kern_ipc_perm* out;
+ struct kern_ipc_perm *out;
int lid = id % SEQ_MULTIPLIER;
- if(lid >= ids->entries->size)
- return NULL;
- out = ids->entries->p[lid];
+ out = idr_find(&ids->ipcs_idr, lid);
return out;
}
-struct kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id)
+struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id)
{
- struct kern_ipc_perm* out;
+ struct kern_ipc_perm *out;
int lid = id % SEQ_MULTIPLIER;
- struct ipc_id_ary* entries;
rcu_read_lock();
- entries = rcu_dereference(ids->entries);
- if(lid >= entries->size) {
- rcu_read_unlock();
- return NULL;
- }
- out = entries->p[lid];
- if(out == NULL) {
+ out = idr_find(&ids->ipcs_idr, lid);
+ if (out == NULL) {
rcu_read_unlock();
return NULL;
}
+
spin_lock(&out->lock);
/* ipc_rmid() may have already freed the ID while ipc_lock
@@ -650,6 +611,7 @@ struct kern_ipc_perm* ipc_lock(struct ip
rcu_read_unlock();
return NULL;
}
+
return out;
}
@@ -707,27 +669,30 @@ struct ipc_proc_iter {
struct ipc_proc_iface *iface;
};
-static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos)
+/*
+ * This routine locks the ipc structure found at least at position pos.
+ */
+struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos,
+ loff_t *new_pos)
{
- struct ipc_proc_iter *iter = s->private;
- struct ipc_proc_iface *iface = iter->iface;
- struct kern_ipc_perm *ipc = it;
- loff_t p;
- struct ipc_ids *ids;
+ struct kern_ipc_perm *ipc;
+ int total, id;
- ids = iter->ns->ids[iface->ids];
+ total = 0;
+ for (id = 0; id < pos && total < ids->in_use; id++) {
+ ipc = idr_find(&ids->ipcs_idr, id);
+ if (ipc != NULL)
+ total++;
+ }
- /* If we had an ipc id locked before, unlock it */
- if (ipc && ipc != SEQ_START_TOKEN)
- ipc_unlock(ipc);
+ if (total >= ids->in_use)
+ return NULL;
- /*
- * p = *pos - 1 (because id 0 starts at position 1)
- * + 1 (because we increment the position by one)
- */
- for (p = *pos; p <= ids->max_id; p++) {
- if ((ipc = ipc_lock(ids, p)) != NULL) {
- *pos = p + 1;
+ for ( ; pos < IPCMNI; pos++) {
+ ipc = idr_find(&ids->ipcs_idr, pos);
+ if (ipc != NULL) {
+ *new_pos = pos + 1;
+ ipc_lock_by_ptr(ipc);
return ipc;
}
}
@@ -736,6 +701,19 @@ static void *sysvipc_proc_next(struct se
return NULL;
}
+static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos)
+{
+ struct ipc_proc_iter *iter = s->private;
+ struct ipc_proc_iface *iface = iter->iface;
+ struct kern_ipc_perm *ipc = it;
+
+ /* If we had an ipc id locked before, unlock it */
+ if (ipc && ipc != SEQ_START_TOKEN)
+ ipc_unlock(ipc);
+
+ return sysvipc_find_ipc(iter->ns->ids[iface->ids], *pos, pos);
+}
+
/*
* File positions: pos 0 -> header, pos n -> ipc id + 1.
* SeqFile iterator: iterator value locked shp or SEQ_TOKEN_START.
@@ -744,8 +722,6 @@ static void *sysvipc_proc_start(struct s
{
struct ipc_proc_iter *iter = s->private;
struct ipc_proc_iface *iface = iter->iface;
- struct kern_ipc_perm *ipc;
- loff_t p;
struct ipc_ids *ids;
ids = iter->ns->ids[iface->ids];
@@ -765,13 +741,7 @@ static void *sysvipc_proc_start(struct s
return SEQ_START_TOKEN;
/* Find the (pos-1)th ipc */
- for (p = *pos - 1; p <= ids->max_id; p++) {
- if ((ipc = ipc_lock(ids, p)) != NULL) {
- *pos = p + 1;
- return ipc;
- }
- }
- return NULL;
+ return sysvipc_find_ipc(ids, *pos - 1, pos);
}
static void sysvipc_proc_stop(struct seq_file *s, void *it)
Index: linux-2.6.23-rc2/ipc/msg.c
===================================================================
--- linux-2.6.23-rc2.orig/ipc/msg.c 2007-08-31 07:49:21.000000000 +0200
+++ linux-2.6.23-rc2/ipc/msg.c 2007-08-31 11:29:21.000000000 +0200
@@ -75,13 +75,12 @@ static struct ipc_ids init_msg_ids;
#define msg_lock(ns, id) ((struct msg_queue*)ipc_lock(&msg_ids(ns), id))
#define msg_unlock(msq) ipc_unlock(&(msq)->q_perm)
-#define msg_rmid(ns, id) ((struct msg_queue*)ipc_rmid(&msg_ids(ns), id))
#define msg_checkid(ns, msq, msgid) \
ipc_checkid(&msg_ids(ns), &msq->q_perm, msgid)
#define msg_buildid(ns, id, seq) \
ipc_buildid(&msg_ids(ns), id, seq)
-static void freeque (struct ipc_namespace *ns, struct msg_queue *msq, int id);
+static void freeque(struct ipc_namespace *, struct msg_queue *);
static int newque (struct ipc_namespace *ns, key_t key, int msgflg);
#ifdef CONFIG_PROC_FS
static int sysvipc_msg_proc_show(struct seq_file *s, void *it);
@@ -93,7 +92,7 @@ static void __msg_init_ns(struct ipc_nam
ns->msg_ctlmax = MSGMAX;
ns->msg_ctlmnb = MSGMNB;
ns->msg_ctlmni = MSGMNI;
- ipc_init_ids(ids, ns->msg_ctlmni);
+ ipc_init_ids(ids);
}
int msg_init_ns(struct ipc_namespace *ns)
@@ -110,20 +109,24 @@ int msg_init_ns(struct ipc_namespace *ns
void msg_exit_ns(struct ipc_namespace *ns)
{
- int i;
struct msg_queue *msq;
+ int next_id;
+ int total, in_use;
mutex_lock(&msg_ids(ns).mutex);
- for (i = 0; i <= msg_ids(ns).max_id; i++) {
- msq = msg_lock(ns, i);
+
+ in_use = msg_ids(ns).in_use;
+
+ for (total = 0, next_id = 0; total < in_use; next_id++) {
+ msq = idr_find(&msg_ids(ns).ipcs_idr, next_id);
if (msq == NULL)
continue;
-
- freeque(ns, msq, i);
+ ipc_lock_by_ptr(&msq->q_perm);
+ freeque(ns, msq);
+ total++;
}
mutex_unlock(&msg_ids(ns).mutex);
- ipc_fini_ids(ns->ids[IPC_MSG_IDS]);
kfree(ns->ids[IPC_MSG_IDS]);
ns->ids[IPC_MSG_IDS] = NULL;
}
@@ -136,6 +139,11 @@ void __init msg_init(void)
IPC_MSG_IDS, sysvipc_msg_proc_show);
}
+static inline void msg_rmid(struct ipc_namespace *ns, struct msg_queue *s)
+{
+ ipc_rmid(&msg_ids(ns), &s->q_perm);
+}
+
static int newque (struct ipc_namespace *ns, key_t key, int msgflg)
{
struct msg_queue *msq;
@@ -155,6 +163,9 @@ static int newque (struct ipc_namespace
return retval;
}
+ /*
+ * ipc_addid() locks msq
+ */
id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
if (id == -1) {
security_msg_queue_free(msq);
@@ -162,7 +173,7 @@ static int newque (struct ipc_namespace
return -ENOSPC;
}
- msq->q_id = msg_buildid(ns, id, msq->q_perm.seq);
+ msq->q_perm.id = msg_buildid(ns, id, msq->q_perm.seq);
msq->q_stime = msq->q_rtime = 0;
msq->q_ctime = get_seconds();
msq->q_cbytes = msq->q_qnum = 0;
@@ -171,9 +182,10 @@ static int newque (struct ipc_namespace
INIT_LIST_HEAD(&msq->q_messages);
INIT_LIST_HEAD(&msq->q_receivers);
INIT_LIST_HEAD(&msq->q_senders);
+
msg_unlock(msq);
- return msq->q_id;
+ return msq->q_perm.id;
}
static inline void ss_add(struct msg_queue *msq, struct msg_sender *mss)
@@ -225,18 +237,18 @@ static void expunge_all(struct msg_queue
/*
* freeque() wakes up waiters on the sender and receiver waiting queue,
* removes the message queue from message queue ID
- * array, and cleans up all the messages associated with this queue.
+ * IDR, and cleans up all the messages associated with this queue.
*
- * msg_ids.mutex and the spinlock for this message queue is hold
+ * msg_ids.mutex and the spinlock for this message queue are held
* before freeque() is called. msg_ids.mutex remains locked on exit.
*/
-static void freeque(struct ipc_namespace *ns, struct msg_queue *msq, int id)
+static void freeque(struct ipc_namespace *ns, struct msg_queue *msq)
{
struct list_head *tmp;
expunge_all(msq, -EIDRM);
ss_wakeup(&msq->q_senders, 1);
- msq = msg_rmid(ns, id);
+ msg_rmid(ns, msq);
msg_unlock(msq);
tmp = msq->q_messages.next;
@@ -255,36 +267,51 @@ static void freeque(struct ipc_namespace
asmlinkage long sys_msgget(key_t key, int msgflg)
{
struct msg_queue *msq;
- int id, ret = -EPERM;
+ int ret;
struct ipc_namespace *ns;
ns = current->nsproxy->ipc_ns;
-
- mutex_lock(&msg_ids(ns).mutex);
- if (key == IPC_PRIVATE)
- ret = newque(ns, key, msgflg);
- else if ((id = ipc_findkey(&msg_ids(ns), key)) == -1) { /* key not used */
- if (!(msgflg & IPC_CREAT))
- ret = -ENOENT;
- else
+
+ ret = idr_pre_get(&msg_ids(ns).ipcs_idr, GFP_KERNEL);
+
+ if (key == IPC_PRIVATE) {
+ if (!ret)
+ ret = -ENOMEM;
+ else {
+ mutex_lock(&msg_ids(ns).mutex);
ret = newque(ns, key, msgflg);
- } else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) {
- ret = -EEXIST;
+ mutex_unlock(&msg_ids(ns).mutex);
+ }
} else {
- msq = msg_lock(ns, id);
- BUG_ON(msq == NULL);
- if (ipcperms(&msq->q_perm, msgflg))
- ret = -EACCES;
- else {
- int qid = msg_buildid(ns, id, msq->q_perm.seq);
+ mutex_lock(&msg_ids(ns).mutex);
+ msq = (struct msg_queue *) ipc_findkey(&msg_ids(ns), key);
+ if (msq == NULL) {
+ /* key not used */
+ if (!(msgflg & IPC_CREAT))
+ ret = -ENOENT;
+ else if (!ret)
+ ret = -ENOMEM;
+ else
+ ret = newque(ns, key, msgflg);
+ } else {
+ /* msq has been locked by ipc_findkey() */
- ret = security_msg_queue_associate(msq, msgflg);
- if (!ret)
- ret = qid;
+ if (msgflg & IPC_CREAT && msgflg & IPC_EXCL)
+ ret = -EEXIST;
+ else {
+ if (ipcperms(&msq->q_perm, msgflg))
+ ret = -EACCES;
+ else {
+ ret = security_msg_queue_associate(
+ msq, msgflg);
+ if (!ret)
+ ret = msq->q_perm.id;
+ }
+ }
+ msg_unlock(msq);
}
- msg_unlock(msq);
+ mutex_unlock(&msg_ids(ns).mutex);
}
- mutex_unlock(&msg_ids(ns).mutex);
return ret;
}
@@ -430,13 +457,13 @@ asmlinkage long sys_msgctl(int msqid, in
msginfo.msgpool = MSGPOOL;
msginfo.msgtql = MSGTQL;
}
- max_id = msg_ids(ns).max_id;
+ max_id = ipc_get_maxid(&msg_ids(ns));
mutex_unlock(&msg_ids(ns).mutex);
if (copy_to_user(buf, &msginfo, sizeof(struct msginfo)))
return -EFAULT;
return (max_id < 0) ? 0 : max_id;
}
- case MSG_STAT:
+ case MSG_STAT: /* msqid is an index rather than a msg queue id */
case IPC_STAT:
{
struct msqid64_ds tbuf;
@@ -444,8 +471,6 @@ asmlinkage long sys_msgctl(int msqid, in
if (!buf)
return -EFAULT;
- if (cmd == MSG_STAT && msqid >= msg_ids(ns).entries->size)
- return -EINVAL;
memset(&tbuf, 0, sizeof(tbuf));
@@ -454,7 +479,7 @@ asmlinkage long sys_msgctl(int msqid, in
return -EINVAL;
if (cmd == MSG_STAT) {
- success_return = msg_buildid(ns, msqid, msq->q_perm.seq);
+ success_return = msq->q_perm.id;
} else {
err = -EIDRM;
if (msg_checkid(ns, msq, msqid))
@@ -552,7 +577,7 @@ asmlinkage long sys_msgctl(int msqid, in
break;
}
case IPC_RMID:
- freeque(ns, msq, msqid);
+ freeque(ns, msq);
break;
}
err = 0;
@@ -926,7 +951,7 @@ static int sysvipc_msg_proc_show(struct
return seq_printf(s,
"%10d %10d %4o %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n",
msq->q_perm.key,
- msq->q_id,
+ msq->q_perm.id,
msq->q_perm.mode,
msq->q_cbytes,
msq->q_qnum,
Index: linux-2.6.23-rc2/ipc/sem.c
===================================================================
--- linux-2.6.23-rc2.orig/ipc/sem.c 2007-08-31 07:49:21.000000000 +0200
+++ linux-2.6.23-rc2/ipc/sem.c 2007-08-31 11:29:21.000000000 +0200
@@ -90,7 +90,6 @@
#define sem_lock(ns, id) ((struct sem_array*)ipc_lock(&sem_ids(ns), id))
#define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm)
-#define sem_rmid(ns, id) ((struct sem_array*)ipc_rmid(&sem_ids(ns), id))
#define sem_checkid(ns, sma, semid) \
ipc_checkid(&sem_ids(ns),&sma->sem_perm,semid)
#define sem_buildid(ns, id, seq) \
@@ -99,7 +98,7 @@
static struct ipc_ids init_sem_ids;
static int newary(struct ipc_namespace *, key_t, int, int);
-static void freeary(struct ipc_namespace *ns, struct sem_array *sma, int id);
+static void freeary(struct ipc_namespace *, struct sem_array *);
#ifdef CONFIG_PROC_FS
static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
#endif
@@ -129,7 +128,7 @@ static void __sem_init_ns(struct ipc_nam
ns->sc_semopm = SEMOPM;
ns->sc_semmni = SEMMNI;
ns->used_sems = 0;
- ipc_init_ids(ids, ns->sc_semmni);
+ ipc_init_ids(ids);
}
int sem_init_ns(struct ipc_namespace *ns)
@@ -146,20 +145,24 @@ int sem_init_ns(struct ipc_namespace *ns
void sem_exit_ns(struct ipc_namespace *ns)
{
- int i;
struct sem_array *sma;
+ int next_id;
+ int total, in_use;
mutex_lock(&sem_ids(ns).mutex);
- for (i = 0; i <= sem_ids(ns).max_id; i++) {
- sma = sem_lock(ns, i);
+
+ in_use = sem_ids(ns).in_use;
+
+ for (total = 0, next_id = 0; total < in_use; next_id++) {
+ sma = idr_find(&sem_ids(ns).ipcs_idr, next_id);
if (sma == NULL)
continue;
-
- freeary(ns, sma, i);
+ ipc_lock_by_ptr(&sma->sem_perm);
+ freeary(ns, sma);
+ total++;
}
mutex_unlock(&sem_ids(ns).mutex);
- ipc_fini_ids(ns->ids[IPC_SEM_IDS]);
kfree(ns->ids[IPC_SEM_IDS]);
ns->ids[IPC_SEM_IDS] = NULL;
}
@@ -172,6 +175,11 @@ void __init sem_init (void)
IPC_SEM_IDS, sysvipc_sem_proc_show);
}
+static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
+{
+ ipc_rmid(&sem_ids(ns), &s->sem_perm);
+}
+
/*
* Lockless wakeup algorithm:
* Without the check/retry algorithm a lockless wakeup is possible:
@@ -243,7 +251,7 @@ static int newary (struct ipc_namespace
}
ns->used_sems += nsems;
- sma->sem_id = sem_buildid(ns, id, sma->sem_perm.seq);
+ sma->sem_perm.id = sem_buildid(ns, id, sma->sem_perm.seq);
sma->sem_base = (struct sem *) &sma[1];
/* sma->sem_pending = NULL; */
sma->sem_pending_last = &sma->sem_pending;
@@ -252,12 +260,12 @@ static int newary (struct ipc_namespace
sma->sem_ctime = get_seconds();
sem_unlock(sma);
- return sma->sem_id;
+ return sma->sem_perm.id;
}
asmlinkage long sys_semget (key_t key, int nsems, int semflg)
{
- int id, err = -EINVAL;
+ int err;
struct sem_array *sma;
struct ipc_namespace *ns;
@@ -265,34 +273,50 @@ asmlinkage long sys_semget (key_t key, i
if (nsems < 0 || nsems > ns->sc_semmsl)
return -EINVAL;
- mutex_lock(&sem_ids(ns).mutex);
-
+
+ err = idr_pre_get(&sem_ids(ns).ipcs_idr, GFP_KERNEL);
+
if (key == IPC_PRIVATE) {
- err = newary(ns, key, nsems, semflg);
- } else if ((id = ipc_findkey(&sem_ids(ns), key)) == -1) { /* key not used */
- if (!(semflg & IPC_CREAT))
- err = -ENOENT;
- else
+ if (!err)
+ err = -ENOMEM;
+ else {
+ mutex_lock(&sem_ids(ns).mutex);
err = newary(ns, key, nsems, semflg);
- } else if (semflg & IPC_CREAT && semflg & IPC_EXCL) {
- err = -EEXIST;
+ mutex_unlock(&sem_ids(ns).mutex);
+ }
} else {
- sma = sem_lock(ns, id);
- BUG_ON(sma==NULL);
- if (nsems > sma->sem_nsems)
- err = -EINVAL;
- else if (ipcperms(&sma->sem_perm, semflg))
- err = -EACCES;
- else {
- int semid = sem_buildid(ns, id, sma->sem_perm.seq);
- err = security_sem_associate(sma, semflg);
- if (!err)
- err = semid;
+ mutex_lock(&sem_ids(ns).mutex);
+ sma = (struct sem_array *) ipc_findkey(&sem_ids(ns), key);
+ if (sma == NULL) {
+ /* key not used */
+ if (!(semflg & IPC_CREAT))
+ err = -ENOENT;
+ else if (!err)
+ err = -ENOMEM;
+ else
+ err = newary(ns, key, nsems, semflg);
+ } else {
+ /* sma has been locked by ipc_findkey() */
+
+ if (semflg & IPC_CREAT && semflg & IPC_EXCL)
+ err = -EEXIST;
+ else {
+ if (nsems > sma->sem_nsems)
+ err = -EINVAL;
+ else if (ipcperms(&sma->sem_perm, semflg))
+ err = -EACCES;
+ else {
+ err = security_sem_associate(sma,
+ semflg);
+ if (!err)
+ err = sma->sem_perm.id;
+ }
+ }
+ sem_unlock(sma);
}
- sem_unlock(sma);
+ mutex_unlock(&sem_ids(ns).mutex);
}
- mutex_unlock(&sem_ids(ns).mutex);
return err;
}
@@ -491,11 +515,10 @@ static int count_semzcnt (struct sem_arr
* the spinlock for this semaphore set hold. sem_ids.mutex remains locked
* on exit.
*/
-static void freeary (struct ipc_namespace *ns, struct sem_array *sma, int id)
+static void freeary(struct ipc_namespace *ns, struct sem_array *sma)
{
struct sem_undo *un;
struct sem_queue *q;
- int size;
/* Invalidate the existing undo structures for this semaphore set.
* (They will be freed without any further action in exit_sem()
@@ -518,12 +541,11 @@ static void freeary (struct ipc_namespac
q = n;
}
- /* Remove the semaphore set from the ID array*/
- sma = sem_rmid(ns, id);
+ /* Remove the semaphore set from the IDR */
+ sem_rmid(ns, sma);
sem_unlock(sma);
ns->used_sems -= sma->sem_nsems;
- size = sizeof (*sma) + sma->sem_nsems * sizeof (struct sem);
security_sem_free(sma);
ipc_rcu_putref(sma);
}
@@ -584,7 +606,7 @@ static int semctl_nolock(struct ipc_name
seminfo.semusz = SEMUSZ;
seminfo.semaem = SEMAEM;
}
- max_id = sem_ids(ns).max_id;
+ max_id = ipc_get_maxid(&sem_ids(ns));
mutex_unlock(&sem_ids(ns).mutex);
if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo)))
return -EFAULT;
@@ -595,9 +617,6 @@ static int semctl_nolock(struct ipc_name
struct semid64_ds tbuf;
int id;
- if(semid >= sem_ids(ns).entries->size)
- return -EINVAL;
-
memset(&tbuf,0,sizeof(tbuf));
sma = sem_lock(ns, semid);
@@ -612,7 +631,7 @@ static int semctl_nolock(struct ipc_name
if (err)
goto out_unlock;
- id = sem_buildid(ns, semid, sma->sem_perm.seq);
+ id = sma->sem_perm.id;
kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);
tbuf.sem_otime = sma->sem_otime;
@@ -894,7 +913,7 @@ static int semctl_down(struct ipc_namesp
switch(cmd){
case IPC_RMID:
- freeary(ns, sma, semid);
+ freeary(ns, sma);
err = 0;
break;
case IPC_SET:
@@ -1402,7 +1421,7 @@ static int sysvipc_sem_proc_show(struct
return seq_printf(s,
"%10d %10d %4o %10lu %5u %5u %5u %5u %10lu %10lu\n",
sma->sem_perm.key,
- sma->sem_id,
+ sma->sem_perm.id,
sma->sem_perm.mode,
sma->sem_nsems,
sma->sem_perm.uid,
Index: linux-2.6.23-rc2/ipc/shm.c
===================================================================
--- linux-2.6.23-rc2.orig/ipc/shm.c 2007-08-31 07:49:21.000000000 +0200
+++ linux-2.6.23-rc2/ipc/shm.c 2007-08-31 11:29:21.000000000 +0200
@@ -84,7 +84,7 @@ static void __shm_init_ns(struct ipc_nam
ns->shm_ctlall = SHMALL;
ns->shm_ctlmni = SHMMNI;
ns->shm_tot = 0;
- ipc_init_ids(ids, 1);
+ ipc_init_ids(ids);
}
static void do_shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *shp)
@@ -112,20 +112,24 @@ int shm_init_ns(struct ipc_namespace *ns
void shm_exit_ns(struct ipc_namespace *ns)
{
- int i;
struct shmid_kernel *shp;
+ int next_id;
+ int total, in_use;
mutex_lock(&shm_ids(ns).mutex);
- for (i = 0; i <= shm_ids(ns).max_id; i++) {
- shp = shm_lock(ns, i);
+
+ in_use = shm_ids(ns).in_use;
+
+ for (total = 0, next_id = 0; total < in_use; next_id++) {
+ shp = idr_find(&shm_ids(ns).ipcs_idr, next_id);
if (shp == NULL)
continue;
-
+ ipc_lock_by_ptr(&shp->shm_perm);
do_shm_rmid(ns, shp);
+ total++;
}
mutex_unlock(&shm_ids(ns).mutex);
- ipc_fini_ids(ns->ids[IPC_SHM_IDS]);
kfree(ns->ids[IPC_SHM_IDS]);
ns->ids[IPC_SHM_IDS] = NULL;
}
@@ -146,9 +150,9 @@ static inline int shm_checkid(struct ipc
return 0;
}
-static inline struct shmid_kernel *shm_rmid(struct ipc_namespace *ns, int id)
+static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s)
{
- return (struct shmid_kernel *)ipc_rmid(&shm_ids(ns), id);
+ ipc_rmid(&shm_ids(ns), &s->shm_perm);
}
static inline int shm_addid(struct ipc_namespace *ns, struct shmid_kernel *shp)
@@ -184,7 +188,7 @@ static void shm_open(struct vm_area_stru
static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
{
ns->shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
- shm_rmid(ns, shp->id);
+ shm_rmid(ns, shp);
shm_unlock(shp);
if (!is_file_hugepages(shp->shm_file))
shmem_lock(shp->shm_file, 0, shp->mlock_user);
@@ -397,17 +401,18 @@ static int newseg (struct ipc_namespace
shp->shm_ctim = get_seconds();
shp->shm_segsz = size;
shp->shm_nattch = 0;
- shp->id = shm_buildid(ns, id, shp->shm_perm.seq);
+ shp->shm_perm.id = shm_buildid(ns, id, shp->shm_perm.seq);
shp->shm_file = file;
/*
* shmid gets reported as "inode#" in /proc/pid/maps.
* proc-ps tools use this. Changing this will break them.
*/
- file->f_dentry->d_inode->i_ino = shp->id;
+ file->f_dentry->d_inode->i_ino = shp->shm_perm.id;
ns->shm_tot += numpages;
+ error = shp->shm_perm.id;
shm_unlock(shp);
- return shp->id;
+ return error;
no_id:
fput(file);
@@ -420,37 +425,52 @@ no_file:
asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
{
struct shmid_kernel *shp;
- int err, id = 0;
+ int err;
struct ipc_namespace *ns;
ns = current->nsproxy->ipc_ns;
- mutex_lock(&shm_ids(ns).mutex);
+ err = idr_pre_get(&shm_ids(ns).ipcs_idr, GFP_KERNEL);
+
if (key == IPC_PRIVATE) {
- err = newseg(ns, key, shmflg, size);
- } else if ((id = ipc_findkey(&shm_ids(ns), key)) == -1) {
- if (!(shmflg & IPC_CREAT))
- err = -ENOENT;
- else
+ if (!err)
+ err = -ENOMEM;
+ else {
+ mutex_lock(&shm_ids(ns).mutex);
err = newseg(ns, key, shmflg, size);
- } else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) {
- err = -EEXIST;
+ mutex_unlock(&shm_ids(ns).mutex);
+ }
} else {
- shp = shm_lock(ns, id);
- BUG_ON(shp==NULL);
- if (shp->shm_segsz < size)
- err = -EINVAL;
- else if (ipcperms(&shp->shm_perm, shmflg))
- err = -EACCES;
- else {
- int shmid = shm_buildid(ns, id, shp->shm_perm.seq);
- err = security_shm_associate(shp, shmflg);
- if (!err)
- err = shmid;
+ 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() */
+
+ 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);
}
- shm_unlock(shp);
+ mutex_unlock(&shm_ids(ns).mutex);
}
- mutex_unlock(&shm_ids(ns).mutex);
return err;
}
@@ -549,17 +569,20 @@ static inline unsigned long copy_shminfo
static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
unsigned long *swp)
{
- int i;
+ int next_id;
+ int total, in_use;
*rss = 0;
*swp = 0;
- for (i = 0; i <= shm_ids(ns).max_id; i++) {
+ in_use = shm_ids(ns).in_use;
+
+ for (total = 0, next_id = 0; total < in_use; next_id++) {
struct shmid_kernel *shp;
struct inode *inode;
- shp = shm_get(ns, i);
- if(!shp)
+ shp = shm_get(ns, next_id);
+ if (shp == NULL)
continue;
inode = shp->shm_file->f_path.dentry->d_inode;
@@ -574,6 +597,8 @@ static void shm_get_stat(struct ipc_name
*swp += info->swapped;
spin_unlock(&info->lock);
}
+
+ total++;
}
}
@@ -610,7 +635,7 @@ asmlinkage long sys_shmctl (int shmid, i
if(copy_shminfo_to_user (buf, &shminfo, version))
return -EFAULT;
/* reading a integer is always atomic */
- err= shm_ids(ns).max_id;
+ err = ipc_get_maxid(&shm_ids(ns));
if(err<0)
err = 0;
goto out;
@@ -630,7 +655,7 @@ asmlinkage long sys_shmctl (int shmid, i
shm_info.shm_tot = ns->shm_tot;
shm_info.swap_attempts = 0;
shm_info.swap_successes = 0;
- err = shm_ids(ns).max_id;
+ err = ipc_get_maxid(&shm_ids(ns));
mutex_unlock(&shm_ids(ns).mutex);
if(copy_to_user (buf, &shm_info, sizeof(shm_info))) {
err = -EFAULT;
@@ -650,11 +675,8 @@ asmlinkage long sys_shmctl (int shmid, i
if(shp==NULL) {
err = -EINVAL;
goto out;
- } else if(cmd==SHM_STAT) {
- err = -EINVAL;
- if (shmid > shm_ids(ns).max_id)
- goto out_unlock;
- result = shm_buildid(ns, shmid, shp->shm_perm.seq);
+ } else if (cmd == SHM_STAT) {
+ result = shp->shm_perm.id;
} else {
err = shm_checkid(ns, shp,shmid);
if(err)
@@ -926,7 +948,7 @@ long do_shmat(int shmid, char __user *sh
file->f_path = path;
file->f_mapping = shp->shm_file->f_mapping;
file->f_mode = f_mode;
- sfd->id = shp->id;
+ sfd->id = shp->shm_perm.id;
sfd->ns = get_ipc_ns(ns);
sfd->file = shp->shm_file;
sfd->vm_ops = NULL;
@@ -1096,7 +1118,7 @@ static int sysvipc_shm_proc_show(struct
format = BIG_STRING;
return seq_printf(s, format,
shp->shm_perm.key,
- shp->id,
+ shp->shm_perm.id,
shp->shm_perm.mode,
shp->shm_segsz,
shp->shm_cprid,
--
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [RFC][PATCH 1/6] Storing ipcs into IDRs
2007-08-31 11:24 ` [RFC][PATCH 1/6] Storing ipcs into IDRs Nadia.Derbey
@ 2007-09-01 22:12 ` Andi Kleen
2007-09-03 10:16 ` Nadia Derbey
2007-09-06 9:33 ` Nadia Derbey
2007-09-10 20:08 ` Andrew Morton
1 sibling, 2 replies; 12+ messages in thread
From: Andi Kleen @ 2007-09-01 22:12 UTC (permalink / raw)
To: Nadia.Derbey; +Cc: linux-kernel, matthltc
Nadia.Derbey@bull.net writes:
> This patch introduces ipcs storage into IDRs. The main changes are:
> . This ipc_ids structure is changed: the entries array is changed into a
> root idr structure.
> . The grow_ary() routine is removed: it is not needed anymore when adding
> an ipc structure, since we are now using the IDR facility.
> . The ipc_rmid() routine interface is changed:
> . there is no need for this routine to return the pointer passed in as
> argument: it is now declared as a void
> . since the id is now part of the kern_ipc_perm structure, no need to
> have it as an argument to the routine
>
Thanks for doing this work. It was long overdue.
Do you have any data how this changes memory consumption with
many objects?
-Andi
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RFC][PATCH 1/6] Storing ipcs into IDRs
2007-09-01 22:12 ` Andi Kleen
@ 2007-09-03 10:16 ` Nadia Derbey
2007-09-06 9:33 ` Nadia Derbey
1 sibling, 0 replies; 12+ messages in thread
From: Nadia Derbey @ 2007-09-03 10:16 UTC (permalink / raw)
To: Andi Kleen; +Cc: linux-kernel, matthltc
Andi Kleen wrote:
> Nadia.Derbey@bull.net writes:
>
>
>>This patch introduces ipcs storage into IDRs. The main changes are:
>> . This ipc_ids structure is changed: the entries array is changed into a
>> root idr structure.
>> . The grow_ary() routine is removed: it is not needed anymore when adding
>> an ipc structure, since we are now using the IDR facility.
>> . The ipc_rmid() routine interface is changed:
>> . there is no need for this routine to return the pointer passed in as
>> argument: it is now declared as a void
>> . since the id is now part of the kern_ipc_perm structure, no need to
>> have it as an argument to the routine
>>
>
>
> Thanks for doing this work. It was long overdue.
>
> Do you have any data how this changes memory consumption with
> many objects?
>
No. Will try to send you this as soon as I've done some measurements.
Regards,
Nadia
--
===============================================================
Name.......... Nadia DERBEY
Organization.. BULL/DT/OSwR&D/Linux
---------------------------------------------------------------
Email......... mailto:Nadia.Derbey@bull.net
Address....... BULL, B.P. 208, 38432 Echirolles Cedex, France
Tel........... (33) 76 29 77 62 [Internal Bull: (229) 77 62]
Telex,Fax..... 980648 F - (33) 76 29 76 00
Internal Bull. Mail: FREC-B1405
===============================================================
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RFC][PATCH 1/6] Storing ipcs into IDRs
2007-09-01 22:12 ` Andi Kleen
2007-09-03 10:16 ` Nadia Derbey
@ 2007-09-06 9:33 ` Nadia Derbey
2007-09-07 15:18 ` Nadia Derbey
1 sibling, 1 reply; 12+ messages in thread
From: Nadia Derbey @ 2007-09-06 9:33 UTC (permalink / raw)
To: Andi Kleen; +Cc: linux-kernel, matthltc
Andi Kleen wrote:
> Nadia.Derbey@bull.net writes:
>
>
>>This patch introduces ipcs storage into IDRs. The main changes are:
>> . This ipc_ids structure is changed: the entries array is changed into a
>> root idr structure.
>> . The grow_ary() routine is removed: it is not needed anymore when adding
>> an ipc structure, since we are now using the IDR facility.
>> . The ipc_rmid() routine interface is changed:
>> . there is no need for this routine to return the pointer passed in as
>> argument: it is now declared as a void
>> . since the id is now part of the kern_ipc_perm structure, no need to
>> have it as an argument to the routine
>>
>
>
> Thanks for doing this work. It was long overdue.
>
> Do you have any data how this changes memory consumption with
> many objects?
>
> -Andi
>
Andi,
Here are the results I got when creating 32768 (IPCMNI) msg queues with
the patched kernel:
http://akt.sourceforge.net/results/2.6.23-rc2-idr/msg11/output.new
It's the output from msg11.c. This script does what follows:
. gets sysinfo(2) results
. captures /proc/meminfo
. captures /proc/slabinfo
. creates XX msg queues (XX given as parameter)
. captures /proc/meminfo
. captures /proc/slabinfo
. gets sysinfo results
. outputs all the results
. removes the created ipcs
sysinfo results: a BEFORE and an AFTER column are output where necessary.
BEFORE means "before creating the objects"
AFTER means "after the objects have been created"
meminfo results: the BEFORE and AFTER files are pasted
slabinfo results: only the differences between the BEFORE and the AFTER
are output.
Here are also the sizes for the ref and the patched kernel:
size linux-2.6.23-rc2.ref/vmlinux linux-2.6.23-rc2/vmlinux
text data bss dec hex filename
4432697 496450 602112 5531259 54667b linux-2.6.23-rc2.ref/vmlinux
4430747 496450 602112 5529309 545edd linux-2.6.23-rc2/vmlinux
The http://akt.sourceforge.net/results/2.6.23-rc2-idr/msg11 directory is
structured as follows:
msg11.c: the script I used to generate the results
output.ref: the output from msg11 with the ref kernel
output.new: the output from msg11 with the patched kernel
size: the output from the size command
ref: directory with the results files for the ref kernel
new: directory with the results files for the patched kernel
In these 2 directories:
*_mem_*before: /proc/meminfo before creating the msg queues
*_mem_*after: /proc/meminfo after creating the msg queues
*_slab_*before: /proc/slabinfo before creating the msg queues
*_slab_*after: /proc/slabinfo after creating the msg queues
Regards,
Nadia
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [RFC][PATCH 1/6] Storing ipcs into IDRs
2007-09-06 9:33 ` Nadia Derbey
@ 2007-09-07 15:18 ` Nadia Derbey
0 siblings, 0 replies; 12+ messages in thread
From: Nadia Derbey @ 2007-09-07 15:18 UTC (permalink / raw)
To: Nadia Derbey; +Cc: Andi Kleen, linux-kernel, matthltc
Nadia Derbey wrote:
> Andi Kleen wrote:
>
>> Nadia.Derbey@bull.net writes:
>>
>>
>>> This patch introduces ipcs storage into IDRs. The main changes are:
>>> . This ipc_ids structure is changed: the entries array is changed
>>> into a
>>> root idr structure.
>>> . The grow_ary() routine is removed: it is not needed anymore when
>>> adding
>>> an ipc structure, since we are now using the IDR facility.
>>> . The ipc_rmid() routine interface is changed:
>>> . there is no need for this routine to return the pointer
>>> passed in as
>>> argument: it is now declared as a void
>>> . since the id is now part of the kern_ipc_perm structure, no
>>> need to
>>> have it as an argument to the routine
>>>
>>
>>
>> Thanks for doing this work. It was long overdue.
>>
>> Do you have any data how this changes memory consumption with many
>> objects?
>> -Andi
>>
>
> Andi,
>
> Here are the results I got when creating 32768 (IPCMNI) msg queues with
> the patched kernel:
>
> http://akt.sourceforge.net/results/2.6.23-rc2-idr/msg11/output.new
>
> It's the output from msg11.c. This script does what follows:
> . gets sysinfo(2) results
> . captures /proc/meminfo
> . captures /proc/slabinfo
> . creates XX msg queues (XX given as parameter)
> . captures /proc/meminfo
> . captures /proc/slabinfo
> . gets sysinfo results
> . outputs all the results
> . removes the created ipcs
>
> sysinfo results: a BEFORE and an AFTER column are output where necessary.
> BEFORE means "before creating the objects"
> AFTER means "after the objects have been created"
>
> meminfo results: the BEFORE and AFTER files are pasted
>
> slabinfo results: only the differences between the BEFORE and the AFTER
> are output.
>
>
> Here are also the sizes for the ref and the patched kernel:
>
> size linux-2.6.23-rc2.ref/vmlinux linux-2.6.23-rc2/vmlinux
> text data bss dec hex filename
> 4432697 496450 602112 5531259 54667b linux-2.6.23-rc2.ref/vmlinux
> 4430747 496450 602112 5529309 545edd linux-2.6.23-rc2/vmlinux
>
>
>
> The http://akt.sourceforge.net/results/2.6.23-rc2-idr/msg11 directory is
> structured as follows:
>
> msg11.c: the script I used to generate the results
> output.ref: the output from msg11 with the ref kernel
> output.new: the output from msg11 with the patched kernel
> size: the output from the size command
> ref: directory with the results files for the ref kernel
> new: directory with the results files for the patched kernel
> In these 2 directories:
> *_mem_*before: /proc/meminfo before creating the msg queues
> *_mem_*after: /proc/meminfo after creating the msg queues
> *_slab_*before: /proc/slabinfo before creating the msg queues
> *_slab_*after: /proc/slabinfo after creating the msg queues
>
Andi,
Here is an annalysis of the results I sent you yesterday (I guess you
don't have enoguh time to look at everything):
ref code:
1) since /proc/sys/kernel/msgmni has been set to 32768, vmalloc(0x20014)
is called to allocate the entries[] array (see grow_ary() -->
ipc_rcu_alloc()).
==>
Before msg queues allocation: VmallocUsed = 2860 kB
After msg queues allocation: VmallocUsed = 2996 KB
Once allocated this array is never freed.
Unfortunately, in the result I sent you yesterday, you can't see the
evolution since it was not the 1st time I was running the test, so the
vmalloc() has not been called.
2) Since 32768 msg queues have been created and a msg_queue structure <
PAGE_SIZE, kmalloc(0x6C) is called 32768 times
==> size-128 in slabinfo: (I slighty simplified the output to make it
fit in the mail):
objs slabs
# name <active> <num> <size> : <active> <num>
before : size-128 1070 1320 128 : 44 44
after : size-128 33840 33840 128 : 1128 1128
patched code:
1) since 32768 msg queues are created, idr_pre_get() is called 32768 times
==> idr_layer_cache in slabinfo:
objs slabs
# name <active> <num> <size> : <active> <num>
before : idr_layer_cache 112 116 136 : 4 4
after : idr_layer_cache 1189 1189 136 : 41 41
2) This point remains unchanged compared to the ref code.
Regards,
Nadia
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RFC][PATCH 1/6] Storing ipcs into IDRs
2007-08-31 11:24 ` [RFC][PATCH 1/6] Storing ipcs into IDRs Nadia.Derbey
2007-09-01 22:12 ` Andi Kleen
@ 2007-09-10 20:08 ` Andrew Morton
1 sibling, 0 replies; 12+ messages in thread
From: Andrew Morton @ 2007-09-10 20:08 UTC (permalink / raw)
To: Nadia.Derbey; +Cc: linux-kernel, matthltc
On Fri, 31 Aug 2007 13:24:46 +0200 Nadia.Derbey@bull.net wrote:
> [PATCH 01/06]
>
>
> This patch introduces ipcs storage into IDRs. The main changes are:
> . This ipc_ids structure is changed: the entries array is changed into a
> root idr structure.
> . The grow_ary() routine is removed: it is not needed anymore when adding
> an ipc structure, since we are now using the IDR facility.
> . The ipc_rmid() routine interface is changed:
> . there is no need for this routine to return the pointer passed in as
> argument: it is now declared as a void
> . since the id is now part of the kern_ipc_perm structure, no need to
> have it as an argument to the routine
>
>
This is a large patch, and I have neither the time nor competence to review
it :(
I hope that someone will find the time to do a detailed review-n-test of
this code, because the IPC code is pretty touchy and isn't well-maintained,
as I'm sure you have noticed.
Meanwhile I'll queue the patches up for a bit of compile-time and runtime
testing, thanks.
> ...
>
> + msq = (struct msg_queue *) ipc_findkey(&msg_ids(ns), key);
As a separate cleanup: the code casts the ipc_findkey to some outer struct
in all cases. It would be nicer to convert this to container_of(). It'll
generate the same code, but it actually represents what the code is doing
and perhaps means that the code will continue to work if the `struct
kern_ipc_perm' is not at the start of the containing struct.
^ permalink raw reply [flat|nested] 12+ messages in thread
* [RFC][PATCH 2/6] Unifying the syscalls code
2007-08-31 11:24 [RFC][PATCH 0/6] An IPC implementation base on Linux IDRs Nadia.Derbey
2007-08-31 11:24 ` [RFC][PATCH 1/6] Storing ipcs into IDRs Nadia.Derbey
@ 2007-08-31 11:24 ` Nadia.Derbey
2007-08-31 11:24 ` [RFC][PATCH 3/6] Removing the ipc_get() routine Nadia.Derbey
` (3 subsequent siblings)
5 siblings, 0 replies; 12+ messages in thread
From: Nadia.Derbey @ 2007-08-31 11:24 UTC (permalink / raw)
To: linux-kernel; +Cc: matthltc, Nadia Derbey
[-- Attachment #1: ipc_syscalls.patch --]
[-- Type: text/plain, Size: 14742 bytes --]
[PATCH 02/06]
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>
---
ipc/msg.c | 61 ++++++++++--------------------------
ipc/sem.c | 78 ++++++++++++++++++-----------------------------
ipc/shm.c | 75 ++++++++++++++++-----------------------------
ipc/util.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
ipc/util.h | 43 +++++++++++++++++++++++++
5 files changed, 217 insertions(+), 141 deletions(-)
Index: linux-2.6.23-rc2/ipc/util.h
===================================================================
--- linux-2.6.23-rc2.orig/ipc/util.h 2007-08-31 11:29:21.000000000 +0200
+++ linux-2.6.23-rc2/ipc/util.h 2007-08-31 11:38:50.000000000 +0200
@@ -35,6 +35,35 @@ struct ipc_ids {
struct idr ipcs_idr;
};
+/*
+ * Structure that holds the parameters needed by the ipc operations
+ * (see after)
+ */
+struct ipc_params {
+ key_t key;
+ int flg;
+ union {
+ size_t size; /* for shared memories */
+ int nsems; /* for semaphores */
+ } u; /* holds the getnew() specific param */
+};
+
+/*
+ * Structure that holds some ipc operations. This structure is used to unify
+ * the calls to sys_msgget(), sys_semget(), sys_shmget()
+ * . routine to call to create a new ipc object. Can be one of newque,
+ * newary, newseg
+ * . routine to call to call to check permissions for a new ipc object.
+ * Can be one of security_msg_associate, security_sem_associate,
+ * security_shm_associate
+ * . routine to call for an extra check if needed
+ */
+struct ipc_ops {
+ int (*getnew) (struct ipc_namespace *, struct ipc_params *);
+ int (*associate) (void *, int);
+ int (*more_checks) (void *, struct ipc_params *);
+};
+
struct seq_file;
void ipc_init_ids(struct ipc_ids *);
@@ -50,7 +79,6 @@ void __init ipc_init_proc_interface(cons
#define IPC_SHM_IDS 2
/* must be called with ids->mutex acquired.*/
-struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key);
int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int);
int ipc_get_maxid(struct ipc_ids *);
@@ -95,5 +123,18 @@ int ipc_parse_version (int *cmd);
extern void free_msg(struct msg_msg *msg);
extern struct msg_msg *load_msg(const void __user *src, int len);
extern int store_msg(void __user *dest, struct msg_msg *msg, int len);
+extern int ipcget_new(struct ipc_namespace *, struct ipc_ids *,
+ struct ipc_ops *, struct ipc_params *);
+extern int ipcget_public(struct ipc_namespace *, struct ipc_ids *,
+ struct ipc_ops *, struct ipc_params *);
+
+static inline int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
+ struct ipc_ops *ops, struct ipc_params *params)
+{
+ if (params->key == IPC_PRIVATE)
+ return ipcget_new(ns, ids, ops, params);
+ else
+ return ipcget_public(ns, ids, ops, params);
+}
#endif
Index: linux-2.6.23-rc2/ipc/util.c
===================================================================
--- linux-2.6.23-rc2.orig/ipc/util.c 2007-08-31 11:34:17.000000000 +0200
+++ linux-2.6.23-rc2/ipc/util.c 2007-08-31 11:40:03.000000000 +0200
@@ -197,7 +197,7 @@ void __init ipc_init_proc_interface(cons
* If key is found ipc contains its ipc structure
*/
-struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
+static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
{
struct kern_ipc_perm *ipc;
int next_id;
@@ -301,6 +301,105 @@ int ipc_addid(struct ipc_ids* ids, struc
}
/**
+ * ipcget_new - create a new ipc object
+ * @ns: namespace
+ * @ids: identifer set
+ * @ops: the actual creation routine to call
+ * @params: its parameters
+ *
+ * This routine is called sys_msgget, sys_semget() and sys_shmget() when
+ * the key is IPC_PRIVATE
+ */
+int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids,
+ struct ipc_ops *ops, struct ipc_params *params)
+{
+ int err;
+
+ err = idr_pre_get(&ids->ipcs_idr, GFP_KERNEL);
+
+ if (!err)
+ return -ENOMEM;
+
+ mutex_lock(&ids->mutex);
+ err = ops->getnew(ns, params);
+ mutex_unlock(&ids->mutex);
+
+ return err;
+}
+
+/**
+ * ipc_check_perms - check security and permissions for an IPC
+ * @ipcp: ipc permission set
+ * @ids: identifer set
+ * @ops: the actual security routine to call
+ * @params: its parameters
+ */
+static int ipc_check_perms(struct kern_ipc_perm *ipcp, struct ipc_ops *ops,
+ struct ipc_params *params)
+{
+ int err;
+
+ if (ipcperms(ipcp, params->flg))
+ err = -EACCES;
+ else {
+ err = ops->associate(ipcp, params->flg);
+ if (!err)
+ err = ipcp->id;
+ }
+
+ return err;
+}
+
+/**
+ * ipcget_public - get an ipc object or create a new one
+ * @ns: namespace
+ * @ids: identifer set
+ * @ops: the actual creation routine to call
+ * @params: its parameters
+ *
+ * This routine is called sys_msgget, sys_semget() and sys_shmget() when
+ * the key is not IPC_PRIVATE
+ */
+int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids,
+ struct ipc_ops *ops, struct ipc_params *params)
+{
+ struct kern_ipc_perm *ipcp;
+ int flg = params->flg;
+ int err;
+
+ err = idr_pre_get(&ids->ipcs_idr, GFP_KERNEL);
+
+ mutex_lock(&ids->mutex);
+ ipcp = ipc_findkey(ids, params->key);
+ if (ipcp == NULL) {
+ /* key not used */
+ if (!(flg & IPC_CREAT))
+ err = -ENOENT;
+ else if (!err)
+ err = -ENOMEM;
+ else
+ err = ops->getnew(ns, params);
+ } else {
+ /* ipc object has been locked by ipc_findkey() */
+
+ if (flg & IPC_CREAT && flg & IPC_EXCL)
+ err = -EEXIST;
+ else {
+ err = 0;
+ if (ops->more_checks)
+ err = ops->more_checks(ipcp, params);
+ if (!err)
+ err = ipc_check_perms(ipcp, ops, params);
+ }
+ ipc_unlock(ipcp);
+ }
+ mutex_unlock(&ids->mutex);
+
+ return err;
+}
+
+
+/**
* ipc_rmid - remove an IPC identifier
* @ids: identifier set
* @id: ipc perm structure containing the identifier to remove
Index: linux-2.6.23-rc2/ipc/msg.c
===================================================================
--- linux-2.6.23-rc2.orig/ipc/msg.c 2007-08-31 11:29:21.000000000 +0200
+++ linux-2.6.23-rc2/ipc/msg.c 2007-08-31 11:42:10.000000000 +0200
@@ -81,7 +81,7 @@ static struct ipc_ids init_msg_ids;
ipc_buildid(&msg_ids(ns), id, seq)
static void freeque(struct ipc_namespace *, struct msg_queue *);
-static int newque (struct ipc_namespace *ns, key_t key, int msgflg);
+static int newque(struct ipc_namespace *, struct ipc_params *);
#ifdef CONFIG_PROC_FS
static int sysvipc_msg_proc_show(struct seq_file *s, void *it);
#endif
@@ -144,10 +144,12 @@ static inline void msg_rmid(struct ipc_n
ipc_rmid(&msg_ids(ns), &s->q_perm);
}
-static int newque (struct ipc_namespace *ns, key_t key, int msgflg)
+static int newque(struct ipc_namespace *ns, struct ipc_params *params)
{
struct msg_queue *msq;
int id, retval;
+ key_t key = params->key;
+ int msgflg = params->flg;
msq = ipc_rcu_alloc(sizeof(*msq));
if (!msq)
@@ -264,56 +266,27 @@ static void freeque(struct ipc_namespace
ipc_rcu_putref(msq);
}
+static inline int msg_security(void *msq, int msgflg)
+{
+ return security_msg_queue_associate((struct msg_queue *) msq, msgflg);
+}
+
asmlinkage long sys_msgget(key_t key, int msgflg)
{
- struct msg_queue *msq;
- int ret;
struct ipc_namespace *ns;
+ struct ipc_ops msg_ops;
+ struct ipc_params msg_params;
ns = current->nsproxy->ipc_ns;
- ret = idr_pre_get(&msg_ids(ns).ipcs_idr, GFP_KERNEL);
-
- if (key == IPC_PRIVATE) {
- if (!ret)
- ret = -ENOMEM;
- else {
- mutex_lock(&msg_ids(ns).mutex);
- ret = newque(ns, key, msgflg);
- mutex_unlock(&msg_ids(ns).mutex);
- }
- } else {
- mutex_lock(&msg_ids(ns).mutex);
- msq = (struct msg_queue *) ipc_findkey(&msg_ids(ns), key);
- if (msq == NULL) {
- /* key not used */
- if (!(msgflg & IPC_CREAT))
- ret = -ENOENT;
- else if (!ret)
- ret = -ENOMEM;
- else
- ret = newque(ns, key, msgflg);
- } else {
- /* msq has been locked by ipc_findkey() */
+ msg_ops.getnew = newque;
+ msg_ops.associate = msg_security;
+ msg_ops.more_checks = NULL;
- if (msgflg & IPC_CREAT && msgflg & IPC_EXCL)
- ret = -EEXIST;
- else {
- if (ipcperms(&msq->q_perm, msgflg))
- ret = -EACCES;
- else {
- ret = security_msg_queue_associate(
- msq, msgflg);
- if (!ret)
- ret = msq->q_perm.id;
- }
- }
- msg_unlock(msq);
- }
- mutex_unlock(&msg_ids(ns).mutex);
- }
+ msg_params.key = key;
+ msg_params.flg = msgflg;
- return ret;
+ return ipcget(ns, &msg_ids(ns), &msg_ops, &msg_params);
}
static inline unsigned long
Index: linux-2.6.23-rc2/ipc/sem.c
===================================================================
--- linux-2.6.23-rc2.orig/ipc/sem.c 2007-08-31 11:29:21.000000000 +0200
+++ linux-2.6.23-rc2/ipc/sem.c 2007-08-31 11:43:58.000000000 +0200
@@ -97,7 +97,7 @@
static struct ipc_ids init_sem_ids;
-static int newary(struct ipc_namespace *, key_t, int, int);
+static int newary(struct ipc_namespace *, struct ipc_params *);
static void freeary(struct ipc_namespace *, struct sem_array *);
#ifdef CONFIG_PROC_FS
static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
@@ -214,12 +214,15 @@ static inline void sem_rmid(struct ipc_n
*/
#define IN_WAKEUP 1
-static int newary (struct ipc_namespace *ns, key_t key, int nsems, int semflg)
+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;
if (!nsems)
return -EINVAL;
@@ -263,61 +266,40 @@ static int newary (struct ipc_namespace
return sma->sem_perm.id;
}
-asmlinkage long sys_semget (key_t key, int nsems, int semflg)
+
+static inline int sem_security(void *sma, int semflg)
+{
+ return security_sem_associate((struct sem_array *) sma, semflg);
+}
+
+static inline int sem_more_checks(void *sma, struct ipc_params *params)
+{
+ if (params->u.nsems > ((struct sem_array *)sma)->sem_nsems)
+ return -EINVAL;
+
+ return 0;
+}
+
+asmlinkage long sys_semget(key_t key, int nsems, int semflg)
{
- int err;
- struct sem_array *sma;
struct ipc_namespace *ns;
+ struct ipc_ops sem_ops;
+ struct ipc_params sem_params;
ns = current->nsproxy->ipc_ns;
if (nsems < 0 || nsems > ns->sc_semmsl)
return -EINVAL;
- err = idr_pre_get(&sem_ids(ns).ipcs_idr, GFP_KERNEL);
+ sem_ops.getnew = newary;
+ sem_ops.associate = sem_security;
+ sem_ops.more_checks = sem_more_checks;
+
+ sem_params.key = key;
+ sem_params.flg = semflg;
+ sem_params.u.nsems = nsems;
- if (key == IPC_PRIVATE) {
- if (!err)
- err = -ENOMEM;
- else {
- mutex_lock(&sem_ids(ns).mutex);
- err = newary(ns, key, nsems, semflg);
- mutex_unlock(&sem_ids(ns).mutex);
- }
- } else {
- mutex_lock(&sem_ids(ns).mutex);
- sma = (struct sem_array *) ipc_findkey(&sem_ids(ns), key);
- if (sma == NULL) {
- /* key not used */
- if (!(semflg & IPC_CREAT))
- err = -ENOENT;
- else if (!err)
- err = -ENOMEM;
- else
- err = newary(ns, key, nsems, semflg);
- } else {
- /* sma has been locked by ipc_findkey() */
-
- if (semflg & IPC_CREAT && semflg & IPC_EXCL)
- err = -EEXIST;
- else {
- if (nsems > sma->sem_nsems)
- err = -EINVAL;
- else if (ipcperms(&sma->sem_perm, semflg))
- err = -EACCES;
- else {
- err = security_sem_associate(sma,
- semflg);
- if (!err)
- err = sma->sem_perm.id;
- }
- }
- sem_unlock(sma);
- }
- mutex_unlock(&sem_ids(ns).mutex);
- }
-
- return err;
+ return ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params);
}
/* Manage the doubly linked list sma->sem_pending as a FIFO:
Index: linux-2.6.23-rc2/ipc/shm.c
===================================================================
--- linux-2.6.23-rc2.orig/ipc/shm.c 2007-08-31 11:29:21.000000000 +0200
+++ linux-2.6.23-rc2/ipc/shm.c 2007-08-31 11:45:57.000000000 +0200
@@ -68,8 +68,7 @@ static struct ipc_ids init_shm_ids;
#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);
@@ -340,8 +339,11 @@ static struct vm_operations_struct shm_v
#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;
@@ -422,57 +424,36 @@ no_file:
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;
+
+ shm_params.key = key;
+ shm_params.flg = shmflg;
+ shm_params.u.size = size;
- 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() */
-
- 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)
--
^ permalink raw reply [flat|nested] 12+ messages in thread* [RFC][PATCH 3/6] Removing the ipc_get() routine
2007-08-31 11:24 [RFC][PATCH 0/6] An IPC implementation base on Linux IDRs Nadia.Derbey
2007-08-31 11:24 ` [RFC][PATCH 1/6] Storing ipcs into IDRs Nadia.Derbey
2007-08-31 11:24 ` [RFC][PATCH 2/6] Unifying the syscalls code Nadia.Derbey
@ 2007-08-31 11:24 ` Nadia.Derbey
2007-08-31 11:24 ` [RFC][PATCH 4/6] Integrating ipc_checkid() into ipc_lock() Nadia.Derbey
` (2 subsequent siblings)
5 siblings, 0 replies; 12+ messages in thread
From: Nadia.Derbey @ 2007-08-31 11:24 UTC (permalink / raw)
To: linux-kernel; +Cc: matthltc, Nadia Derbey
[-- Attachment #1: ipc_get.patch --]
[-- Type: text/plain, Size: 3402 bytes --]
[PATCH 03/06]
This is a trivial patch that removes the ipc_get() routine: it is replaced
by a call to idr_find().
Signed-off-by: Nadia Derbey <Nadia.Derbey@bull.net>
---
ipc/shm.c | 16 +++++++++++++---
ipc/util.c | 19 -------------------
ipc/util.h | 1 -
3 files changed, 13 insertions(+), 23 deletions(-)
Index: linux-2.6.23-rc2/ipc/util.h
===================================================================
--- linux-2.6.23-rc2.orig/ipc/util.h 2007-08-31 11:38:50.000000000 +0200
+++ linux-2.6.23-rc2/ipc/util.h 2007-08-31 11:59:11.000000000 +0200
@@ -103,7 +103,6 @@ void* ipc_rcu_alloc(int size);
void ipc_rcu_getref(void *ptr);
void ipc_rcu_putref(void *ptr);
-struct kern_ipc_perm* ipc_get(struct ipc_ids* ids, int id);
struct kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id);
void ipc_lock_by_ptr(struct kern_ipc_perm *ipcp);
void ipc_unlock(struct kern_ipc_perm* perm);
Index: linux-2.6.23-rc2/ipc/util.c
===================================================================
--- linux-2.6.23-rc2.orig/ipc/util.c 2007-08-31 11:40:03.000000000 +0200
+++ linux-2.6.23-rc2/ipc/util.c 2007-08-31 11:59:46.000000000 +0200
@@ -669,25 +669,6 @@ void ipc64_perm_to_ipc_perm (struct ipc6
out->seq = in->seq;
}
-/*
- * So far only shm_get_stat() calls ipc_get() via shm_get(), so ipc_get()
- * is called with shm_ids.mutex locked. Since grow_ary() is also called with
- * shm_ids.mutex down(for Shared Memory), there is no need to add read
- * barriers here to gurantee the writes in grow_ary() are seen in order
- * here (for Alpha).
- *
- * However ipc_get() itself does not necessary require ipc_ids.mutex down. So
- * if in the future ipc_get() is used by other places without ipc_ids.mutex
- * down, then ipc_get() needs read memery barriers as ipc_lock() does.
- */
-struct kern_ipc_perm *ipc_get(struct ipc_ids *ids, int id)
-{
- struct kern_ipc_perm *out;
- int lid = id % SEQ_MULTIPLIER;
- out = idr_find(&ids->ipcs_idr, lid);
- return out;
-}
-
struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id)
{
struct kern_ipc_perm *out;
Index: linux-2.6.23-rc2/ipc/shm.c
===================================================================
--- linux-2.6.23-rc2.orig/ipc/shm.c 2007-08-31 11:45:57.000000000 +0200
+++ linux-2.6.23-rc2/ipc/shm.c 2007-08-31 12:13:27.000000000 +0200
@@ -63,8 +63,6 @@ static struct ipc_ids init_shm_ids;
((struct shmid_kernel*)ipc_lock(&shm_ids(ns),id))
#define shm_unlock(shp) \
ipc_unlock(&(shp)->shm_perm)
-#define shm_get(ns, id) \
- ((struct shmid_kernel*)ipc_get(&shm_ids(ns),id))
#define shm_buildid(ns, id, seq) \
ipc_buildid(&shm_ids(ns), id, seq)
@@ -562,7 +560,19 @@ static void shm_get_stat(struct ipc_name
struct shmid_kernel *shp;
struct inode *inode;
- shp = shm_get(ns, next_id);
+ /*
+ * idr_find() is called via shm_get(), so with shm_ids.mutex
+ * locked. Since ipc_addid() is also called with
+ * shm_ids.mutex down, there is no need to add read barriers
+ * here to gurantee the writes in ipc_addid() are seen in
+ * order here (for Alpha).
+ * However idr_find() itself does not necessary require
+ * ipc_ids.mutex down. So if idr_find() is used by other
+ * places without ipc_ids.mutex down, then it needs read
+ * read memory barriers as ipc_lock() does.
+ */
+
+ shp = idr_find(&shm_ids(ns).ipcs_idr, next_id);
if (shp == NULL)
continue;
--
^ permalink raw reply [flat|nested] 12+ messages in thread* [RFC][PATCH 4/6] Integrating ipc_checkid() into ipc_lock()
2007-08-31 11:24 [RFC][PATCH 0/6] An IPC implementation base on Linux IDRs Nadia.Derbey
` (2 preceding siblings ...)
2007-08-31 11:24 ` [RFC][PATCH 3/6] Removing the ipc_get() routine Nadia.Derbey
@ 2007-08-31 11:24 ` Nadia.Derbey
2007-08-31 11:24 ` [RFC][PATCH 5/6] Introducing the ipcid_to_idx macro Nadia.Derbey
2007-08-31 11:24 ` [RFC][PATCH 6/6] Inlining ipc_buildid() Nadia.Derbey
5 siblings, 0 replies; 12+ messages in thread
From: Nadia.Derbey @ 2007-08-31 11:24 UTC (permalink / raw)
To: linux-kernel; +Cc: matthltc, Nadia Derbey
[-- Attachment #1: ipc_lock_and_check.patch --]
[-- Type: text/plain, Size: 15524 bytes --]
[PATCH 04/06]
This patch introduces a new ipc_lock_check() routine interface:
. each time ipc_checkid() is called, this is done after calling ipc_lock().
ipc_checkid() is now called from inside ipc_lock_check().
Signed-off-by: Nadia Derbey <Nadia.Derbey@bull.net>
---
ipc/msg.c | 62 ++++++++++++++++++++----------------------
ipc/sem.c | 70 ++++++++++++++++++++++-------------------------
ipc/shm.c | 90 ++++++++++++++++++++++++++++++++-----------------------------
ipc/util.c | 23 +--------------
ipc/util.h | 40 ++++++++++++++++++++++++---
5 files changed, 149 insertions(+), 136 deletions(-)
Index: linux-2.6.23-rc2/ipc/util.h
===================================================================
--- linux-2.6.23-rc2.orig/ipc/util.h 2007-08-31 11:59:11.000000000 +0200
+++ linux-2.6.23-rc2/ipc/util.h 2007-08-31 12:26:31.000000000 +0200
@@ -103,11 +103,8 @@ void* ipc_rcu_alloc(int size);
void ipc_rcu_getref(void *ptr);
void ipc_rcu_putref(void *ptr);
-struct kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id);
-void ipc_lock_by_ptr(struct kern_ipc_perm *ipcp);
-void ipc_unlock(struct kern_ipc_perm* perm);
+struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int);
int ipc_buildid(struct ipc_ids* ids, int id, int seq);
-int ipc_checkid(struct ipc_ids* ids, struct kern_ipc_perm* ipcp, int uid);
void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
@@ -127,6 +124,41 @@ extern int ipcget_new(struct ipc_namespa
extern int ipcget_public(struct ipc_namespace *, struct ipc_ids *,
struct ipc_ops *, struct ipc_params *);
+static inline int ipc_checkid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp,
+ int uid)
+{
+ if (uid / SEQ_MULTIPLIER != ipcp->seq)
+ return 1;
+ return 0;
+}
+
+static inline void ipc_lock_by_ptr(struct kern_ipc_perm *perm)
+{
+ spin_lock(&perm->lock);
+}
+
+static inline void ipc_unlock(struct kern_ipc_perm *perm)
+{
+ spin_unlock(&perm->lock);
+}
+
+static inline struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids,
+ int id)
+{
+ struct kern_ipc_perm *out;
+
+ out = ipc_lock(ids, id);
+ if (IS_ERR(out))
+ return out;
+
+ if (ipc_checkid(ids, out, id)) {
+ spin_unlock(&out->lock);
+ return ERR_PTR(-EIDRM);
+ }
+
+ return out;
+}
+
static inline int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
struct ipc_ops *ops, struct ipc_params *params)
{
Index: linux-2.6.23-rc2/ipc/util.c
===================================================================
--- linux-2.6.23-rc2.orig/ipc/util.c 2007-08-31 11:59:46.000000000 +0200
+++ linux-2.6.23-rc2/ipc/util.c 2007-08-31 12:29:32.000000000 +0200
@@ -678,7 +678,7 @@ struct kern_ipc_perm *ipc_lock(struct ip
out = idr_find(&ids->ipcs_idr, lid);
if (out == NULL) {
rcu_read_unlock();
- return NULL;
+ return ERR_PTR(-EINVAL);
}
spin_lock(&out->lock);
@@ -689,36 +689,17 @@ struct kern_ipc_perm *ipc_lock(struct ip
if (out->deleted) {
spin_unlock(&out->lock);
rcu_read_unlock();
- return NULL;
+ return ERR_PTR(-EINVAL);
}
return out;
}
-void ipc_lock_by_ptr(struct kern_ipc_perm *perm)
-{
- rcu_read_lock();
- spin_lock(&perm->lock);
-}
-
-void ipc_unlock(struct kern_ipc_perm* perm)
-{
- spin_unlock(&perm->lock);
- rcu_read_unlock();
-}
-
int ipc_buildid(struct ipc_ids* ids, int id, int seq)
{
return SEQ_MULTIPLIER*seq + id;
}
-int ipc_checkid(struct ipc_ids* ids, struct kern_ipc_perm* ipcp, int uid)
-{
- if(uid/SEQ_MULTIPLIER != ipcp->seq)
- return 1;
- return 0;
-}
-
#ifdef __ARCH_WANT_IPC_PARSE_VERSION
Index: linux-2.6.23-rc2/ipc/msg.c
===================================================================
--- linux-2.6.23-rc2.orig/ipc/msg.c 2007-08-31 11:42:10.000000000 +0200
+++ linux-2.6.23-rc2/ipc/msg.c 2007-08-31 12:33:38.000000000 +0200
@@ -73,10 +73,7 @@ static struct ipc_ids init_msg_ids;
#define msg_ids(ns) (*((ns)->ids[IPC_MSG_IDS]))
-#define msg_lock(ns, id) ((struct msg_queue*)ipc_lock(&msg_ids(ns), id))
#define msg_unlock(msq) ipc_unlock(&(msq)->q_perm)
-#define msg_checkid(ns, msq, msgid) \
- ipc_checkid(&msg_ids(ns), &msq->q_perm, msgid)
#define msg_buildid(ns, id, seq) \
ipc_buildid(&msg_ids(ns), id, seq)
@@ -139,6 +136,17 @@ void __init msg_init(void)
IPC_MSG_IDS, sysvipc_msg_proc_show);
}
+static inline struct msg_queue *msg_lock(struct ipc_namespace *ns, int id)
+{
+ return (struct msg_queue *) ipc_lock(&msg_ids(ns), id);
+}
+
+static inline struct msg_queue *msg_lock_check(struct ipc_namespace *ns,
+ int id)
+{
+ return (struct msg_queue *) ipc_lock_check(&msg_ids(ns), id);
+}
+
static inline void msg_rmid(struct ipc_namespace *ns, struct msg_queue *s)
{
ipc_rmid(&msg_ids(ns), &s->q_perm);
@@ -445,18 +453,15 @@ asmlinkage long sys_msgctl(int msqid, in
if (!buf)
return -EFAULT;
- memset(&tbuf, 0, sizeof(tbuf));
-
- msq = msg_lock(ns, msqid);
- if (msq == NULL)
- return -EINVAL;
-
if (cmd == MSG_STAT) {
+ msq = msg_lock(ns, msqid);
+ if (IS_ERR(msq))
+ return PTR_ERR(msq);
success_return = msq->q_perm.id;
} else {
- err = -EIDRM;
- if (msg_checkid(ns, msq, msqid))
- goto out_unlock;
+ msq = msg_lock_check(ns, msqid);
+ if (IS_ERR(msq))
+ return PTR_ERR(msq);
success_return = 0;
}
err = -EACCES;
@@ -467,6 +472,8 @@ asmlinkage long sys_msgctl(int msqid, in
if (err)
goto out_unlock;
+ memset(&tbuf, 0, sizeof(tbuf));
+
kernel_to_ipc64_perm(&msq->q_perm, &tbuf.msg_perm);
tbuf.msg_stime = msq->q_stime;
tbuf.msg_rtime = msq->q_rtime;
@@ -494,14 +501,12 @@ asmlinkage long sys_msgctl(int msqid, in
}
mutex_lock(&msg_ids(ns).mutex);
- msq = msg_lock(ns, msqid);
- err = -EINVAL;
- if (msq == NULL)
+ msq = msg_lock_check(ns, msqid);
+ if (IS_ERR(msq)) {
+ err = PTR_ERR(msq);
goto out_up;
+ }
- err = -EIDRM;
- if (msg_checkid(ns, msq, msqid))
- goto out_unlock_up;
ipcp = &msq->q_perm;
err = audit_ipc_obj(ipcp);
@@ -644,14 +649,11 @@ long do_msgsnd(int msqid, long mtype, vo
msg->m_type = mtype;
msg->m_ts = msgsz;
- msq = msg_lock(ns, msqid);
- err = -EINVAL;
- if (msq == NULL)
+ msq = msg_lock_check(ns, msqid);
+ if (IS_ERR(msq)) {
+ err = PTR_ERR(msq);
goto out_free;
-
- err= -EIDRM;
- if (msg_checkid(ns, msq, msqid))
- goto out_unlock_free;
+ }
for (;;) {
struct msg_sender s;
@@ -758,13 +760,9 @@ long do_msgrcv(int msqid, long *pmtype,
mode = convert_mode(&msgtyp, msgflg);
ns = current->nsproxy->ipc_ns;
- msq = msg_lock(ns, msqid);
- if (msq == NULL)
- return -EINVAL;
-
- msg = ERR_PTR(-EIDRM);
- if (msg_checkid(ns, msq, msqid))
- goto out_unlock;
+ msq = msg_lock_check(ns, msqid);
+ if (IS_ERR(msq))
+ return PTR_ERR(msq);
for (;;) {
struct msg_receiver msr_d;
Index: linux-2.6.23-rc2/ipc/sem.c
===================================================================
--- linux-2.6.23-rc2.orig/ipc/sem.c 2007-08-31 11:43:58.000000000 +0200
+++ linux-2.6.23-rc2/ipc/sem.c 2007-08-31 12:38:20.000000000 +0200
@@ -88,7 +88,6 @@
#define sem_ids(ns) (*((ns)->ids[IPC_SEM_IDS]))
-#define sem_lock(ns, id) ((struct sem_array*)ipc_lock(&sem_ids(ns), id))
#define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm)
#define sem_checkid(ns, sma, semid) \
ipc_checkid(&sem_ids(ns),&sma->sem_perm,semid)
@@ -175,6 +174,17 @@ void __init sem_init (void)
IPC_SEM_IDS, sysvipc_sem_proc_show);
}
+static inline struct sem_array *sem_lock(struct ipc_namespace *ns, int id)
+{
+ return (struct sem_array *) ipc_lock(&sem_ids(ns), id);
+}
+
+static inline struct sem_array *sem_lock_check(struct ipc_namespace *ns,
+ int id)
+{
+ return (struct sem_array *) ipc_lock_check(&sem_ids(ns), id);
+}
+
static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
{
ipc_rmid(&sem_ids(ns), &s->sem_perm);
@@ -599,11 +609,9 @@ static int semctl_nolock(struct ipc_name
struct semid64_ds tbuf;
int id;
- memset(&tbuf,0,sizeof(tbuf));
-
sma = sem_lock(ns, semid);
- if(sma == NULL)
- return -EINVAL;
+ if (IS_ERR(sma))
+ return PTR_ERR(sma);
err = -EACCES;
if (ipcperms (&sma->sem_perm, S_IRUGO))
@@ -615,6 +623,8 @@ static int semctl_nolock(struct ipc_name
id = sma->sem_perm.id;
+ memset(&tbuf, 0, sizeof(tbuf));
+
kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);
tbuf.sem_otime = sma->sem_otime;
tbuf.sem_ctime = sma->sem_ctime;
@@ -643,16 +653,12 @@ static int semctl_main(struct ipc_namesp
ushort* sem_io = fast_sem_io;
int nsems;
- sma = sem_lock(ns, semid);
- if(sma==NULL)
- return -EINVAL;
+ sma = sem_lock_check(ns, semid);
+ if (IS_ERR(sma))
+ return PTR_ERR(sma);
nsems = sma->sem_nsems;
- err=-EIDRM;
- if (sem_checkid(ns,sma,semid))
- goto out_unlock;
-
err = -EACCES;
if (ipcperms (&sma->sem_perm, (cmd==SETVAL||cmd==SETALL)?S_IWUGO:S_IRUGO))
goto out_unlock;
@@ -864,14 +870,10 @@ static int semctl_down(struct ipc_namesp
if(copy_semid_from_user (&setbuf, arg.buf, version))
return -EFAULT;
}
- sma = sem_lock(ns, semid);
- if(sma==NULL)
- return -EINVAL;
+ sma = sem_lock_check(ns, semid);
+ if (IS_ERR(sma))
+ return PTR_ERR(sma);
- if (sem_checkid(ns,sma,semid)) {
- err=-EIDRM;
- goto out_unlock;
- }
ipcp = &sma->sem_perm;
err = audit_ipc_obj(ipcp);
@@ -1055,15 +1057,10 @@ static struct sem_undo *find_undo(struct
goto out;
/* no undo structure around - allocate one. */
- sma = sem_lock(ns, semid);
- un = ERR_PTR(-EINVAL);
- if(sma==NULL)
- goto out;
- un = ERR_PTR(-EIDRM);
- if (sem_checkid(ns,sma,semid)) {
- sem_unlock(sma);
- goto out;
- }
+ sma = sem_lock_check(ns, semid);
+ if (IS_ERR(sma))
+ return ERR_PTR(PTR_ERR(sma));
+
nsems = sma->sem_nsems;
ipc_rcu_getref(sma);
sem_unlock(sma);
@@ -1169,15 +1166,14 @@ retry_undos:
} else
un = NULL;
- sma = sem_lock(ns, semid);
- error=-EINVAL;
- if(sma==NULL)
+ sma = sem_lock_check(ns, semid);
+ if (IS_ERR(sma)) {
+ error = PTR_ERR(sma);
goto out_free;
- error = -EIDRM;
- if (sem_checkid(ns,sma,semid))
- goto out_unlock_free;
+ }
+
/*
- * semid identifies are not unique - find_undo may have
+ * semid identifiers are not unique - find_undo may have
* allocated an undo structure, it was invalidated by an RMID
* and now a new array with received the same id. Check and retry.
*/
@@ -1243,7 +1239,7 @@ retry_undos:
}
sma = sem_lock(ns, semid);
- if(sma==NULL) {
+ if (IS_ERR(sma)) {
BUG_ON(queue.prev != NULL);
error = -EIDRM;
goto out_free;
@@ -1343,7 +1339,7 @@ void exit_sem(struct task_struct *tsk)
if(semid == -1)
continue;
sma = sem_lock(ns, semid);
- if (sma == NULL)
+ if (IS_ERR(sma))
continue;
if (u->semid == -1)
Index: linux-2.6.23-rc2/ipc/shm.c
===================================================================
--- linux-2.6.23-rc2.orig/ipc/shm.c 2007-08-31 12:13:27.000000000 +0200
+++ linux-2.6.23-rc2/ipc/shm.c 2007-08-31 12:43:28.000000000 +0200
@@ -59,8 +59,6 @@ static struct ipc_ids init_shm_ids;
#define shm_ids(ns) (*((ns)->ids[IPC_SHM_IDS]))
-#define shm_lock(ns, id) \
- ((struct shmid_kernel*)ipc_lock(&shm_ids(ns),id))
#define shm_unlock(shp) \
ipc_unlock(&(shp)->shm_perm)
#define shm_buildid(ns, id, seq) \
@@ -139,12 +137,15 @@ void __init shm_init (void)
IPC_SHM_IDS, sysvipc_shm_proc_show);
}
-static inline int shm_checkid(struct ipc_namespace *ns,
- struct shmid_kernel *s, int id)
+static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
{
- if (ipc_checkid(&shm_ids(ns), &s->shm_perm, id))
- return -EIDRM;
- return 0;
+ return (struct shmid_kernel *) ipc_lock(&shm_ids(ns), id);
+}
+
+static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns,
+ int id)
+{
+ return (struct shmid_kernel *) ipc_lock_check(&shm_ids(ns), id);
}
static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s)
@@ -167,7 +168,7 @@ static void shm_open(struct vm_area_stru
struct shmid_kernel *shp;
shp = shm_lock(sfd->ns, sfd->id);
- BUG_ON(!shp);
+ BUG_ON(IS_ERR(shp));
shp->shm_atim = get_seconds();
shp->shm_lprid = current->tgid;
shp->shm_nattch++;
@@ -213,7 +214,7 @@ static void shm_close(struct vm_area_str
mutex_lock(&shm_ids(ns).mutex);
/* remove from the list of attaches of the shm segment */
shp = shm_lock(ns, sfd->id);
- BUG_ON(!shp);
+ BUG_ON(IS_ERR(shp));
shp->shm_lprid = current->tgid;
shp->shm_dtim = get_seconds();
shp->shm_nattch--;
@@ -661,17 +662,25 @@ asmlinkage long sys_shmctl (int shmid, i
{
struct shmid64_ds tbuf;
int result;
- memset(&tbuf, 0, sizeof(tbuf));
- shp = shm_lock(ns, shmid);
- if(shp==NULL) {
- err = -EINVAL;
+
+ if (!buf) {
+ err = -EFAULT;
goto out;
- } else if (cmd == SHM_STAT) {
+ }
+
+ if (cmd == SHM_STAT) {
+ shp = shm_lock(ns, shmid);
+ if (IS_ERR(shp)) {
+ err = PTR_ERR(shp);
+ goto out;
+ }
result = shp->shm_perm.id;
} else {
- err = shm_checkid(ns, shp,shmid);
- if(err)
- goto out_unlock;
+ shp = shm_lock_check(ns, shmid);
+ if (IS_ERR(shp)) {
+ err = PTR_ERR(shp);
+ goto out;
+ }
result = 0;
}
err=-EACCES;
@@ -680,6 +689,7 @@ asmlinkage long sys_shmctl (int shmid, i
err = security_shm_shmctl(shp, cmd);
if (err)
goto out_unlock;
+ memset(&tbuf, 0, sizeof(tbuf));
kernel_to_ipc64_perm(&shp->shm_perm, &tbuf.shm_perm);
tbuf.shm_segsz = shp->shm_segsz;
tbuf.shm_atime = shp->shm_atim;
@@ -698,14 +708,11 @@ asmlinkage long sys_shmctl (int shmid, i
case SHM_LOCK:
case SHM_UNLOCK:
{
- shp = shm_lock(ns, shmid);
- if(shp==NULL) {
- err = -EINVAL;
+ shp = shm_lock_check(ns, shmid);
+ if (IS_ERR(shp)) {
+ err = PTR_ERR(shp);
goto out;
}
- err = shm_checkid(ns, shp,shmid);
- if(err)
- goto out_unlock;
err = audit_ipc_obj(&(shp->shm_perm));
if (err)
@@ -755,13 +762,11 @@ asmlinkage long sys_shmctl (int shmid, i
* the name away when the usage hits zero.
*/
mutex_lock(&shm_ids(ns).mutex);
- shp = shm_lock(ns, shmid);
- err = -EINVAL;
- if (shp == NULL)
+ shp = shm_lock_check(ns, shmid);
+ if (IS_ERR(shp)) {
+ err = PTR_ERR(shp);
goto out_up;
- err = shm_checkid(ns, shp, shmid);
- if(err)
- goto out_unlock_up;
+ }
err = audit_ipc_obj(&(shp->shm_perm));
if (err)
@@ -785,18 +790,21 @@ asmlinkage long sys_shmctl (int shmid, i
case IPC_SET:
{
+ if (!buf) {
+ err = -EFAULT;
+ goto out;
+ }
+
if (copy_shmid_from_user (&setbuf, buf, version)) {
err = -EFAULT;
goto out;
}
mutex_lock(&shm_ids(ns).mutex);
- shp = shm_lock(ns, shmid);
- err=-EINVAL;
- if(shp==NULL)
+ shp = shm_lock_check(ns, shmid);
+ if (IS_ERR(shp)) {
+ err = PTR_ERR(shp);
goto out_up;
- err = shm_checkid(ns, shp,shmid);
- if(err)
- goto out_unlock_up;
+ }
err = audit_ipc_obj(&(shp->shm_perm));
if (err)
goto out_unlock_up;
@@ -902,13 +910,11 @@ long do_shmat(int shmid, char __user *sh
* additional creator id...
*/
ns = current->nsproxy->ipc_ns;
- shp = shm_lock(ns, shmid);
- if(shp == NULL)
+ shp = shm_lock_check(ns, shmid);
+ if (IS_ERR(shp)) {
+ err = PTR_ERR(shp);
goto out;
-
- err = shm_checkid(ns, shp,shmid);
- if (err)
- goto out_unlock;
+ }
err = -EACCES;
if (ipcperms(&shp->shm_perm, acc_mode))
@@ -971,7 +977,7 @@ invalid:
out_nattch:
mutex_lock(&shm_ids(ns).mutex);
shp = shm_lock(ns, shmid);
- BUG_ON(!shp);
+ BUG_ON(IS_ERR(shp));
shp->shm_nattch--;
if(shp->shm_nattch == 0 &&
shp->shm_perm.mode & SHM_DEST)
--
^ permalink raw reply [flat|nested] 12+ messages in thread* [RFC][PATCH 5/6] Introducing the ipcid_to_idx macro
2007-08-31 11:24 [RFC][PATCH 0/6] An IPC implementation base on Linux IDRs Nadia.Derbey
` (3 preceding siblings ...)
2007-08-31 11:24 ` [RFC][PATCH 4/6] Integrating ipc_checkid() into ipc_lock() Nadia.Derbey
@ 2007-08-31 11:24 ` Nadia.Derbey
2007-08-31 11:24 ` [RFC][PATCH 6/6] Inlining ipc_buildid() Nadia.Derbey
5 siblings, 0 replies; 12+ messages in thread
From: Nadia.Derbey @ 2007-08-31 11:24 UTC (permalink / raw)
To: linux-kernel; +Cc: matthltc, Nadia Derbey
[-- Attachment #1: ipcid_to_idx.patch --]
[-- Type: text/plain, Size: 1613 bytes --]
[PATCH 05/06]
This is a trivial patch that changes all the (id % SEQ_MULTIPLIER) into a call
to the ipcid_to_idx(id) macro.
Signed-off-by: Nadia Derbey <Nadia.Derbey@bull.net>
---
ipc/util.c | 4 ++--
ipc/util.h | 2 ++
2 files changed, 4 insertions(+), 2 deletions(-)
Index: linux-2.6.23-rc2/ipc/util.h
===================================================================
--- linux-2.6.23-rc2.orig/ipc/util.h 2007-08-31 12:26:31.000000000 +0200
+++ linux-2.6.23-rc2/ipc/util.h 2007-08-31 12:53:30.000000000 +0200
@@ -78,6 +78,8 @@ void __init ipc_init_proc_interface(cons
#define IPC_MSG_IDS 1
#define IPC_SHM_IDS 2
+#define ipcid_to_idx(id) ((id) % SEQ_MULTIPLIER)
+
/* must be called with ids->mutex acquired.*/
int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int);
int ipc_get_maxid(struct ipc_ids *);
Index: linux-2.6.23-rc2/ipc/util.c
===================================================================
--- linux-2.6.23-rc2.orig/ipc/util.c 2007-08-31 12:29:32.000000000 +0200
+++ linux-2.6.23-rc2/ipc/util.c 2007-08-31 12:54:39.000000000 +0200
@@ -413,7 +413,7 @@ int ipcget_public(struct ipc_namespace *
void ipc_rmid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)
{
- int lid = ipcp->id % SEQ_MULTIPLIER;
+ int lid = ipcid_to_idx(ipcp->id);
idr_remove(&ids->ipcs_idr, lid);
@@ -672,7 +672,7 @@ void ipc64_perm_to_ipc_perm (struct ipc6
struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id)
{
struct kern_ipc_perm *out;
- int lid = id % SEQ_MULTIPLIER;
+ int lid = ipcid_to_idx(id);
rcu_read_lock();
out = idr_find(&ids->ipcs_idr, lid);
--
^ permalink raw reply [flat|nested] 12+ messages in thread* [RFC][PATCH 6/6] Inlining ipc_buildid()
2007-08-31 11:24 [RFC][PATCH 0/6] An IPC implementation base on Linux IDRs Nadia.Derbey
` (4 preceding siblings ...)
2007-08-31 11:24 ` [RFC][PATCH 5/6] Introducing the ipcid_to_idx macro Nadia.Derbey
@ 2007-08-31 11:24 ` Nadia.Derbey
5 siblings, 0 replies; 12+ messages in thread
From: Nadia.Derbey @ 2007-08-31 11:24 UTC (permalink / raw)
To: linux-kernel; +Cc: matthltc, Nadia Derbey
[-- Attachment #1: ipc_buildid.patch --]
[-- Type: text/plain, Size: 1724 bytes --]
[PATCH 06/06]
This is a trivial patch that changes the ipc_buildid() routine into a static
inline.
Signed-off-by: Nadia Derbey <Nadia.Derbey@bull.net>
---
ipc/util.c | 5 -----
ipc/util.h | 6 +++++-
2 files changed, 5 insertions(+), 6 deletions(-)
Index: linux-2.6.23-rc2/ipc/util.h
===================================================================
--- linux-2.6.23-rc2.orig/ipc/util.h 2007-08-31 12:53:30.000000000 +0200
+++ linux-2.6.23-rc2/ipc/util.h 2007-08-31 12:58:14.000000000 +0200
@@ -106,7 +106,6 @@ void ipc_rcu_getref(void *ptr);
void ipc_rcu_putref(void *ptr);
struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int);
-int ipc_buildid(struct ipc_ids* ids, int id, int seq);
void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
@@ -126,6 +125,11 @@ extern int ipcget_new(struct ipc_namespa
extern int ipcget_public(struct ipc_namespace *, struct ipc_ids *,
struct ipc_ops *, struct ipc_params *);
+static inline int ipc_buildid(struct ipc_ids *ids, int id, int seq)
+{
+ return SEQ_MULTIPLIER * seq + id;
+}
+
static inline int ipc_checkid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp,
int uid)
{
Index: linux-2.6.23-rc2/ipc/util.c
===================================================================
--- linux-2.6.23-rc2.orig/ipc/util.c 2007-08-31 12:54:39.000000000 +0200
+++ linux-2.6.23-rc2/ipc/util.c 2007-08-31 12:58:40.000000000 +0200
@@ -695,11 +695,6 @@ struct kern_ipc_perm *ipc_lock(struct ip
return out;
}
-int ipc_buildid(struct ipc_ids* ids, int id, int seq)
-{
- return SEQ_MULTIPLIER*seq + id;
-}
-
#ifdef __ARCH_WANT_IPC_PARSE_VERSION
--
^ permalink raw reply [flat|nested] 12+ messages in thread