From: Seiji Aguchi
Git-commit: e59310adf5eebce108f78b6c47bb330aae2e1666
Patch-mainline: v3.9-rc1
References: bnc#808680
Target: openSUSE 12.3
[Issue]
There is a scenario which efi_pstore may hang up:
- cpuA grabs efivars->lock
- cpuB panics and calls smp_send_stop
- smp_send_stop sends IRQ to cpuA
- after 1 second, cpuB gives up on cpuA and sends an NMI instead
- cpuA is now in an NMI handler while still holding efivars->lock
- cpuB is deadlocked
This case may happen if a firmware has a bug and
cpuA is stuck talking with it.
[Solution]
This patch changes a spin_lock to a spin_trylock in non-blocking paths.
and if the spin_lock has already taken by another cpu,
it returns without accessing to a firmware to avoid the deadlock.
Signed-off-by: Seiji Aguchi
Acked-by: Don Zickus
Signed-off-by: Tony Luck
Acked-by: Lee, Chun-Yi
---
drivers/firmware/efivars.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -1194,7 +1194,16 @@ static int efi_pstore_write(enum pstore_
sprintf(stub_name, "dump-type%u-%u-", type, part);
sprintf(name, "%s%lu", stub_name, get_seconds());
- spin_lock(&efivars->lock);
+ if (pstore_cannot_block_path(reason)) {
+ /*
+ * If the lock is taken by another cpu in non-blocking path,
+ * this driver returns without entering firmware to avoid
+ * hanging up.
+ */
+ if (!spin_trylock(&efivars->lock))
+ return -EBUSY;
+ } else
+ spin_lock(&efivars->lock);
/*
* Check if there is a space enough to log.
--
To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org
To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org