[PATCH 1/7] Add die_spin_lock_{irqsave,irqrestore}
Anton Blanchard
anton at samba.org
Mon Feb 23 19:30:28 PST 2015
Many architectures have their own oops locking code that allows
the lock to be taken recursively. Create a common version.
Avoid creating generic locking functions, so they can't be
abused in other parts of the kernel.
Signed-off-by: Anton Blanchard <anton at samba.org>
---
include/linux/die_lock.h | 23 +++++++++++++++++++++++
lib/Makefile | 1 +
lib/die_lock.c | 43 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 67 insertions(+)
create mode 100644 include/linux/die_lock.h
create mode 100644 lib/die_lock.c
diff --git a/include/linux/die_lock.h b/include/linux/die_lock.h
new file mode 100644
index 0000000..540d09d
--- /dev/null
+++ b/include/linux/die_lock.h
@@ -0,0 +1,23 @@
+#ifndef __LINUX_DIE_LOCK_H
+#define __LINUX_DIE_LOCK_H
+
+#include <linux/typecheck.h>
+
+/**
+ * die_spin_lock_irqsave - lock die spinlock
+ * @flags: interrupt state is saved here
+ *
+ * The die spinlock is used to serialise output during oopses, BUGs and
+ * WARNs. It can be taken recursively so that nested oopses will not
+ * lock up.
+ */
+unsigned long __die_spin_lock_irqsave(void);
+#define die_spin_lock_irqsave(flags) \
+ do { \
+ typecheck(unsigned long, flags); \
+ flags = __die_spin_lock_irqsave(); \
+ } while (0)
+
+void die_spin_unlock_irqrestore(unsigned long flags);
+
+#endif /* __LINUX_DIE_LOCK_H */
diff --git a/lib/Makefile b/lib/Makefile
index 3c3b30b..7d87a80 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -28,6 +28,7 @@ obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o \
percpu-refcount.o percpu_ida.o rhashtable.o reciprocal_div.o
obj-y += string_helpers.o
+obj-y += die_lock.o
obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o
obj-y += kstrtox.o
obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
diff --git a/lib/die_lock.c b/lib/die_lock.c
new file mode 100644
index 0000000..5d2de2e
--- /dev/null
+++ b/lib/die_lock.c
@@ -0,0 +1,43 @@
+#include <linux/spinlock.h>
+#include <linux/smp.h>
+
+static arch_spinlock_t die_lock = __ARCH_SPIN_LOCK_UNLOCKED;
+static int die_owner = -1;
+static unsigned int die_nest_count;
+
+unsigned long __die_spin_lock_irqsave(void)
+{
+ unsigned long flags;
+ int cpu;
+
+ /* racy, but better than risking deadlock. */
+ raw_local_irq_save(flags);
+
+ cpu = smp_processor_id();
+ if (!arch_spin_trylock(&die_lock)) {
+ if (cpu != die_owner)
+ arch_spin_lock(&die_lock);
+ }
+ die_nest_count++;
+ die_owner = cpu;
+
+ return flags;
+}
+
+/**
+ * die_spin_unlock_irqrestore - Unlock die spinlock
+ * @flags: interrupt state to restore
+ *
+ * Unlock die spinlock and restore interrupt state. This must be
+ * paired with die_spin_lock_irqsave.
+ */
+void die_spin_unlock_irqrestore(unsigned long flags)
+{
+ die_nest_count--;
+ if (!die_nest_count) {
+ die_owner = -1;
+ /* Nest count reaches zero, release the lock. */
+ arch_spin_unlock(&die_lock);
+ }
+ raw_local_irq_restore(flags);
+}
--
2.1.0
More information about the linux-arm-kernel
mailing list