Fastboot Patch 2 6 27
This is the Fastboot Patch to the 2.6.27 Kernel. There have been expressed constents about this so use at your own risk it does work fine for me!
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index b1c723f..d5d30ca 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -904,5 +904,5 @@ static void __exit acpi_battery_exit(void)
#endif
}
-module_init(acpi_battery_init);
+module_init_async(acpi_battery_init);
module_exit(acpi_battery_exit);
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 1dfec41..46b3805 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -545,5 +545,5 @@ static void __exit acpi_button_exit(void)
remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
}
-module_init(acpi_button_init);
+module_init_async(acpi_button_init);
module_exit(acpi_button_exit);
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 9127036..c07f9ba 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -1876,5 +1876,5 @@ static void __exit acpi_thermal_exit(void)
return;
}
-module_init(acpi_thermal_init);
+module_init_async(acpi_thermal_init);
module_exit(acpi_thermal_exit);
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 2281b50..8e72c91 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -32,7 +32,7 @@ config BLK_DEV_MD
config MD_AUTODETECT
bool "Autodetect RAID arrays during kernel boot"
- depends on BLK_DEV_MD=y
+ depends on BLK_DEV_MD
default y
---help---
If you say Y here, then the kernel will try to autodetect raid
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index c9884bb..a9301a2 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1909,7 +1909,7 @@ static int __devinit pci_setup(char *str)
}
early_param("pci", pci_setup);
-device_initcall(pci_init);
+device_initcall_sync(pci_init);
EXPORT_SYMBOL(pci_reenable_device);
EXPORT_SYMBOL(pci_enable_device_io);
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index d343afa..c431abe 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1116,7 +1116,7 @@ err_debug:
clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
return retval;
}
-module_init(ehci_hcd_init);
+module_init_async(ehci_hcd_init);
static void __exit ehci_hcd_cleanup(void)
{
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 8647dab..3f47bf6 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1185,7 +1185,7 @@ static int __init ohci_hcd_mod_init(void)
clear_bit(USB_OHCI_LOADED, &usb_hcds_loaded);
return retval;
}
-module_init(ohci_hcd_mod_init);
+module_init_async(ohci_hcd_mod_init);
static void __exit ohci_hcd_mod_exit(void)
{
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index cf5e4cf..a646297 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -1001,7 +1001,7 @@ static void __exit uhci_hcd_cleanup(void)
clear_bit(USB_UHCI_LOADED, &usb_hcds_loaded);
}
-module_init(uhci_hcd_init);
+module_init_async(uhci_hcd_init);
module_exit(uhci_hcd_cleanup);
MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 74c5faf..3111159 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -384,8 +384,12 @@
*(.initcall5.init) \
*(.initcall5s.init) \
*(.initcallrootfs.init) \
+ *(.initcall6s.init) \
+ VMLINUX_SYMBOL(__async_initcall_start) = .; \
+ *(.initcall6a.init) \
+ VMLINUX_SYMBOL(__async_initcall_end) = .; \
*(.initcall6.init) \
- *(.initcall6s.init) \
+ VMLINUX_SYMBOL(__device_initcall_end) = .; \
*(.initcall7.init) \
*(.initcall7s.init)
diff --git a/include/linux/init.h b/include/linux/init.h
index ad63824..af9b3ab 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -143,6 +143,8 @@ extern int do_one_initcall(initcall_t fn);
extern char __initdata boot_command_line[];
extern char *saved_command_line;
extern unsigned int reset_devices;
+extern int do_one_initcall(initcall_t fn);
+
/* used by init/main.c */
void setup_arch(char **);
@@ -197,11 +199,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
@@ -254,6 +258,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
@@ -276,10 +281,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) \
diff --git a/init/Kconfig b/init/Kconfig
index 5ceff32..bb8d30f 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -524,6 +524,17 @@ config CC_OPTIMIZE_FOR_SIZE
If unsure, say Y.
+config FASTBOOT
+ bool "Fast boot support"
+ help
+ The fastboot option will cause the kernel to try to optimize
+ for faster boot.
+
+ This includes doing some of the device initialization asynchronously
+ as well as opportunistically trying to mount the root fs early.
+
+ If unsure, say N.
+
config SYSCTL
bool
diff --git a/init/do_mounts.c b/init/do_mounts.c
index d055b19..b7b613c 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -369,9 +369,11 @@ void __init prepare_namespace(void)
ssleep(root_delay);
}
+#ifndef CONFIG_FASTBOOT
/* wait for the known devices to complete their probing */
while (driver_probe_done() != 0)
msleep(100);
+#endif
md_run_setup();
diff --git a/init/initramfs.c b/init/initramfs.c
index 4f5ba75..3d98d25 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -5,6 +5,7 @@
#include <linux/fcntl.h>
#include <linux/delay.h>
#include <linux/string.h>
+#include <linux/dirent.h>
#include <linux/syscalls.h>
#include <linux/utime.h>
@@ -166,8 +167,6 @@ static __initdata char *victim;
static __initdata unsigned count;
static __initdata loff_t this_header, next_header;
-static __initdata int dry_run;
-
static inline void __init eat(unsigned n)
{
victim += n;
@@ -229,10 +228,6 @@ static int __init do_header(void)
parse_header(collected);
next_header = this_header + N_ALIGN(name_len) + body_len;
next_header = (next_header + 3) & ~3;
- if (dry_run) {
- read_into(name_buf, N_ALIGN(name_len), GotName);
- return 0;
- }
state = SkipIt;
if (name_len <= 0 || name_len > PATH_MAX)
return 0;
@@ -303,8 +298,6 @@ static int __init do_name(void)
free_hash();
return 0;
}
- if (dry_run)
- return 0;
clean_path(collected, mode);
if (S_ISREG(mode)) {
int ml = maybe_link();
@@ -475,10 +468,9 @@ static void __init flush_window(void)
outcnt = 0;
}
-static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only)
+static char * __init unpack_to_rootfs(char *buf, unsigned len)
{
int written;
- dry_run = check_only;
header_buf = kmalloc(110, GFP_KERNEL);
symlink_buf = kmalloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1, GFP_KERNEL);
name_buf = kmalloc(N_ALIGN(PATH_MAX), GFP_KERNEL);
@@ -573,10 +565,59 @@ skip:
initrd_end = 0;
}
+#ifdef CONFIG_BLK_DEV_RAM
+#define BUF_SIZE 1024
+static void __init clean_rootfs(void)
+{
+ int fd;
+ void *buf;
+ struct linux_dirent64 *dirp;
+ int count;
+
+ fd = sys_open("/", O_RDONLY, 0);
+ WARN_ON(fd < 0);
+ if (fd < 0)
+ return;
+ buf = kzalloc(BUF_SIZE, GFP_KERNEL);
+ WARN_ON(!buf);
+ if (!buf) {
+ sys_close(fd);
+ return;
+ }
+
+ dirp = buf;
+ count = sys_getdents64(fd, dirp, BUF_SIZE);
+ while (count > 0) {
+ while (count > 0) {
+ struct stat st;
+ int ret;
+
+ ret = sys_newlstat(dirp->d_name, &st);
+ WARN_ON_ONCE(ret);
+ if (!ret) {
+ if (S_ISDIR(st.st_mode))
+ sys_rmdir(dirp->d_name);
+ else
+ sys_unlink(dirp->d_name);
+ }
+
+ count -= dirp->d_reclen;
+ dirp = (void *)dirp + dirp->d_reclen;
+ }
+ dirp = buf;
+ memset(buf, 0, BUF_SIZE);
+ count = sys_getdents64(fd, dirp, BUF_SIZE);
+ }
+
+ sys_close(fd);
+ kfree(buf);
+}
+#endif
+
static int __init populate_rootfs(void)
{
char *err = unpack_to_rootfs(__initramfs_start,
- __initramfs_end - __initramfs_start, 0);
+ __initramfs_end - __initramfs_start);
if (err)
panic(err);
if (initrd_start) {
@@ -584,13 +625,15 @@ static int __init populate_rootfs(void)
int fd;
printk(KERN_INFO "checking if image is initramfs...");
err = unpack_to_rootfs((char *)initrd_start,
- initrd_end - initrd_start, 1);
+ initrd_end - initrd_start);
if (!err) {
printk(" it is\n");
- unpack_to_rootfs((char *)initrd_start,
- initrd_end - initrd_start, 0);
free_initrd();
return 0;
+ } else {
+ clean_rootfs();
+ unpack_to_rootfs(__initramfs_start,
+ __initramfs_end - __initramfs_start);
}
printk("it isn't (%s); looks like an initrd\n", err);
fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 0700);
@@ -603,7 +646,7 @@ static int __init populate_rootfs(void)
#else
printk(KERN_INFO "Unpacking initramfs...");
err = unpack_to_rootfs((char *)initrd_start,
- initrd_end - initrd_start, 0);
+ initrd_end - initrd_start);
if (err)
panic(err);
printk(" done\n");
diff --git a/init/main.c b/init/main.c
index 27f6bf6..68f38ee 100644
--- a/init/main.c
+++ b/init/main.c
@@ -745,16 +745,68 @@ 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[];
+extern initcall_t __device_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 compatibility with normal init calls... take the BKL
+ * not pretty, not desirable, but compatibility first
+ */
+ lock_kernel();
+ for (call = __async_initcall_start; call < __async_initcall_end; call++)
do_one_initcall(*call);
+ unlock_kernel();
+}
+
+static struct workqueue_struct *async_init_wq;
- /* Make sure there is no pending stuff from the initcall sequence */
+
+
+static void __init do_initcalls(void)
+{
+ initcall_t *call;
+ static DECLARE_WORK(async_work, do_async_initcalls);
+ /*
+ * 0 = levels 0 - 6,
+ * 1 = level 6a,
+ * 2 = after level 6a,
+ * 3 = after level 6
+ */
+ int phase = 0;
+
+ 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;
+#ifdef CONFIG_FASTBOOT
+ queue_work(async_init_wq, &async_work);
+#else
+ do_async_initcalls(NULL);
+#endif
+ }
+ if (phase == 1 && call >= __async_initcall_end)
+ phase = 2;
+ if (phase == 2 && call >= __device_initcall_end) {
+ phase = 3;
+ /* make sure all async work is done before level 7 */
+ flush_workqueue(async_init_wq);
+ }
+ if (phase != 1)
+ do_one_initcall(*call);
+ }
+
+ /*
+ * 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);
}
/*
@@ -794,6 +846,7 @@ static void run_init_process(char *init_filename)
*/
static int noinline init_post(void)
{
+ int retry_count = 1;
free_initmem();
unlock_kernel();
mark_rodata_ro();
@@ -814,6 +867,7 @@ static int noinline init_post(void)
ramdisk_execute_command);
}
+retry:
/*
* We try each of these until one succeeds.
*
@@ -826,6 +880,23 @@ static int noinline init_post(void)
"defaults...\n", execute_command);
}
run_init_process("/sbin/init");
+
+ if (retry_count > 0) {
+ retry_count--;
+ /*
+ * We haven't found init yet... potentially because the device
+ * is still being probed. We need to
+ * - flush keventd and friends
+ * - wait for the known devices to complete their probing
+ * - try to mount the root fs again
+ */
+ flush_scheduled_work();
+ while (driver_probe_done() != 0)
+ msleep(100);
+ prepare_namespace();
+ goto retry;
+ }
+
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");