2008-04-29 12:00:42 +04:00
/*
* 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 */
2008-04-29 12:00:44 +04:00
case IPCNS_CREATED :
case IPCNS_REMOVED :
2008-04-29 12:00:42 +04:00
/*
* 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 1 st 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 )
{
2008-07-25 12:48:08 +04:00
int rc ;
2008-04-29 12:00:42 +04:00
memset ( & ns - > ipcns_nb , 0 , sizeof ( ns - > ipcns_nb ) ) ;
ns - > ipcns_nb . notifier_call = ipcns_callback ;
ns - > ipcns_nb . priority = IPCNS_CALLBACK_PRI ;
2008-07-25 12:48:08 +04:00
rc = blocking_notifier_chain_register ( & ipcns_chain , & ns - > ipcns_nb ) ;
if ( ! rc )
ns - > auto_msgmni = 1 ;
return rc ;
2008-04-29 12:00:42 +04:00
}
2008-04-29 12:00:45 +04:00
int cond_register_ipcns_notifier ( struct ipc_namespace * ns )
{
2008-07-25 12:48:08 +04:00
int rc ;
2008-04-29 12:00:45 +04:00
memset ( & ns - > ipcns_nb , 0 , sizeof ( ns - > ipcns_nb ) ) ;
ns - > ipcns_nb . notifier_call = ipcns_callback ;
ns - > ipcns_nb . priority = IPCNS_CALLBACK_PRI ;
2008-07-25 12:48:08 +04:00
rc = blocking_notifier_chain_cond_register ( & ipcns_chain ,
2008-04-29 12:00:45 +04:00
& ns - > ipcns_nb ) ;
2008-07-25 12:48:08 +04:00
if ( ! rc )
ns - > auto_msgmni = 1 ;
return rc ;
2008-04-29 12:00:45 +04:00
}
2008-07-25 12:48:08 +04:00
void unregister_ipcns_notifier ( struct ipc_namespace * ns )
2008-04-29 12:00:42 +04:00
{
2008-07-25 12:48:08 +04:00
blocking_notifier_chain_unregister ( & ipcns_chain , & ns - > ipcns_nb ) ;
ns - > auto_msgmni = 0 ;
2008-04-29 12:00:42 +04:00
}
int ipcns_notify ( unsigned long val )
{
return blocking_notifier_call_chain ( & ipcns_chain , val , NULL ) ;
}