we check if initrd is initramfs first and then do real unpack. The check isn't required, we can directly do unpack. If initrd isn't initramfs, we can remove garbage. In my laptop, this saves 0.1s boot time. This penalizes non-initramfs case, but now initramfs is mostly widely used. Signed-off-by: Shaohua Li diff --git a/init/initramfs.c b/init/initramfs.c index 644fc01..da8d030 100644 --- a/init/initramfs.c +++ b/init/initramfs.c @@ -5,6 +5,7 @@ #include #include #include +#include #include static __initdata char *message; @@ -121,8 +122,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; @@ -183,10 +182,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; @@ -257,8 +252,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(); @@ -423,10 +416,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); @@ -520,10 +512,57 @@ skip: initrd_end = 0; } +#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); +} + 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) { @@ -531,13 +570,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); @@ -550,7 +591,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");