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