aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
Diffstat (limited to 'ipc')
-rw-r--r--ipc/Makefile3
-rw-r--r--ipc/ipcns_notifier.c71
-rw-r--r--ipc/msg.c2
-rw-r--r--ipc/namespace.c11
-rw-r--r--ipc/util.c33
-rw-r--r--ipc/util.h2
6 files changed, 120 insertions, 2 deletions
diff --git a/ipc/Makefile b/ipc/Makefile
index 5fc5e33ea047..388e4d259f02 100644
--- a/ipc/Makefile
+++ b/ipc/Makefile
@@ -3,7 +3,8 @@
3# 3#
4 4
5obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o 5obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o
6obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o 6obj_mem-$(CONFIG_MEMORY_HOTPLUG) += ipcns_notifier.o
7obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o $(obj_mem-y)
7obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o 8obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o
8obj_mq-$(CONFIG_COMPAT) += compat_mq.o 9obj_mq-$(CONFIG_COMPAT) += compat_mq.o
9obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y) 10obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y)
diff --git a/ipc/ipcns_notifier.c b/ipc/ipcns_notifier.c
new file mode 100644
index 000000000000..0786af6ce3ec
--- /dev/null
+++ b/ipc/ipcns_notifier.c
@@ -0,0 +1,71 @@
1/*
2 * linux/ipc/ipcns_notifier.c
3 * Copyright (C) 2007 BULL SA. Nadia Derbey
4 *
5 * Notification mechanism for ipc namespaces:
6 * The callback routine registered in the memory chain invokes the ipcns
7 * notifier chain with the IPCNS_MEMCHANGED event.
8 * Each callback routine registered in the ipcns namespace recomputes msgmni
9 * for the owning namespace.
10 */
11
12#include <linux/msg.h>
13#include <linux/rcupdate.h>
14#include <linux/notifier.h>
15#include <linux/nsproxy.h>
16#include <linux/ipc_namespace.h>
17
18#include "util.h"
19
20
21
22static BLOCKING_NOTIFIER_HEAD(ipcns_chain);
23
24
25static int ipcns_callback(struct notifier_block *self,
26 unsigned long action, void *arg)
27{
28 struct ipc_namespace *ns;
29
30 switch (action) {
31 case IPCNS_MEMCHANGED: /* amount of lowmem has changed */
32 /*
33 * It's time to recompute msgmni
34 */
35 ns = container_of(self, struct ipc_namespace, ipcns_nb);
36 /*
37 * No need to get a reference on the ns: the 1st job of
38 * free_ipc_ns() is to unregister the callback routine.
39 * blocking_notifier_chain_unregister takes the wr lock to do
40 * it.
41 * When this callback routine is called the rd lock is held by
42 * blocking_notifier_call_chain.
43 * So the ipc ns cannot be freed while we are here.
44 */
45 recompute_msgmni(ns);
46 break;
47 default:
48 break;
49 }
50
51 return NOTIFY_OK;
52}
53
54int register_ipcns_notifier(struct ipc_namespace *ns)
55{
56 memset(&ns->ipcns_nb, 0, sizeof(ns->ipcns_nb));
57 ns->ipcns_nb.notifier_call = ipcns_callback;
58 ns->ipcns_nb.priority = IPCNS_CALLBACK_PRI;
59 return blocking_notifier_chain_register(&ipcns_chain, &ns->ipcns_nb);
60}
61
62int unregister_ipcns_notifier(struct ipc_namespace *ns)
63{
64 return blocking_notifier_chain_unregister(&ipcns_chain,
65 &ns->ipcns_nb);
66}
67
68int ipcns_notify(unsigned long val)
69{
70 return blocking_notifier_call_chain(&ipcns_chain, val, NULL);
71}
diff --git a/ipc/msg.c b/ipc/msg.c
index be8449d48a8e..7d9b0694c743 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -84,7 +84,7 @@ static int sysvipc_msg_proc_show(struct seq_file *s, void *it);
84 * Also take into account the number of nsproxies created so far. 84 * Also take into account the number of nsproxies created so far.
85 * This should be done staying within the (MSGMNI , IPCMNI/nr_ipc_ns) range. 85 * This should be done staying within the (MSGMNI , IPCMNI/nr_ipc_ns) range.
86 */ 86 */
87static void recompute_msgmni(struct ipc_namespace *ns) 87void recompute_msgmni(struct ipc_namespace *ns)
88{ 88{
89 struct sysinfo i; 89 struct sysinfo i;
90 unsigned long allowed; 90 unsigned long allowed;
diff --git a/ipc/namespace.c b/ipc/namespace.c
index fe3c97aa99dc..f7a35be2e771 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -26,6 +26,8 @@ static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns)
26 msg_init_ns(ns); 26 msg_init_ns(ns);
27 shm_init_ns(ns); 27 shm_init_ns(ns);
28 28
29 register_ipcns_notifier(ns);
30
29 kref_init(&ns->kref); 31 kref_init(&ns->kref);
30 return ns; 32 return ns;
31} 33}
@@ -81,6 +83,15 @@ void free_ipc_ns(struct kref *kref)
81 struct ipc_namespace *ns; 83 struct ipc_namespace *ns;
82 84
83 ns = container_of(kref, struct ipc_namespace, kref); 85 ns = container_of(kref, struct ipc_namespace, kref);
86 /*
87 * Unregistering the hotplug notifier at the beginning guarantees
88 * that the ipc namespace won't be freed while we are inside the
89 * callback routine. Since the blocking_notifier_chain_XXX routines
90 * hold a rw lock on the notifier list, unregister_ipcns_notifier()
91 * won't take the rw lock before blocking_notifier_call_chain() has
92 * released the rd lock.
93 */
94 unregister_ipcns_notifier(ns);
84 sem_exit_ns(ns); 95 sem_exit_ns(ns);
85 msg_exit_ns(ns); 96 msg_exit_ns(ns);
86 shm_exit_ns(ns); 97 shm_exit_ns(ns);
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 @@
33#include <linux/audit.h> 33#include <linux/audit.h>
34#include <linux/nsproxy.h> 34#include <linux/nsproxy.h>
35#include <linux/rwsem.h> 35#include <linux/rwsem.h>
36#include <linux/memory.h>
36#include <linux/ipc_namespace.h> 37#include <linux/ipc_namespace.h>
37 38
38#include <asm/unistd.h> 39#include <asm/unistd.h>
@@ -55,11 +56,41 @@ struct ipc_namespace init_ipc_ns = {
55atomic_t nr_ipc_ns = ATOMIC_INIT(1); 56atomic_t nr_ipc_ns = ATOMIC_INIT(1);
56 57
57 58
59#ifdef CONFIG_MEMORY_HOTPLUG
60
61static int ipc_memory_callback(struct notifier_block *self,
62 unsigned long action, void *arg)
63{
64 switch (action) {
65 case MEM_ONLINE: /* memory successfully brought online */
66 case MEM_OFFLINE: /* or offline: it's time to recompute msgmni */
67 /*
68 * This is done by invoking the ipcns notifier chain with the
69 * IPC_MEMCHANGED event.
70 */
71 ipcns_notify(IPCNS_MEMCHANGED);
72 break;
73 case MEM_GOING_ONLINE:
74 case MEM_GOING_OFFLINE:
75 case MEM_CANCEL_ONLINE:
76 case MEM_CANCEL_OFFLINE:
77 default:
78 break;
79 }
80
81 return NOTIFY_OK;
82}
83
84#endif /* CONFIG_MEMORY_HOTPLUG */
85
58/** 86/**
59 * ipc_init - initialise IPC subsystem 87 * ipc_init - initialise IPC subsystem
60 * 88 *
61 * The various system5 IPC resources (semaphores, messages and shared 89 * The various system5 IPC resources (semaphores, messages and shared
62 * memory) are initialised 90 * memory) are initialised
91 * A callback routine is registered into the memory hotplug notifier
92 * chain: since msgmni scales to lowmem this callback routine will be
93 * called upon successful memory add / remove to recompute msmgni.
63 */ 94 */
64 95
65static int __init ipc_init(void) 96static int __init ipc_init(void)
@@ -67,6 +98,8 @@ static int __init ipc_init(void)
67 sem_init(); 98 sem_init();
68 msg_init(); 99 msg_init();
69 shm_init(); 100 shm_init();
101 hotplug_memory_notifier(ipc_memory_callback, IPC_CALLBACK_PRI);
102 register_ipcns_notifier(&init_ipc_ns);
70 return 0; 103 return 0;
71} 104}
72__initcall(ipc_init); 105__initcall(ipc_init);
diff --git a/ipc/util.h b/ipc/util.h
index f37d160c98fe..0e3d79037a2a 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -124,6 +124,8 @@ extern void free_msg(struct msg_msg *msg);
124extern struct msg_msg *load_msg(const void __user *src, int len); 124extern struct msg_msg *load_msg(const void __user *src, int len);
125extern int store_msg(void __user *dest, struct msg_msg *msg, int len); 125extern int store_msg(void __user *dest, struct msg_msg *msg, int len);
126 126
127extern void recompute_msgmni(struct ipc_namespace *);
128
127static inline int ipc_buildid(int id, int seq) 129static inline int ipc_buildid(int id, int seq)
128{ 130{
129 return SEQ_MULTIPLIER * seq + id; 131 return SEQ_MULTIPLIER * seq + id;