forked from Minki/linux
9eefe520c8
This patch proposes an alternative to the "magical positive-versus-negative number trick" Andrew complained about last week in http://lkml.org/lkml/2008/6/24/418. This had been introduced with the patches that scale msgmni to the amount of lowmem. With these patches, msgmni has a registered notification routine that recomputes msgmni value upon memory add/remove or ipc namespace creation/ removal. When msgmni is changed from user space (i.e. value written to the proc file), that notification routine is unregistered, and the way to make it registered back is to write a negative value into the proc file. This is the "magical positive-versus-negative number trick". To fix this, a new proc file is introduced: /proc/sys/kernel/auto_msgmni. This file acts as ON/OFF for msgmni automatic recomputing. With this patch, the process is the following: 1) kernel boots in "automatic recomputing mode" /proc/sys/kernel/msgmni contains the value that has been computed (depends on lowmem) /proc/sys/kernel/automatic_msgmni contains "1" 2) echo <val> > /proc/sys/kernel/msgmni . sets msg_ctlmni to <val> . de-activates automatic recomputing (i.e. if, say, some memory is added msgmni won't be recomputed anymore) . /proc/sys/kernel/automatic_msgmni now contains "0" 3) echo "0" > /proc/sys/kernel/automatic_msgmni . de-activates msgmni automatic recomputing this has the same effect as 2) except that msg_ctlmni's value stays blocked at its current value) 3) echo "1" > /proc/sys/kernel/automatic_msgmni . recomputes msgmni's value based on the current available memory size and number of ipc namespaces . re-activates automatic recomputing for msgmni. Signed-off-by: Nadia Derbey <Nadia.Derbey@bull.net> Cc: Solofo Ramangalahy <Solofo.Ramangalahy@bull.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
93 lines
2.2 KiB
C
93 lines
2.2 KiB
C
/*
|
|
* linux/ipc/ipcns_notifier.c
|
|
* Copyright (C) 2007 BULL SA. Nadia Derbey
|
|
*
|
|
* Notification mechanism for ipc namespaces:
|
|
* The callback routine registered in the memory chain invokes the ipcns
|
|
* notifier chain with the IPCNS_MEMCHANGED event.
|
|
* Each callback routine registered in the ipcns namespace recomputes msgmni
|
|
* for the owning namespace.
|
|
*/
|
|
|
|
#include <linux/msg.h>
|
|
#include <linux/rcupdate.h>
|
|
#include <linux/notifier.h>
|
|
#include <linux/nsproxy.h>
|
|
#include <linux/ipc_namespace.h>
|
|
|
|
#include "util.h"
|
|
|
|
|
|
|
|
static BLOCKING_NOTIFIER_HEAD(ipcns_chain);
|
|
|
|
|
|
static int ipcns_callback(struct notifier_block *self,
|
|
unsigned long action, void *arg)
|
|
{
|
|
struct ipc_namespace *ns;
|
|
|
|
switch (action) {
|
|
case IPCNS_MEMCHANGED: /* amount of lowmem has changed */
|
|
case IPCNS_CREATED:
|
|
case IPCNS_REMOVED:
|
|
/*
|
|
* It's time to recompute msgmni
|
|
*/
|
|
ns = container_of(self, struct ipc_namespace, ipcns_nb);
|
|
/*
|
|
* No need to get a reference on the ns: the 1st job of
|
|
* free_ipc_ns() is to unregister the callback routine.
|
|
* blocking_notifier_chain_unregister takes the wr lock to do
|
|
* it.
|
|
* When this callback routine is called the rd lock is held by
|
|
* blocking_notifier_call_chain.
|
|
* So the ipc ns cannot be freed while we are here.
|
|
*/
|
|
recompute_msgmni(ns);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return NOTIFY_OK;
|
|
}
|
|
|
|
int register_ipcns_notifier(struct ipc_namespace *ns)
|
|
{
|
|
int rc;
|
|
|
|
memset(&ns->ipcns_nb, 0, sizeof(ns->ipcns_nb));
|
|
ns->ipcns_nb.notifier_call = ipcns_callback;
|
|
ns->ipcns_nb.priority = IPCNS_CALLBACK_PRI;
|
|
rc = blocking_notifier_chain_register(&ipcns_chain, &ns->ipcns_nb);
|
|
if (!rc)
|
|
ns->auto_msgmni = 1;
|
|
return rc;
|
|
}
|
|
|
|
int cond_register_ipcns_notifier(struct ipc_namespace *ns)
|
|
{
|
|
int rc;
|
|
|
|
memset(&ns->ipcns_nb, 0, sizeof(ns->ipcns_nb));
|
|
ns->ipcns_nb.notifier_call = ipcns_callback;
|
|
ns->ipcns_nb.priority = IPCNS_CALLBACK_PRI;
|
|
rc = blocking_notifier_chain_cond_register(&ipcns_chain,
|
|
&ns->ipcns_nb);
|
|
if (!rc)
|
|
ns->auto_msgmni = 1;
|
|
return rc;
|
|
}
|
|
|
|
void unregister_ipcns_notifier(struct ipc_namespace *ns)
|
|
{
|
|
blocking_notifier_chain_unregister(&ipcns_chain, &ns->ipcns_nb);
|
|
ns->auto_msgmni = 0;
|
|
}
|
|
|
|
int ipcns_notify(unsigned long val)
|
|
{
|
|
return blocking_notifier_call_chain(&ipcns_chain, val, NULL);
|
|
}
|