aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNadia Derbey <Nadia.Derbey@bull.net>2008-04-29 04:00:45 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-29 11:06:13 -0400
commit6546bc4279241e8fa432de1bb63a4f6f791fd669 (patch)
tree308f5c1621b1019a44800622ffc468a372f09434
parent91cfb2b4b57816de0c96de417b3238249f0b125f (diff)
ipc: re-enable msgmni automatic recomputing msgmni if set to negative
The enhancement as asked for by Yasunori: if msgmni is set to a negative value, register it back into the ipcns notifier chain. A new interface has been added to the notification mechanism: notifier_chain_cond_register() registers a notifier block only if not already registered. With that new interface we avoid taking care of the states changes in procfs. Signed-off-by: Nadia Derbey <Nadia.Derbey@bull.net> Cc: Yasunori Goto <y-goto@jp.fujitsu.com> Cc: Matt Helsley <matthltc@us.ibm.com> Cc: Mingming Cao <cmm@us.ibm.com> Cc: Pierre Peiffer <pierre.peiffer@bull.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/ipc_namespace.h1
-rw-r--r--include/linux/notifier.h4
-rw-r--r--ipc/ipc_sysctl.c45
-rw-r--r--ipc/ipcns_notifier.c9
-rw-r--r--kernel/notifier.c38
5 files changed, 87 insertions, 10 deletions
diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h
index c3b1da9e5feb..ea6c18a8b0d4 100644
--- a/include/linux/ipc_namespace.h
+++ b/include/linux/ipc_namespace.h
@@ -52,6 +52,7 @@ extern atomic_t nr_ipc_ns;
52#define INIT_IPC_NS(ns) .ns = &init_ipc_ns, 52#define INIT_IPC_NS(ns) .ns = &init_ipc_ns,
53 53
54extern int register_ipcns_notifier(struct ipc_namespace *); 54extern int register_ipcns_notifier(struct ipc_namespace *);
55extern int cond_register_ipcns_notifier(struct ipc_namespace *);
55extern int unregister_ipcns_notifier(struct ipc_namespace *); 56extern int unregister_ipcns_notifier(struct ipc_namespace *);
56extern int ipcns_notify(unsigned long); 57extern int ipcns_notify(unsigned long);
57 58
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 20dfed590183..0ff6224d172a 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -121,6 +121,10 @@ extern int raw_notifier_chain_register(struct raw_notifier_head *nh,
121extern int srcu_notifier_chain_register(struct srcu_notifier_head *nh, 121extern int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
122 struct notifier_block *nb); 122 struct notifier_block *nb);
123 123
124extern int blocking_notifier_chain_cond_register(
125 struct blocking_notifier_head *nh,
126 struct notifier_block *nb);
127
124extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh, 128extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
125 struct notifier_block *nb); 129 struct notifier_block *nb);
126extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh, 130extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c
index d12ff5cd2a0b..d3497465cc0a 100644
--- a/ipc/ipc_sysctl.c
+++ b/ipc/ipc_sysctl.c
@@ -15,6 +15,8 @@
15#include <linux/sysctl.h> 15#include <linux/sysctl.h>
16#include <linux/uaccess.h> 16#include <linux/uaccess.h>
17#include <linux/ipc_namespace.h> 17#include <linux/ipc_namespace.h>
18#include <linux/msg.h>
19#include "util.h"
18 20
19static void *get_ipc(ctl_table *table) 21static void *get_ipc(ctl_table *table)
20{ 22{
@@ -24,6 +26,27 @@ static void *get_ipc(ctl_table *table)
24 return which; 26 return which;
25} 27}
26 28
29/*
30 * Routine that is called when a tunable has successfully been changed by
31 * hand and it has a callback routine registered on the ipc namespace notifier
32 * chain: we don't want such tunables to be recomputed anymore upon memory
33 * add/remove or ipc namespace creation/removal.
34 * They can come back to a recomputable state by being set to a <0 value.
35 */
36static void tunable_set_callback(int val)
37{
38 if (val >= 0)
39 unregister_ipcns_notifier(current->nsproxy->ipc_ns);
40 else {
41 /*
42 * Re-enable automatic recomputing only if not already
43 * enabled.
44 */
45 recompute_msgmni(current->nsproxy->ipc_ns);
46 cond_register_ipcns_notifier(current->nsproxy->ipc_ns);
47 }
48}
49
27#ifdef CONFIG_PROC_FS 50#ifdef CONFIG_PROC_FS
28static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp, 51static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp,
29 void __user *buffer, size_t *lenp, loff_t *ppos) 52 void __user *buffer, size_t *lenp, loff_t *ppos)
@@ -38,17 +61,17 @@ static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp,
38static int proc_ipc_callback_dointvec(ctl_table *table, int write, 61static int proc_ipc_callback_dointvec(ctl_table *table, int write,
39 struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) 62 struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos)
40{ 63{
64 struct ctl_table ipc_table;
41 size_t lenp_bef = *lenp; 65 size_t lenp_bef = *lenp;
42 int rc; 66 int rc;
43 67
44 rc = proc_ipc_dointvec(table, write, filp, buffer, lenp, ppos); 68 memcpy(&ipc_table, table, sizeof(ipc_table));
69 ipc_table.data = get_ipc(table);
70
71 rc = proc_dointvec(&ipc_table, write, filp, buffer, lenp, ppos);
45 72
46 if (write && !rc && lenp_bef == *lenp) 73 if (write && !rc && lenp_bef == *lenp)
47 /* 74 tunable_set_callback(*((int *)(ipc_table.data)));
48 * Tunable has successfully been changed from userland:
49 * disable its automatic recomputing.
50 */
51 unregister_ipcns_notifier(current->nsproxy->ipc_ns);
52 75
53 return rc; 76 return rc;
54} 77}
@@ -119,12 +142,14 @@ static int sysctl_ipc_registered_data(ctl_table *table, int __user *name,
119 rc = sysctl_ipc_data(table, name, nlen, oldval, oldlenp, newval, 142 rc = sysctl_ipc_data(table, name, nlen, oldval, oldlenp, newval,
120 newlen); 143 newlen);
121 144
122 if (newval && newlen && rc > 0) 145 if (newval && newlen && rc > 0) {
123 /* 146 /*
124 * Tunable has successfully been changed from userland: 147 * Tunable has successfully been changed from userland
125 * disable its automatic recomputing.
126 */ 148 */
127 unregister_ipcns_notifier(current->nsproxy->ipc_ns); 149 int *data = get_ipc(table);
150
151 tunable_set_callback(*data);
152 }
128 153
129 return rc; 154 return rc;
130} 155}
diff --git a/ipc/ipcns_notifier.c b/ipc/ipcns_notifier.c
index c7974609defc..70ff09183f7b 100644
--- a/ipc/ipcns_notifier.c
+++ b/ipc/ipcns_notifier.c
@@ -61,6 +61,15 @@ int register_ipcns_notifier(struct ipc_namespace *ns)
61 return blocking_notifier_chain_register(&ipcns_chain, &ns->ipcns_nb); 61 return blocking_notifier_chain_register(&ipcns_chain, &ns->ipcns_nb);
62} 62}
63 63
64int cond_register_ipcns_notifier(struct ipc_namespace *ns)
65{
66 memset(&ns->ipcns_nb, 0, sizeof(ns->ipcns_nb));
67 ns->ipcns_nb.notifier_call = ipcns_callback;
68 ns->ipcns_nb.priority = IPCNS_CALLBACK_PRI;
69 return blocking_notifier_chain_cond_register(&ipcns_chain,
70 &ns->ipcns_nb);
71}
72
64int unregister_ipcns_notifier(struct ipc_namespace *ns) 73int unregister_ipcns_notifier(struct ipc_namespace *ns)
65{ 74{
66 return blocking_notifier_chain_unregister(&ipcns_chain, 75 return blocking_notifier_chain_unregister(&ipcns_chain,
diff --git a/kernel/notifier.c b/kernel/notifier.c
index 643360d1bb14..823be11584ef 100644
--- a/kernel/notifier.c
+++ b/kernel/notifier.c
@@ -31,6 +31,21 @@ static int notifier_chain_register(struct notifier_block **nl,
31 return 0; 31 return 0;
32} 32}
33 33
34static int notifier_chain_cond_register(struct notifier_block **nl,
35 struct notifier_block *n)
36{
37 while ((*nl) != NULL) {
38 if ((*nl) == n)
39 return 0;
40 if (n->priority > (*nl)->priority)
41 break;
42 nl = &((*nl)->next);
43 }
44 n->next = *nl;
45 rcu_assign_pointer(*nl, n);
46 return 0;
47}
48
34static int notifier_chain_unregister(struct notifier_block **nl, 49static int notifier_chain_unregister(struct notifier_block **nl,
35 struct notifier_block *n) 50 struct notifier_block *n)
36{ 51{
@@ -205,6 +220,29 @@ int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
205EXPORT_SYMBOL_GPL(blocking_notifier_chain_register); 220EXPORT_SYMBOL_GPL(blocking_notifier_chain_register);
206 221
207/** 222/**
223 * blocking_notifier_chain_cond_register - Cond add notifier to a blocking notifier chain
224 * @nh: Pointer to head of the blocking notifier chain
225 * @n: New entry in notifier chain
226 *
227 * Adds a notifier to a blocking notifier chain, only if not already
228 * present in the chain.
229 * Must be called in process context.
230 *
231 * Currently always returns zero.
232 */
233int blocking_notifier_chain_cond_register(struct blocking_notifier_head *nh,
234 struct notifier_block *n)
235{
236 int ret;
237
238 down_write(&nh->rwsem);
239 ret = notifier_chain_cond_register(&nh->head, n);
240 up_write(&nh->rwsem);
241 return ret;
242}
243EXPORT_SYMBOL_GPL(blocking_notifier_chain_cond_register);
244
245/**
208 * blocking_notifier_chain_unregister - Remove notifier from a blocking notifier chain 246 * blocking_notifier_chain_unregister - Remove notifier from a blocking notifier chain
209 * @nh: Pointer to head of the blocking notifier chain 247 * @nh: Pointer to head of the blocking notifier chain
210 * @n: Entry to remove from notifier chain 248 * @n: Entry to remove from notifier chain