Commit 43653667 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] Warn when smp_call_function() is called with interrupts disabled

From: Keith Owens <kaos@sgi.com>

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.
parent 5805ad40
...@@ -820,6 +820,9 @@ smp_call_function_on_cpu (void (*func) (void *info), void *info, int retry, ...@@ -820,6 +820,9 @@ smp_call_function_on_cpu (void (*func) (void *info), void *info, int retry,
unsigned long timeout; unsigned long timeout;
int num_cpus_to_call; int num_cpus_to_call;
/* Can deadlock when called with interrupts disabled */
WARN_ON(irqs_disabled());
data.func = func; data.func = func;
data.info = info; data.info = info;
data.wait = wait; data.wait = wait;
......
...@@ -519,6 +519,9 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, ...@@ -519,6 +519,9 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
if (!cpus) if (!cpus)
return 0; return 0;
/* Can deadlock when called with interrupts disabled */
WARN_ON(irqs_disabled());
data.func = func; data.func = func;
data.info = info; data.info = info;
atomic_set(&data.started, 0); atomic_set(&data.started, 0);
......
...@@ -1106,6 +1106,9 @@ smp_call_function (void (*func) (void *info), void *info, int retry, ...@@ -1106,6 +1106,9 @@ smp_call_function (void (*func) (void *info), void *info, int retry,
if (!mask) if (!mask)
return 0; return 0;
/* Can deadlock when called with interrupts disabled */
WARN_ON(irqs_disabled());
data.func = func; data.func = func;
data.info = info; data.info = info;
data.started = mask; data.started = mask;
......
...@@ -308,6 +308,9 @@ smp_call_function (void (*func) (void *info), void *info, int nonatomic, int wai ...@@ -308,6 +308,9 @@ smp_call_function (void (*func) (void *info), void *info, int nonatomic, int wai
if (!cpus) if (!cpus)
return 0; return 0;
/* Can deadlock when called with interrupts disabled */
WARN_ON(irqs_disabled());
data.func = func; data.func = func;
data.info = info; data.info = info;
atomic_set(&data.started, 0); atomic_set(&data.started, 0);
......
...@@ -151,6 +151,9 @@ int smp_call_function (void (*func) (void *info), void *info, int retry, ...@@ -151,6 +151,9 @@ int smp_call_function (void (*func) (void *info), void *info, int retry,
if (!cpus) if (!cpus)
return 0; return 0;
/* Can deadlock when called with interrupts disabled */
WARN_ON(irqs_disabled());
data.func = func; data.func = func;
data.info = info; data.info = info;
atomic_set(&data.started, 0); atomic_set(&data.started, 0);
......
...@@ -327,6 +327,9 @@ smp_call_function (void (*func) (void *info), void *info, int retry, int wait) ...@@ -327,6 +327,9 @@ smp_call_function (void (*func) (void *info), void *info, int retry, int wait)
struct smp_call_struct data; struct smp_call_struct data;
unsigned long timeout; unsigned long timeout;
static spinlock_t lock = SPIN_LOCK_UNLOCKED; static spinlock_t lock = SPIN_LOCK_UNLOCKED;
/* Can deadlock when called with interrupts disabled */
WARN_ON(irqs_disabled());
data.func = func; data.func = func;
data.info = info; data.info = info;
......
...@@ -211,6 +211,8 @@ int smp_call_function(void (*func) (void *info), void *info, int nonatomic, ...@@ -211,6 +211,8 @@ int smp_call_function(void (*func) (void *info), void *info, int nonatomic,
bitmask. --RR */ bitmask. --RR */
if (num_online_cpus() <= 1) if (num_online_cpus() <= 1)
return 0; return 0;
/* Can deadlock when called with interrupts disabled */
WARN_ON(irqs_disabled());
return __smp_call_function(func, info, wait, MSG_ALL_BUT_SELF); return __smp_call_function(func, info, wait, MSG_ALL_BUT_SELF);
} }
......
...@@ -692,6 +692,9 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, ...@@ -692,6 +692,9 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
int ret = -1, cpus; int ret = -1, cpus;
unsigned long timeout; unsigned long timeout;
/* Can deadlock when called with interrupts disabled */
WARN_ON(irqs_disabled());
data.func = func; data.func = func;
data.info = info; data.info = info;
atomic_set(&data.started, 0); atomic_set(&data.started, 0);
......
...@@ -127,6 +127,9 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, ...@@ -127,6 +127,9 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
if (cpus <= 0) if (cpus <= 0)
return 0; return 0;
/* Can deadlock when called with interrupts disabled */
WARN_ON(irqs_disabled());
data.func = func; data.func = func;
data.info = info; data.info = info;
atomic_set(&data.started, 0); atomic_set(&data.started, 0);
......
...@@ -181,6 +181,9 @@ int smp_call_function(void (*func)(void *info), void *info, int retry, int wait) ...@@ -181,6 +181,9 @@ int smp_call_function(void (*func)(void *info), void *info, int retry, int wait)
if (nr_cpus < 2) if (nr_cpus < 2)
return 0; return 0;
/* Can deadlock when called with interrupts disabled */
WARN_ON(irqs_disabled());
spin_lock(&smp_fn_call.lock); spin_lock(&smp_fn_call.lock);
atomic_set(&smp_fn_call.finished, 0); atomic_set(&smp_fn_call.finished, 0);
......
...@@ -598,6 +598,9 @@ int smp_call_function(void (*func)(void *info), void *info, ...@@ -598,6 +598,9 @@ int smp_call_function(void (*func)(void *info), void *info,
if (!cpus) if (!cpus)
return 0; return 0;
/* Can deadlock when called with interrupts disabled */
WARN_ON(irqs_disabled());
data.func = func; data.func = func;
data.info = info; data.info = info;
atomic_set(&data.finished, 0); atomic_set(&data.finished, 0);
......
...@@ -266,6 +266,9 @@ int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic, ...@@ -266,6 +266,9 @@ int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic,
if (!cpus) if (!cpus)
return 0; return 0;
/* Can deadlock when called with interrupts disabled */
WARN_ON(irqs_disabled());
spin_lock_bh(&call_lock); spin_lock_bh(&call_lock);
atomic_set(&scf_started, 0); atomic_set(&scf_started, 0);
atomic_set(&scf_finished, 0); atomic_set(&scf_finished, 0);
......
...@@ -404,6 +404,9 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, ...@@ -404,6 +404,9 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
if (!cpus) if (!cpus)
return 0; return 0;
/* Can deadlock when called with interrupts disabled */
WARN_ON(irqs_disabled());
data.func = func; data.func = func;
data.info = info; data.info = info;
atomic_set(&data.started, 0); atomic_set(&data.started, 0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment