From: Solofo Ramangalahy <[email protected]>
The msgmnb and msgmni values are coupled for deactivation and
reactivation of value computation.
The uncoupling of msgmn{b,i} for deactivation/reactivation of
recomputation adds flexibility and testability.
. Flexibility was discussed during the msgmni series development and
ended up with reactivation by negative value on /proc.
. Testability allows to experiment with the automatic computation of
msgmn{b,i} values. For example, if current algorithm does not fit
application needs.
As msgmni value is based in msgmnb and msgmnb*msgmni should not be
bigger than 1/32 of low memory, reenabling msgmnb triggers one shot
recomputation of msgmni.
Signed-off-by: Solofo Ramangalahy <[email protected]>
---
Documentation/sysctl/kernel.txt | 1
include/linux/ipc_namespace.h | 3 +-
ipc/ipc_sysctl.c | 53 ++++++++++++++++++++++++++++++----------
ipc/ipcns_notifier.c | 9 ------
ipc/msg.c | 6 ++++
5 files changed, 49 insertions(+), 23 deletions(-)
Index: b/include/linux/ipc_namespace.h
===================================================================
--- a/include/linux/ipc_namespace.h
+++ b/include/linux/ipc_namespace.h
@@ -34,7 +34,9 @@ struct ipc_namespace {
int msg_ctlmax;
int msg_ctlmnb;
+ bool msg_ctlmnb_activated; /* recompute_msgmnb activation */
int msg_ctlmni;
+ bool msg_ctlmni_activated; /* recompute_msgmni activation */
atomic_t msg_bytes;
atomic_t msg_hdrs;
@@ -53,7 +55,6 @@ extern atomic_t nr_ipc_ns;
#define INIT_IPC_NS(ns) .ns = &init_ipc_ns,
extern int register_ipcns_notifier(struct ipc_namespace *);
-extern int cond_register_ipcns_notifier(struct ipc_namespace *);
extern int unregister_ipcns_notifier(struct ipc_namespace *);
extern int ipcns_notify(unsigned long);
Index: b/ipc/msg.c
===================================================================
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -91,6 +91,8 @@ void recompute_msgmni(struct ipc_namespa
unsigned long allowed;
int nb_ns;
+ if (!ns->msg_ctlmni_activated)
+ return;
si_meminfo(&i);
allowed = (((i.totalram - i.totalhigh) / MSG_MEM_SCALE) * i.mem_unit)
/ ns->msg_ctlmnb;
@@ -114,6 +116,8 @@ void recompute_msgmni(struct ipc_namespa
*/
void recompute_msgmnb(struct ipc_namespace *ns)
{
+ if (!ns->msg_ctlmnb_activated)
+ return;
ns->msg_ctlmnb =
min(MSGMNB * num_online_cpus(), MSGMNB * MSG_CPU_SCALE);
}
@@ -121,6 +125,8 @@ void recompute_msgmnb(struct ipc_namespa
void msg_init_ns(struct ipc_namespace *ns)
{
ns->msg_ctlmax = MSGMAX;
+ ns->msg_ctlmnb_activated = true;
+ ns->msg_ctlmni_activated = true;
recompute_msgmnb(ns);
recompute_msgmni(ns);
Index: b/ipc/ipc_sysctl.c
===================================================================
--- a/ipc/ipc_sysctl.c
+++ b/ipc/ipc_sysctl.c
@@ -33,18 +33,46 @@ static void *get_ipc(ctl_table *table)
* add/remove or ipc namespace creation/removal.
* They can come back to a recomputable state by being set to a <0 value.
*/
-static void tunable_set_callback(int val)
+static void tunable_set_callback(int val, ctl_table *table)
{
- if (val >= 0)
- unregister_ipcns_notifier(current->nsproxy->ipc_ns);
- else {
+ int tunable = table->ctl_name;
+
+ if (val >= 0) {
+ switch (tunable) {
+ case KERN_MSGMNB:
+ current->nsproxy->ipc_ns->msg_ctlmnb_activated = false;
+ break;
+ case KERN_MSGMNI:
+ current->nsproxy->ipc_ns->msg_ctlmni_activated = false;
+ break;
+ default:
+ printk(KERN_ERR "ipc: unexpected value %s\n",
+ table->procname);
+ break;
+ }
+ } else {
/*
* Re-enable automatic recomputing only if not already
* enabled.
*/
- recompute_msgmnb(current->nsproxy->ipc_ns);
- recompute_msgmni(current->nsproxy->ipc_ns);
- cond_register_ipcns_notifier(current->nsproxy->ipc_ns);
+ switch (tunable) {
+ case KERN_MSGMNB:
+ current->nsproxy->ipc_ns->msg_ctlmnb_activated = true;
+ recompute_msgmnb(current->nsproxy->ipc_ns);
+ /*
+ * msgmni adjustment is needed not to overflow
+ * 1/MSG_MEM_SCALE limit.
+ */
+ recompute_msgmni(current->nsproxy->ipc_ns);
+ case KERN_MSGMNI:
+ current->nsproxy->ipc_ns->msg_ctlmni_activated = true;
+ recompute_msgmni(current->nsproxy->ipc_ns);
+ break;
+ default:
+ printk(KERN_ERR "ipc: unexpected value %s\n",
+ table->procname);
+ break;
+ }
}
}
@@ -71,9 +99,10 @@ static int proc_ipc_callback_dointvec(ct
rc = proc_dointvec(&ipc_table, write, filp, buffer, lenp, ppos);
- if (write && !rc && lenp_bef == *lenp)
- tunable_set_callback(*((int *)(ipc_table.data)));
-
+ if (write && !rc && lenp_bef == *lenp) {
+ BUG_ON(table == NULL);
+ tunable_set_callback(*((int *)(ipc_table.data)), table);
+ }
return rc;
}
@@ -148,8 +177,8 @@ static int sysctl_ipc_registered_data(ct
* Tunable has successfully been changed from userland
*/
int *data = get_ipc(table);
-
- tunable_set_callback(*data);
+ BUG_ON(table == NULL);
+ tunable_set_callback(*data, table);
}
return rc;
Index: b/ipc/ipcns_notifier.c
===================================================================
--- a/ipc/ipcns_notifier.c
+++ b/ipc/ipcns_notifier.c
@@ -65,15 +65,6 @@ int register_ipcns_notifier(struct ipc_n
return blocking_notifier_chain_register(&ipcns_chain, &ns->ipcns_nb);
}
-int cond_register_ipcns_notifier(struct ipc_namespace *ns)
-{
- memset(&ns->ipcns_nb, 0, sizeof(ns->ipcns_nb));
- ns->ipcns_nb.notifier_call = ipcns_callback;
- ns->ipcns_nb.priority = IPCNS_CALLBACK_PRI;
- return blocking_notifier_chain_cond_register(&ipcns_chain,
- &ns->ipcns_nb);
-}
-
int unregister_ipcns_notifier(struct ipc_namespace *ns)
{
return blocking_notifier_chain_unregister(&ipcns_chain,
Index: b/Documentation/sysctl/kernel.txt
===================================================================
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -203,7 +203,6 @@ The exact value is automatically (re)com
# echo -1 > /proc/sys/kernel/msgmnb
See recompute_msgmnb() function in ipc/ directory for details.
-The value of msgmnb is coupled with the value of msgmni.
==============================================================
--