The Notification System (2.6.5)
Event notification is important when a kernel component needs to be
made aware that something happened without having to inquire about it
repeatedly. Event notification is like signals for user programs.
Unlike signals, the component has to sign up (register) for the
notification, and is thus notified only of the events it has
registered for. There is no default notifier for events, as
default handlers for signals.
A component signs up for notification by registering a
notifier_block with a notifier_chain. The notifier
block must contain the callback function to call when the event occurs.
This function is executed in the context that triggered the
notification on the chain [... ???]
The header file
include/linux/notifier.h defines the struct notifier_block,
- next, a pointer to the next notifier_block on the list;
- priority;
- notifier_call() the notification callback; it returns an integer
and takes three arguments: a pointer to a notifier_block (the block
itself), the value code of the event (unsigned long),
and a generic void * pointer (either NULL, or whatever might be
useful). The last two are the second and third arguments of the
function notifier_call_chain() passed unmodified
to the callback.
A chain of notification is a list of notifier blocks.
The notification system is implemented in kernel/sys.c and exports
three API,
- notifier_chain_register;
- notifier_chain_unregister;
- notifier_call_chain;
The first two take a pointer to a list of notifier_block's and a pointer
to the notifier_block. The last one takes a pointer to a list of
notifier_block's, a unsigned long event code, and a void *.
The callback is usually a (big) switch on the event code, and should
return NOTIFY_DONE to indicate success.
The function notifier_call_chain invokes the callbacks
of the registered notifier_block, passing them the notifier_block itself,
the event code, and the void * pointer.
It stops if a callback return has the NOTIFY_STOP_MASK bit active.
The kernel lists of notifier_block's have grown are
- cpu_chain (kernel/cpu.c).
Called when the cpu has gone down (code CPU_DEAD),
or while is coming up (codes CPU_UP_PREPARE,
CPU_ONLINE, and CPU_UP_CANCELED).
- module_notify_list (kernel/module.c).
Called by sys_module_init() with code MODULE_STATE_COMING,
and last argument the pointer to the new module struct.
- panic_notifier_list (kernel/panic.c). It is called
by panic() with code 0, and last argument a buffer string
with the message of panic().
- exit_task_notifier, exit_mmap_notifier,
exec_unmap_notifier, and profile_listeners
(kernel/profile.c), if kernel profiling is enabled
(CONFIG_PROFILING).
- reboot_notifier_list (kernel/sys.c);
list of notifiers that want to be called at shutdown.
It is fired by sys_reboot()
with one of the event codes SYS_HALT, SYS_SHUTDOWN,
SYS_POWER_OFF and SYS_RESTART.
It is also called when the
user presses ctrl-alt-del and the keyboard interrupt invokes
deferred_cad().
The cpufreq_notifier is called by cpufreq_set() and cpufrq_get().
[where did it go?]
Several driver and network code use lists of notifier_block.
net/core/dev.c has a netdev_chain list of notifier_block's,
and net/ipv4/devinet.c has a inetaddr_chain list.
The table below summarizes the cases when the netdev_chain
is notified.
|
event code |
pointer |
a net_device changes state (dev_set_allmulti())
|
NETDEV_CHANGE |
net_device |
a net_device changes from "down" to "up" (dev_oopen())
|
NETDEV_UP |
net_device |
a net_device is about to go "down" (dev_close) |
NETDEV_GOING_DOWN |
net_device |
a net_device has gone "down" (dev_close) |
NETDEV_DOWN |
net_device |
a net_device changes MTU (dev_ifsioc() with command SIOCSIFMTU)
|
NETDEV_CHANGEMTU |
net_device |
a net_device changes MAC address (dev_ifsioc() with command
SIOCGIFHWADDR) or broadcst address (dev_ifsioc() with
SIOCSIFHWBROADCAST) |
NETDEV_CHANGEADDR |
net_device |
a net_device changes name (dev_ifsioc() with command
SIOCSIFNAME) |
NETDEV_CHANGENAME |
net_device |
a net_device registers with the net core (register_netdevice)
|
NETDEV_REGISTER |
net_device |
a net_device unregisters from the net core (unregister_netdevice)
|
NETDEV_UNREGISTER |
net_device |
For example net/ipv4 has
- inetaddr_chain, used for events related to net_device's;
the ip_netdev_notifier defines the callback
inetdev_event, to which the event code is passed as
unsigend long, and the void * points to the net_device.
- the FIB code, where the notifier_block
fib_inetaddr_notifier with callback fib_inetaddr_event,
fib_netdev_notifier with fib_netdev_event,
and fib_rules_notifier with fib_rules_event.
- ip_mr_notifier with callback ipmr_device_event.
Exercise
Write a driver that register with the
module_notifier_list
and when a new module is insmod-ed prints a message.
Example and
Makefile.
Marco Corvi - 2003, 2005