From: Keith Owens Almost every architecture has a comment above smp_call_function() * You must not call this function with disabled interrupts or from a * hardware interrupt handler or from a bottom half handler. I have not seen any problems with calling smp_call_function() from a bottom half handler, but calling it with interrupts disabled can definitely deadlock. This bug is hard to reproduce and even harder to debug. CPU A CPU B Disable interrupts smp_call_function() Take call_lock Send IPIs Wait for all cpus to acknowledge IPI CPU A has not responded, spin waiting for cpu A to respond, holding call_lock smp_call_function() Spin waiting for call_lock Deadlock Deadlock Change all smp_call_function() to WARN_ON(irqs_disabled()). It should be BUG_ON() but some buggy code like SCSI sg will break with BUG_ON, so just warn for now. Change it to BUG_ON after the buggy code has been fixed. --- 25-akpm/arch/alpha/kernel/smp.c | 3 +++ 25-akpm/arch/i386/kernel/smp.c | 3 +++ 25-akpm/arch/i386/mach-voyager/voyager_smp.c | 3 +++ 25-akpm/arch/ia64/kernel/smp.c | 3 +++ 25-akpm/arch/mips/kernel/smp.c | 3 +++ 25-akpm/arch/parisc/kernel/smp.c | 3 +++ 25-akpm/arch/ppc/kernel/smp.c | 2 ++ 25-akpm/arch/ppc64/kernel/smp.c | 3 +++ 25-akpm/arch/s390/kernel/smp.c | 3 +++ 25-akpm/arch/sh/kernel/smp.c | 3 +++ 25-akpm/arch/sparc64/kernel/smp.c | 3 +++ 25-akpm/arch/um/kernel/smp.c | 3 +++ 25-akpm/arch/x86_64/kernel/smp.c | 3 +++ 13 files changed, 38 insertions(+) diff -puN arch/alpha/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled arch/alpha/kernel/smp.c --- 25/arch/alpha/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled 2004-05-05 23:16:07.980642304 -0700 +++ 25-akpm/arch/alpha/kernel/smp.c 2004-05-05 23:16:08.000639264 -0700 @@ -820,6 +820,9 @@ smp_call_function_on_cpu (void (*func) ( unsigned long timeout; int num_cpus_to_call; + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); + data.func = func; data.info = info; data.wait = wait; diff -puN arch/i386/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled arch/i386/kernel/smp.c --- 25/arch/i386/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled 2004-05-05 23:16:07.981642152 -0700 +++ 25-akpm/arch/i386/kernel/smp.c 2004-05-05 23:16:08.000639264 -0700 @@ -528,6 +528,9 @@ int smp_call_function (void (*func) (voi if (!cpus) return 0; + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); + data.func = func; data.info = info; atomic_set(&data.started, 0); diff -puN arch/i386/mach-voyager/voyager_smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled arch/i386/mach-voyager/voyager_smp.c --- 25/arch/i386/mach-voyager/voyager_smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled 2004-05-05 23:16:07.983641848 -0700 +++ 25-akpm/arch/i386/mach-voyager/voyager_smp.c 2004-05-05 23:16:08.002638960 -0700 @@ -1105,6 +1105,9 @@ smp_call_function (void (*func) (void *i if (!mask) return 0; + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); + data.func = func; data.info = info; data.started = mask; diff -puN arch/ia64/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled arch/ia64/kernel/smp.c --- 25/arch/ia64/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled 2004-05-05 23:16:07.984641696 -0700 +++ 25-akpm/arch/ia64/kernel/smp.c 2004-05-05 23:16:08.002638960 -0700 @@ -332,6 +332,9 @@ smp_call_function (void (*func) (void *i if (!cpus) return 0; + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); + data.func = func; data.info = info; atomic_set(&data.started, 0); diff -puN arch/mips/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled arch/mips/kernel/smp.c --- 25/arch/mips/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled 2004-05-05 23:16:07.986641392 -0700 +++ 25-akpm/arch/mips/kernel/smp.c 2004-05-05 23:16:08.003638808 -0700 @@ -151,6 +151,9 @@ int smp_call_function (void (*func) (voi if (!cpus) return 0; + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); + data.func = func; data.info = info; atomic_set(&data.started, 0); diff -puN arch/parisc/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled arch/parisc/kernel/smp.c --- 25/arch/parisc/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled 2004-05-05 23:16:07.987641240 -0700 +++ 25-akpm/arch/parisc/kernel/smp.c 2004-05-05 23:16:08.004638656 -0700 @@ -327,6 +327,9 @@ smp_call_function (void (*func) (void *i struct smp_call_struct data; unsigned long timeout; static spinlock_t lock = SPIN_LOCK_UNLOCKED; + + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); data.func = func; data.info = info; diff -puN arch/ppc64/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled arch/ppc64/kernel/smp.c --- 25/arch/ppc64/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled 2004-05-05 23:16:07.988641088 -0700 +++ 25-akpm/arch/ppc64/kernel/smp.c 2004-05-05 23:16:08.005638504 -0700 @@ -692,6 +692,9 @@ int smp_call_function (void (*func) (voi int ret = -1, cpus; unsigned long timeout; + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); + data.func = func; data.info = info; atomic_set(&data.started, 0); diff -puN arch/ppc/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled arch/ppc/kernel/smp.c --- 25/arch/ppc/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled 2004-05-05 23:16:07.989640936 -0700 +++ 25-akpm/arch/ppc/kernel/smp.c 2004-05-05 23:16:08.006638352 -0700 @@ -211,6 +211,8 @@ int smp_call_function(void (*func) (void bitmask. --RR */ if (num_online_cpus() <= 1) return 0; + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); return __smp_call_function(func, info, wait, MSG_ALL_BUT_SELF); } diff -puN arch/s390/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled arch/s390/kernel/smp.c --- 25/arch/s390/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled 2004-05-05 23:16:07.991640632 -0700 +++ 25-akpm/arch/s390/kernel/smp.c 2004-05-05 23:16:08.006638352 -0700 @@ -127,6 +127,9 @@ int smp_call_function (void (*func) (voi if (cpus <= 0) return 0; + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); + data.func = func; data.info = info; atomic_set(&data.started, 0); diff -puN arch/sh/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled arch/sh/kernel/smp.c --- 25/arch/sh/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled 2004-05-05 23:16:07.992640480 -0700 +++ 25-akpm/arch/sh/kernel/smp.c 2004-05-05 23:16:08.007638200 -0700 @@ -181,6 +181,9 @@ int smp_call_function(void (*func)(void if (nr_cpus < 2) return 0; + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); + spin_lock(&smp_fn_call.lock); atomic_set(&smp_fn_call.finished, 0); diff -puN arch/sparc64/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled arch/sparc64/kernel/smp.c --- 25/arch/sparc64/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled 2004-05-05 23:16:07.993640328 -0700 +++ 25-akpm/arch/sparc64/kernel/smp.c 2004-05-05 23:16:08.008638048 -0700 @@ -598,6 +598,9 @@ int smp_call_function(void (*func)(void if (!cpus) return 0; + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); + data.func = func; data.info = info; atomic_set(&data.finished, 0); diff -puN arch/um/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled arch/um/kernel/smp.c --- 25/arch/um/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled 2004-05-05 23:16:07.995640024 -0700 +++ 25-akpm/arch/um/kernel/smp.c 2004-05-05 23:16:08.008638048 -0700 @@ -266,6 +266,9 @@ int smp_call_function(void (*_func)(void if (!cpus) return 0; + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); + spin_lock_bh(&call_lock); atomic_set(&scf_started, 0); atomic_set(&scf_finished, 0); diff -puN arch/x86_64/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled arch/x86_64/kernel/smp.c --- 25/arch/x86_64/kernel/smp.c~warn-when-smp_call_function-is-called-with-interrupts-disabled 2004-05-05 23:16:07.996639872 -0700 +++ 25-akpm/arch/x86_64/kernel/smp.c 2004-05-05 23:16:08.009637896 -0700 @@ -416,6 +416,9 @@ int smp_call_function (void (*func) (voi if (!cpus) return 0; + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); + data.func = func; data.info = info; atomic_set(&data.started, 0); _