CPU HotPlug notifier

Source: Internet
Author: User
If your code needs to detect whether the current CPU is hotplug, you can refer to the following sample code
#include <linux/cpu.h>
static int foobar_cpu_callback (struct notifier_block *NFB,
unsigned long action, void *HCPU)
{
unsigned int cpu = (unsigned long) hcpu;


Switch (action) {
Case Cpu_online:
Case Cpu_online_frozen:
Foobar_online_action (CPU);
Break
Case Cpu_dead:
Case Cpu_dead_frozen:
Foobar_dead_action (CPU);
Break
}
return NOTIFY_OK;
}


static struct Notifier_block Foobar_cpu_notifier =
{
. Notifier_call = Foobar_cpu_callback,
};


Be sure to include <linux/cpu.h> or you will get an error
Second, call Register_cpu_notifier (&foobar_cpu_notifier) or register_hotcpu_notifier (&foobar_cpu_notifier); To register a notify so that when the CPU is online or dead it will call Foobar_cpu_callback
There is no difference between register_cpu_notifier and Register_hotcpu_notifier. The definition of Register_hotcpu_notifier is as follows:
#define Register_hotcpu_notifier (NB) register_cpu_notifier (NB)
Then foobar_online_action and foobar_dead_action can handle CPU online and cpu_dead.
int register_cpu_notifier (struct notifier_block *nb)
{
int ret;
Cpu_maps_update_begin ();
ret = Raw_notifier_chain_register (&cpu_chain, NB);
Cpu_maps_update_done ();
return ret;
}
Register_cpu_notifier is to add the previously defined notifier_call to the Cpu_chain list.
int Raw_notifier_chain_register (struct raw_notifier_head *nh,
struct Notifier_block *n)
{
Return Notifier_chain_register (&nh->head, N);
}
In Raw_notifier_chain_register, you get the head of the Cpu_chain list, and then you add N.
static int notifier_chain_register (struct notifier_block **nl,
struct Notifier_block *n)
{
while ((*NL)!= NULL) {
if (N->priority > (*NL)->priority)
Break
NL = & ((*NL)->next);
}
N->next = *NL;
Rcu_assign_pointer (*NL, N);
return 0;
}
Notifier_chain_register is prioritized when added to the Cpu_chain->head list, with priority from high to low.
When CPU hotplug occurs, Cpu_notify is invoked to notify events on the Cpu_chain list.
static int cpu_notify (unsigned long val, unsigned int cpu)
{
Return __cpu_notify (val, CPU,-1, NULL);
}


static int __cpu_notify (unsigned long val, unsigned int cpu, int nr_to_call,
int *nr_calls)
{
unsigned long mod = Cpuhp_tasks_frozen? cpu_tasks_frozen:0;
void *hcpu = (void *) (long) CPU;


int ret;


ret = __raw_notifier_call_chain (&cpu_chain, Val | mod, HCPU, Nr_to_call,
Nr_calls);


Return Notifier_to_errno (ret);
}
__cpu_notify gets the current HotPlug CPU number HCPU, and then calls __raw_notifier_call_chain
int __raw_notifier_call_chain (struct raw_notifier_head *nh,
unsigned long val, void *v,
int nr_to_call, int *nr_calls)
{
Return Notifier_call_chain (&nh->head, Val, V, Nr_to_call, nr_calls);
}
And registration is the same as getting head, which is the head of the list
static int Notifier_call_chain (struct notifier_block **nl,
unsigned long val, void *v,
int nr_to_call, int *nr_calls)
{
int ret = Notify_done;
struct Notifier_block *nb, *next_nb;


NB = Rcu_dereference_raw (*NL);


while (NB && Nr_to_call) {
NEXT_NB = Rcu_dereference_raw (Nb->next);


#ifdef config_debug_notifiers
if (Unlikely (!func_ptr_is_kernel_text (Nb->notifier_call)) {
WARN (1, "Invalid notifier called!");
NB = NEXT_NB;
Continue
}
#endif
ret = Nb->notifier_call (nb, Val, v);


if (nr_calls)
(*nr_calls) + +;


if (ret & notify_stop_mask) = = Notify_stop_mask)
Break
NB = NEXT_NB;
nr_to_call--;
}
return ret;
}
Will traverse the entire cpu_chain->head, respectively, call Notifier_call, this example we registered Notifier_call = = Foobar_cpu_callback, then NB = NEXT_NB to continue the iteration.
The registration notify must have been done in kernel space, which is callback's function address, either in kernel Buildin or in module, so notifier_call_chain can make this decision, The prerequisite is to open the config_debug_notifiers.
And Func_ptr_is_kernel_text is to determine whether callback's function address is in kernel Buildin or module.
int func_ptr_is_kernel_text (void *ptr)
{
unsigned long addr;
Addr = (unsigned long) dereference_function_descriptor (PTR);
if (Core_kernel_text (addr))
return 1;
return is_module_text_address (addr);
}
Since it is the debug option, the individual thinks it is best to print the symbol for the function address by%PF better, that is, change to the following
int func_ptr_is_kernel_text (void *ptr)
{
unsigned long addr;
Addr = (unsigned long) dereference_function_descriptor (PTR);
WARN (1, "addr =%pf", addr);
if (Core_kernel_text (addr))
return 1;
return is_module_text_address (addr);

}


If you want to run your callback on the CPU, you can refer to the following code, the above article to understand, the following code understanding is very simple

Cpu_notifier_register_begin ();
For_each_online_cpu (i) {
Foobar_cpu_callback (&foobar_cpu_notifier,
   cpu_up_prepare, i);
Foobar_cpu_callback (&foobar_cpu_notifier,
   cpu_online, i);
}

__register_cpu_notifier (&foobar_cpu_notifier);
Cpu_notifier_register_done ();

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.