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");