[PATCH 01/06]
This patch introduces ipcs storage into radix trees. The main changes are:
. This ipc_ids structure is changed: the entries array is changed into a
root radix_tree structure.
. The grow_ary() routine is removed: it is not needed anymore when adding
an ipc structure, due to radix trees introduction
Signed-off-by: Nadia Derbey <[email protected]>
---
include/linux/ipc.h | 1
include/linux/msg.h | 1
include/linux/sem.h | 1
include/linux/shm.h | 1
ipc/msg.c | 64 ++++++-------
ipc/sem.c | 63 ++++++------
ipc/shm.c | 63 ++++++------
ipc/util.c | 253 ++++++++++++++++++++++++++++------------------------
ipc/util.h | 30 +-----
9 files changed, 248 insertions(+), 229 deletions(-)
Index: linux-2.6.21/ipc/util.h
===================================================================
--- linux-2.6.21.orig/ipc/util.h 2007-06-07 11:00:30.000000000 +0200
+++ linux-2.6.21/ipc/util.h 2007-06-07 11:07:22.000000000 +0200
@@ -13,6 +13,8 @@
#define USHRT_MAX 0xffff
#define SEQ_MULTIPLIER (IPCMNI)
+#define IPCS_MAX_SCAN_ENTRIES 256
+
void sem_init (void);
void msg_init (void);
void shm_init (void);
@@ -25,19 +27,15 @@ 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;
+ int first_free;
unsigned short seq;
unsigned short seq_max;
struct mutex mutex;
- struct ipc_id_ary nullentry;
- struct ipc_id_ary* entries;
+ struct radix_tree_root id_tree;
+ DECLARE_BITMAP(in_use_bitmap, IPCMNI);
};
struct seq_file;
@@ -46,7 +44,7 @@ struct seq_file;
#else
#define __ipc_init __init
#endif
-void __ipc_init ipc_init_ids(struct ipc_ids *ids, int size);
+void __ipc_init 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 *));
@@ -59,8 +57,8 @@ 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 *, key_t);
+int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int);
/* must be called with both locks acquired. */
struct kern_ipc_perm* ipc_rmid(struct ipc_ids* ids, int id);
@@ -83,18 +81,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.21/ipc/util.c
===================================================================
--- linux-2.6.21.orig/ipc/util.c 2007-06-07 11:00:30.000000000 +0200
+++ linux-2.6.21/ipc/util.c 2007-06-07 11:29:43.000000000 +0200
@@ -33,6 +33,7 @@
#include <linux/proc_fs.h>
#include <linux/audit.h>
#include <linux/nsproxy.h>
+#include <linux/radix-tree.h>
#include <asm/unistd.h>
@@ -51,6 +52,8 @@ struct ipc_namespace init_ipc_ns = {
},
};
+static void ipc_set_max_id(struct ipc_ids *);
+
#ifdef CONFIG_IPC_NS
static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns)
{
@@ -172,23 +175,18 @@ __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 radix tree.
*/
-void __ipc_init ipc_init_ids(struct ipc_ids* ids, int size)
+void __ipc_init 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->first_free = 0;
ids->seq = 0;
{
int seq_limit = INT_MAX/SEQ_MULTIPLIER;
@@ -198,17 +196,8 @@ void __ipc_init ipc_init_ids(struct ipc_
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;
+ INIT_RADIX_TREE(&ids->id_tree, GFP_KERNEL);
+ bitmap_zero(ids->in_use_bitmap, IPCMNI);
}
#ifdef CONFIG_PROC_FS
@@ -252,72 +241,94 @@ 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;
+ struct kern_ipc_perm *ipcs[IPCS_MAX_SCAN_ENTRIES];
+ int next_id;
+ int nb_ipcs, i;
+ int total;
+
+ next_id = 0;
+ for (total = 0; total < ids->in_use; total += nb_ipcs) {
+ nb_ipcs = radix_tree_gang_lookup(&ids->id_tree,
+ (void **) ipcs, next_id, IPCS_MAX_SCAN_ENTRIES);
+ if (nb_ipcs <= 0)
+ return NULL;
+ for (i = 0; i < nb_ipcs; i++) {
+ ipc = ipcs[i];
+ if (ipc->key == key) {
+ ipc_lock_by_ptr(ipc);
+ BUG_ON(ipc->key != key);
+ return ipc;
+ }
+ }
- /*
- * 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)
- continue;
- if (key == p->key)
- return id;
+ /* prepare for next id gang lookup */
+ next_id = (ipcs[nb_ipcs - 1]->id % SEQ_MULTIPLIER) + 1;
}
- return -1;
+
+ return NULL;
}
-/*
- * Requires ipc_ids.mutex locked
+/**
+ * ipc_set_max_id - set the last assigned id
+ * @ids: IPC identifier set
+ *
+ * Sets the new value for ids->max_id after max_id has been removed
+ * during ipc_rmid().
+ * When this routine is called ids->in_use has already been updated.
+ *
+ * Called with ipc_ids.mutex held.
*/
-static int grow_ary(struct ipc_ids* ids, int newsize)
+
+static void ipc_set_max_id(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;
+ unsigned long next_bit;
+ unsigned long next_zero;
+
+
+ if (ids->in_use == 0) {
+ ids->max_id = -1;
+ return;
}
- old = ids->entries;
- /*
- * 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 == ids->max_id) {
+ /* No hole in the ids */
+ ids->max_id--;
+ return;
+ }
- __ipc_fini_ids(ids, old);
- return newsize;
+ /* Look for the last assigned id */
+ next_bit = find_first_bit(ids->in_use_bitmap, ids->max_id);
+
+ do {
+ next_zero = find_next_zero_bit(ids->in_use_bitmap,
+ ids->max_id, next_bit);
+ if (next_zero >= ids->max_id) {
+ ids->max_id--;
+ return;
+ } else
+ next_bit = find_next_bit(ids->in_use_bitmap,
+ ids->max_id, next_zero);
+ } while (next_bit < ids->max_id);
+
+ ids->max_id = next_zero - 1;
+ return;
}
/**
* 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 radix tree. 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.
@@ -329,22 +340,33 @@ int ipc_addid(struct ipc_ids* ids, struc
{
int id;
- size = grow_ary(ids,size);
-
/*
* 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;
+
+ id = ids->first_free;
+
+ if (radix_tree_insert(&ids->id_tree, id, new))
+ return -1;
+
+ set_bit(id, ids->in_use_bitmap);
ids->in_use++;
if (id > ids->max_id)
ids->max_id = id;
+ if (ids->in_use == ids->max_id + 1) {
+ /* No hole in the ids */
+ ids->first_free = ids->in_use;
+ } else
+ ids->first_free = find_next_zero_bit(ids->in_use_bitmap,
+ ids->max_id, id);
+
new->cuid = new->uid = current->euid;
new->gid = new->cgid = current->egid;
@@ -356,7 +378,6 @@ found:
new->deleted = 0;
rcu_read_lock();
spin_lock(&new->lock);
- ids->entries->p[id] = new;
return id;
}
@@ -377,26 +398,27 @@ struct kern_ipc_perm* ipc_rmid(struct ip
{
struct kern_ipc_perm* p;
int lid = id % SEQ_MULTIPLIER;
- BUG_ON(lid >= ids->entries->size);
+ BUG_ON(lid > ids->max_id);
/*
* 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);
+ p = radix_tree_delete(&ids->id_tree, lid);
+ BUG_ON(p == NULL);
+
+ BUG_ON(ids->in_use <= 0);
ids->in_use--;
- if (lid == ids->max_id) {
- do {
- lid--;
- if(lid == -1)
- break;
- } while (ids->entries->p[lid] == NULL);
- ids->max_id = lid;
- }
+ clear_bit(lid, ids->in_use_bitmap);
+ if (lid < ids->first_free)
+ ids->first_free = lid;
+
+ if (lid == ids->max_id)
+ ipc_set_max_id(ids);
+
p->deleted = 1;
+
return p;
}
@@ -492,6 +514,7 @@ static inline int rcu_use_vmalloc(int si
void* ipc_rcu_alloc(int size)
{
void* out;
+
/*
* We prepend the allocation with the rcu struct, and
* workqueue if necessary (for vmalloc).
@@ -660,9 +683,9 @@ struct kern_ipc_perm* ipc_get(struct ipc
{
struct kern_ipc_perm* out;
int lid = id % SEQ_MULTIPLIER;
- if(lid >= ids->entries->size)
+ if (lid > ids->max_id)
return NULL;
- out = ids->entries->p[lid];
+ out = radix_tree_lookup(&ids->id_tree, lid);
return out;
}
@@ -670,15 +693,13 @@ struct kern_ipc_perm* ipc_lock(struct ip
{
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) {
+ if (lid > ids->max_id) {
rcu_read_unlock();
return NULL;
}
- out = entries->p[lid];
+ out = radix_tree_lookup(&ids->id_tree, lid);
if(out == NULL) {
rcu_read_unlock();
return NULL;
@@ -755,8 +776,9 @@ static void *sysvipc_proc_next(struct se
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 *ipcs[1];
+ int nb_ipcs;
ids = iter->ns->ids[iface->ids];
@@ -764,19 +786,18 @@ static void *sysvipc_proc_next(struct se
if (ipc && ipc != SEQ_START_TOKEN)
ipc_unlock(ipc);
- /*
- * 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;
- return ipc;
- }
- }
+ nb_ipcs = radix_tree_gang_lookup(&ids->id_tree, (void **) ipcs,
+ *pos, 1);
/* Out of range - return NULL to terminate iteration */
- return NULL;
+ if (nb_ipcs <= 0)
+ return NULL;
+
+ ipc = ipcs[0];
+ ipc_lock_by_ptr(ipc);
+ *pos = (ipc->id % SEQ_MULTIPLIER) + 1;
+
+ return ipc;
}
/*
@@ -788,8 +809,9 @@ 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;
+ struct kern_ipc_perm *ipcs[1];
+ int nb_ipcs;
ids = iter->ns->ids[iface->ids];
@@ -808,13 +830,16 @@ 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;
+ nb_ipcs = radix_tree_gang_lookup(&ids->id_tree, (void **) ipcs,
+ *pos - 1, 1);
+ if (nb_ipcs <= 0)
+ return NULL;
+
+ ipc = ipcs[0];
+ ipc_lock_by_ptr(ipc);
+ *pos = (ipc->id % SEQ_MULTIPLIER) + 1;
+
+ return ipc;
}
static void sysvipc_proc_stop(struct seq_file *s, void *it)
Index: linux-2.6.21/ipc/msg.c
===================================================================
--- linux-2.6.21.orig/ipc/msg.c 2007-06-07 11:00:30.000000000 +0200
+++ linux-2.6.21/ipc/msg.c 2007-06-07 11:28:16.000000000 +0200
@@ -93,7 +93,7 @@ static void __ipc_init __msg_init_ns(str
ns->msg_ctlmax = MSGMAX;
ns->msg_ctlmnb = MSGMNB;
ns->msg_ctlmni = MSGMNI;
- ipc_init_ids(ids, ns->msg_ctlmni);
+ ipc_init_ids(ids);
}
#ifdef CONFIG_IPC_NS
@@ -124,7 +124,6 @@ void msg_exit_ns(struct ipc_namespace *n
}
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;
}
@@ -164,7 +163,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;
@@ -175,7 +174,7 @@ static int newque (struct ipc_namespace
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)
@@ -227,9 +226,9 @@ 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.
+ * radix tree, 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)
@@ -257,7 +256,7 @@ 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 = -EPERM;
struct ipc_namespace *ns;
ns = current->nsproxy->ipc_ns;
@@ -265,26 +264,31 @@ asmlinkage long sys_msgget(key_t key, in
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 = newque(ns, key, msgflg);
- } else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) {
- ret = -EEXIST;
- } 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);
+ else {
+ msq = (struct msg_queue *) ipc_findkey(&msg_ids(ns), key);
+ if (msq == NULL) {
+ /* key not used */
+ if (!(msgflg & IPC_CREAT))
+ ret = -ENOENT;
+ 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);
@@ -446,7 +450,7 @@ asmlinkage long sys_msgctl(int msqid, in
if (!buf)
return -EFAULT;
- if (cmd == MSG_STAT && msqid >= msg_ids(ns).entries->size)
+ if (cmd == MSG_STAT && msqid > msg_ids(ns).max_id)
return -EINVAL;
memset(&tbuf, 0, sizeof(tbuf));
@@ -455,9 +459,9 @@ asmlinkage long sys_msgctl(int msqid, in
if (msq == NULL)
return -EINVAL;
- if (cmd == MSG_STAT) {
- success_return = msg_buildid(ns, msqid, msq->q_perm.seq);
- } else {
+ if (cmd == MSG_STAT)
+ success_return = msq->q_perm.id;
+ else {
err = -EIDRM;
if (msg_checkid(ns, msq, msqid))
goto out_unlock;
@@ -928,7 +932,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.21/ipc/sem.c
===================================================================
--- linux-2.6.21.orig/ipc/sem.c 2007-06-07 11:00:30.000000000 +0200
+++ linux-2.6.21/ipc/sem.c 2007-06-07 11:25:20.000000000 +0200
@@ -130,7 +130,7 @@ static void __ipc_init __sem_init_ns(str
ns->sc_semopm = SEMOPM;
ns->sc_semmni = SEMMNI;
ns->used_sems = 0;
- ipc_init_ids(ids, ns->sc_semmni);
+ ipc_init_ids(ids);
}
#ifdef CONFIG_IPC_NS
@@ -161,7 +161,6 @@ void sem_exit_ns(struct ipc_namespace *n
}
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;
}
@@ -246,7 +245,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;
@@ -255,12 +254,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 = -EINVAL;
struct sem_array *sma;
struct ipc_namespace *ns;
@@ -272,27 +271,33 @@ asmlinkage long sys_semget (key_t key, i
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
- err = newary(ns, key, nsems, semflg);
- } else if (semflg & IPC_CREAT && semflg & IPC_EXCL) {
- err = -EEXIST;
} 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;
+ sma = (struct sem_array *) ipc_findkey(&sem_ids(ns), key);
+ if (sma == NULL) {
+ /* key not used */
+ if (!(semflg & IPC_CREAT))
+ err = -ENOENT;
+ 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);
@@ -498,7 +503,6 @@ static void freeary (struct ipc_namespac
{
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()
@@ -521,12 +525,11 @@ static void freeary (struct ipc_namespac
q = n;
}
- /* Remove the semaphore set from the ID array*/
+ /* Remove the semaphore set from the ID radix tree */
sma = sem_rmid(ns, id);
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);
}
@@ -598,7 +601,7 @@ static int semctl_nolock(struct ipc_name
struct semid64_ds tbuf;
int id;
- if(semid >= sem_ids(ns).entries->size)
+ if (semid > sem_ids(ns).max_id)
return -EINVAL;
memset(&tbuf,0,sizeof(tbuf));
@@ -615,7 +618,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;
@@ -1405,7 +1408,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.21/ipc/shm.c
===================================================================
--- linux-2.6.21.orig/ipc/shm.c 2007-06-07 11:00:30.000000000 +0200
+++ linux-2.6.21/ipc/shm.c 2007-06-07 11:20:50.000000000 +0200
@@ -84,7 +84,7 @@ static void __ipc_init __shm_init_ns(str
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)
@@ -126,7 +126,6 @@ void shm_exit_ns(struct ipc_namespace *n
}
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;
}
@@ -186,7 +185,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_perm.id);
shm_unlock(shp);
if (!is_file_hugepages(shp->shm_file))
shmem_lock(shp->shm_file, 0, shp->mlock_user);
@@ -395,12 +394,13 @@ 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;
ns->shm_tot += numpages;
+ error = shp->shm_perm.id;
shm_unlock(shp);
- return shp->id;
+ return error;
no_id:
fput(file);
@@ -413,7 +413,7 @@ 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;
@@ -421,27 +421,32 @@ asmlinkage long sys_shmget (key_t key, s
mutex_lock(&shm_ids(ns).mutex);
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
- err = newseg(ns, key, shmflg, size);
- } else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) {
- err = -EEXIST;
} 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;
+ shp = (struct shmid_kernel *) ipc_findkey(&shm_ids(ns), key);
+ if (shp == NULL) {
+ if (!(shmflg & IPC_CREAT))
+ err = -ENOENT;
+ 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);
@@ -645,9 +650,7 @@ asmlinkage long sys_shmctl (int shmid, i
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);
+ result = shp->shm_perm.id;
} else {
err = shm_checkid(ns, shp,shmid);
if(err)
@@ -919,7 +922,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;
@@ -1089,7 +1092,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,
Index: linux-2.6.21/include/linux/ipc.h
===================================================================
--- linux-2.6.21.orig/include/linux/ipc.h 2007-06-07 11:00:29.000000000 +0200
+++ linux-2.6.21/include/linux/ipc.h 2007-06-07 11:14:20.000000000 +0200
@@ -60,6 +60,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.21/include/linux/sem.h
===================================================================
--- linux-2.6.21.orig/include/linux/sem.h 2007-06-07 11:00:29.000000000 +0200
+++ linux-2.6.21/include/linux/sem.h 2007-06-07 11:15:16.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.21/include/linux/shm.h
===================================================================
--- linux-2.6.21.orig/include/linux/shm.h 2007-06-07 11:00:29.000000000 +0200
+++ linux-2.6.21/include/linux/shm.h 2007-06-07 11:16:06.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.21/include/linux/msg.h
===================================================================
--- linux-2.6.21.orig/include/linux/msg.h 2007-06-07 11:00:29.000000000 +0200
+++ linux-2.6.21/include/linux/msg.h 2007-06-07 11:16:31.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 */
--
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]