kernel/lib: add additional debug capabilites for data corruption

Data corruptions in the kernel often end up in system crashes that
are easier to debug closer to the time of detection. Specifically,
if we do not panic immediately after lock or list corruptions have been
detected, the problem context is lost in the ensuing system mayhem.
Add support for allowing system crash immediately after such corruptions
are detected. The CONFIG option controls the enabling/disabling of the
feature.

Change-Id: I9b2eb62da506a13007acff63e85e9515145909ff
Signed-off-by: Syed Rameez Mustafa <rameezmustafa@codeaurora.org>
diff --git a/include/linux/bug.h b/include/linux/bug.h
index 7f48186..91eedf5 100644
--- a/include/linux/bug.h
+++ b/include/linux/bug.h
@@ -109,4 +109,10 @@
 }
 
 #endif	/* CONFIG_GENERIC_BUG */
+
+#ifdef CONFIG_PANIC_ON_DATA_CORRUPTION
+#define PANIC_CORRUPTION 1
+#else
+#define PANIC_CORRUPTION 0
+#endif  /* CONFIG_PANIC_ON_DATA_CORRUPTION */
 #endif	/* _LINUX_BUG_H */
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index ee8e29a..e49d674 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -47,6 +47,7 @@
 #include <linux/nodemask.h>
 #include <linux/moduleparam.h>
 #include <linux/uaccess.h>
+#include <linux/bug.h>
 
 #include "workqueue_internal.h"
 
@@ -2185,6 +2186,7 @@
 		       current->comm, preempt_count(), task_pid_nr(current),
 		       worker->current_func);
 		debug_show_held_locks(current);
+		BUG_ON(PANIC_CORRUPTION);
 		dump_stack();
 	}
 
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 566cf2b..9861ae9 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1475,6 +1475,13 @@
 
 	  If unsure, say N.
 
+config PANIC_ON_DATA_CORRUPTION
+	bool "Cause a Kernel Panic When Data Corruption is detected"
+	help
+	 Select this option to upgrade warnings for potentially
+	 recoverable data corruption scenarios to system-halting panics,
+	 for easier detection and debug.
+
 source "samples/Kconfig"
 
 source "lib/Kconfig.kgdb"
diff --git a/lib/list_debug.c b/lib/list_debug.c
index c24c2f7..8cf180b 100644
--- a/lib/list_debug.c
+++ b/lib/list_debug.c
@@ -11,6 +11,7 @@
 #include <linux/bug.h>
 #include <linux/kernel.h>
 #include <linux/rculist.h>
+#include <linux/bug.h>
 
 /*
  * Insert a new entry between two known consecutive entries.
@@ -34,6 +35,10 @@
 	WARN(new == prev || new == next,
 	     "list_add double add: new=%p, prev=%p, next=%p.\n",
 	     new, prev, next);
+
+	BUG_ON((prev->next != next || next->prev != prev ||
+		 new == prev || new == next) && PANIC_CORRUPTION);
+
 	next->prev = new;
 	new->next = next;
 	new->prev = prev;
@@ -59,8 +64,10 @@
 		"but was %p\n", entry, prev->next) ||
 	    WARN(next->prev != entry,
 		"list_del corruption. next->prev should be %p, "
-		"but was %p\n", entry, next->prev))
+		"but was %p\n", entry, next->prev)) {
+		BUG_ON(PANIC_CORRUPTION);
 		return;
+	}
 
 	__list_del(prev, next);
 }
diff --git a/lib/spinlock_debug.c b/lib/spinlock_debug.c
index 0374a59..6011c19 100644
--- a/lib/spinlock_debug.c
+++ b/lib/spinlock_debug.c
@@ -12,6 +12,7 @@
 #include <linux/debug_locks.h>
 #include <linux/delay.h>
 #include <linux/export.h>
+#include <linux/bug.h>
 
 void __raw_spin_lock_init(raw_spinlock_t *lock, const char *name,
 			  struct lock_class_key *key)
@@ -64,6 +65,7 @@
 		owner ? owner->comm : "<none>",
 		owner ? task_pid_nr(owner) : -1,
 		lock->owner_cpu);
+	BUG_ON(PANIC_CORRUPTION);
 	dump_stack();
 }