aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/ipc_namespace.h43
-rw-r--r--include/linux/memory.h1
-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
8 files changed, 162 insertions, 4 deletions
diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h
index 878d7ac286fa..cfb2a08b28f5 100644
--- a/include/linux/ipc_namespace.h
+++ b/include/linux/ipc_namespace.h
@@ -4,6 +4,17 @@
4#include <linux/err.h> 4#include <linux/err.h>
5#include <linux/idr.h> 5#include <linux/idr.h>
6#include <linux/rwsem.h> 6#include <linux/rwsem.h>
7#ifdef CONFIG_MEMORY_HOTPLUG
8#include <linux/notifier.h>
9#endif /* CONFIG_MEMORY_HOTPLUG */
10
11/*
12 * ipc namespace events
13 */
14#define IPCNS_MEMCHANGED 0x00000001 /* Notify lowmem size changed */
15
16#define IPCNS_CALLBACK_PRI 0
17
7 18
8struct ipc_ids { 19struct ipc_ids {
9 int in_use; 20 int in_use;
@@ -30,6 +41,10 @@ struct ipc_namespace {
30 size_t shm_ctlall; 41 size_t shm_ctlall;
31 int shm_ctlmni; 42 int shm_ctlmni;
32 int shm_tot; 43 int shm_tot;
44
45#ifdef CONFIG_MEMORY_HOTPLUG
46 struct notifier_block ipcns_nb;
47#endif
33}; 48};
34 49
35extern struct ipc_namespace init_ipc_ns; 50extern struct ipc_namespace init_ipc_ns;
@@ -37,9 +52,33 @@ extern atomic_t nr_ipc_ns;
37 52
38#ifdef CONFIG_SYSVIPC 53#ifdef CONFIG_SYSVIPC
39#define INIT_IPC_NS(ns) .ns = &init_ipc_ns, 54#define INIT_IPC_NS(ns) .ns = &init_ipc_ns,
40#else 55
56#ifdef CONFIG_MEMORY_HOTPLUG
57
58extern int register_ipcns_notifier(struct ipc_namespace *);
59extern int unregister_ipcns_notifier(struct ipc_namespace *);
60extern int ipcns_notify(unsigned long);
61
62#else /* CONFIG_MEMORY_HOTPLUG */
63
64static inline int register_ipcns_notifier(struct ipc_namespace *ipcns)
65{
66 return 0;
67}
68static inline int unregister_ipcns_notifier(struct ipc_namespace *ipcns)
69{
70 return 0;
71}
72static inline int ipcns_notify(unsigned long ev)
73{
74 return 0;
75}
76
77#endif /* CONFIG_MEMORY_HOTPLUG */
78
79#else /* CONFIG_SYSVIPC */
41#define INIT_IPC_NS(ns) 80#define INIT_IPC_NS(ns)
42#endif 81#endif /* CONFIG_SYSVIPC */
43 82
44#if defined(CONFIG_SYSVIPC) && defined(CONFIG_IPC_NS) 83#if defined(CONFIG_SYSVIPC) && defined(CONFIG_IPC_NS)
45extern void free_ipc_ns(struct kref *kref); 84extern void free_ipc_ns(struct kref *kref);
diff --git a/include/linux/memory.h b/include/linux/memory.h
index 39628dfe4a4c..2f5f8a5ef2a0 100644
--- a/include/linux/memory.h
+++ b/include/linux/memory.h
@@ -58,6 +58,7 @@ struct mem_section;
58 * order in the callback chain) 58 * order in the callback chain)
59 */ 59 */
60#define SLAB_CALLBACK_PRI 1 60#define SLAB_CALLBACK_PRI 1
61#define IPC_CALLBACK_PRI 10
61 62
62#ifndef CONFIG_MEMORY_HOTPLUG_SPARSE 63#ifndef CONFIG_MEMORY_HOTPLUG_SPARSE
63static inline int memory_dev_init(void) 64static inline int memory_dev_init(void)
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;