insmod moduleb.ko & sleep 1; insmod modulec.ko

C waits for B to finish to resolve its symbols, holding the lock.

B request_module's A, which blocks since A's init_module() can't
finish without the lock.

Deadlock, resolved by timeout.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 kernel/Makefile  |    1 +
 kernel/modulea.c |   16 ++++++++++++++++
 kernel/moduleb.c |   26 ++++++++++++++++++++++++++
 kernel/modulec.c |   15 +++++++++++++++
 4 files changed, 58 insertions(+)

diff --git a/kernel/Makefile b/kernel/Makefile
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -105,6 +105,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.
 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
 obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
 obj-$(CONFIG_PADATA) += padata.o
+obj-m += modulea.o moduleb.o modulec.o
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --git a/kernel/modulea.c b/kernel/modulea.c
new file mode 100644
--- /dev/null
+++ b/kernel/modulea.c
@@ -0,0 +1,16 @@
+#include <linux/module.h>
+#include <linux/init.h>
+
+int module_a_symbol = 0xAA;
+
+EXPORT_SYMBOL(module_a_symbol);
+
+static int slow_init(void)
+{
+	printk("Module A initializing slowly\n");
+	msleep(2000);
+	printk("Module A finishing\n");
+	return 0;
+}
+module_init(slow_init);
+
diff --git a/kernel/moduleb.c b/kernel/moduleb.c
new file mode 100644
--- /dev/null
+++ b/kernel/moduleb.c
@@ -0,0 +1,26 @@
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+
+int module_b_symbol = 42;
+extern int module_a_symbol;
+
+EXPORT_SYMBOL(module_b_symbol);
+
+static int init(void)
+{
+	int err;
+	printk("Requesting Module A\n");
+	err = request_module("modulea");
+	printk("Requested Module A: %i\n", err);
+	printk("module_a_symbol = %p\n", symbol_get(module_a_symbol));
+	return 0;
+}
+module_init(init);
+
+static void fini(void)
+{
+	symbol_put(module_a_symbol);
+}
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff --git a/kernel/modulec.c b/kernel/modulec.c
new file mode 100644
--- /dev/null
+++ b/kernel/modulec.c
@@ -0,0 +1,15 @@
+#include <linux/module.h>
+
+extern int module_b_symbol;
+
+static int init(void)
+{
+	printk("Module B symbol is %u\n", module_b_symbol);
+	return 0;
+}
+module_init(init);
+
+static void fini(void)
+{
+}
+module_exit(fini);
