diff options
63 files changed, 677 insertions, 472 deletions
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index 9402624453c2..dd8769670596 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -43,7 +43,7 @@ #include <asm/setup.h> #include <asm/io.h> -extern struct notifier_block *panic_notifier_list; +extern struct atomic_notifier_head panic_notifier_list; static int alpha_panic_event(struct notifier_block *, unsigned long, void *); static struct notifier_block alpha_panic_block = { alpha_panic_event, @@ -500,7 +500,8 @@ setup_arch(char **cmdline_p) } /* Register a call for panic conditions. */ - notifier_chain_register(&panic_notifier_list, &alpha_panic_block); + atomic_notifier_chain_register(&panic_notifier_list, + &alpha_panic_block); #ifdef CONFIG_ALPHA_GENERIC /* Assume that we've booted from SRM if we haven't booted from MILO. diff --git a/arch/arm/mach-omap1/board-netstar.c b/arch/arm/mach-omap1/board-netstar.c index 60d5f8a3339c..7520e602d7a2 100644 --- a/arch/arm/mach-omap1/board-netstar.c +++ b/arch/arm/mach-omap1/board-netstar.c @@ -141,7 +141,7 @@ static int __init netstar_late_init(void) /* TODO: Setup front panel switch here */ /* Setup panic notifier */ - notifier_chain_register(&panic_notifier_list, &panic_block); + atomic_notifier_chain_register(&panic_notifier_list, &panic_block); return 0; } diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c index bfd5fdd1a875..52e4a9d69642 100644 --- a/arch/arm/mach-omap1/board-voiceblue.c +++ b/arch/arm/mach-omap1/board-voiceblue.c @@ -235,7 +235,7 @@ static struct notifier_block panic_block = { static int __init voiceblue_setup(void) { /* Setup panic notifier */ - notifier_chain_register(&panic_notifier_list, &panic_block); + atomic_notifier_chain_register(&panic_notifier_list, &panic_block); return 0; } diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 4624f8ca2459..6b63a5aa1e46 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -92,22 +92,21 @@ asmlinkage void spurious_interrupt_bug(void); asmlinkage void machine_check(void); static int kstack_depth_to_print = 24; -struct notifier_block *i386die_chain; -static DEFINE_SPINLOCK(die_notifier_lock); +ATOMIC_NOTIFIER_HEAD(i386die_chain); int register_die_notifier(struct notifier_block *nb) { - int err = 0; - unsigned long flags; - vmalloc_sync_all(); - spin_lock_irqsave(&die_notifier_lock, flags); - err = notifier_chain_register(&i386die_chain, nb); - spin_unlock_irqrestore(&die_notifier_lock, flags); - return err; + return atomic_notifier_chain_register(&i386die_chain, nb); } EXPORT_SYMBOL(register_die_notifier); +int unregister_die_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&i386die_chain, nb); +} +EXPORT_SYMBOL(unregister_die_notifier); + static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) { return p > (void *)tinfo && diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c index dabd6c32641e..7c1ddc8ac443 100644 --- a/arch/ia64/kernel/traps.c +++ b/arch/ia64/kernel/traps.c @@ -30,19 +30,19 @@ extern spinlock_t timerlist_lock; fpswa_interface_t *fpswa_interface; EXPORT_SYMBOL(fpswa_interface); -struct notifier_block *ia64die_chain; +ATOMIC_NOTIFIER_HEAD(ia64die_chain); int register_die_notifier(struct notifier_block *nb) { - return notifier_chain_register(&ia64die_chain, nb); + return atomic_notifier_chain_register(&ia64die_chain, nb); } EXPORT_SYMBOL_GPL(register_die_notifier); int unregister_die_notifier(struct notifier_block *nb) { - return notifier_chain_unregister(&ia64die_chain, nb); + return atomic_notifier_chain_unregister(&ia64die_chain, nb); } EXPORT_SYMBOL_GPL(unregister_die_notifier); diff --git a/arch/mips/lasat/setup.c b/arch/mips/lasat/setup.c index 83eb08b7a072..e9e9a89c6741 100644 --- a/arch/mips/lasat/setup.c +++ b/arch/mips/lasat/setup.c @@ -165,7 +165,8 @@ void __init plat_setup(void) /* Set up panic notifier */ for (i = 0; i < sizeof(lasat_panic_block) / sizeof(struct notifier_block); i++) - notifier_chain_register(&panic_notifier_list, &lasat_panic_block[i]); + atomic_notifier_chain_register(&panic_notifier_list, + &lasat_panic_block[i]); lasat_reboot_setup(); diff --git a/arch/mips/sgi-ip22/ip22-reset.c b/arch/mips/sgi-ip22/ip22-reset.c index 92a3b3c15ed3..a9c58e067b53 100644 --- a/arch/mips/sgi-ip22/ip22-reset.c +++ b/arch/mips/sgi-ip22/ip22-reset.c @@ -238,7 +238,7 @@ static int __init reboot_setup(void) request_irq(SGI_PANEL_IRQ, panel_int, 0, "Front Panel", NULL); init_timer(&blink_timer); blink_timer.function = blink_timeout; - notifier_chain_register(&panic_notifier_list, &panic_block); + atomic_notifier_chain_register(&panic_notifier_list, &panic_block); return 0; } diff --git a/arch/mips/sgi-ip32/ip32-reset.c b/arch/mips/sgi-ip32/ip32-reset.c index 0c948008b023..ab9d9cef089e 100644 --- a/arch/mips/sgi-ip32/ip32-reset.c +++ b/arch/mips/sgi-ip32/ip32-reset.c @@ -193,7 +193,7 @@ static __init int ip32_reboot_setup(void) init_timer(&blink_timer); blink_timer.function = blink_timeout; - notifier_chain_register(&panic_notifier_list, &panic_block); + atomic_notifier_chain_register(&panic_notifier_list, &panic_block); request_irq(MACEISA_RTC_IRQ, ip32_rtc_int, 0, "rtc", NULL); diff --git a/arch/parisc/kernel/pdc_chassis.c b/arch/parisc/kernel/pdc_chassis.c index 2a01fe1bdc98..0cea6958f427 100644 --- a/arch/parisc/kernel/pdc_chassis.c +++ b/arch/parisc/kernel/pdc_chassis.c @@ -150,7 +150,8 @@ void __init parisc_pdc_chassis_init(void) if (handle) { /* initialize panic notifier chain */ - notifier_chain_register(&panic_notifier_list, &pdc_chassis_panic_block); + atomic_notifier_chain_register(&panic_notifier_list, + &pdc_chassis_panic_block); /* initialize reboot notifier chain */ register_reboot_notifier(&pdc_chassis_reboot_block); diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 2f3fdad35594..e20c1fae3423 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -579,7 +579,8 @@ void __init setup_arch(char **cmdline_p) panic_timeout = 180; if (ppc_md.panic) - notifier_chain_register(&panic_notifier_list, &ppc64_panic_block); + atomic_notifier_chain_register(&panic_notifier_list, + &ppc64_panic_block); init_mm.start_code = PAGE_OFFSET; init_mm.end_code = (unsigned long) _etext; diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 98660aedeeb7..9763faab6739 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -74,19 +74,19 @@ EXPORT_SYMBOL(__debugger_dabr_match); EXPORT_SYMBOL(__debugger_fault_handler); #endif -struct notifier_block *powerpc_die_chain; -static DEFINE_SPINLOCK(die_notifier_lock); +ATOMIC_NOTIFIER_HEAD(powerpc_die_chain); int register_die_notifier(struct notifier_block *nb) { - int err = 0; - unsigned long flags; + return atomic_notifier_chain_register(&powerpc_die_chain, nb); +} +EXPORT_SYMBOL(register_die_notifier); - spin_lock_irqsave(&die_notifier_lock, flags); - err = notifier_chain_register(&powerpc_die_chain, nb); - spin_unlock_irqrestore(&die_notifier_lock, flags); - return err; +int unregister_die_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&powerpc_die_chain, nb); } +EXPORT_SYMBOL(unregister_die_notifier); /* * Trap & Exception support diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index 86cfa6ecdcf3..5ad90676567a 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c @@ -94,16 +94,16 @@ static struct device_node *derive_parent(const char *path) return parent; } -static struct notifier_block *pSeries_reconfig_chain; +static BLOCKING_NOTIFIER_HEAD(pSeries_reconfig_chain); int pSeries_reconfig_notifier_register(struct notifier_block *nb) { - return notifier_chain_register(&pSeries_reconfig_chain, nb); + return blocking_notifier_chain_register(&pSeries_reconfig_chain, nb); } void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { - notifier_chain_unregister(&pSeries_reconfig_chain, nb); + blocking_notifier_chain_unregister(&pSeries_reconfig_chain, nb); } static int pSeries_reconfig_add_node(const char *path, struct property *proplist) @@ -131,7 +131,7 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist goto out_err; } - err = notifier_call_chain(&pSeries_reconfig_chain, + err = blocking_notifier_call_chain(&pSeries_reconfig_chain, PSERIES_RECONFIG_ADD, np); if (err == NOTIFY_BAD) { printk(KERN_ERR "Failed to add device node %s\n", path); @@ -171,7 +171,7 @@ static int pSeries_reconfig_remove_node(struct device_node *np) remove_node_proc_entries(np); - notifier_call_chain(&pSeries_reconfig_chain, + blocking_notifier_call_chain(&pSeries_reconfig_chain, PSERIES_RECONFIG_REMOVE, np); of_detach_node(np); diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c index a0fc628ffb1e..d95c05d9824d 100644 --- a/arch/ppc/platforms/prep_setup.c +++ b/arch/ppc/platforms/prep_setup.c @@ -736,7 +736,7 @@ ibm_statusled_progress(char *s, unsigned short hex) hex = 0xfff; if (!notifier_installed) { ++notifier_installed; - notifier_chain_register(&panic_notifier_list, + atomic_notifier_chain_register(&panic_notifier_list, &ibm_statusled_block); } } diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 99182a415fe7..4a0f5a1551ea 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -76,17 +76,17 @@ unsigned long thread_saved_pc(struct task_struct *tsk) /* * Need to know about CPUs going idle? */ -static struct notifier_block *idle_chain; +static ATOMIC_NOTIFIER_HEAD(idle_chain); int register_idle_notifier(struct notifier_block *nb) { - return notifier_chain_register(&idle_chain, nb); + return atomic_notifier_chain_register(&idle_chain, nb); } EXPORT_SYMBOL(register_idle_notifier); int unregister_idle_notifier(struct notifier_block *nb) { - return notifier_chain_unregister(&idle_chain, nb); + return atomic_notifier_chain_unregister(&idle_chain, nb); } EXPORT_SYMBOL(unregister_idle_notifier); @@ -95,7 +95,7 @@ void do_monitor_call(struct pt_regs *regs, long interruption_code) /* disable monitor call class 0 */ __ctl_clear_bit(8, 15); - notifier_call_chain(&idle_chain, CPU_NOT_IDLE, + atomic_notifier_call_chain(&idle_chain, CPU_NOT_IDLE, (void *)(long) smp_processor_id()); } @@ -116,7 +116,8 @@ static void default_idle(void) return; } - rc = notifier_call_chain(&idle_chain, CPU_IDLE, (void *)(long) cpu); + rc = atomic_notifier_call_chain(&idle_chain, + CPU_IDLE, (void *)(long) cpu); if (rc != NOTIFY_OK && rc != NOTIFY_DONE) BUG(); if (rc != NOTIFY_OK) { diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index df612e4f75f9..ff090bb9734b 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -43,18 +43,19 @@ #include <linux/kmod.h> #endif -struct notifier_block *sparc64die_chain; -static DEFINE_SPINLOCK(die_notifier_lock); +ATOMIC_NOTIFIER_HEAD(sparc64die_chain); int register_die_notifier(struct notifier_block *nb) { - int err = 0; - unsigned long flags; - spin_lock_irqsave(&die_notifier_lock, flags); - err = notifier_chain_register(&sparc64die_chain, nb); - spin_unlock_irqrestore(&die_notifier_lock, flags); - return err; + return atomic_notifier_chain_register(&sparc64die_chain, nb); } +EXPORT_SYMBOL(register_die_notifier); + +int unregister_die_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&sparc64die_chain, nb); +} +EXPORT_SYMBOL(unregister_die_notifier); /* When an irrecoverable trap occurs at tl > 0, the trap entry * code logs the trap state registers at every level in the trap diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 54388d10bcf9..1488816588ea 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -762,7 +762,8 @@ static struct notifier_block panic_exit_notifier = { static int add_notifier(void) { - notifier_chain_register(&panic_notifier_list, &panic_exit_notifier); + atomic_notifier_chain_register(&panic_notifier_list, + &panic_exit_notifier); return(0); } diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index bb1c87211ac1..7d51dd7201c3 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -477,7 +477,8 @@ static struct notifier_block panic_exit_notifier = { void __init setup_arch(char **cmdline_p) { - notifier_chain_register(&panic_notifier_list, &panic_exit_notifier); + atomic_notifier_chain_register(&panic_notifier_list, + &panic_exit_notifier); paging_init(); strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); *cmdline_p = command_line; diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index 0370720515f1..70dd8e5c6889 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -66,24 +66,17 @@ EXPORT_SYMBOL(boot_option_idle_override); void (*pm_idle)(void); static DEFINE_PER_CPU(unsigned int, cpu_idle_state); -static struct notifier_block *idle_notifier; -static DEFINE_SPINLOCK(idle_notifier_lock); +static ATOMIC_NOTIFIER_HEAD(idle_notifier); void idle_notifier_register(struct notifier_block *n) { - unsigned long flags; - spin_lock_irqsave(&idle_notifier_lock, flags); - notifier_chain_register(&idle_notifier, n); - spin_unlock_irqrestore(&idle_notifier_lock, flags); + atomic_notifier_chain_register(&idle_notifier, n); } EXPORT_SYMBOL_GPL(idle_notifier_register); void idle_notifier_unregister(struct notifier_block *n) { - unsigned long flags; - spin_lock_irqsave(&idle_notifier_lock, flags); - notifier_chain_unregister(&idle_notifier, n); - spin_unlock_irqrestore(&idle_notifier_lock, flags); + atomic_notifier_chain_unregister(&idle_notifier, n); } EXPORT_SYMBOL(idle_notifier_unregister); @@ -93,13 +86,13 @@ static DEFINE_PER_CPU(enum idle_state, idle_state) = CPU_NOT_IDLE; void enter_idle(void) { __get_cpu_var(idle_state) = CPU_IDLE; - notifier_call_chain(&idle_notifier, IDLE_START, NULL); + atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL); } static void __exit_idle(void) { __get_cpu_var(idle_state) = CPU_NOT_IDLE; - notifier_call_chain(&idle_notifier, IDLE_END, NULL); + atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL); } /* Called from interrupts to signify idle end */ diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 7b148309c529..edaa9fe654dc 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -69,20 +69,20 @@ asmlinkage void alignment_check(void); asmlinkage void machine_check(void); asmlinkage void spurious_interrupt_bug(void); -struct notifier_block *die_chain; -static DEFINE_SPINLOCK(die_notifier_lock); +ATOMIC_NOTIFIER_HEAD(die_chain); int register_die_notifier(struct notifier_block *nb) { - int err = 0; - unsigned long flags; - vmalloc_sync_all(); - spin_lock_irqsave(&die_notifier_lock, flags); - err = notifier_chain_register(&die_chain, nb); - spin_unlock_irqrestore(&die_notifier_lock, flags); - return err; + return atomic_notifier_chain_register(&die_chain, nb); +} +EXPORT_SYMBOL(register_die_notifier); + +int unregister_die_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&die_chain, nb); } +EXPORT_SYMBOL(unregister_die_notifier); static inline void conditional_sti(struct pt_regs *regs) { diff --git a/arch/xtensa/platform-iss/setup.c b/arch/xtensa/platform-iss/setup.c index 2e6dcbf0cc04..23790a5610e2 100644 --- a/arch/xtensa/platform-iss/setup.c +++ b/arch/xtensa/platform-iss/setup.c @@ -108,5 +108,5 @@ static struct notifier_block iss_panic_block = { void __init platform_setup(char **p_cmdline) { - notifier_chain_register(&panic_notifier_list, &iss_panic_block); + atomic_notifier_chain_register(&panic_notifier_list, &iss_panic_block); } diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 105a0d61eb1f..dd547af4681a 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -47,16 +47,16 @@ static struct kset_uevent_ops memory_uevent_ops = { .uevent = memory_uevent, }; -static struct notifier_block *memory_chain; +static BLOCKING_NOTIFIER_HEAD(memory_chain); int register_memory_notifier(struct notifier_block *nb) { - return notifier_chain_register(&memory_chain, nb); + return blocking_notifier_chain_register(&memory_chain, nb); } void unregister_memory_notifier(struct notifier_block *nb) { - notifier_chain_unregister(&memory_chain, nb); + blocking_notifier_chain_unregister(&memory_chain, nb); } /* @@ -140,7 +140,7 @@ static ssize_t show_mem_state(struct sys_device *dev, char *buf) static inline int memory_notify(unsigned long val, void *v) { - return notifier_call_chain(&memory_chain, val, v); + return blocking_notifier_call_chain(&memory_chain, val, v); } /* diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index b8fb87c6c29f..40eb005b9d77 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -3744,7 +3744,7 @@ static int ipmi_init_msghandler(void) ipmi_timer.expires = jiffies + IPMI_TIMEOUT_JIFFIES; add_timer(&ipmi_timer); - notifier_chain_register(&panic_notifier_list, &panic_block); + atomic_notifier_chain_register(&panic_notifier_list, &panic_block); initialized = 1; @@ -3764,7 +3764,7 @@ static __exit void cleanup_ipmi(void) if (!initialized) return; - notifier_chain_unregister(&panic_notifier_list, &panic_block); + atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block); /* This can't be called if any interfaces exist, so no worry about shutting down the interfaces. */ diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 12f858dc9994..35fbd4d8ed4b 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -237,10 +237,10 @@ struct smi_info static int try_smi_init(struct smi_info *smi); -static struct notifier_block *xaction_notifier_list; +static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list); static int register_xaction_notifier(struct notifier_block * nb) { - return notifier_chain_register(&xaction_notifier_list, nb); + return atomic_notifier_chain_register(&xaction_notifier_list, nb); } static void si_restart_short_timer(struct smi_info *smi_info); @@ -302,7 +302,8 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) do_gettimeofday(&t); printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif - err = notifier_call_chain(&xaction_notifier_list, 0, smi_info); + err = atomic_notifier_call_chain(&xaction_notifier_list, + 0, smi_info); if (err & NOTIFY_STOP_MASK) { rv = SI_SM_CALL_WITHOUT_DELAY; goto out; diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 616539310d9a..7ece9f3c8f70 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -1158,7 +1158,8 @@ static int __init ipmi_wdog_init(void) } register_reboot_notifier(&wdog_reboot_notifier); - notifier_chain_register(&panic_notifier_list, &wdog_panic_notifier); + atomic_notifier_chain_register(&panic_notifier_list, + &wdog_panic_notifier); printk(KERN_INFO PFX "driver initialized\n"); @@ -1176,7 +1177,8 @@ static __exit void ipmi_unregister_watchdog(void) release_nmi(&ipmi_nmi_handler); #endif - notifier_chain_unregister(&panic_notifier_list, &wdog_panic_notifier); + atomic_notifier_chain_unregister(&panic_notifier_list, + &wdog_panic_notifier); unregister_reboot_notifier(&wdog_reboot_notifier); if (! watchdog_user) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index aed80e6aec6d..9b6ae7dc8b8a 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -52,9 +52,8 @@ static void handle_update(void *data); * changes to devices when the CPU clock speed changes. * The mutex locks both lists. */ -static struct notifier_block *cpufreq_policy_notifier_list; -static struct notifier_block *cpufreq_transition_notifier_list; -static DECLARE_RWSEM (cpufreq_notifier_rwsem); +static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list); +static BLOCKING_NOTIFIER_HEAD(cpufreq_transition_notifier_list); static LIST_HEAD(cpufreq_governor_list); @@ -247,8 +246,6 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) dprintk("notification %u of frequency transition to %u kHz\n", state, freqs->new); - down_read(&cpufreq_notifier_rwsem); - policy = cpufreq_cpu_data[freqs->cpu]; switch (state) { @@ -266,20 +263,19 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) freqs->old = policy->cur; } } - notifier_call_chain(&cpufreq_transition_notifier_list, - CPUFREQ_PRECHANGE, freqs); + blocking_notifier_call_chain(&cpufreq_transition_notifier_list, + CPUFREQ_PRECHANGE, freqs); adjust_jiffies(CPUFREQ_PRECHANGE, freqs); break; case CPUFREQ_POSTCHANGE: adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); - notifier_call_chain(&cpufreq_transition_notifier_list, - CPUFREQ_POSTCHANGE, freqs); + blocking_notifier_call_chain(&cpufreq_transition_notifier_list, + CPUFREQ_POSTCHANGE, freqs); if (likely(policy) && likely(policy->cpu == freqs->cpu)) policy->cur = freqs->new; break; } - up_read(&cpufreq_notifier_rwsem); } EXPORT_SYMBOL_GPL(cpufreq_notify_transition); @@ -1007,7 +1003,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg) freqs.old = cpu_policy->cur; freqs.new = cur_freq; - notifier_call_chain(&cpufreq_transition_notifier_list, + blocking_notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_SUSPENDCHANGE, &freqs); adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs); @@ -1088,7 +1084,8 @@ static int cpufreq_resume(struct sys_device * sysdev) freqs.old = cpu_policy->cur; freqs.new = cur_freq; - notifier_call_chain(&cpufreq_transition_notifier_list, + blocking_notifier_call_chain( + &cpufreq_transition_notifier_list, CPUFREQ_RESUMECHANGE, &freqs); adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs); @@ -1125,24 +1122,24 @@ static struct sysdev_driver cpufreq_sysdev_driver = { * changes in cpufreq policy. * * This function may sleep, and has the same return conditions as - * notifier_chain_register. + * blocking_notifier_chain_register. */ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list) { int ret; - down_write(&cpufreq_notifier_rwsem); switch (list) { case CPUFREQ_TRANSITION_NOTIFIER: - ret = notifier_chain_register(&cpufreq_transition_notifier_list, nb); + ret = blocking_notifier_chain_register( + &cpufreq_transition_notifier_list, nb); break; case CPUFREQ_POLICY_NOTIFIER: - ret = notifier_chain_register(&cpufreq_policy_notifier_list, nb); + ret = blocking_notifier_chain_register( + &cpufreq_policy_notifier_list, nb); break; default: ret = -EINVAL; } - up_write(&cpufreq_notifier_rwsem); return ret; } @@ -1157,24 +1154,24 @@ EXPORT_SYMBOL(cpufreq_register_notifier); * Remove a driver from the CPU frequency notifier list. * * This function may sleep, and has the same return conditions as - * notifier_chain_unregister. + * blocking_notifier_chain_unregister. */ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list) { int ret; - down_write(&cpufreq_notifier_rwsem); switch (list) { case CPUFREQ_TRANSITION_NOTIFIER: - ret = notifier_chain_unregister(&cpufreq_transition_notifier_list, nb); + ret = blocking_notifier_chain_unregister( + &cpufreq_transition_notifier_list, nb); break; case CPUFREQ_POLICY_NOTIFIER: - ret = notifier_chain_unregister(&cpufreq_policy_notifier_list, nb); + ret = blocking_notifier_chain_unregister( + &cpufreq_policy_notifier_list, nb); break; default: ret = -EINVAL; } - up_write(&cpufreq_notifier_rwsem); return ret; } @@ -1346,29 +1343,23 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_poli if (ret) goto error_out; - down_read(&cpufreq_notifier_rwsem); - /* adjust if necessary - all reasons */ - notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_ADJUST, - policy); + blocking_notifier_call_chain(&cpufreq_policy_notifier_list, + CPUFREQ_ADJUST, policy); /* adjust if necessary - hardware incompatibility*/ - notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_INCOMPATIBLE, - policy); + blocking_notifier_call_chain(&cpufreq_policy_notifier_list, + CPUFREQ_INCOMPATIBLE, policy); /* verify the cpu speed can be set within this limit, which might be different to the first one */ ret = cpufreq_driver->verify(policy); - if (ret) { - up_read(&cpufreq_notifier_rwsem); + if (ret) goto error_out; - } /* notification of the new policy */ - notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_NOTIFY, - policy); - - up_read(&cpufreq_notifier_rwsem); + blocking_notifier_call_chain(&cpufreq_policy_notifier_list, + CPUFREQ_NOTIFY, policy); data->min = policy->min; data->max = policy->max; diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c index d6543fc4a923..339f405ff708 100644 --- a/drivers/firmware/dcdbas.c +++ b/drivers/firmware/dcdbas.c @@ -484,26 +484,15 @@ static void dcdbas_host_control(void) static int dcdbas_reboot_notify(struct notifier_block *nb, unsigned long code, void *unused) { - static unsigned int notify_cnt = 0; - switch (code) { case SYS_DOWN: case SYS_HALT: case SYS_POWER_OFF: if (host_control_on_shutdown) { /* firmware is going to perform host control action */ - if (++notify_cnt == 2) { - printk(KERN_WARNING - "Please wait for shutdown " - "action to complete...\n"); - dcdbas_host_control(); - } - /* - * register again and initiate the host control - * action on the second notification to allow - * everyone that registered to be notified - */ - register_reboot_notifier(nb); + printk(KERN_WARNING "Please wait for shutdown " + "action to complete...\n"); + dcdbas_host_control(); } break; } @@ -514,7 +503,7 @@ static int dcdbas_reboot_notify(struct notifier_block *nb, unsigned long code, static struct notifier_block dcdbas_reboot_nb = { .notifier_call = dcdbas_reboot_notify, .next = NULL, - .priority = 0 + .priority = INT_MIN }; static DCDBAS_BIN_ATTR_RW(smi_data); diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index d2ead1776c16..34fcabac5fdb 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -80,7 +80,7 @@ static struct adb_driver *adb_driver_list[] = { static struct class *adb_dev_class; struct adb_driver *adb_controller; -struct notifier_block *adb_client_list = NULL; +BLOCKING_NOTIFIER_HEAD(adb_client_list); static int adb_got_sleep; static int adb_inited; static pid_t adb_probe_task_pid; @@ -354,7 +354,8 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when) /* Stop autopoll */ if (adb_controller->autopoll) adb_controller->autopoll(0); - ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL); + ret = blocking_notifier_call_chain(&adb_client_list, + ADB_MSG_POWERDOWN, NULL); if (ret & NOTIFY_STOP_MASK) { up(&adb_probe_mutex); return PBOOK_SLEEP_REFUSE; @@ -391,7 +392,8 @@ do_adb_reset_bus(void) if (adb_controller->autopoll) adb_controller->autopoll(0); - nret = notifier_call_chain(&adb_client_list, ADB_MSG_PRE_RESET, NULL); + nret = blocking_notifier_call_chain(&adb_client_list, + ADB_MSG_PRE_RESET, NULL); if (nret & NOTIFY_STOP_MASK) { if (adb_controller->autopoll) adb_controller->autopoll(autopoll_devs); @@ -426,7 +428,8 @@ do_adb_reset_bus(void) } up(&adb_handler_sem); - nret = notifier_call_chain(&adb_client_list, ADB_MSG_POST_RESET, NULL); + nret = blocking_notifier_call_chain(&adb_client_list, + ADB_MSG_POST_RESET, NULL); if (nret & NOTIFY_STOP_MASK) return -EBUSY; diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index c0b46bceb5df..f5779a73184d 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -1214,7 +1214,8 @@ static int __init adbhid_init(void) adbhid_probe(); - notifier_chain_register(&adb_client_list, &adbhid_adb_notifier); + blocking_notifier_chain_register(&adb_client_list, + &adbhid_adb_notifier); return 0; } diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 4f5f3abc9cb3..0b5ff553e39a 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -187,7 +187,7 @@ extern int disable_kernel_backlight; int __fake_sleep; int asleep; -struct notifier_block *sleep_notifier_list; +BLOCKING_NOTIFIER_HEAD(sleep_notifier_list); #ifdef CONFIG_ADB static int adb_dev_map = 0; diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c index f08e52f2107b..35b70323e7e3 100644 --- a/drivers/macintosh/via-pmu68k.c +++ b/drivers/macintosh/via-pmu68k.c @@ -102,7 +102,7 @@ static int pmu_kind = PMU_UNKNOWN; static int pmu_fully_inited = 0; int asleep; -struct notifier_block *sleep_notifier_list; +BLOCKING_NOTIFIER_HEAD(sleep_notifier_list); static int pmu_probe(void); static int pmu_init(void); @@ -913,7 +913,8 @@ int powerbook_sleep(void) struct adb_request sleep_req; /* Notify device drivers */ - ret = notifier_call_chain(&sleep_notifier_list, PBOOK_SLEEP, NULL); + ret = blocking_notifier_call_chain(&sleep_notifier_list, + PBOOK_SLEEP, NULL); if (ret & NOTIFY_STOP_MASK) return -EBUSY; @@ -984,7 +985,7 @@ int powerbook_sleep(void) enable_irq(i); /* Notify drivers */ - notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL); + blocking_notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL); /* reenable ADB autopoll */ pmu_adb_autopoll(adb_dev_map); diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c index 6c0ba04bc57a..ab3faa702d58 100644 --- a/drivers/macintosh/windfarm_core.c +++ b/drivers/macintosh/windfarm_core.c @@ -52,7 +52,7 @@ static LIST_HEAD(wf_controls); static LIST_HEAD(wf_sensors); static DEFINE_MUTEX(wf_lock); -static struct notifier_block *wf_client_list; +static BLOCKING_NOTIFIER_HEAD(wf_client_list); static int wf_client_count; static unsigned int wf_overtemp; static unsigned int wf_overtemp_counter; @@ -68,7 +68,7 @@ static struct platform_device wf_platform_device = { static inline void wf_notify(int event, void *param) { - notifier_call_chain(&wf_client_list, event, param); + blocking_notifier_call_chain(&wf_client_list, event, param); } int wf_critical_overtemp(void) @@ -398,7 +398,7 @@ int wf_register_client(struct notifier_block *nb) struct wf_sensor *sr; mutex_lock(&wf_lock); - rc = notifier_chain_register(&wf_client_list, nb); + rc = blocking_notifier_chain_register(&wf_client_list, nb); if (rc != 0) goto bail; wf_client_count++; @@ -417,7 +417,7 @@ EXPORT_SYMBOL_GPL(wf_register_client); int wf_unregister_client(struct notifier_block *nb) { mutex_lock(&wf_lock); - notifier_chain_unregister(&wf_client_list, nb); + blocking_notifier_chain_unregister(&wf_client_list, nb); wf_client_count++; if (wf_client_count == 0) wf_stop_thread(); diff --git a/drivers/misc/ibmasm/heartbeat.c b/drivers/misc/ibmasm/heartbeat.c index f295401fac21..7fd7a43e38de 100644 --- a/drivers/misc/ibmasm/heartbeat.c +++ b/drivers/misc/ibmasm/heartbeat.c @@ -52,12 +52,13 @@ static struct notifier_block panic_notifier = { panic_happened, NULL, 1 }; void ibmasm_register_panic_notifier(void) { - notifier_chain_register(&panic_notifier_list, &panic_notifier); + atomic_notifier_chain_register(&panic_notifier_list, &panic_notifier); } void ibmasm_unregister_panic_notifier(void) { - notifier_chain_unregister(&panic_notifier_list, &panic_notifier); + atomic_notifier_chain_unregister(&panic_notifier_list, + &panic_notifier); } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 2d0ac169a86c..f13a539dc169 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3159,7 +3159,7 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave * bond_netdev_event: handle netdev notifier chain events. * * This function receives events for the netdev chain. The caller (an - * ioctl handler calling notifier_call_chain) holds the necessary + * ioctl handler calling blocking_notifier_call_chain) holds the necessary * locks for us to safely manipulate the slave devices (RTNL lock, * dev_probe_lock). */ diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index 3627a2d7f79f..298f2ddb2c17 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c @@ -499,11 +499,16 @@ static int led_halt(struct notifier_block *, unsigned long, void *); static struct notifier_block led_notifier = { .notifier_call = led_halt, }; +static int notifier_disabled = 0; static int led_halt(struct notifier_block *nb, unsigned long event, void *buf) { char *txt; - + + if (notifier_disabled) + return NOTIFY_OK; + + notifier_disabled = 1; switch (event) { case SYS_RESTART: txt = "SYSTEM RESTART"; break; @@ -527,7 +532,6 @@ static int led_halt(struct notifier_block *nb, unsigned long event, void *buf) if (led_func_ptr) led_func_ptr(0xff); /* turn all LEDs ON */ - unregister_reboot_notifier(&led_notifier); return NOTIFY_OK; } @@ -758,6 +762,12 @@ not_found: return 1; } +static void __exit led_exit(void) +{ + unregister_reboot_notifier(&led_notifier); + return; +} + #ifdef CONFIG_PROC_FS module_init(led_create_procfs) #endif diff --git a/drivers/parisc/power.c b/drivers/parisc/power.c index 54b2b7f20b96..0bcab83b4080 100644 --- a/drivers/parisc/power.c +++ b/drivers/parisc/power.c @@ -251,7 +251,8 @@ static int __init power_init(void) } /* Register a call for panic conditions. */ - notifier_chain_register(&panic_notifier_list, &parisc_panic_block); + atomic_notifier_chain_register(&panic_notifier_list, + &parisc_panic_block); tasklet_enable(&power_tasklet); @@ -264,7 +265,8 @@ static void __exit power_exit(void) return; tasklet_disable(&power_tasklet); - notifier_chain_unregister(&panic_notifier_list, &parisc_panic_block); + atomic_notifier_chain_unregister(&panic_notifier_list, + &parisc_panic_block); power_tasklet.func = NULL; pdc_soft_power_button(0); } diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 62e3cda859af..7f7013e80a88 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -671,7 +671,7 @@ static struct file_operations gdth_fops = { static struct notifier_block gdth_notifier = { gdth_halt, NULL, 0 }; - +static int notifier_disabled = 0; static void gdth_delay(int milliseconds) { @@ -4595,13 +4595,13 @@ static int __init gdth_detect(struct scsi_host_template *shtp) add_timer(&gdth_timer); #endif major = register_chrdev(0,"gdth",&gdth_fops); + notifier_disabled = 0; register_reboot_notifier(&gdth_notifier); } gdth_polling = FALSE; return gdth_ctr_vcount; } - static int gdth_release(struct Scsi_Host *shp) { int hanum; @@ -5632,10 +5632,14 @@ static int gdth_halt(struct notifier_block *nb, ulong event, void *buf) char cmnd[MAX_COMMAND_SIZE]; #endif + if (notifier_disabled) + return NOTIFY_OK; + TRACE2(("gdth_halt() event %d\n",(int)event)); if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF) return NOTIFY_DONE; + notifier_disabled = 1; printk("GDT-HA: Flushing all host drives .. "); for (hanum = 0; hanum < gdth_ctr_count; ++hanum) { gdth_flush(hanum); @@ -5679,7 +5683,6 @@ static int gdth_halt(struct notifier_block *nb, ulong event, void *buf) #ifdef GDTH_STATISTICS del_timer(&gdth_timer); #endif - unregister_reboot_notifier(&gdth_notifier); return NOTIFY_OK; } diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c index 4b55285de9a0..fe0ed54fa0ae 100644 --- a/drivers/usb/core/notify.c +++ b/drivers/usb/core/notify.c @@ -16,57 +16,7 @@ #include <linux/mutex.h> #include "usb.h" - -static struct notifier_block *usb_notifier_list; -static DEFINE_MUTEX(usb_notifier_lock); - -static void usb_notifier_chain_register(struct notifier_block **list, - struct notifier_block *n) -{ - mutex_lock(&usb_notifier_lock); - while (*list) { - if (n->priority > (*list)->priority) - break; - list = &((*list)->next); - } - n->next = *list; - *list = n; - mutex_unlock(&usb_notifier_lock); -} - -static void usb_notifier_chain_unregister(struct notifier_block **nl, - struct notifier_block *n) -{ - mutex_lock(&usb_notifier_lock); - while ((*nl)!=NULL) { - if ((*nl)==n) { - *nl = n->next; - goto exit; - } - nl=&((*nl)->next); - } -exit: - mutex_unlock(&usb_notifier_lock); -} - -static int usb_notifier_call_chain(struct notifier_block **n, - unsigned long val, void *v) -{ - int ret=NOTIFY_DONE; - struct notifier_block *nb = *n; - - mutex_lock(&usb_notifier_lock); - while (nb) { - ret = nb->notifier_call(nb,val,v); - if (ret&NOTIFY_STOP_MASK) { - goto exit; - } - nb = nb->next; - } -exit: - mutex_unlock(&usb_notifier_lock); - return ret; -} +static BLOCKING_NOTIFIER_HEAD(usb_notifier_list); /** * usb_register_notify - register a notifier callback whenever a usb change happens @@ -76,7 +26,7 @@ exit: */ void usb_register_notify(struct notifier_block *nb) { - usb_notifier_chain_register(&usb_notifier_list, nb); + blocking_notifier_chain_register(&usb_notifier_list, nb); } EXPORT_SYMBOL_GPL(usb_register_notify); @@ -89,27 +39,28 @@ EXPORT_SYMBOL_GPL(usb_register_notify); */ void usb_unregister_notify(struct notifier_block *nb) { - usb_notifier_chain_unregister(&usb_notifier_list, nb); + blocking_notifier_chain_unregister(&usb_notifier_list, nb); } EXPORT_SYMBOL_GPL(usb_unregister_notify); void usb_notify_add_device(struct usb_device *udev) { - usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_ADD, udev); + blocking_notifier_call_chain(&usb_notifier_list, USB_DEVICE_ADD, udev); } void usb_notify_remove_device(struct usb_device *udev) { - usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_REMOVE, udev); + blocking_notifier_call_chain(&usb_notifier_list, + USB_DEVICE_REMOVE, udev); } void usb_notify_add_bus(struct usb_bus *ubus) { - usb_notifier_call_chain(&usb_notifier_list, USB_BUS_ADD, ubus); + blocking_notifier_call_chain(&usb_notifier_list, USB_BUS_ADD, ubus); } void usb_notify_remove_bus(struct usb_bus *ubus) { - usb_notifier_call_chain(&usb_notifier_list, USB_BUS_REMOVE, ubus); + blocking_notifier_call_chain(&usb_notifier_list, USB_BUS_REMOVE, ubus); } diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 07d882b14396..b1a8dca76430 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -55,7 +55,7 @@ #define FBPIXMAPSIZE (1024 * 8) -static struct notifier_block *fb_notifier_list; +static BLOCKING_NOTIFIER_HEAD(fb_notifier_list); struct fb_info *registered_fb[FB_MAX]; int num_registered_fb; @@ -784,7 +784,7 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) event.info = info; event.data = &mode1; - ret = notifier_call_chain(&fb_notifier_list, + ret = blocking_notifier_call_chain(&fb_notifier_list, FB_EVENT_MODE_DELETE, &event); } @@ -830,8 +830,8 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) info->flags &= ~FBINFO_MISC_USEREVENT; event.info = info; - notifier_call_chain(&fb_notifier_list, evnt, - &event); + blocking_notifier_call_chain(&fb_notifier_list, + evnt, &event); } } } @@ -854,7 +854,8 @@ fb_blank(struct fb_info *info, int blank) event.info = info; event.data = ␣ - notifier_call_chain(&fb_notifier_list, FB_EVENT_BLANK, &event); + blocking_notifier_call_chain(&fb_notifier_list, + FB_EVENT_BLANK, &event); } return ret; @@ -925,7 +926,7 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, con2fb.framebuffer = -1; event.info = info; event.data = &con2fb; - notifier_call_chain(&fb_notifier_list, + blocking_notifier_call_chain(&fb_notifier_list, FB_EVENT_GET_CONSOLE_MAP, &event); return copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0; @@ -944,7 +945,7 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, return -EINVAL; event.info = info; event.data = &con2fb; - return notifier_call_chain(&fb_notifier_list, + return blocking_notifier_call_chain(&fb_notifier_list, FB_EVENT_SET_CONSOLE_MAP, &event); case FBIOBLANK: @@ -1324,7 +1325,7 @@ register_framebuffer(struct fb_info *fb_info) devfs_mk_cdev(MKDEV(FB_MAJOR, i), S_IFCHR | S_IRUGO | S_IWUGO, "fb/%d", i); event.info = fb_info; - notifier_call_chain(&fb_notifier_list, + blocking_notifier_call_chain(&fb_notifier_list, FB_EVENT_FB_REGISTERED, &event); return 0; } @@ -1366,7 +1367,7 @@ unregister_framebuffer(struct fb_info *fb_info) */ int fb_register_client(struct notifier_block *nb) { - return notifier_chain_register(&fb_notifier_list, nb); + return blocking_notifier_chain_register(&fb_notifier_list, nb); } /** @@ -1375,7 +1376,7 @@ int fb_register_client(struct notifier_block *nb) */ int fb_unregister_client(struct notifier_block *nb) { - return notifier_chain_unregister(&fb_notifier_list, nb); + return blocking_notifier_chain_unregister(&fb_notifier_list, nb); } /** @@ -1393,11 +1394,13 @@ void fb_set_suspend(struct fb_info *info, int state) event.info = info; if (state) { - notifier_call_chain(&fb_notifier_list, FB_EVENT_SUSPEND, &event); + blocking_notifier_call_chain(&fb_notifier_list, + FB_EVENT_SUSPEND, &event); info->state = FBINFO_STATE_SUSPENDED; } else { info->state = FBINFO_STATE_RUNNING; - notifier_call_chain(&fb_notifier_list, FB_EVENT_RESUME, &event); + blocking_notifier_call_chain(&fb_notifier_list, + FB_EVENT_RESUME, &event); } } @@ -1469,7 +1472,7 @@ int fb_new_modelist(struct fb_info *info) if (!list_empty(&info->modelist)) { event.info = info; - err = notifier_call_chain(&fb_notifier_list, + err = blocking_notifier_call_chain(&fb_notifier_list, FB_EVENT_NEW_MODELIST, &event); } @@ -1495,7 +1498,7 @@ int fb_con_duit(struct fb_info *info, int event, void *data) evnt.info = info; evnt.data = data; - return notifier_call_chain(&fb_notifier_list, event, &evnt); + return blocking_notifier_call_chain(&fb_notifier_list, event, &evnt); } EXPORT_SYMBOL(fb_con_duit); diff --git a/include/asm-i386/kdebug.h b/include/asm-i386/kdebug.h index 316138e89910..96d0828ce096 100644 --- a/include/asm-i386/kdebug.h +++ b/include/asm-i386/kdebug.h @@ -17,11 +17,9 @@ struct die_args { int signr; }; -/* Note - you should never unregister because that can race with NMIs. - If you really want to do it first unregister - then synchronize_sched - then free. - */ -int register_die_notifier(struct notifier_block *nb); -extern struct notifier_block *i386die_chain; +extern int register_die_notifier(struct notifier_block *); +extern int unregister_die_notifier(struct notifier_block *); +extern struct atomic_notifier_head i386die_chain; /* Grossly misnamed. */ @@ -51,7 +49,7 @@ static inline int notify_die(enum die_val val, const char *str, .trapnr = trap, .signr = sig }; - return notifier_call_chain(&i386die_chain, val, &args); + return atomic_notifier_call_chain(&i386die_chain, val, &args); } #endif diff --git a/include/asm-ia64/kdebug.h b/include/asm-ia64/kdebug.h index 8b01a083dde6..218c458ab60c 100644 --- a/include/asm-ia64/kdebug.h +++ b/include/asm-ia64/kdebug.h @@ -40,7 +40,7 @@ struct die_args { extern int register_die_notifier(struct notifier_block *); extern int unregister_die_notifier(struct notifier_block *); -extern struct notifier_block *ia64die_chain; +extern struct atomic_notifier_head ia64die_chain; enum die_val { DIE_BREAK = 1, @@ -81,7 +81,7 @@ static inline int notify_die(enum die_val val, char *str, struct pt_regs *regs, .signr = sig }; - return notifier_call_chain(&ia64die_chain, val, &args); + return atomic_notifier_call_chain(&ia64die_chain, val, &args); } #endif diff --git a/include/asm-powerpc/kdebug.h b/include/asm-powerpc/kdebug.h index 7c16265568e0..c01786ab5fa6 100644 --- a/include/asm-powerpc/kdebug.h +++ b/include/asm-powerpc/kdebug.h @@ -16,13 +16,9 @@ struct die_args { int signr; }; -/* - Note - you should never unregister because that can race with NMIs. - If you really want to do it first unregister - then synchronize_sched - - then free. - */ -int register_die_notifier(struct notifier_block *nb); -extern struct notifier_block *powerpc_die_chain; +extern int register_die_notifier(struct notifier_block *); +extern int unregister_die_notifier(struct notifier_block *); +extern struct atomic_notifier_head powerpc_die_chain; /* Grossly misnamed. */ enum die_val { @@ -37,7 +33,7 @@ enum die_val { static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,long err,int trap, int sig) { struct die_args args = { .regs=regs, .str=str, .err=err, .trapnr=trap,.signr=sig }; - return notifier_call_chain(&powerpc_die_chain, val, &args); + return atomic_notifier_call_chain(&powerpc_die_chain, val, &args); } #endif /* __KERNEL__ */ diff --git a/include/asm-sparc64/kdebug.h b/include/asm-sparc64/kdebug.h index 6321f5a0198d..4040d127ac3e 100644 --- a/include/asm-sparc64/kdebug.h +++ b/include/asm-sparc64/kdebug.h @@ -15,12 +15,9 @@ struct die_args { int signr; }; -/* Note - you should never unregister because that can race with NMIs. - * If you really want to do it first unregister - then synchronize_sched - * - then free. - */ -int register_die_notifier(struct notifier_block *nb); -extern struct notifier_block *sparc64die_chain; +extern int register_die_notifier(struct notifier_block *); +extern int unregister_die_notifier(struct notifier_block *); +extern struct atomic_notifier_head sparc64die_chain; extern void bad_trap(struct pt_regs *, long); @@ -46,7 +43,7 @@ static inline int notify_die(enum die_val val,char *str, struct pt_regs *regs, .trapnr = trap, .signr = sig }; - return notifier_call_chain(&sparc64die_chain, val, &args); + return atomic_notifier_call_chain(&sparc64die_chain, val, &args); } #endif diff --git a/include/asm-x86_64/kdebug.h b/include/asm-x86_64/kdebug.h index b9ed4c0c8783..cf795631d9b4 100644 --- a/include/asm-x86_64/kdebug.h +++ b/include/asm-x86_64/kdebug.h @@ -5,21 +5,20 @@ struct pt_regs; -struct die_args { +struct die_args { struct pt_regs *regs; const char *str; - long err; + long err; int trapnr; int signr; -}; +}; + +extern int register_die_notifier(struct notifier_block *); +extern int unregister_die_notifier(struct notifier_block *); +extern struct atomic_notifier_head die_chain; -/* Note - you should never unregister because that can race with NMIs. - If you really want to do it first unregister - then synchronize_sched - then free. - */ -int register_die_notifier(struct notifier_block *nb); -extern struct notifier_block *die_chain; /* Grossly misnamed. */ -enum die_val { +enum die_val { DIE_OOPS = 1, DIE_INT3, DIE_DEBUG, @@ -33,8 +32,8 @@ enum die_val { DIE_CALL, DIE_NMI_IPI, DIE_PAGE_FAULT, -}; - +}; + static inline int notify_die(enum die_val val, const char *str, struct pt_regs *regs, long err, int trap, int sig) { @@ -45,7 +44,7 @@ static inline int notify_die(enum die_val val, const char *str, .trapnr = trap, .signr = sig }; - return notifier_call_chain(&die_chain, val, &args); + return atomic_notifier_call_chain(&die_chain, val, &args); } extern int printk_address(unsigned long address); diff --git a/include/linux/adb.h b/include/linux/adb.h index e9fdc63483c7..b7305b178279 100644 --- a/include/linux/adb.h +++ b/include/linux/adb.h @@ -85,7 +85,7 @@ enum adb_message { ADB_MSG_POST_RESET /* Called after resetting the bus (re-do init & register) */ }; extern struct adb_driver *adb_controller; -extern struct notifier_block *adb_client_list; +extern struct blocking_notifier_head adb_client_list; int adb_request(struct adb_request *req, void (*done)(struct adb_request *), int flags, int nbytes, ...); diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 03d6cfaa5b8a..a3720f973ea5 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -87,7 +87,7 @@ extern int cond_resched(void); (__x < 0) ? -__x : __x; \ }) -extern struct notifier_block *panic_notifier_list; +extern struct atomic_notifier_head panic_notifier_list; extern long (*panic_blink)(long time); NORET_TYPE void panic(const char * fmt, ...) __attribute__ ((NORET_AND format (printf, 1, 2))); diff --git a/include/linux/memory.h b/include/linux/memory.h index e251dc43d0f5..8f04143ca363 100644 --- a/include/linux/memory.h +++ b/include/linux/memory.h @@ -77,7 +77,6 @@ extern int remove_memory_block(unsigned long, struct mem_section *, int); #define CONFIG_MEM_BLOCK_SIZE (PAGES_PER_SECTION<<PAGE_SHIFT) -struct notifier_block; #endif /* CONFIG_MEMORY_HOTPLUG */ diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h index f32d75c4f4cf..d54d7b278e96 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack.h +++ b/include/linux/netfilter_ipv4/ip_conntrack.h @@ -308,29 +308,30 @@ DECLARE_PER_CPU(struct ip_conntrack_ecache, ip_conntrack_ecache); #define CONNTRACK_ECACHE(x) (__get_cpu_var(ip_conntrack_ecache).x) -extern struct notifier_block *ip_conntrack_chain; -extern struct notifier_block *ip_conntrack_expect_chain; +extern struct atomic_notifier_head ip_conntrack_chain; +extern struct atomic_notifier_head ip_conntrack_expect_chain; static inline int ip_conntrack_register_notifier(struct notifier_block *nb) { - return notifier_chain_register(&ip_conntrack_chain, nb); + return atomic_notifier_chain_register(&ip_conntrack_chain, nb); } static inline int ip_conntrack_unregister_notifier(struct notifier_block *nb) { - return notifier_chain_unregister(&ip_conntrack_chain, nb); + return atomic_notifier_chain_unregister(&ip_conntrack_chain, nb); } static inline int ip_conntrack_expect_register_notifier(struct notifier_block *nb) { - return notifier_chain_register(&ip_conntrack_expect_chain, nb); + return atomic_notifier_chain_register(&ip_conntrack_expect_chain, nb); } static inline int ip_conntrack_expect_unregister_notifier(struct notifier_block *nb) { - return notifier_chain_unregister(&ip_conntrack_expect_chain, nb); + return atomic_notifier_chain_unregister(&ip_conntrack_expect_chain, + nb); } extern void ip_ct_deliver_cached_events(const struct ip_conntrack *ct); @@ -355,14 +356,14 @@ static inline void ip_conntrack_event(enum ip_conntrack_events event, struct ip_conntrack *ct) { if (is_confirmed(ct) && !is_dying(ct)) - notifier_call_chain(&ip_conntrack_chain, event, ct); + atomic_notifier_call_chain(&ip_conntrack_chain, event, ct); } static inline void ip_conntrack_expect_event(enum ip_conntrack_expect_events event, struct ip_conntrack_expect *exp) { - notifier_call_chain(&ip_conntrack_expect_chain, event, exp); + atomic_notifier_call_chain(&ip_conntrack_expect_chain, event, exp); } #else /* CONFIG_IP_NF_CONNTRACK_EVENTS */ static inline void ip_conntrack_event_cache(enum ip_conntrack_events event, diff --git a/include/linux/notifier.h b/include/linux/notifier.h index 5937dd6053c3..51dbab9710c7 100644 --- a/include/linux/notifier.h +++ b/include/linux/notifier.h @@ -10,25 +10,107 @@ #ifndef _LINUX_NOTIFIER_H #define _LINUX_NOTIFIER_H #include <linux/errno.h> +#include <linux/mutex.h> +#include <linux/rwsem.h> -struct notifier_block -{ - int (*notifier_call)(struct notifier_block *self, unsigned long, void *); +/* + * Notifier chains are of three types: + * + * Atomic notifier chains: Chain callbacks run in interrupt/atomic + * context. Callouts are not allowed to block. + * Blocking notifier chains: Chain callbacks run in process context. + * Callouts are allowed to block. + * Raw notifier chains: There are no restrictions on callbacks, + * registration, or unregistration. All locking and protection + * must be provided by the caller. + * + * atomic_notifier_chain_register() may be called from an atomic context, + * but blocking_notifier_chain_register() must be called from a process + * context. Ditto for the corresponding _unregister() routines. + * + * atomic_notifier_chain_unregister() and blocking_notifier_chain_unregister() + * _must not_ be called from within the call chain. + */ + +struct notifier_block { + int (*notifier_call)(struct notifier_block *, unsigned long, void *); struct notifier_block *next; int priority; }; +struct atomic_notifier_head { + spinlock_t lock; + struct notifier_block *head; +}; + +struct blocking_notifier_head { + struct rw_semaphore rwsem; + struct notifier_block *head; +}; + +struct raw_notifier_head { + struct notifier_block *head; +}; + +#define ATOMIC_INIT_NOTIFIER_HEAD(name) do { \ + spin_lock_init(&(name)->lock); \ + (name)->head = NULL; \ + } while (0) +#define BLOCKING_INIT_NOTIFIER_HEAD(name) do { \ + init_rwsem(&(name)->rwsem); \ + (name)->head = NULL; \ + } while (0) +#define RAW_INIT_NOTIFIER_HEAD(name) do { \ + (name)->head = NULL; \ + } while (0) + +#define ATOMIC_NOTIFIER_INIT(name) { \ + .lock = SPIN_LOCK_UNLOCKED, \ + .head = NULL } +#define BLOCKING_NOTIFIER_INIT(name) { \ + .rwsem = __RWSEM_INITIALIZER((name).rwsem), \ + .head = NULL } +#define RAW_NOTIFIER_INIT(name) { \ + .head = NULL } + +#define ATOMIC_NOTIFIER_HEAD(name) \ + struct atomic_notifier_head name = \ + ATOMIC_NOTIFIER_INIT(name) +#define BLOCKING_NOTIFIER_HEAD(name) \ + struct blocking_notifier_head name = \ + BLOCKING_NOTIFIER_INIT(name) +#define RAW_NOTIFIER_HEAD(name) \ + struct raw_notifier_head name = \ + RAW_NOTIFIER_INIT(name) #ifdef __KERNEL__ -extern int notifier_chain_register(struct notifier_block **list, struct notifier_block *n); -extern int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n); -extern int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v); +extern int atomic_notifier_chain_register(struct atomic_notifier_head *, + struct notifier_block *); +extern int blocking_notifier_chain_register(struct blocking_notifier_head *, + struct notifier_block *); +extern int raw_notifier_chain_register(struct raw_notifier_head *, + struct notifier_block *); + +extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *, + struct notifier_block *); +extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *, + struct notifier_block *); +extern int raw_notifier_chain_unregister(struct raw_notifier_head *, + struct notifier_block *); + +extern int atomic_notifier_call_chain(struct atomic_notifier_head *, + unsigned long val, void *v); +extern int blocking_notifier_call_chain(struct blocking_notifier_head *, + unsigned long val, void *v); +extern int raw_notifier_call_chain(struct raw_notifier_head *, + unsigned long val, void *v); #define NOTIFY_DONE 0x0000 /* Don't care */ #define NOTIFY_OK 0x0001 /* Suits me */ #define NOTIFY_STOP_MASK 0x8000 /* Don't call further */ -#define NOTIFY_BAD (NOTIFY_STOP_MASK|0x0002) /* Bad/Veto action */ +#define NOTIFY_BAD (NOTIFY_STOP_MASK|0x0002) + /* Bad/Veto action */ /* * Clean way to return from the notifier and stop further calls. */ diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index b6f0905a4ee2..916013ca4a5c 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -300,29 +300,30 @@ DECLARE_PER_CPU(struct nf_conntrack_ecache, nf_conntrack_ecache); #define CONNTRACK_ECACHE(x) (__get_cpu_var(nf_conntrack_ecache).x) -extern struct notifier_block *nf_conntrack_chain; -extern struct notifier_block *nf_conntrack_expect_chain; +extern struct atomic_notifier_head nf_conntrack_chain; +extern struct atomic_notifier_head nf_conntrack_expect_chain; static inline int nf_conntrack_register_notifier(struct notifier_block *nb) { - return notifier_chain_register(&nf_conntrack_chain, nb); + return atomic_notifier_chain_register(&nf_conntrack_chain, nb); } static inline int nf_conntrack_unregister_notifier(struct notifier_block *nb) { - return notifier_chain_unregister(&nf_conntrack_chain, nb); + return atomic_notifier_chain_unregister(&nf_conntrack_chain, nb); } static inline int nf_conntrack_expect_register_notifier(struct notifier_block *nb) { - return notifier_chain_register(&nf_conntrack_expect_chain, nb); + return atomic_notifier_chain_register(&nf_conntrack_expect_chain, nb); } static inline int nf_conntrack_expect_unregister_notifier(struct notifier_block *nb) { - return notifier_chain_unregister(&nf_conntrack_expect_chain, nb); + return atomic_notifier_chain_unregister(&nf_conntrack_expect_chain, + nb); } extern void nf_ct_deliver_cached_events(const struct nf_conn *ct); @@ -347,14 +348,14 @@ static inline void nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct) { if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) - notifier_call_chain(&nf_conntrack_chain, event, ct); + atomic_notifier_call_chain(&nf_conntrack_chain, event, ct); } static inline void nf_conntrack_expect_event(enum ip_conntrack_expect_events event, struct nf_conntrack_expect *exp) { - notifier_call_chain(&nf_conntrack_expect_chain, event, exp); + atomic_notifier_call_chain(&nf_conntrack_expect_chain, event, exp); } #else /* CONFIG_NF_CONNTRACK_EVENTS */ static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, diff --git a/kernel/cpu.c b/kernel/cpu.c index 8be22bd80933..fe2b8d0bfe4c 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -18,7 +18,7 @@ /* This protects CPUs going up and down... */ static DECLARE_MUTEX(cpucontrol); -static struct notifier_block *cpu_chain; +static BLOCKING_NOTIFIER_HEAD(cpu_chain); #ifdef CONFIG_HOTPLUG_CPU static struct task_struct *lock_cpu_hotplug_owner; @@ -71,21 +71,13 @@ EXPORT_SYMBOL_GPL(lock_cpu_hotplug_interruptible); /* Need to know about CPUs going up/down? */ int register_cpu_notifier(struct notifier_block *nb) { - int ret; - - if ((ret = lock_cpu_hotplug_interruptible()) != 0) - return ret; - ret = notifier_chain_register(&cpu_chain, nb); - unlock_cpu_hotplug(); - return ret; + return blocking_notifier_chain_register(&cpu_chain, nb); } EXPORT_SYMBOL(register_cpu_notifier); void unregister_cpu_notifier(struct notifier_block *nb) { - lock_cpu_hotplug(); - notifier_chain_unregister(&cpu_chain, nb); - unlock_cpu_hotplug(); + blocking_notifier_chain_unregister(&cpu_chain, nb); } EXPORT_SYMBOL(unregister_cpu_notifier); @@ -141,7 +133,7 @@ int cpu_down(unsigned int cpu) goto out; } - err = notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, + err = blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, (void *)(long)cpu); if (err == NOTIFY_BAD) { printk("%s: attempt to take down CPU %u failed\n", @@ -159,7 +151,7 @@ int cpu_down(unsigned int cpu) p = __stop_machine_run(take_cpu_down, NULL, cpu); if (IS_ERR(p)) { /* CPU didn't die: tell everyone. Can't complain. */ - if (notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED, + if (blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED, (void *)(long)cpu) == NOTIFY_BAD) BUG(); @@ -182,8 +174,8 @@ int cpu_down(unsigned int cpu) put_cpu(); /* CPU is completely dead: tell everyone. Too late to complain. */ - if (notifier_call_chain(&cpu_chain, CPU_DEAD, (void *)(long)cpu) - == NOTIFY_BAD) + if (blocking_notifier_call_chain(&cpu_chain, CPU_DEAD, + (void *)(long)cpu) == NOTIFY_BAD) BUG(); check_for_tasks(cpu); @@ -211,7 +203,7 @@ int __devinit cpu_up(unsigned int cpu) goto out; } - ret = notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu); + ret = blocking_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu); if (ret == NOTIFY_BAD) { printk("%s: attempt to bring up CPU %u failed\n", __FUNCTION__, cpu); @@ -226,11 +218,12 @@ int __devinit cpu_up(unsigned int cpu) BUG_ON(!cpu_online(cpu)); /* Now call notifier in preparation. */ - notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu); + blocking_notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu); out_notify: if (ret != 0) - notifier_call_chain(&cpu_chain, CPU_UP_CANCELED, hcpu); + blocking_notifier_call_chain(&cpu_chain, + CPU_UP_CANCELED, hcpu); out: unlock_cpu_hotplug(); return ret; diff --git a/kernel/module.c b/kernel/module.c index ddfe45ac2fd1..4fafd58038a0 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -64,26 +64,17 @@ static DEFINE_SPINLOCK(modlist_lock); static DEFINE_MUTEX(module_mutex); static LIST_HEAD(modules); -static DEFINE_MUTEX(notify_mutex); -static struct notifier_block * module_notify_list; +static BLOCKING_NOTIFIER_HEAD(module_notify_list); int register_module_notifier(struct notifier_block * nb) { - int err; - mutex_lock(¬ify_mutex); - err = notifier_chain_register(&module_notify_list, nb); - mutex_unlock(¬ify_mutex); - return err; + return blocking_notifier_chain_register(&module_notify_list, nb); } EXPORT_SYMBOL(register_module_notifier); int unregister_module_notifier(struct notifier_block * nb) { - int err; - mutex_lock(¬ify_mutex); - err = notifier_chain_unregister(&module_notify_list, nb); - mutex_unlock(¬ify_mutex); - return err; + return blocking_notifier_chain_unregister(&module_notify_list, nb); } EXPORT_SYMBOL(unregister_module_notifier); @@ -1816,9 +1807,8 @@ sys_init_module(void __user *umod, /* Drop lock so they can recurse */ mutex_unlock(&module_mutex); - mutex_lock(¬ify_mutex); - notifier_call_chain(&module_notify_list, MODULE_STATE_COMING, mod); - mutex_unlock(¬ify_mutex); + blocking_notifier_call_chain(&module_notify_list, + MODULE_STATE_COMING, mod); /* Start the module */ if (mod->init != NULL) diff --git a/kernel/panic.c b/kernel/panic.c index acd95adddb93..f895c7c01d5b 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -29,7 +29,7 @@ static DEFINE_SPINLOCK(pause_on_oops_lock); int panic_timeout; EXPORT_SYMBOL(panic_timeout); -struct notifier_block *panic_notifier_list; +ATOMIC_NOTIFIER_HEAD(panic_notifier_list); EXPORT_SYMBOL(panic_notifier_list); @@ -97,7 +97,7 @@ NORET_TYPE void panic(const char * fmt, ...) smp_send_stop(); #endif - notifier_call_chain(&panic_notifier_list, 0, buf); + atomic_notifier_call_chain(&panic_notifier_list, 0, buf); if (!panic_blink) panic_blink = no_blink; diff --git a/kernel/profile.c b/kernel/profile.c index ad81f799a9b4..5a730fdb1a2c 100644 --- a/kernel/profile.c +++ b/kernel/profile.c @@ -87,72 +87,52 @@ void __init profile_init(void) #ifdef CONFIG_PROFILING -static DECLARE_RWSEM(profile_rwsem); -static DEFINE_RWLOCK(handoff_lock); -static struct notifier_block * task_exit_notifier; -static struct notifier_block * task_free_notifier; -static struct notifier_block * munmap_notifier; +static BLOCKING_NOTIFIER_HEAD(task_exit_notifier); +static ATOMIC_NOTIFIER_HEAD(task_free_notifier); +static BLOCKING_NOTIFIER_HEAD(munmap_notifier); void profile_task_exit(struct task_struct * task) { - down_read(&profile_rwsem); - notifier_call_chain(&task_exit_notifier, 0, task); - up_read(&profile_rwsem); + blocking_notifier_call_chain(&task_exit_notifier, 0, task); } int profile_handoff_task(struct task_struct * task) { int ret; - read_lock(&handoff_lock); - ret = notifier_call_chain(&task_free_notifier, 0, task); - read_unlock(&handoff_lock); + ret = atomic_notifier_call_chain(&task_free_notifier, 0, task); return (ret == NOTIFY_OK) ? 1 : 0; } void profile_munmap(unsigned long addr) { - down_read(&profile_rwsem); - notifier_call_chain(&munmap_notifier, 0, (void *)addr); - up_read(&profile_rwsem); + blocking_notifier_call_chain(&munmap_notifier, 0, (void *)addr); } int task_handoff_register(struct notifier_block * n) { - int err = -EINVAL; - - write_lock(&handoff_lock); - err = notifier_chain_register(&task_free_notifier, n); - write_unlock(&handoff_lock); - return err; + return atomic_notifier_chain_register(&task_free_notifier, n); } int task_handoff_unregister(struct notifier_block * n) { - int err = -EINVAL; - - write_lock(&handoff_lock); - err = notifier_chain_unregister(&task_free_notifier, n); - write_unlock(&handoff_lock); - return err; + return atomic_notifier_chain_unregister(&task_free_notifier, n); } int profile_event_register(enum profile_type type, struct notifier_block * n) { int err = -EINVAL; - down_write(&profile_rwsem); - switch (type) { case PROFILE_TASK_EXIT: - err = notifier_chain_register(&task_exit_notifier, n); + err = blocking_notifier_chain_register( + &task_exit_notifier, n); break; case PROFILE_MUNMAP: - err = notifier_chain_register(&munmap_notifier, n); + err = blocking_notifier_chain_register( + &munmap_notifier, n); break; } - up_write(&profile_rwsem); - return err; } @@ -161,18 +141,17 @@ int profile_event_unregister(enum profile_type type, struct notifier_block * n) { int err = -EINVAL; - down_write(&profile_rwsem); - switch (type) { case PROFILE_TASK_EXIT: - err = notifier_chain_unregister(&task_exit_notifier, n); + err = blocking_notifier_chain_unregister( + &task_exit_notifier, n); break; case PROFILE_MUNMAP: - err = notifier_chain_unregister(&munmap_notifier, n); + err = blocking_notifier_chain_unregister( + &munmap_notifier, n); break; } - up_write(&profile_rwsem); return err; } diff --git a/kernel/softlockup.c b/kernel/softlockup.c index d9b3d5847ed8..ced91e1ff564 100644 --- a/kernel/softlockup.c +++ b/kernel/softlockup.c @@ -152,5 +152,5 @@ __init void spawn_softlockup_task(void) cpu_callback(&cpu_nfb, CPU_ONLINE, cpu); register_cpu_notifier(&cpu_nfb); - notifier_chain_register(&panic_notifier_list, &panic_block); + atomic_notifier_chain_register(&panic_notifier_list, &panic_block); } diff --git a/kernel/sys.c b/kernel/sys.c index 38bc73ede2ba..c93d37f71aef 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -95,99 +95,304 @@ int cad_pid = 1; * and the like. */ -static struct notifier_block *reboot_notifier_list; -static DEFINE_RWLOCK(notifier_lock); +static BLOCKING_NOTIFIER_HEAD(reboot_notifier_list); + +/* + * Notifier chain core routines. The exported routines below + * are layered on top of these, with appropriate locking added. + */ + +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; +} + +static int notifier_chain_unregister(struct notifier_block **nl, + struct notifier_block *n) +{ + while ((*nl) != NULL) { + if ((*nl) == n) { + rcu_assign_pointer(*nl, n->next); + return 0; + } + nl = &((*nl)->next); + } + return -ENOENT; +} + +static int __kprobes notifier_call_chain(struct notifier_block **nl, + unsigned long val, void *v) +{ + int ret = NOTIFY_DONE; + struct notifier_block *nb; + + nb = rcu_dereference(*nl); + while (nb) { + ret = nb->notifier_call(nb, val, v); + if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK) + break; + nb = rcu_dereference(nb->next); + } + return ret; +} + +/* + * Atomic notifier chain routines. Registration and unregistration + * use a mutex, and call_chain is synchronized by RCU (no locks). + */ /** - * notifier_chain_register - Add notifier to a notifier chain - * @list: Pointer to root list pointer + * atomic_notifier_chain_register - Add notifier to an atomic notifier chain + * @nh: Pointer to head of the atomic notifier chain * @n: New entry in notifier chain * - * Adds a notifier to a notifier chain. + * Adds a notifier to an atomic notifier chain. * * Currently always returns zero. */ + +int atomic_notifier_chain_register(struct atomic_notifier_head *nh, + struct notifier_block *n) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&nh->lock, flags); + ret = notifier_chain_register(&nh->head, n); + spin_unlock_irqrestore(&nh->lock, flags); + return ret; +} + +EXPORT_SYMBOL_GPL(atomic_notifier_chain_register); + +/** + * atomic_notifier_chain_unregister - Remove notifier from an atomic notifier chain + * @nh: Pointer to head of the atomic notifier chain + * @n: Entry to remove from notifier chain + * + * Removes a notifier from an atomic notifier chain. + * + * Returns zero on success or %-ENOENT on failure. + */ +int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh, + struct notifier_block *n) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&nh->lock, flags); + ret = notifier_chain_unregister(&nh->head, n); + spin_unlock_irqrestore(&nh->lock, flags); + synchronize_rcu(); + return ret; +} + +EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister); + +/** + * atomic_notifier_call_chain - Call functions in an atomic notifier chain + * @nh: Pointer to head of the atomic notifier chain + * @val: Value passed unmodified to notifier function + * @v: Pointer passed unmodified to notifier function + * + * Calls each function in a notifier chain in turn. The functions + * run in an atomic context, so they must not block. + * This routine uses RCU to synchronize with changes to the chain. + * + * If the return value of the notifier can be and'ed + * with %NOTIFY_STOP_MASK then atomic_notifier_call_chain + * will return immediately, with the return value of + * the notifier function which halted execution. + * Otherwise the return value is the return value + * of the last notifier function called. + */ -int notifier_chain_register(struct notifier_block **list, struct notifier_block *n) +int atomic_notifier_call_chain(struct atomic_notifier_head *nh, + unsigned long val, void *v) { - write_lock(¬ifier_lock); - while(*list) - { - if(n->priority > (*list)->priority) - break; - list= &((*list)->next); - } - n->next = *list; - *list=n; - write_unlock(¬ifier_lock); - return 0; + int ret; + + rcu_read_lock(); + ret = notifier_call_chain(&nh->head, val, v); + rcu_read_unlock(); + return ret; } -EXPORT_SYMBOL(notifier_chain_register); +EXPORT_SYMBOL_GPL(atomic_notifier_call_chain); + +/* + * Blocking notifier chain routines. All access to the chain is + * synchronized by an rwsem. + */ /** - * notifier_chain_unregister - Remove notifier from a notifier chain - * @nl: Pointer to root list pointer + * blocking_notifier_chain_register - Add notifier to a blocking notifier chain + * @nh: Pointer to head of the blocking notifier chain * @n: New entry in notifier chain * - * Removes a notifier from a notifier chain. + * Adds a notifier to a blocking notifier chain. + * Must be called in process context. * - * Returns zero on success, or %-ENOENT on failure. + * Currently always returns zero. */ -int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n) +int blocking_notifier_chain_register(struct blocking_notifier_head *nh, + struct notifier_block *n) { - write_lock(¬ifier_lock); - while((*nl)!=NULL) - { - if((*nl)==n) - { - *nl=n->next; - write_unlock(¬ifier_lock); - return 0; - } - nl=&((*nl)->next); - } - write_unlock(¬ifier_lock); - return -ENOENT; + int ret; + + /* + * This code gets used during boot-up, when task switching is + * not yet working and interrupts must remain disabled. At + * such times we must not call down_write(). + */ + if (unlikely(system_state == SYSTEM_BOOTING)) + return notifier_chain_register(&nh->head, n); + + down_write(&nh->rwsem); + ret = notifier_chain_register(&nh->head, n); + up_write(&nh->rwsem); + return ret; } -EXPORT_SYMBOL(notifier_chain_unregister); +EXPORT_SYMBOL_GPL(blocking_notifier_chain_register); /** - * notifier_call_chain - Call functions in a notifier chain - * @n: Pointer to root pointer of notifier chain + * blocking_notifier_chain_unregister - Remove notifier from a blocking notifier chain + * @nh: Pointer to head of the blocking notifier chain + * @n: Entry to remove from notifier chain + * + * Removes a notifier from a blocking notifier chain. + * Must be called from process context. + * + * Returns zero on success or %-ENOENT on failure. + */ +int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh, + struct notifier_block *n) +{ + int ret; + + /* + * This code gets used during boot-up, when task switching is + * not yet working and interrupts must remain disabled. At + * such times we must not call down_write(). + */ + if (unlikely(system_state == SYSTEM_BOOTING)) + return notifier_chain_unregister(&nh->head, n); + + down_write(&nh->rwsem); + ret = notifier_chain_unregister(&nh->head, n); + up_write(&nh->rwsem); + return ret; +} + +EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister); + +/** + * blocking_notifier_call_chain - Call functions in a blocking notifier chain + * @nh: Pointer to head of the blocking notifier chain * @val: Value passed unmodified to notifier function * @v: Pointer passed unmodified to notifier function * - * Calls each function in a notifier chain in turn. + * Calls each function in a notifier chain in turn. The functions + * run in a process context, so they are allowed to block. * - * If the return value of the notifier can be and'd - * with %NOTIFY_STOP_MASK, then notifier_call_chain + * If the return value of the notifier can be and'ed + * with %NOTIFY_STOP_MASK then blocking_notifier_call_chain * will return immediately, with the return value of * the notifier function which halted execution. - * Otherwise, the return value is the return value + * Otherwise the return value is the return value * of the last notifier function called. */ -int __kprobes notifier_call_chain(struct notifier_block **n, unsigned long val, void *v) +int blocking_notifier_call_chain(struct blocking_notifier_head *nh, + unsigned long val, void *v) { - int ret=NOTIFY_DONE; - struct notifier_block *nb = *n; + int ret; - while(nb) - { - ret=nb->notifier_call(nb,val,v); - if(ret&NOTIFY_STOP_MASK) - { - return ret; - } - nb=nb->next; - } + down_read(&nh->rwsem); + ret = notifier_call_chain(&nh->head, val, v); + up_read(&nh->rwsem); return ret; } -EXPORT_SYMBOL(notifier_call_chain); +EXPORT_SYMBOL_GPL(blocking_notifier_call_chain); + +/* + * Raw notifier chain routines. There is no protection; + * the caller must provide it. Use at your own risk! + */ + +/** + * raw_notifier_chain_register - Add notifier to a raw notifier chain + * @nh: Pointer to head of the raw notifier chain + * @n: New entry in notifier chain + * + * Adds a notifier to a raw notifier chain. + * All locking must be provided by the caller. + * + * Currently always returns zero. + */ + +int raw_notifier_chain_register(struct raw_notifier_head *nh, + struct notifier_block *n) +{ + return notifier_chain_register(&nh->head, n); +} + +EXPORT_SYMBOL_GPL(raw_notifier_chain_register); + +/** + * raw_notifier_chain_unregister - Remove notifier from a raw notifier chain + * @nh: Pointer to head of the raw notifier chain + * @n: Entry to remove from notifier chain + * + * Removes a notifier from a raw notifier chain. + * All locking must be provided by the caller. + * + * Returns zero on success or %-ENOENT on failure. + */ +int raw_notifier_chain_unregister(struct raw_notifier_head *nh, + struct notifier_block *n) +{ + return notifier_chain_unregister(&nh->head, n); +} + +EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister); + +/** + * raw_notifier_call_chain - Call functions in a raw notifier chain + * @nh: Pointer to head of the raw notifier chain + * @val: Value passed unmodified to notifier function + * @v: Pointer passed unmodified to notifier function + * + * Calls each function in a notifier chain in turn. The functions + * run in an undefined context. + * All locking must be provided by the caller. + * + * If the return value of the notifier can be and'ed + * with %NOTIFY_STOP_MASK then raw_notifier_call_chain + * will return immediately, with the return value of + * the notifier function which halted execution. + * Otherwise the return value is the return value + * of the last notifier function called. + */ + +int raw_notifier_call_chain(struct raw_notifier_head *nh, + unsigned long val, void *v) +{ + return notifier_call_chain(&nh->head, val, v); +} + +EXPORT_SYMBOL_GPL(raw_notifier_call_chain); /** * register_reboot_notifier - Register function to be called at reboot time @@ -196,13 +401,13 @@ EXPORT_SYMBOL(notifier_call_chain); * Registers a function with the list of functions * to be called at reboot time. * - * Currently always returns zero, as notifier_chain_register + * Currently always returns zero, as blocking_notifier_chain_register * always returns zero. */ int register_reboot_notifier(struct notifier_block * nb) { - return notifier_chain_register(&reboot_notifier_list, nb); + return blocking_notifier_chain_register(&reboot_notifier_list, nb); } EXPORT_SYMBOL(register_reboot_notifier); @@ -219,7 +424,7 @@ EXPORT_SYMBOL(register_reboot_notifier); int unregister_reboot_notifier(struct notifier_block * nb) { - return notifier_chain_unregister(&reboot_notifier_list, nb); + return blocking_notifier_chain_unregister(&reboot_notifier_list, nb); } EXPORT_SYMBOL(unregister_reboot_notifier); @@ -380,7 +585,7 @@ EXPORT_SYMBOL_GPL(emergency_restart); void kernel_restart_prepare(char *cmd) { - notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); + blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); system_state = SYSTEM_RESTART; device_shutdown(); } @@ -430,7 +635,7 @@ EXPORT_SYMBOL_GPL(kernel_kexec); void kernel_shutdown_prepare(enum system_states state) { - notifier_call_chain(&reboot_notifier_list, + blocking_notifier_call_chain(&reboot_notifier_list, (state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL); system_state = state; device_shutdown(); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9106354c781e..a49a6975092d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -73,23 +73,23 @@ DEFINE_RWLOCK(hci_cb_list_lock); struct hci_proto *hci_proto[HCI_MAX_PROTO]; /* HCI notifiers list */ -static struct notifier_block *hci_notifier; +static ATOMIC_NOTIFIER_HEAD(hci_notifier); /* ---- HCI notifications ---- */ int hci_register_notifier(struct notifier_block *nb) { - return notifier_chain_register(&hci_notifier, nb); + return atomic_notifier_chain_register(&hci_notifier, nb); } int hci_unregister_notifier(struct notifier_block *nb) { - return notifier_chain_unregister(&hci_notifier, nb); + return atomic_notifier_chain_unregister(&hci_notifier, nb); } static void hci_notify(struct hci_dev *hdev, int event) { - notifier_call_chain(&hci_notifier, event, hdev); + atomic_notifier_call_chain(&hci_notifier, event, hdev); } /* ---- HCI requests ---- */ diff --git a/net/core/dev.c b/net/core/dev.c index 8e1dc3051222..a3ab11f34153 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -193,7 +193,7 @@ static inline struct hlist_head *dev_index_hash(int ifindex) * Our notifier list */ -static struct notifier_block *netdev_chain; +static BLOCKING_NOTIFIER_HEAD(netdev_chain); /* * Device drivers call our routines to queue packets here. We empty the @@ -736,7 +736,8 @@ int dev_change_name(struct net_device *dev, char *newname) if (!err) { hlist_del(&dev->name_hlist); hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name)); - notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); + blocking_notifier_call_chain(&netdev_chain, + NETDEV_CHANGENAME, dev); } return err; @@ -750,7 +751,7 @@ int dev_change_name(struct net_device *dev, char *newname) */ void netdev_features_change(struct net_device *dev) { - notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev); + blocking_notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev); } EXPORT_SYMBOL(netdev_features_change); @@ -765,7 +766,8 @@ EXPORT_SYMBOL(netdev_features_change); void netdev_state_change(struct net_device *dev) { if (dev->flags & IFF_UP) { - notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev); + blocking_notifier_call_chain(&netdev_chain, + NETDEV_CHANGE, dev); rtmsg_ifinfo(RTM_NEWLINK, dev, 0); } } @@ -862,7 +864,7 @@ int dev_open(struct net_device *dev) /* * ... and announce new interface. */ - notifier_call_chain(&netdev_chain, NETDEV_UP, dev); + blocking_notifier_call_chain(&netdev_chain, NETDEV_UP, dev); } return ret; } @@ -885,7 +887,7 @@ int dev_close(struct net_device *dev) * Tell people we are going down, so that they can * prepare to death, when device is still operating. */ - notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev); + blocking_notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev); dev_deactivate(dev); @@ -922,7 +924,7 @@ int dev_close(struct net_device *dev) /* * Tell people we are down */ - notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); + blocking_notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); return 0; } @@ -953,7 +955,7 @@ int register_netdevice_notifier(struct notifier_block *nb) int err; rtnl_lock(); - err = notifier_chain_register(&netdev_chain, nb); + err = blocking_notifier_chain_register(&netdev_chain, nb); if (!err) { for (dev = dev_base; dev; dev = dev->next) { nb->notifier_call(nb, NETDEV_REGISTER, dev); @@ -981,7 +983,7 @@ int unregister_netdevice_notifier(struct notifier_block *nb) int err; rtnl_lock(); - err = notifier_chain_unregister(&netdev_chain, nb); + err = blocking_notifier_chain_unregister(&netdev_chain, nb); rtnl_unlock(); return err; } @@ -992,12 +994,12 @@ int unregister_netdevice_notifier(struct notifier_block *nb) * @v: pointer passed unmodified to notifier function * * Call all network notifier blocks. Parameters and return value - * are as for notifier_call_chain(). + * are as for blocking_notifier_call_chain(). */ int call_netdevice_notifiers(unsigned long val, void *v) { - return notifier_call_chain(&netdev_chain, val, v); + return blocking_notifier_call_chain(&netdev_chain, val, v); } /* When > 0 there are consumers of rx skb time stamps */ @@ -2242,7 +2244,8 @@ int dev_change_flags(struct net_device *dev, unsigned flags) if (dev->flags & IFF_UP && ((old_flags ^ dev->flags) &~ (IFF_UP | IFF_PROMISC | IFF_ALLMULTI | IFF_VOLATILE))) - notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev); + blocking_notifier_call_chain(&netdev_chain, + NETDEV_CHANGE, dev); if ((flags ^ dev->gflags) & IFF_PROMISC) { int inc = (flags & IFF_PROMISC) ? +1 : -1; @@ -2286,8 +2289,8 @@ int dev_set_mtu(struct net_device *dev, int new_mtu) else dev->mtu = new_mtu; if (!err && dev->flags & IFF_UP) - notifier_call_chain(&netdev_chain, - NETDEV_CHANGEMTU, dev); + blocking_notifier_call_chain(&netdev_chain, + NETDEV_CHANGEMTU, dev); return err; } @@ -2303,7 +2306,8 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa) return -ENODEV; err = dev->set_mac_address(dev, sa); if (!err) - notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev); + blocking_notifier_call_chain(&netdev_chain, + NETDEV_CHANGEADDR, dev); return err; } @@ -2359,7 +2363,7 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) return -EINVAL; memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len)); - notifier_call_chain(&netdev_chain, + blocking_notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev); return 0; @@ -2813,7 +2817,7 @@ int register_netdevice(struct net_device *dev) write_unlock_bh(&dev_base_lock); /* Notify protocols, that a new device appeared. */ - notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); + blocking_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); /* Finish registration after unlock */ net_set_todo(dev); @@ -2892,7 +2896,7 @@ static void netdev_wait_allrefs(struct net_device *dev) rtnl_lock(); /* Rebroadcast unregister notification */ - notifier_call_chain(&netdev_chain, + blocking_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); if (test_bit(__LINK_STATE_LINKWATCH_PENDING, @@ -3148,7 +3152,7 @@ int unregister_netdevice(struct net_device *dev) /* Notify protocols, that we are about to destroy this device. They should clean all the things. */ - notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); + blocking_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); /* * Flush the multicast chain diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index cc7b9d9255ef..d2ae9893ca17 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -68,7 +68,7 @@ __le16 decnet_address = 0; static DEFINE_RWLOCK(dndev_lock); static struct net_device *decnet_default_device; -static struct notifier_block *dnaddr_chain; +static BLOCKING_NOTIFIER_HEAD(dnaddr_chain); static struct dn_dev *dn_dev_create(struct net_device *dev, int *err); static void dn_dev_delete(struct net_device *dev); @@ -446,7 +446,7 @@ static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr **ifap, int de } rtmsg_ifa(RTM_DELADDR, ifa1); - notifier_call_chain(&dnaddr_chain, NETDEV_DOWN, ifa1); + blocking_notifier_call_chain(&dnaddr_chain, NETDEV_DOWN, ifa1); if (destroy) { dn_dev_free_ifa(ifa1); @@ -481,7 +481,7 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa) dn_db->ifa_list = ifa; rtmsg_ifa(RTM_NEWADDR, ifa); - notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa); + blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa); return 0; } @@ -1285,12 +1285,12 @@ void dn_dev_devices_on(void) int register_dnaddr_notifier(struct notifier_block *nb) { - return notifier_chain_register(&dnaddr_chain, nb); + return blocking_notifier_chain_register(&dnaddr_chain, nb); } int unregister_dnaddr_notifier(struct notifier_block *nb) { - return notifier_chain_unregister(&dnaddr_chain, nb); + return blocking_notifier_chain_unregister(&dnaddr_chain, nb); } #ifdef CONFIG_PROC_FS diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 44fdf1413e2c..81c2f7885292 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -81,7 +81,7 @@ static struct ipv4_devconf ipv4_devconf_dflt = { static void rtmsg_ifa(int event, struct in_ifaddr *); -static struct notifier_block *inetaddr_chain; +static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy); #ifdef CONFIG_SYSCTL @@ -267,7 +267,8 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, *ifap1 = ifa->ifa_next; rtmsg_ifa(RTM_DELADDR, ifa); - notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa); + blocking_notifier_call_chain(&inetaddr_chain, + NETDEV_DOWN, ifa); inet_free_ifa(ifa); } else { promote = ifa; @@ -291,7 +292,7 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, So that, this order is correct. */ rtmsg_ifa(RTM_DELADDR, ifa1); - notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); + blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); if (promote) { @@ -303,7 +304,8 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, promote->ifa_flags &= ~IFA_F_SECONDARY; rtmsg_ifa(RTM_NEWADDR, promote); - notifier_call_chain(&inetaddr_chain, NETDEV_UP, promote); + blocking_notifier_call_chain(&inetaddr_chain, + NETDEV_UP, promote); for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) { if (ifa1->ifa_mask != ifa->ifa_mask || !inet_ifa_match(ifa1->ifa_address, ifa)) @@ -366,7 +368,7 @@ static int inet_insert_ifa(struct in_ifaddr *ifa) Notifier will trigger FIB update, so that listeners of netlink will know about new ifaddr */ rtmsg_ifa(RTM_NEWADDR, ifa); - notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa); + blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa); return 0; } @@ -938,12 +940,12 @@ u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scop int register_inetaddr_notifier(struct notifier_block *nb) { - return notifier_chain_register(&inetaddr_chain, nb); + return blocking_notifier_chain_register(&inetaddr_chain, nb); } int unregister_inetaddr_notifier(struct notifier_block *nb) { - return notifier_chain_unregister(&inetaddr_chain, nb); + return blocking_notifier_chain_unregister(&inetaddr_chain, nb); } /* Rename ifa_labels for a device name change. Make some effort to preserve existing diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 9e34034729a6..ceaabc18202b 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -80,8 +80,8 @@ static int ip_conntrack_vmalloc; static unsigned int ip_conntrack_next_id; static unsigned int ip_conntrack_expect_next_id; #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS -struct notifier_block *ip_conntrack_chain; -struct notifier_block *ip_conntrack_expect_chain; +ATOMIC_NOTIFIER_HEAD(ip_conntrack_chain); +ATOMIC_NOTIFIER_HEAD(ip_conntrack_expect_chain); DEFINE_PER_CPU(struct ip_conntrack_ecache, ip_conntrack_ecache); @@ -92,7 +92,7 @@ __ip_ct_deliver_cached_events(struct ip_conntrack_ecache *ecache) { DEBUGP("ecache: delivering events for %p\n", ecache->ct); if (is_confirmed(ecache->ct) && !is_dying(ecache->ct) && ecache->events) - notifier_call_chain(&ip_conntrack_chain, ecache->events, + atomic_notifier_call_chain(&ip_conntrack_chain, ecache->events, ecache->ct); ecache->events = 0; ip_conntrack_put(ecache->ct); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 01c62a0d3742..445006ee4522 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -143,7 +143,7 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev, struct prefix_info *pinfo); static int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev); -static struct notifier_block *inet6addr_chain; +static ATOMIC_NOTIFIER_HEAD(inet6addr_chain); struct ipv6_devconf ipv6_devconf = { .forwarding = 0, @@ -593,7 +593,7 @@ out2: read_unlock_bh(&addrconf_lock); if (likely(err == 0)) - notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa); + atomic_notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa); else { kfree(ifa); ifa = ERR_PTR(err); @@ -688,7 +688,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) ipv6_ifa_notify(RTM_DELADDR, ifp); - notifier_call_chain(&inet6addr_chain,NETDEV_DOWN,ifp); + atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifp); addrconf_del_timer(ifp); @@ -3767,12 +3767,12 @@ static void addrconf_sysctl_unregister(struct ipv6_devconf *p) int register_inet6addr_notifier(struct notifier_block *nb) { - return notifier_chain_register(&inet6addr_chain, nb); + return atomic_notifier_chain_register(&inet6addr_chain, nb); } int unregister_inet6addr_notifier(struct notifier_block *nb) { - return notifier_chain_unregister(&inet6addr_chain,nb); + return atomic_notifier_chain_unregister(&inet6addr_chain,nb); } /* diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 0ae281d9bfc3..56389c83557c 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -90,8 +90,8 @@ static int nf_conntrack_vmalloc; static unsigned int nf_conntrack_next_id; static unsigned int nf_conntrack_expect_next_id; #ifdef CONFIG_NF_CONNTRACK_EVENTS -struct notifier_block *nf_conntrack_chain; -struct notifier_block *nf_conntrack_expect_chain; +ATOMIC_NOTIFIER_HEAD(nf_conntrack_chain); +ATOMIC_NOTIFIER_HEAD(nf_conntrack_expect_chain); DEFINE_PER_CPU(struct nf_conntrack_ecache, nf_conntrack_ecache); @@ -103,7 +103,7 @@ __nf_ct_deliver_cached_events(struct nf_conntrack_ecache *ecache) DEBUGP("ecache: delivering events for %p\n", ecache->ct); if (nf_ct_is_confirmed(ecache->ct) && !nf_ct_is_dying(ecache->ct) && ecache->events) - notifier_call_chain(&nf_conntrack_chain, ecache->events, + atomic_notifier_call_chain(&nf_conntrack_chain, ecache->events, ecache->ct); ecache->events = 0; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index d00a9034cb5f..2a233ffcf618 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -123,7 +123,7 @@ static void netlink_destroy_callback(struct netlink_callback *cb); static DEFINE_RWLOCK(nl_table_lock); static atomic_t nl_table_users = ATOMIC_INIT(0); -static struct notifier_block *netlink_chain; +static ATOMIC_NOTIFIER_HEAD(netlink_chain); static u32 netlink_group_mask(u32 group) { @@ -469,7 +469,8 @@ static int netlink_release(struct socket *sock) .protocol = sk->sk_protocol, .pid = nlk->pid, }; - notifier_call_chain(&netlink_chain, NETLINK_URELEASE, &n); + atomic_notifier_call_chain(&netlink_chain, + NETLINK_URELEASE, &n); } if (nlk->module) @@ -1695,12 +1696,12 @@ static struct file_operations netlink_seq_fops = { int netlink_register_notifier(struct notifier_block *nb) { - return notifier_chain_register(&netlink_chain, nb); + return atomic_notifier_chain_register(&netlink_chain, nb); } int netlink_unregister_notifier(struct notifier_block *nb) { - return notifier_chain_unregister(&netlink_chain, nb); + return atomic_notifier_chain_unregister(&netlink_chain, nb); } static const struct proto_ops netlink_ops = { |