Fastboot Patch 2 6 27

From ThinkWiki
Revision as of 20:30, 21 October 2008 by Blk (Talk | contribs) (Fastboot patch for vanilla 2.6.27)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

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