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-04 22:59:50.823843424 -0700 +++ 25-akpm/arch/alpha/kernel/smp.c 2004-05-04 22:59:50.843840384 -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-04 22:59:50.824843272 -0700 +++ 25-akpm/arch/i386/kernel/smp.c 2004-05-04 22:59:50.844840232 -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-04 22:59:50.826842968 -0700 +++ 25-akpm/arch/i386/mach-voyager/voyager_smp.c 2004-05-04 22:59:50.845840080 -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-04 22:59:50.827842816 -0700 +++ 25-akpm/arch/ia64/kernel/smp.c 2004-05-04 22:59:50.846839928 -0700 @@ -308,6 +308,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-04 22:59:50.829842512 -0700 +++ 25-akpm/arch/mips/kernel/smp.c 2004-05-04 22:59:50.846839928 -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-04 22:59:50.830842360 -0700 +++ 25-akpm/arch/parisc/kernel/smp.c 2004-05-04 22:59:50.847839776 -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-04 22:59:50.831842208 -0700 +++ 25-akpm/arch/ppc64/kernel/smp.c 2004-05-04 22:59:50.848839624 -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-04 22:59:50.832842056 -0700 +++ 25-akpm/arch/ppc/kernel/smp.c 2004-05-04 22:59:50.848839624 -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-04 22:59:50.834841752 -0700 +++ 25-akpm/arch/s390/kernel/smp.c 2004-05-04 22:59:50.849839472 -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-04 22:59:50.835841600 -0700 +++ 25-akpm/arch/sh/kernel/smp.c 2004-05-04 22:59:50.849839472 -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-04 22:59:50.836841448 -0700 +++ 25-akpm/arch/sparc64/kernel/smp.c 2004-05-04 22:59:50.850839320 -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-04 22:59:50.838841144 -0700 +++ 25-akpm/arch/um/kernel/smp.c 2004-05-04 22:59:50.851839168 -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-04 22:59:50.839840992 -0700 +++ 25-akpm/arch/x86_64/kernel/smp.c 2004-05-04 22:59:50.851839168 -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); _