134 lines
5.1 KiB
Diff
134 lines
5.1 KiB
Diff
From ac9103dd8e4dc65c110d6cba9a3380c6c617ffa7 Mon Sep 17 00:00:00 2001
|
|
From: Arjan van de Ven <arjan@linux.intel.com>
|
|
Date: Fri, 18 Jul 2008 15:16:08 -0700
|
|
Subject: [PATCH] fastboot: create a "asynchronous" initlevel
|
|
|
|
This patch creates an asynchronous initlevel (6a) which is at the same
|
|
level as the normal device initcalls, but with the difference that they
|
|
are run asynchronous from all the other initcalls. The purpose of this
|
|
*selective* level is that we can move long waiting inits that are not
|
|
boot-critical to this level one at a time.
|
|
|
|
To keep things not totally insane, the asynchronous initcalls are async
|
|
to the other initcalls, but are still ordered to themselves; think of it
|
|
as "bottom-half-not-softirq". This has the benefit that async drivers
|
|
still have stable device ordering between them.
|
|
|
|
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
|
|
Signed-off-by: Ingo Molnar <mingo@elte.hu>
|
|
---
|
|
include/asm-generic/vmlinux.lds.h | 3 +++
|
|
include/linux/init.h | 6 ++++++
|
|
init/main.c | 35 ++++++++++++++++++++++++++++++++---
|
|
3 files changed, 41 insertions(+), 3 deletions(-)
|
|
|
|
Index: linux-2.6.27/include/asm-generic/vmlinux.lds.h
|
|
===================================================================
|
|
--- linux-2.6.27.orig/include/asm-generic/vmlinux.lds.h 2008-10-14 16:55:43.000000000 +0200
|
|
+++ linux-2.6.27/include/asm-generic/vmlinux.lds.h 2008-10-14 17:00:59.000000000 +0200
|
|
@@ -376,6 +376,9 @@
|
|
*(.initcall5.init) \
|
|
*(.initcall5s.init) \
|
|
*(.initcallrootfs.init) \
|
|
+ __async_initcall_start = .; \
|
|
+ *(.initcall6a.init) \
|
|
+ __async_initcall_end = .; \
|
|
*(.initcall6.init) \
|
|
*(.initcall6s.init) \
|
|
*(.initcall7.init) \
|
|
Index: linux-2.6.27/include/linux/init.h
|
|
===================================================================
|
|
--- linux-2.6.27.orig/include/linux/init.h 2008-10-14 16:55:45.000000000 +0200
|
|
+++ linux-2.6.27/include/linux/init.h 2008-10-14 17:00:59.000000000 +0200
|
|
@@ -197,11 +197,13 @@ extern void (*late_time_init)(void);
|
|
#define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)
|
|
#define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)
|
|
#define device_initcall(fn) __define_initcall("6",fn,6)
|
|
+#define device_initcall_async(fn) __define_initcall("6a", fn, 6a)
|
|
#define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
|
|
#define late_initcall(fn) __define_initcall("7",fn,7)
|
|
#define late_initcall_sync(fn) __define_initcall("7s",fn,7s)
|
|
|
|
#define __initcall(fn) device_initcall(fn)
|
|
+#define __initcall_async(fn) device_initcall_async(fn)
|
|
|
|
#define __exitcall(fn) \
|
|
static exitcall_t __exitcall_##fn __exit_call = fn
|
|
@@ -257,6 +259,7 @@ void __init parse_early_param(void);
|
|
* be one per module.
|
|
*/
|
|
#define module_init(x) __initcall(x);
|
|
+#define module_init_async(x) __initcall_async(x);
|
|
|
|
/**
|
|
* module_exit() - driver exit entry point
|
|
@@ -279,10 +282,13 @@ void __init parse_early_param(void);
|
|
#define subsys_initcall(fn) module_init(fn)
|
|
#define fs_initcall(fn) module_init(fn)
|
|
#define device_initcall(fn) module_init(fn)
|
|
+#define device_initcall_async(fn) module_init(fn)
|
|
#define late_initcall(fn) module_init(fn)
|
|
|
|
#define security_initcall(fn) module_init(fn)
|
|
|
|
+#define module_init_async(fn) module_init(fn)
|
|
+
|
|
/* Each module must use one module_init(). */
|
|
#define module_init(initfn) \
|
|
static inline initcall_t __inittest(void) \
|
|
Index: linux-2.6.27/init/main.c
|
|
===================================================================
|
|
--- linux-2.6.27.orig/init/main.c 2008-10-14 16:55:47.000000000 +0200
|
|
+++ linux-2.6.27/init/main.c 2008-10-14 17:00:59.000000000 +0200
|
|
@@ -745,18 +745,47 @@ int do_one_initcall(initcall_t fn)
|
|
|
|
|
|
extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];
|
|
+extern initcall_t __async_initcall_start[], __async_initcall_end[];
|
|
|
|
-static void __init do_initcalls(void)
|
|
+static void __init do_async_initcalls(struct work_struct *dummy)
|
|
{
|
|
initcall_t *call;
|
|
|
|
- for (call = __early_initcall_end; call < __initcall_end; call++)
|
|
+ for (call = __async_initcall_start; call < __async_initcall_end; call++)
|
|
do_one_initcall(*call);
|
|
+}
|
|
+
|
|
+static struct workqueue_struct *async_init_wq;
|
|
+
|
|
+static void __init do_initcalls(void)
|
|
+{
|
|
+ initcall_t *call;
|
|
+ static DECLARE_WORK(async_work, do_async_initcalls);
|
|
+ int phase = 0; /* 0 = levels 0 - 6, 1 = level 6a, 2 = after level 6a */
|
|
+
|
|
+ async_init_wq = create_singlethread_workqueue("kasyncinit");
|
|
+
|
|
+ for (call = __early_initcall_end; call < __initcall_end; call++) {
|
|
+ if (phase == 0 && call >= __async_initcall_start) {
|
|
+ phase = 1;
|
|
+ queue_work(async_init_wq, &async_work);
|
|
+ }
|
|
+ if (phase == 1 && call >= __async_initcall_end)
|
|
+ phase = 2;
|
|
+ if (phase != 1)
|
|
+ do_one_initcall(*call);
|
|
+ }
|
|
|
|
- /* Make sure there is no pending stuff from the initcall sequence */
|
|
+ /*
|
|
+ * Make sure there is no pending stuff from the initcall sequence,
|
|
+ * including the async initcalls
|
|
+ */
|
|
flush_scheduled_work();
|
|
+ flush_workqueue(async_init_wq);
|
|
+ destroy_workqueue(async_init_wq);
|
|
}
|
|
|
|
+
|
|
/*
|
|
* Ok, the machine is now initialized. None of the devices
|
|
* have been touched yet, but the CPU subsystem is up and
|