notification chainsand its main purpose to provide a way for different subsystems to subscribe on asynchronous events from other subsystems. Note that this mechanism is only for communication inside kernel, but there are other mechanisms for communication between kernel and userspace.
notification chainsAPI and implementation of this API, let's look at
Notification chainsmechanism from theoretical side as we did it in other parts of this book. Everything which is related to
notification chainsmechanism is located in the include/linux/notifier.h header file and kernel/notifier.c source code file. So let's open them and start to dive.
notification chainsmechanism from related data structures. As I wrote above, main data structures should be located in the include/linux/notifier.h header file, so the Linux kernel provides generic API which does not depend on certain architecture. In general, the
notification chainsmechanism represents a list (that's why it's named
chains) of callback functions which are will be executed when an event will be occurred.
notifier_fn_ttype in the Linux kernel:
nb- is linked list of function pointers (will see it now);
action- is type of an event. A notification chain may support multiple events, so we need this parameter to distinguish an event from other events;
data- is storage for private information. Actually it allows to provide additional data information about an event.
notifier_fn_treturns an integer value. This integer value maybe one of:
NOTIFY_DONE- subscriber does not interested in notification;
NOTIFY_OK- notification was processed correctly;
NOTIFY_BAD- something went wrong;
NOTIFY_STOP- notification is done, but no further callbacks should be called for this event.
NOTIFY_STOP_MASKrepresented by the:
notifier_fn_tcallback function. Main role of the
notification chainsmechanism is to call certain callbacks when an asynchronous event occurred.
notification chainsmechanism is the
notifier_call, link to the next notification callback and
priorityof a callback function as functions with higher priority are executed first.
blocking notifier chains, callbacks will be called/executed in process context. This means that the calls in a notification chain may be blocked.
SRCU notifier chainsrepresent alternative form of
blocking notifier chains. In the first case, blocking notifier chains uses
rw_semaphoresynchronization primitive to protect chain links.
SRCUnotifier chains run in process context too, but uses special form of RCU mechanism which is permissible to block in an read-side critical section.
atomic notifier chainsruns in interrupt or atomic context and protected by spinlock synchronization primitive. The last
raw notifier chainsprovides special type of notifier chains without any locking restrictions on callbacks. This means that protection rests on the shoulders of caller side. It is very useful when we want to protect our chain with very specific locking mechanism.
notifier_blockstructure, we will see that it contains pointer to the
nextelement from a notification chain list, but we have no head. Actually a head of such list is in separate structure depends on type of a notification chain. For example for the
blocking notifier chains:
atomic notification chains:
notification chainsmechanism let's consider implementation of its API.
blocking notification chainsin this part, because of other types of notification chains are similar to it and differ mostly in protection mechanisms.
NULL. Besides the
BLOCKING_INIT_NOTIFIER_HEADmacro, the Linux kernel additionally provides
srcu_init_notifierfunction for initialization atomic and other types of notification chains.
blocking_notifier_chain_registerfunction. Implementation of this function is located in the kernel/notifier.c source code file and as we may see the
blocking_notifier_chain_registertakes two parameters:
nh- head of a notification chain;
nb- notification descriptor.
notifier_chain_registerfunction from the same source code file and as we may understand this function does all job for us. Definition of the
blocking_notifier_chain_registeris pretty simple. First of all there is check which check current system state and if a system in rebooting state we just call the
notifier_chain_register. In other way we do the same call of the
notifier_chain_registerbut as you may see this call is protected with read/write semaphores. Now let's look at the implementation of the
notifier_block(given by a subsystem which wants to get notifications) to the notification chain list. Besides subscribing on an event, subscriber may unsubscribe from a certain events with the set of
*.notifier_call_chainfunction will be called. As you already may guess each type of notification chains provides own function to produce notification:
__blocking_notifier_call_chainfunction. As we may see, the
blocking_notifer_call_chaintakes three parameters:
nh- head of notification chain list;
val- type of a notification;
v- input parameter which may be used by handlers.
__blocking_notifier_call_chainfunction takes five parameters:
nr_callsare number of notifier functions to be called and number of sent notifications. As you may guess the main goal of the
__blocking_notifer_call_chainfunction and other functions for other notification types is to call callback function when an event occurs. Implementation of the
__blocking_notifier_call_chainis pretty simple, it just calls the
notifier_call_chainfunction from the same source code file protected with read/write semaphore:
notifier_call_chainfunction. Main purpose of this function is to inform registered notifiers about an asynchronous event:
module_notify_listin the kernel/module.c source code file. This definition determines head of list of blocking notifier chains related to kernel modules. There are at least three following events:
blocking_notifier_chain_registerand etc., most notification chains come with a set of wrappers used to register to them. Registration on these modules events is going with the help of such wrapper:
tracepoint_module_nbprovides callback function:
MODULE_STATE_GOINGevents occurred. For example the
MODULE_STATE_COMINGnotifications will be sent during execution of the init_module system call. Or for example
MODULE_STATE_GOINGwill be sent during execution of the delete_module
tracepoint_module_notifycallback function will be called.