1*457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2fe9d4f57SAlexey Dobriyan #include <linux/kdebug.h> 3fe9d4f57SAlexey Dobriyan #include <linux/kprobes.h> 49984de1aSPaul Gortmaker #include <linux/export.h> 5fe9d4f57SAlexey Dobriyan #include <linux/notifier.h> 6fe9d4f57SAlexey Dobriyan #include <linux/rcupdate.h> 7fe9d4f57SAlexey Dobriyan #include <linux/vmalloc.h> 8c166f23cSAdrian Bunk #include <linux/reboot.h> 9fe9d4f57SAlexey Dobriyan 10fe9d4f57SAlexey Dobriyan /* 11fe9d4f57SAlexey Dobriyan * Notifier list for kernel code which wants to be called 12fe9d4f57SAlexey Dobriyan * at shutdown. This is used to stop any idling DMA operations 13fe9d4f57SAlexey Dobriyan * and the like. 14fe9d4f57SAlexey Dobriyan */ 15fe9d4f57SAlexey Dobriyan BLOCKING_NOTIFIER_HEAD(reboot_notifier_list); 16fe9d4f57SAlexey Dobriyan 17fe9d4f57SAlexey Dobriyan /* 18fe9d4f57SAlexey Dobriyan * Notifier chain core routines. The exported routines below 19fe9d4f57SAlexey Dobriyan * are layered on top of these, with appropriate locking added. 20fe9d4f57SAlexey Dobriyan */ 21fe9d4f57SAlexey Dobriyan 22fe9d4f57SAlexey Dobriyan static int notifier_chain_register(struct notifier_block **nl, 23fe9d4f57SAlexey Dobriyan struct notifier_block *n) 24fe9d4f57SAlexey Dobriyan { 25fe9d4f57SAlexey Dobriyan while ((*nl) != NULL) { 2683124657SVasily Averin WARN_ONCE(((*nl) == n), "double register detected"); 27fe9d4f57SAlexey Dobriyan if (n->priority > (*nl)->priority) 28fe9d4f57SAlexey Dobriyan break; 29fe9d4f57SAlexey Dobriyan nl = &((*nl)->next); 30fe9d4f57SAlexey Dobriyan } 31fe9d4f57SAlexey Dobriyan n->next = *nl; 32fe9d4f57SAlexey Dobriyan rcu_assign_pointer(*nl, n); 33fe9d4f57SAlexey Dobriyan return 0; 34fe9d4f57SAlexey Dobriyan } 35fe9d4f57SAlexey Dobriyan 366546bc42SNadia Derbey static int notifier_chain_cond_register(struct notifier_block **nl, 376546bc42SNadia Derbey struct notifier_block *n) 386546bc42SNadia Derbey { 396546bc42SNadia Derbey while ((*nl) != NULL) { 406546bc42SNadia Derbey if ((*nl) == n) 416546bc42SNadia Derbey return 0; 426546bc42SNadia Derbey if (n->priority > (*nl)->priority) 436546bc42SNadia Derbey break; 446546bc42SNadia Derbey nl = &((*nl)->next); 456546bc42SNadia Derbey } 466546bc42SNadia Derbey n->next = *nl; 476546bc42SNadia Derbey rcu_assign_pointer(*nl, n); 486546bc42SNadia Derbey return 0; 496546bc42SNadia Derbey } 506546bc42SNadia Derbey 51fe9d4f57SAlexey Dobriyan static int notifier_chain_unregister(struct notifier_block **nl, 52fe9d4f57SAlexey Dobriyan struct notifier_block *n) 53fe9d4f57SAlexey Dobriyan { 54fe9d4f57SAlexey Dobriyan while ((*nl) != NULL) { 55fe9d4f57SAlexey Dobriyan if ((*nl) == n) { 56fe9d4f57SAlexey Dobriyan rcu_assign_pointer(*nl, n->next); 57fe9d4f57SAlexey Dobriyan return 0; 58fe9d4f57SAlexey Dobriyan } 59fe9d4f57SAlexey Dobriyan nl = &((*nl)->next); 60fe9d4f57SAlexey Dobriyan } 61fe9d4f57SAlexey Dobriyan return -ENOENT; 62fe9d4f57SAlexey Dobriyan } 63fe9d4f57SAlexey Dobriyan 64fe9d4f57SAlexey Dobriyan /** 65fe9d4f57SAlexey Dobriyan * notifier_call_chain - Informs the registered notifiers about an event. 66fe9d4f57SAlexey Dobriyan * @nl: Pointer to head of the blocking notifier chain 67fe9d4f57SAlexey Dobriyan * @val: Value passed unmodified to notifier function 68fe9d4f57SAlexey Dobriyan * @v: Pointer passed unmodified to notifier function 69fe9d4f57SAlexey Dobriyan * @nr_to_call: Number of notifier functions to be called. Don't care 70fe9d4f57SAlexey Dobriyan * value of this parameter is -1. 71fe9d4f57SAlexey Dobriyan * @nr_calls: Records the number of notifications sent. Don't care 72fe9d4f57SAlexey Dobriyan * value of this field is NULL. 73fe9d4f57SAlexey Dobriyan * @returns: notifier_call_chain returns the value returned by the 74fe9d4f57SAlexey Dobriyan * last notifier function called. 75fe9d4f57SAlexey Dobriyan */ 76b40a2cb6SMasami Hiramatsu static int notifier_call_chain(struct notifier_block **nl, 77fe9d4f57SAlexey Dobriyan unsigned long val, void *v, 78fe9d4f57SAlexey Dobriyan int nr_to_call, int *nr_calls) 79fe9d4f57SAlexey Dobriyan { 80fe9d4f57SAlexey Dobriyan int ret = NOTIFY_DONE; 81fe9d4f57SAlexey Dobriyan struct notifier_block *nb, *next_nb; 82fe9d4f57SAlexey Dobriyan 83d11c563dSPaul E. McKenney nb = rcu_dereference_raw(*nl); 84fe9d4f57SAlexey Dobriyan 85fe9d4f57SAlexey Dobriyan while (nb && nr_to_call) { 86d11c563dSPaul E. McKenney next_nb = rcu_dereference_raw(nb->next); 871b2439dbSArjan van de Ven 881b2439dbSArjan van de Ven #ifdef CONFIG_DEBUG_NOTIFIERS 89ab7476cfSArjan van de Ven if (unlikely(!func_ptr_is_kernel_text(nb->notifier_call))) { 901b2439dbSArjan van de Ven WARN(1, "Invalid notifier called!"); 911b2439dbSArjan van de Ven nb = next_nb; 921b2439dbSArjan van de Ven continue; 931b2439dbSArjan van de Ven } 941b2439dbSArjan van de Ven #endif 95fe9d4f57SAlexey Dobriyan ret = nb->notifier_call(nb, val, v); 96fe9d4f57SAlexey Dobriyan 97fe9d4f57SAlexey Dobriyan if (nr_calls) 98fe9d4f57SAlexey Dobriyan (*nr_calls)++; 99fe9d4f57SAlexey Dobriyan 1003e6dadedSViresh Kumar if (ret & NOTIFY_STOP_MASK) 101fe9d4f57SAlexey Dobriyan break; 102fe9d4f57SAlexey Dobriyan nb = next_nb; 103fe9d4f57SAlexey Dobriyan nr_to_call--; 104fe9d4f57SAlexey Dobriyan } 105fe9d4f57SAlexey Dobriyan return ret; 106fe9d4f57SAlexey Dobriyan } 107b40a2cb6SMasami Hiramatsu NOKPROBE_SYMBOL(notifier_call_chain); 108fe9d4f57SAlexey Dobriyan 109fe9d4f57SAlexey Dobriyan /* 110fe9d4f57SAlexey Dobriyan * Atomic notifier chain routines. Registration and unregistration 111fe9d4f57SAlexey Dobriyan * use a spinlock, and call_chain is synchronized by RCU (no locks). 112fe9d4f57SAlexey Dobriyan */ 113fe9d4f57SAlexey Dobriyan 114fe9d4f57SAlexey Dobriyan /** 115fe9d4f57SAlexey Dobriyan * atomic_notifier_chain_register - Add notifier to an atomic notifier chain 116fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the atomic notifier chain 117fe9d4f57SAlexey Dobriyan * @n: New entry in notifier chain 118fe9d4f57SAlexey Dobriyan * 119fe9d4f57SAlexey Dobriyan * Adds a notifier to an atomic notifier chain. 120fe9d4f57SAlexey Dobriyan * 121fe9d4f57SAlexey Dobriyan * Currently always returns zero. 122fe9d4f57SAlexey Dobriyan */ 123fe9d4f57SAlexey Dobriyan int atomic_notifier_chain_register(struct atomic_notifier_head *nh, 124fe9d4f57SAlexey Dobriyan struct notifier_block *n) 125fe9d4f57SAlexey Dobriyan { 126fe9d4f57SAlexey Dobriyan unsigned long flags; 127fe9d4f57SAlexey Dobriyan int ret; 128fe9d4f57SAlexey Dobriyan 129fe9d4f57SAlexey Dobriyan spin_lock_irqsave(&nh->lock, flags); 130fe9d4f57SAlexey Dobriyan ret = notifier_chain_register(&nh->head, n); 131fe9d4f57SAlexey Dobriyan spin_unlock_irqrestore(&nh->lock, flags); 132fe9d4f57SAlexey Dobriyan return ret; 133fe9d4f57SAlexey Dobriyan } 134fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(atomic_notifier_chain_register); 135fe9d4f57SAlexey Dobriyan 136fe9d4f57SAlexey Dobriyan /** 137fe9d4f57SAlexey Dobriyan * atomic_notifier_chain_unregister - Remove notifier from an atomic notifier chain 138fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the atomic notifier chain 139fe9d4f57SAlexey Dobriyan * @n: Entry to remove from notifier chain 140fe9d4f57SAlexey Dobriyan * 141fe9d4f57SAlexey Dobriyan * Removes a notifier from an atomic notifier chain. 142fe9d4f57SAlexey Dobriyan * 143fe9d4f57SAlexey Dobriyan * Returns zero on success or %-ENOENT on failure. 144fe9d4f57SAlexey Dobriyan */ 145fe9d4f57SAlexey Dobriyan int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh, 146fe9d4f57SAlexey Dobriyan struct notifier_block *n) 147fe9d4f57SAlexey Dobriyan { 148fe9d4f57SAlexey Dobriyan unsigned long flags; 149fe9d4f57SAlexey Dobriyan int ret; 150fe9d4f57SAlexey Dobriyan 151fe9d4f57SAlexey Dobriyan spin_lock_irqsave(&nh->lock, flags); 152fe9d4f57SAlexey Dobriyan ret = notifier_chain_unregister(&nh->head, n); 153fe9d4f57SAlexey Dobriyan spin_unlock_irqrestore(&nh->lock, flags); 154fe9d4f57SAlexey Dobriyan synchronize_rcu(); 155fe9d4f57SAlexey Dobriyan return ret; 156fe9d4f57SAlexey Dobriyan } 157fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister); 158fe9d4f57SAlexey Dobriyan 159fe9d4f57SAlexey Dobriyan /** 160fe9d4f57SAlexey Dobriyan * __atomic_notifier_call_chain - Call functions in an atomic notifier chain 161fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the atomic notifier chain 162fe9d4f57SAlexey Dobriyan * @val: Value passed unmodified to notifier function 163fe9d4f57SAlexey Dobriyan * @v: Pointer passed unmodified to notifier function 164fe9d4f57SAlexey Dobriyan * @nr_to_call: See the comment for notifier_call_chain. 165fe9d4f57SAlexey Dobriyan * @nr_calls: See the comment for notifier_call_chain. 166fe9d4f57SAlexey Dobriyan * 167fe9d4f57SAlexey Dobriyan * Calls each function in a notifier chain in turn. The functions 168fe9d4f57SAlexey Dobriyan * run in an atomic context, so they must not block. 169fe9d4f57SAlexey Dobriyan * This routine uses RCU to synchronize with changes to the chain. 170fe9d4f57SAlexey Dobriyan * 171fe9d4f57SAlexey Dobriyan * If the return value of the notifier can be and'ed 172fe9d4f57SAlexey Dobriyan * with %NOTIFY_STOP_MASK then atomic_notifier_call_chain() 173fe9d4f57SAlexey Dobriyan * will return immediately, with the return value of 174fe9d4f57SAlexey Dobriyan * the notifier function which halted execution. 175fe9d4f57SAlexey Dobriyan * Otherwise the return value is the return value 176fe9d4f57SAlexey Dobriyan * of the last notifier function called. 177fe9d4f57SAlexey Dobriyan */ 178b40a2cb6SMasami Hiramatsu int __atomic_notifier_call_chain(struct atomic_notifier_head *nh, 179fe9d4f57SAlexey Dobriyan unsigned long val, void *v, 180fe9d4f57SAlexey Dobriyan int nr_to_call, int *nr_calls) 181fe9d4f57SAlexey Dobriyan { 182fe9d4f57SAlexey Dobriyan int ret; 183fe9d4f57SAlexey Dobriyan 184fe9d4f57SAlexey Dobriyan rcu_read_lock(); 185fe9d4f57SAlexey Dobriyan ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls); 186fe9d4f57SAlexey Dobriyan rcu_read_unlock(); 187fe9d4f57SAlexey Dobriyan return ret; 188fe9d4f57SAlexey Dobriyan } 189fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(__atomic_notifier_call_chain); 190b40a2cb6SMasami Hiramatsu NOKPROBE_SYMBOL(__atomic_notifier_call_chain); 191fe9d4f57SAlexey Dobriyan 192b40a2cb6SMasami Hiramatsu int atomic_notifier_call_chain(struct atomic_notifier_head *nh, 193fe9d4f57SAlexey Dobriyan unsigned long val, void *v) 194fe9d4f57SAlexey Dobriyan { 195fe9d4f57SAlexey Dobriyan return __atomic_notifier_call_chain(nh, val, v, -1, NULL); 196fe9d4f57SAlexey Dobriyan } 197fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(atomic_notifier_call_chain); 198b40a2cb6SMasami Hiramatsu NOKPROBE_SYMBOL(atomic_notifier_call_chain); 199fe9d4f57SAlexey Dobriyan 200fe9d4f57SAlexey Dobriyan /* 201fe9d4f57SAlexey Dobriyan * Blocking notifier chain routines. All access to the chain is 202fe9d4f57SAlexey Dobriyan * synchronized by an rwsem. 203fe9d4f57SAlexey Dobriyan */ 204fe9d4f57SAlexey Dobriyan 205fe9d4f57SAlexey Dobriyan /** 206fe9d4f57SAlexey Dobriyan * blocking_notifier_chain_register - Add notifier to a blocking notifier chain 207fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the blocking notifier chain 208fe9d4f57SAlexey Dobriyan * @n: New entry in notifier chain 209fe9d4f57SAlexey Dobriyan * 210fe9d4f57SAlexey Dobriyan * Adds a notifier to a blocking notifier chain. 211fe9d4f57SAlexey Dobriyan * Must be called in process context. 212fe9d4f57SAlexey Dobriyan * 213fe9d4f57SAlexey Dobriyan * Currently always returns zero. 214fe9d4f57SAlexey Dobriyan */ 215fe9d4f57SAlexey Dobriyan int blocking_notifier_chain_register(struct blocking_notifier_head *nh, 216fe9d4f57SAlexey Dobriyan struct notifier_block *n) 217fe9d4f57SAlexey Dobriyan { 218fe9d4f57SAlexey Dobriyan int ret; 219fe9d4f57SAlexey Dobriyan 220fe9d4f57SAlexey Dobriyan /* 221fe9d4f57SAlexey Dobriyan * This code gets used during boot-up, when task switching is 222fe9d4f57SAlexey Dobriyan * not yet working and interrupts must remain disabled. At 223fe9d4f57SAlexey Dobriyan * such times we must not call down_write(). 224fe9d4f57SAlexey Dobriyan */ 225fe9d4f57SAlexey Dobriyan if (unlikely(system_state == SYSTEM_BOOTING)) 226fe9d4f57SAlexey Dobriyan return notifier_chain_register(&nh->head, n); 227fe9d4f57SAlexey Dobriyan 228fe9d4f57SAlexey Dobriyan down_write(&nh->rwsem); 229fe9d4f57SAlexey Dobriyan ret = notifier_chain_register(&nh->head, n); 230fe9d4f57SAlexey Dobriyan up_write(&nh->rwsem); 231fe9d4f57SAlexey Dobriyan return ret; 232fe9d4f57SAlexey Dobriyan } 233fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(blocking_notifier_chain_register); 234fe9d4f57SAlexey Dobriyan 235fe9d4f57SAlexey Dobriyan /** 2366546bc42SNadia Derbey * blocking_notifier_chain_cond_register - Cond add notifier to a blocking notifier chain 2376546bc42SNadia Derbey * @nh: Pointer to head of the blocking notifier chain 2386546bc42SNadia Derbey * @n: New entry in notifier chain 2396546bc42SNadia Derbey * 2406546bc42SNadia Derbey * Adds a notifier to a blocking notifier chain, only if not already 2416546bc42SNadia Derbey * present in the chain. 2426546bc42SNadia Derbey * Must be called in process context. 2436546bc42SNadia Derbey * 2446546bc42SNadia Derbey * Currently always returns zero. 2456546bc42SNadia Derbey */ 2466546bc42SNadia Derbey int blocking_notifier_chain_cond_register(struct blocking_notifier_head *nh, 2476546bc42SNadia Derbey struct notifier_block *n) 2486546bc42SNadia Derbey { 2496546bc42SNadia Derbey int ret; 2506546bc42SNadia Derbey 2516546bc42SNadia Derbey down_write(&nh->rwsem); 2526546bc42SNadia Derbey ret = notifier_chain_cond_register(&nh->head, n); 2536546bc42SNadia Derbey up_write(&nh->rwsem); 2546546bc42SNadia Derbey return ret; 2556546bc42SNadia Derbey } 2566546bc42SNadia Derbey EXPORT_SYMBOL_GPL(blocking_notifier_chain_cond_register); 2576546bc42SNadia Derbey 2586546bc42SNadia Derbey /** 259fe9d4f57SAlexey Dobriyan * blocking_notifier_chain_unregister - Remove notifier from a blocking notifier chain 260fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the blocking notifier chain 261fe9d4f57SAlexey Dobriyan * @n: Entry to remove from notifier chain 262fe9d4f57SAlexey Dobriyan * 263fe9d4f57SAlexey Dobriyan * Removes a notifier from a blocking notifier chain. 264fe9d4f57SAlexey Dobriyan * Must be called from process context. 265fe9d4f57SAlexey Dobriyan * 266fe9d4f57SAlexey Dobriyan * Returns zero on success or %-ENOENT on failure. 267fe9d4f57SAlexey Dobriyan */ 268fe9d4f57SAlexey Dobriyan int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh, 269fe9d4f57SAlexey Dobriyan struct notifier_block *n) 270fe9d4f57SAlexey Dobriyan { 271fe9d4f57SAlexey Dobriyan int ret; 272fe9d4f57SAlexey Dobriyan 273fe9d4f57SAlexey Dobriyan /* 274fe9d4f57SAlexey Dobriyan * This code gets used during boot-up, when task switching is 275fe9d4f57SAlexey Dobriyan * not yet working and interrupts must remain disabled. At 276fe9d4f57SAlexey Dobriyan * such times we must not call down_write(). 277fe9d4f57SAlexey Dobriyan */ 278fe9d4f57SAlexey Dobriyan if (unlikely(system_state == SYSTEM_BOOTING)) 279fe9d4f57SAlexey Dobriyan return notifier_chain_unregister(&nh->head, n); 280fe9d4f57SAlexey Dobriyan 281fe9d4f57SAlexey Dobriyan down_write(&nh->rwsem); 282fe9d4f57SAlexey Dobriyan ret = notifier_chain_unregister(&nh->head, n); 283fe9d4f57SAlexey Dobriyan up_write(&nh->rwsem); 284fe9d4f57SAlexey Dobriyan return ret; 285fe9d4f57SAlexey Dobriyan } 286fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister); 287fe9d4f57SAlexey Dobriyan 288fe9d4f57SAlexey Dobriyan /** 289fe9d4f57SAlexey Dobriyan * __blocking_notifier_call_chain - Call functions in a blocking notifier chain 290fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the blocking notifier chain 291fe9d4f57SAlexey Dobriyan * @val: Value passed unmodified to notifier function 292fe9d4f57SAlexey Dobriyan * @v: Pointer passed unmodified to notifier function 293fe9d4f57SAlexey Dobriyan * @nr_to_call: See comment for notifier_call_chain. 294fe9d4f57SAlexey Dobriyan * @nr_calls: See comment for notifier_call_chain. 295fe9d4f57SAlexey Dobriyan * 296fe9d4f57SAlexey Dobriyan * Calls each function in a notifier chain in turn. The functions 297fe9d4f57SAlexey Dobriyan * run in a process context, so they are allowed to block. 298fe9d4f57SAlexey Dobriyan * 299fe9d4f57SAlexey Dobriyan * If the return value of the notifier can be and'ed 300fe9d4f57SAlexey Dobriyan * with %NOTIFY_STOP_MASK then blocking_notifier_call_chain() 301fe9d4f57SAlexey Dobriyan * will return immediately, with the return value of 302fe9d4f57SAlexey Dobriyan * the notifier function which halted execution. 303fe9d4f57SAlexey Dobriyan * Otherwise the return value is the return value 304fe9d4f57SAlexey Dobriyan * of the last notifier function called. 305fe9d4f57SAlexey Dobriyan */ 306fe9d4f57SAlexey Dobriyan int __blocking_notifier_call_chain(struct blocking_notifier_head *nh, 307fe9d4f57SAlexey Dobriyan unsigned long val, void *v, 308fe9d4f57SAlexey Dobriyan int nr_to_call, int *nr_calls) 309fe9d4f57SAlexey Dobriyan { 310fe9d4f57SAlexey Dobriyan int ret = NOTIFY_DONE; 311fe9d4f57SAlexey Dobriyan 312fe9d4f57SAlexey Dobriyan /* 313fe9d4f57SAlexey Dobriyan * We check the head outside the lock, but if this access is 314fe9d4f57SAlexey Dobriyan * racy then it does not matter what the result of the test 315fe9d4f57SAlexey Dobriyan * is, we re-check the list after having taken the lock anyway: 316fe9d4f57SAlexey Dobriyan */ 3178857563bSPaul E. McKenney if (rcu_access_pointer(nh->head)) { 318fe9d4f57SAlexey Dobriyan down_read(&nh->rwsem); 319fe9d4f57SAlexey Dobriyan ret = notifier_call_chain(&nh->head, val, v, nr_to_call, 320fe9d4f57SAlexey Dobriyan nr_calls); 321fe9d4f57SAlexey Dobriyan up_read(&nh->rwsem); 322fe9d4f57SAlexey Dobriyan } 323fe9d4f57SAlexey Dobriyan return ret; 324fe9d4f57SAlexey Dobriyan } 325fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(__blocking_notifier_call_chain); 326fe9d4f57SAlexey Dobriyan 327fe9d4f57SAlexey Dobriyan int blocking_notifier_call_chain(struct blocking_notifier_head *nh, 328fe9d4f57SAlexey Dobriyan unsigned long val, void *v) 329fe9d4f57SAlexey Dobriyan { 330fe9d4f57SAlexey Dobriyan return __blocking_notifier_call_chain(nh, val, v, -1, NULL); 331fe9d4f57SAlexey Dobriyan } 332fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(blocking_notifier_call_chain); 333fe9d4f57SAlexey Dobriyan 334fe9d4f57SAlexey Dobriyan /* 335fe9d4f57SAlexey Dobriyan * Raw notifier chain routines. There is no protection; 336fe9d4f57SAlexey Dobriyan * the caller must provide it. Use at your own risk! 337fe9d4f57SAlexey Dobriyan */ 338fe9d4f57SAlexey Dobriyan 339fe9d4f57SAlexey Dobriyan /** 340fe9d4f57SAlexey Dobriyan * raw_notifier_chain_register - Add notifier to a raw notifier chain 341fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the raw notifier chain 342fe9d4f57SAlexey Dobriyan * @n: New entry in notifier chain 343fe9d4f57SAlexey Dobriyan * 344fe9d4f57SAlexey Dobriyan * Adds a notifier to a raw notifier chain. 345fe9d4f57SAlexey Dobriyan * All locking must be provided by the caller. 346fe9d4f57SAlexey Dobriyan * 347fe9d4f57SAlexey Dobriyan * Currently always returns zero. 348fe9d4f57SAlexey Dobriyan */ 349fe9d4f57SAlexey Dobriyan int raw_notifier_chain_register(struct raw_notifier_head *nh, 350fe9d4f57SAlexey Dobriyan struct notifier_block *n) 351fe9d4f57SAlexey Dobriyan { 352fe9d4f57SAlexey Dobriyan return notifier_chain_register(&nh->head, n); 353fe9d4f57SAlexey Dobriyan } 354fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(raw_notifier_chain_register); 355fe9d4f57SAlexey Dobriyan 356fe9d4f57SAlexey Dobriyan /** 357fe9d4f57SAlexey Dobriyan * raw_notifier_chain_unregister - Remove notifier from a raw notifier chain 358fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the raw notifier chain 359fe9d4f57SAlexey Dobriyan * @n: Entry to remove from notifier chain 360fe9d4f57SAlexey Dobriyan * 361fe9d4f57SAlexey Dobriyan * Removes a notifier from a raw notifier chain. 362fe9d4f57SAlexey Dobriyan * All locking must be provided by the caller. 363fe9d4f57SAlexey Dobriyan * 364fe9d4f57SAlexey Dobriyan * Returns zero on success or %-ENOENT on failure. 365fe9d4f57SAlexey Dobriyan */ 366fe9d4f57SAlexey Dobriyan int raw_notifier_chain_unregister(struct raw_notifier_head *nh, 367fe9d4f57SAlexey Dobriyan struct notifier_block *n) 368fe9d4f57SAlexey Dobriyan { 369fe9d4f57SAlexey Dobriyan return notifier_chain_unregister(&nh->head, n); 370fe9d4f57SAlexey Dobriyan } 371fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister); 372fe9d4f57SAlexey Dobriyan 373fe9d4f57SAlexey Dobriyan /** 374fe9d4f57SAlexey Dobriyan * __raw_notifier_call_chain - Call functions in a raw notifier chain 375fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the raw notifier chain 376fe9d4f57SAlexey Dobriyan * @val: Value passed unmodified to notifier function 377fe9d4f57SAlexey Dobriyan * @v: Pointer passed unmodified to notifier function 378fe9d4f57SAlexey Dobriyan * @nr_to_call: See comment for notifier_call_chain. 379fe9d4f57SAlexey Dobriyan * @nr_calls: See comment for notifier_call_chain 380fe9d4f57SAlexey Dobriyan * 381fe9d4f57SAlexey Dobriyan * Calls each function in a notifier chain in turn. The functions 382fe9d4f57SAlexey Dobriyan * run in an undefined context. 383fe9d4f57SAlexey Dobriyan * All locking must be provided by the caller. 384fe9d4f57SAlexey Dobriyan * 385fe9d4f57SAlexey Dobriyan * If the return value of the notifier can be and'ed 386fe9d4f57SAlexey Dobriyan * with %NOTIFY_STOP_MASK then raw_notifier_call_chain() 387fe9d4f57SAlexey Dobriyan * will return immediately, with the return value of 388fe9d4f57SAlexey Dobriyan * the notifier function which halted execution. 389fe9d4f57SAlexey Dobriyan * Otherwise the return value is the return value 390fe9d4f57SAlexey Dobriyan * of the last notifier function called. 391fe9d4f57SAlexey Dobriyan */ 392fe9d4f57SAlexey Dobriyan int __raw_notifier_call_chain(struct raw_notifier_head *nh, 393fe9d4f57SAlexey Dobriyan unsigned long val, void *v, 394fe9d4f57SAlexey Dobriyan int nr_to_call, int *nr_calls) 395fe9d4f57SAlexey Dobriyan { 396fe9d4f57SAlexey Dobriyan return notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls); 397fe9d4f57SAlexey Dobriyan } 398fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(__raw_notifier_call_chain); 399fe9d4f57SAlexey Dobriyan 400fe9d4f57SAlexey Dobriyan int raw_notifier_call_chain(struct raw_notifier_head *nh, 401fe9d4f57SAlexey Dobriyan unsigned long val, void *v) 402fe9d4f57SAlexey Dobriyan { 403fe9d4f57SAlexey Dobriyan return __raw_notifier_call_chain(nh, val, v, -1, NULL); 404fe9d4f57SAlexey Dobriyan } 405fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(raw_notifier_call_chain); 406fe9d4f57SAlexey Dobriyan 40783fe27eaSPranith Kumar #ifdef CONFIG_SRCU 408fe9d4f57SAlexey Dobriyan /* 409fe9d4f57SAlexey Dobriyan * SRCU notifier chain routines. Registration and unregistration 410fe9d4f57SAlexey Dobriyan * use a mutex, and call_chain is synchronized by SRCU (no locks). 411fe9d4f57SAlexey Dobriyan */ 412fe9d4f57SAlexey Dobriyan 413fe9d4f57SAlexey Dobriyan /** 414fe9d4f57SAlexey Dobriyan * srcu_notifier_chain_register - Add notifier to an SRCU notifier chain 415fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the SRCU notifier chain 416fe9d4f57SAlexey Dobriyan * @n: New entry in notifier chain 417fe9d4f57SAlexey Dobriyan * 418fe9d4f57SAlexey Dobriyan * Adds a notifier to an SRCU notifier chain. 419fe9d4f57SAlexey Dobriyan * Must be called in process context. 420fe9d4f57SAlexey Dobriyan * 421fe9d4f57SAlexey Dobriyan * Currently always returns zero. 422fe9d4f57SAlexey Dobriyan */ 423fe9d4f57SAlexey Dobriyan int srcu_notifier_chain_register(struct srcu_notifier_head *nh, 424fe9d4f57SAlexey Dobriyan struct notifier_block *n) 425fe9d4f57SAlexey Dobriyan { 426fe9d4f57SAlexey Dobriyan int ret; 427fe9d4f57SAlexey Dobriyan 428fe9d4f57SAlexey Dobriyan /* 429fe9d4f57SAlexey Dobriyan * This code gets used during boot-up, when task switching is 430fe9d4f57SAlexey Dobriyan * not yet working and interrupts must remain disabled. At 431fe9d4f57SAlexey Dobriyan * such times we must not call mutex_lock(). 432fe9d4f57SAlexey Dobriyan */ 433fe9d4f57SAlexey Dobriyan if (unlikely(system_state == SYSTEM_BOOTING)) 434fe9d4f57SAlexey Dobriyan return notifier_chain_register(&nh->head, n); 435fe9d4f57SAlexey Dobriyan 436fe9d4f57SAlexey Dobriyan mutex_lock(&nh->mutex); 437fe9d4f57SAlexey Dobriyan ret = notifier_chain_register(&nh->head, n); 438fe9d4f57SAlexey Dobriyan mutex_unlock(&nh->mutex); 439fe9d4f57SAlexey Dobriyan return ret; 440fe9d4f57SAlexey Dobriyan } 441fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(srcu_notifier_chain_register); 442fe9d4f57SAlexey Dobriyan 443fe9d4f57SAlexey Dobriyan /** 444fe9d4f57SAlexey Dobriyan * srcu_notifier_chain_unregister - Remove notifier from an SRCU notifier chain 445fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the SRCU notifier chain 446fe9d4f57SAlexey Dobriyan * @n: Entry to remove from notifier chain 447fe9d4f57SAlexey Dobriyan * 448fe9d4f57SAlexey Dobriyan * Removes a notifier from an SRCU notifier chain. 449fe9d4f57SAlexey Dobriyan * Must be called from process context. 450fe9d4f57SAlexey Dobriyan * 451fe9d4f57SAlexey Dobriyan * Returns zero on success or %-ENOENT on failure. 452fe9d4f57SAlexey Dobriyan */ 453fe9d4f57SAlexey Dobriyan int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh, 454fe9d4f57SAlexey Dobriyan struct notifier_block *n) 455fe9d4f57SAlexey Dobriyan { 456fe9d4f57SAlexey Dobriyan int ret; 457fe9d4f57SAlexey Dobriyan 458fe9d4f57SAlexey Dobriyan /* 459fe9d4f57SAlexey Dobriyan * This code gets used during boot-up, when task switching is 460fe9d4f57SAlexey Dobriyan * not yet working and interrupts must remain disabled. At 461fe9d4f57SAlexey Dobriyan * such times we must not call mutex_lock(). 462fe9d4f57SAlexey Dobriyan */ 463fe9d4f57SAlexey Dobriyan if (unlikely(system_state == SYSTEM_BOOTING)) 464fe9d4f57SAlexey Dobriyan return notifier_chain_unregister(&nh->head, n); 465fe9d4f57SAlexey Dobriyan 466fe9d4f57SAlexey Dobriyan mutex_lock(&nh->mutex); 467fe9d4f57SAlexey Dobriyan ret = notifier_chain_unregister(&nh->head, n); 468fe9d4f57SAlexey Dobriyan mutex_unlock(&nh->mutex); 469fe9d4f57SAlexey Dobriyan synchronize_srcu(&nh->srcu); 470fe9d4f57SAlexey Dobriyan return ret; 471fe9d4f57SAlexey Dobriyan } 472fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister); 473fe9d4f57SAlexey Dobriyan 474fe9d4f57SAlexey Dobriyan /** 475fe9d4f57SAlexey Dobriyan * __srcu_notifier_call_chain - Call functions in an SRCU notifier chain 476fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the SRCU notifier chain 477fe9d4f57SAlexey Dobriyan * @val: Value passed unmodified to notifier function 478fe9d4f57SAlexey Dobriyan * @v: Pointer passed unmodified to notifier function 479fe9d4f57SAlexey Dobriyan * @nr_to_call: See comment for notifier_call_chain. 480fe9d4f57SAlexey Dobriyan * @nr_calls: See comment for notifier_call_chain 481fe9d4f57SAlexey Dobriyan * 482fe9d4f57SAlexey Dobriyan * Calls each function in a notifier chain in turn. The functions 483fe9d4f57SAlexey Dobriyan * run in a process context, so they are allowed to block. 484fe9d4f57SAlexey Dobriyan * 485fe9d4f57SAlexey Dobriyan * If the return value of the notifier can be and'ed 486fe9d4f57SAlexey Dobriyan * with %NOTIFY_STOP_MASK then srcu_notifier_call_chain() 487fe9d4f57SAlexey Dobriyan * will return immediately, with the return value of 488fe9d4f57SAlexey Dobriyan * the notifier function which halted execution. 489fe9d4f57SAlexey Dobriyan * Otherwise the return value is the return value 490fe9d4f57SAlexey Dobriyan * of the last notifier function called. 491fe9d4f57SAlexey Dobriyan */ 492fe9d4f57SAlexey Dobriyan int __srcu_notifier_call_chain(struct srcu_notifier_head *nh, 493fe9d4f57SAlexey Dobriyan unsigned long val, void *v, 494fe9d4f57SAlexey Dobriyan int nr_to_call, int *nr_calls) 495fe9d4f57SAlexey Dobriyan { 496fe9d4f57SAlexey Dobriyan int ret; 497fe9d4f57SAlexey Dobriyan int idx; 498fe9d4f57SAlexey Dobriyan 499fe9d4f57SAlexey Dobriyan idx = srcu_read_lock(&nh->srcu); 500fe9d4f57SAlexey Dobriyan ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls); 501fe9d4f57SAlexey Dobriyan srcu_read_unlock(&nh->srcu, idx); 502fe9d4f57SAlexey Dobriyan return ret; 503fe9d4f57SAlexey Dobriyan } 504fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(__srcu_notifier_call_chain); 505fe9d4f57SAlexey Dobriyan 506fe9d4f57SAlexey Dobriyan int srcu_notifier_call_chain(struct srcu_notifier_head *nh, 507fe9d4f57SAlexey Dobriyan unsigned long val, void *v) 508fe9d4f57SAlexey Dobriyan { 509fe9d4f57SAlexey Dobriyan return __srcu_notifier_call_chain(nh, val, v, -1, NULL); 510fe9d4f57SAlexey Dobriyan } 511fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(srcu_notifier_call_chain); 512fe9d4f57SAlexey Dobriyan 513fe9d4f57SAlexey Dobriyan /** 514fe9d4f57SAlexey Dobriyan * srcu_init_notifier_head - Initialize an SRCU notifier head 515fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the srcu notifier chain 516fe9d4f57SAlexey Dobriyan * 517fe9d4f57SAlexey Dobriyan * Unlike other sorts of notifier heads, SRCU notifier heads require 518fe9d4f57SAlexey Dobriyan * dynamic initialization. Be sure to call this routine before 519fe9d4f57SAlexey Dobriyan * calling any of the other SRCU notifier routines for this head. 520fe9d4f57SAlexey Dobriyan * 521fe9d4f57SAlexey Dobriyan * If an SRCU notifier head is deallocated, it must first be cleaned 522fe9d4f57SAlexey Dobriyan * up by calling srcu_cleanup_notifier_head(). Otherwise the head's 523fe9d4f57SAlexey Dobriyan * per-cpu data (used by the SRCU mechanism) will leak. 524fe9d4f57SAlexey Dobriyan */ 525fe9d4f57SAlexey Dobriyan void srcu_init_notifier_head(struct srcu_notifier_head *nh) 526fe9d4f57SAlexey Dobriyan { 527fe9d4f57SAlexey Dobriyan mutex_init(&nh->mutex); 528fe9d4f57SAlexey Dobriyan if (init_srcu_struct(&nh->srcu) < 0) 529fe9d4f57SAlexey Dobriyan BUG(); 530fe9d4f57SAlexey Dobriyan nh->head = NULL; 531fe9d4f57SAlexey Dobriyan } 532fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(srcu_init_notifier_head); 533fe9d4f57SAlexey Dobriyan 53483fe27eaSPranith Kumar #endif /* CONFIG_SRCU */ 53583fe27eaSPranith Kumar 536fe9d4f57SAlexey Dobriyan static ATOMIC_NOTIFIER_HEAD(die_chain); 537fe9d4f57SAlexey Dobriyan 538b40a2cb6SMasami Hiramatsu int notrace notify_die(enum die_val val, const char *str, 539fe9d4f57SAlexey Dobriyan struct pt_regs *regs, long err, int trap, int sig) 540fe9d4f57SAlexey Dobriyan { 541fe9d4f57SAlexey Dobriyan struct die_args args = { 542fe9d4f57SAlexey Dobriyan .regs = regs, 543fe9d4f57SAlexey Dobriyan .str = str, 544fe9d4f57SAlexey Dobriyan .err = err, 545fe9d4f57SAlexey Dobriyan .trapnr = trap, 546fe9d4f57SAlexey Dobriyan .signr = sig, 547fe9d4f57SAlexey Dobriyan 548fe9d4f57SAlexey Dobriyan }; 5495778077dSLinus Torvalds RCU_LOCKDEP_WARN(!rcu_is_watching(), 550e727c7d7SAndy Lutomirski "notify_die called but RCU thinks we're quiescent"); 551fe9d4f57SAlexey Dobriyan return atomic_notifier_call_chain(&die_chain, val, &args); 552fe9d4f57SAlexey Dobriyan } 553b40a2cb6SMasami Hiramatsu NOKPROBE_SYMBOL(notify_die); 554fe9d4f57SAlexey Dobriyan 555fe9d4f57SAlexey Dobriyan int register_die_notifier(struct notifier_block *nb) 556fe9d4f57SAlexey Dobriyan { 557fe9d4f57SAlexey Dobriyan vmalloc_sync_all(); 558fe9d4f57SAlexey Dobriyan return atomic_notifier_chain_register(&die_chain, nb); 559fe9d4f57SAlexey Dobriyan } 560fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(register_die_notifier); 561fe9d4f57SAlexey Dobriyan 562fe9d4f57SAlexey Dobriyan int unregister_die_notifier(struct notifier_block *nb) 563fe9d4f57SAlexey Dobriyan { 564fe9d4f57SAlexey Dobriyan return atomic_notifier_chain_unregister(&die_chain, nb); 565fe9d4f57SAlexey Dobriyan } 566fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(unregister_die_notifier); 567