From 48dea404ed01869313f1908cca8a15774dcd8ee5 Mon Sep 17 00:00:00 2001 From: Pierre Peiffer Date: Tue, 29 Apr 2008 01:00:35 -0700 Subject: IPC: use ipc_buildid() directly from ipc_addid() By continuing to consolidate a little the IPC code, each id can be built directly in ipc_addid() instead of having it built from each callers of ipc_addid() And I also remove shm_addid() in order to have, as much as possible, the same code for shm/sem/msg. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Pierre Peiffer Cc: Nadia Derbey Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/util.c | 1 + 1 file changed, 1 insertion(+) (limited to 'ipc/util.c') diff --git a/ipc/util.c b/ipc/util.c index fd1b50da9db8..cb017c7b9370 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -231,6 +231,7 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) if(ids->seq > ids->seq_max) ids->seq = 0; + new->id = ipc_buildid(id, new->seq); spin_lock_init(&new->lock); new->deleted = 0; rcu_read_lock(); -- cgit v1.2.3 From 4d89dc6ab2711258bfd12c72d753f3ad56b244e2 Mon Sep 17 00:00:00 2001 From: Nadia Derbey Date: Tue, 29 Apr 2008 01:00:40 -0700 Subject: ipc: scale msgmni to the number of ipc namespaces Since all the namespaces see the same amount of memory (the total one) this patch introduces a new variable that counts the ipc namespaces and divides msg_ctlmni by this counter. Signed-off-by: Nadia Derbey Cc: Yasunori Goto Cc: Matt Helsley Cc: Mingming Cao Cc: Pierre Peiffer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/util.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'ipc/util.c') diff --git a/ipc/util.c b/ipc/util.c index cb017c7b9370..c27f0e92f489 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -52,6 +52,9 @@ struct ipc_namespace init_ipc_ns = { }, }; +atomic_t nr_ipc_ns = ATOMIC_INIT(1); + + /** * ipc_init - initialise IPC subsystem * -- cgit v1.2.3 From b6b337ad1c1d6fe11b09b35d75464b84b3e11f07 Mon Sep 17 00:00:00 2001 From: Nadia Derbey Date: Tue, 29 Apr 2008 01:00:42 -0700 Subject: ipc: recompute msgmni on memory add / remove Introduce the registration of a callback routine that recomputes msg_ctlmni upon memory add / remove. A single notifier block is registered in the hotplug memory chain for all the ipc namespaces. Since the ipc namespaces are not linked together, they have their own notification chain: one notifier_block is defined per ipc namespace. Each time an ipc namespace is created (removed) it registers (unregisters) its notifier block in (from) the ipcns chain. The callback routine registered in the memory chain invokes the ipcns notifier chain with the IPCNS_LOWMEM event. Each callback routine registered in the ipcns namespace, in turn, recomputes msgmni for the owning namespace. Signed-off-by: Nadia Derbey Cc: Yasunori Goto Cc: Matt Helsley Cc: Mingming Cao Cc: Pierre Peiffer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/util.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'ipc/util.c') diff --git a/ipc/util.c b/ipc/util.c index c27f0e92f489..2d545d7144a7 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -55,11 +56,41 @@ struct ipc_namespace init_ipc_ns = { atomic_t nr_ipc_ns = ATOMIC_INIT(1); +#ifdef CONFIG_MEMORY_HOTPLUG + +static int ipc_memory_callback(struct notifier_block *self, + unsigned long action, void *arg) +{ + switch (action) { + case MEM_ONLINE: /* memory successfully brought online */ + case MEM_OFFLINE: /* or offline: it's time to recompute msgmni */ + /* + * This is done by invoking the ipcns notifier chain with the + * IPC_MEMCHANGED event. + */ + ipcns_notify(IPCNS_MEMCHANGED); + break; + case MEM_GOING_ONLINE: + case MEM_GOING_OFFLINE: + case MEM_CANCEL_ONLINE: + case MEM_CANCEL_OFFLINE: + default: + break; + } + + return NOTIFY_OK; +} + +#endif /* CONFIG_MEMORY_HOTPLUG */ + /** * ipc_init - initialise IPC subsystem * * The various system5 IPC resources (semaphores, messages and shared * memory) are initialised + * A callback routine is registered into the memory hotplug notifier + * chain: since msgmni scales to lowmem this callback routine will be + * called upon successful memory add / remove to recompute msmgni. */ static int __init ipc_init(void) @@ -67,6 +98,8 @@ static int __init ipc_init(void) sem_init(); msg_init(); shm_init(); + hotplug_memory_notifier(ipc_memory_callback, IPC_CALLBACK_PRI); + register_ipcns_notifier(&init_ipc_ns); return 0; } __initcall(ipc_init); -- cgit v1.2.3 From 424450c1dbe72b6e2637e91108417d7d9580c4c3 Mon Sep 17 00:00:00 2001 From: Nadia Derbey Date: Tue, 29 Apr 2008 01:00:43 -0700 Subject: ipc: invoke the ipcns notifier chain as a work item Make the memory hotplug chain's mutex held for a shorter time: when memory is offlined or onlined a work item is added to the global workqueue. When the work item is run, it notifies the ipcns notifier chain with the IPCNS_MEMCHANGED event. Signed-off-by: Nadia Derbey Cc: Yasunori Goto Cc: Matt Helsley Cc: Mingming Cao Cc: Pierre Peiffer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/util.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'ipc/util.c') diff --git a/ipc/util.c b/ipc/util.c index 2d545d7144a7..7a5d5e393c4b 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -58,6 +58,14 @@ atomic_t nr_ipc_ns = ATOMIC_INIT(1); #ifdef CONFIG_MEMORY_HOTPLUG +static void ipc_memory_notifier(struct work_struct *work) +{ + ipcns_notify(IPCNS_MEMCHANGED); +} + +static DECLARE_WORK(ipc_memory_wq, ipc_memory_notifier); + + static int ipc_memory_callback(struct notifier_block *self, unsigned long action, void *arg) { @@ -67,8 +75,13 @@ static int ipc_memory_callback(struct notifier_block *self, /* * This is done by invoking the ipcns notifier chain with the * IPC_MEMCHANGED event. + * In order not to keep the lock on the hotplug memory chain + * for too long, queue a work item that will, when waken up, + * activate the ipcns notification chain. + * No need to keep several ipc work items on the queue. */ - ipcns_notify(IPCNS_MEMCHANGED); + if (!work_pending(&ipc_memory_wq)) + schedule_work(&ipc_memory_wq); break; case MEM_GOING_ONLINE: case MEM_GOING_OFFLINE: -- cgit v1.2.3 From 8f4a3809c18ff3107bdbb1fabe3f4e5d2a928321 Mon Sep 17 00:00:00 2001 From: Pierre Peiffer Date: Tue, 29 Apr 2008 01:00:51 -0700 Subject: IPC: introduce ipc_update_perm() The IPC_SET command performs the same permission setting for all IPCs. This patch introduces a common ipc_update_perm() function to update these permissions and makes use of it for all IPCs. Signed-off-by: Pierre Peiffer Acked-by: Serge Hallyn Cc: Nadia Derbey Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/util.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'ipc/util.c') diff --git a/ipc/util.c b/ipc/util.c index 7a5d5e393c4b..dc8943aa9719 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -811,6 +811,19 @@ int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids, return ipcget_public(ns, ids, ops, params); } +/** + * ipc_update_perm - update the permissions of an IPC. + * @in: the permission given as input. + * @out: the permission of the ipc to set. + */ +void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out) +{ + out->uid = in->uid; + out->gid = in->gid; + out->mode = (out->mode & ~S_IRWXUGO) + | (in->mode & S_IRWXUGO); +} + #ifdef __ARCH_WANT_IPC_PARSE_VERSION -- cgit v1.2.3 From a5f75e7f256f75759ec3d6dbef0ba932f1b397d2 Mon Sep 17 00:00:00 2001 From: Pierre Peiffer Date: Tue, 29 Apr 2008 01:00:54 -0700 Subject: IPC: consolidate all xxxctl_down() functions semctl_down(), msgctl_down() and shmctl_down() are used to handle the same set of commands for each kind of IPC. They all start to do the same job (they retrieve the ipc and do some permission checks) before handling the commands on their own. This patch proposes to consolidate this by moving these same pieces of code into one common function called ipcctl_pre_down(). It simplifies a little these xxxctl_down() functions and increases a little the maintainability. Signed-off-by: Pierre Peiffer Acked-by: Serge Hallyn Cc: Nadia Derbey Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/util.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'ipc/util.c') diff --git a/ipc/util.c b/ipc/util.c index dc8943aa9719..c4f1d33b89e4 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -824,6 +824,57 @@ void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out) | (in->mode & S_IRWXUGO); } +/** + * ipcctl_pre_down - retrieve an ipc and check permissions for some IPC_XXX cmd + * @ids: the table of ids where to look for the ipc + * @id: the id of the ipc to retrieve + * @cmd: the cmd to check + * @perm: the permission to set + * @extra_perm: one extra permission parameter used by msq + * + * This function does some common audit and permissions check for some IPC_XXX + * cmd and is called from semctl_down, shmctl_down and msgctl_down. + * It must be called without any lock held and + * - retrieves the ipc with the given id in the given table. + * - performs some audit and permission check, depending on the given cmd + * - returns the ipc with both ipc and rw_mutex locks held in case of success + * or an err-code without any lock held otherwise. + */ +struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd, + struct ipc64_perm *perm, int extra_perm) +{ + struct kern_ipc_perm *ipcp; + int err; + + down_write(&ids->rw_mutex); + ipcp = ipc_lock_check_down(ids, id); + if (IS_ERR(ipcp)) { + err = PTR_ERR(ipcp); + goto out_up; + } + + err = audit_ipc_obj(ipcp); + if (err) + goto out_unlock; + + if (cmd == IPC_SET) { + err = audit_ipc_set_perm(extra_perm, perm->uid, + perm->gid, perm->mode); + if (err) + goto out_unlock; + } + if (current->euid == ipcp->cuid || + current->euid == ipcp->uid || capable(CAP_SYS_ADMIN)) + return ipcp; + + err = -EPERM; +out_unlock: + ipc_unlock(ipcp); +out_up: + up_write(&ids->rw_mutex); + return ERR_PTR(err); +} + #ifdef __ARCH_WANT_IPC_PARSE_VERSION -- cgit v1.2.3 From 44f564a4bf6ac70f2a84806203045cf515bc9367 Mon Sep 17 00:00:00 2001 From: "Zhang, Yanmin" Date: Tue, 29 Apr 2008 01:00:55 -0700 Subject: ipc: add definitions of USHORT_MAX and others Add definitions of USHORT_MAX and others into kernel. ipc uses it and slub implementation might also use it. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Zhang Yanmin Reviewed-by: Christoph Lameter Cc: Nadia Derbey Cc: "Pierre Peiffer" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ipc/util.c') diff --git a/ipc/util.c b/ipc/util.c index c4f1d33b89e4..4c465cb22360 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -133,8 +133,8 @@ void ipc_init_ids(struct ipc_ids *ids) ids->seq = 0; { int seq_limit = INT_MAX/SEQ_MULTIPLIER; - if(seq_limit > USHRT_MAX) - ids->seq_max = USHRT_MAX; + if (seq_limit > USHORT_MAX) + ids->seq_max = USHORT_MAX; else ids->seq_max = seq_limit; } -- cgit v1.2.3 From 6a6375db13703b42dd51b28576d444bb73c541b9 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Tue, 29 Apr 2008 01:02:12 -0700 Subject: sysvipc: use non-racy method for proc entries creation Use proc_create_data() to make sure that ->proc_fops and ->data be setup before gluing PDE to main tree. Signed-off-by: Denis V. Lunev Cc: Alexey Dobriyan Cc: "Eric W. Biederman" Cc: Nadia Derbey Cc: Pierre Peiffer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/util.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'ipc/util.c') diff --git a/ipc/util.c b/ipc/util.c index 4c465cb22360..3339177b336c 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -165,13 +165,12 @@ void __init ipc_init_proc_interface(const char *path, const char *header, iface->ids = ids; iface->show = show; - pde = create_proc_entry(path, - S_IRUGO, /* world readable */ - NULL /* parent dir */); - if (pde) { - pde->data = iface; - pde->proc_fops = &sysvipc_proc_fops; - } else { + pde = proc_create_data(path, + S_IRUGO, /* world readable */ + NULL, /* parent dir */ + &sysvipc_proc_fops, + iface); + if (!pde) { kfree(iface); } } -- cgit v1.2.3