* [RFC][PATCH 0/6] An IPC implementation base on Linux IDRs
@ 2007-08-31 11:24 Nadia.Derbey
2007-08-31 11:24 ` [RFC][PATCH 1/6] Storing ipcs into IDRs Nadia.Derbey
` (5 more replies)
0 siblings, 6 replies; 12+ messages in thread
From: Nadia.Derbey @ 2007-08-31 11:24 UTC (permalink / raw)
To: linux-kernel; +Cc: matthltc
A couple of months ago, I dropped a series of patches that introduced the
AKT framework (Automatic Kernel Tunables).
(see thread http://lkml.org/lkml/2007/1/16/16)
When reading the patches, people complained that I was trying to treat a
symptom, not the problem itself, and that it'd be better try to rewrite
things where necessary (better data structures / implementations).
(see http://lkml.org/lkml/2007/2/7/248)
I'm trying to achieve this for the IPC case, with this new series of patches:
after proposing a radix tree based implementation at the beginning of July,
I'm now proposing a new ipc implementation based on the Linux idr API.
In the current ipc implementation, the ipc structures pointers are stored
in an array that is resized each time the corresponding tunable is changed
(resized means that a new array is allocated with the new size, the old one
is copied into that new array and the old array is de-allocated).
With this new implementation, there is no need for the array resizing since
the size change becomes "natural".
With this completely dynamic implementation, it becomes possible to set the
kernel default maximum values higher in order to prevent early DoS feedback,
on configurations with a high amount of memory. Even if the maximum values are
huge, no memory space will be wasted, since the allocations are done "on
demand". This is not the case with the existing array based implementation:
an array of the maximum number of entries is allocated only if a single ipc
object is actually created.
These patches should be applied to 2.6.23-rc2, in the following order:
[PATCH 1/6]: ipc_idr.patch
[PATCH 2/6]: ipc_syscalls.patch
[PATCH 3/6]: ipc_get.patch
[PATCH 4/6]: ipc_lock_and_check.patch
[PATCH 5/6]: ipcid_to_idx.patch
[PATCH 6/6]: ipc_buildid.patch
--
Regards,
Nadia
^ permalink raw reply [flat|nested] 12+ messages in thread
* [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
* [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
* 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
end of thread, other threads:[~2007-09-10 20:10 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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-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
2007-09-10 20:08 ` Andrew Morton
2007-08-31 11:24 ` [RFC][PATCH 2/6] Unifying the syscalls code Nadia.Derbey
2007-08-31 11:24 ` [RFC][PATCH 3/6] Removing the ipc_get() routine Nadia.Derbey
2007-08-31 11:24 ` [RFC][PATCH 4/6] Integrating ipc_checkid() into ipc_lock() 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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox