diff options
Diffstat (limited to 'init/initramfs.c')
| -rw-r--r-- | init/initramfs.c | 86 |
1 files changed, 52 insertions, 34 deletions
diff --git a/init/initramfs.c b/init/initramfs.c index 80cd713f6cc..a8497fab1c3 100644 --- a/init/initramfs.c +++ b/init/initramfs.c @@ -1,3 +1,13 @@ +/* + * Many of the syscalls used in this file expect some of the arguments + * to be __user pointers not __kernel pointers. To limit the sparse + * noise, turn off sparse checking for this file. + */ +#ifdef __CHECKER__ +#undef __CHECKER__ +#warning "Sparse checking disabled for this file" +#endif + #include <linux/init.h> #include <linux/fs.h> #include <linux/slab.h> @@ -22,7 +32,7 @@ static void __init error(char *x) static __initdata struct hash { int ino, minor, major; - mode_t mode; + umode_t mode; struct hash *next; char name[N_ALIGN(PATH_MAX)]; } *head[32]; @@ -35,7 +45,7 @@ static inline int hash(int major, int minor, int ino) } static char __init *find_link(int major, int minor, int ino, - mode_t mode, char *name) + umode_t mode, char *name) { struct hash **p, *q; for (p = head + hash(major, minor, ino); *p; p = &(*p)->next) { @@ -74,7 +84,7 @@ static void __init free_hash(void) } } -static long __init do_utime(char __user *filename, time_t mtime) +static long __init do_utime(char *filename, time_t mtime) { struct timespec t[2]; @@ -120,7 +130,7 @@ static __initdata time_t mtime; /* cpio header parsing */ static __initdata unsigned long ino, major, minor, nlink; -static __initdata mode_t mode; +static __initdata umode_t mode; static __initdata unsigned long body_len, name_len; static __initdata uid_t uid; static __initdata gid_t gid; @@ -276,7 +286,7 @@ static int __init maybe_link(void) return 0; } -static void __init clean_path(char *path, mode_t mode) +static void __init clean_path(char *path, umode_t mode) { struct stat st; @@ -310,7 +320,8 @@ static int __init do_name(void) if (wfd >= 0) { sys_fchown(wfd, uid, gid); sys_fchmod(wfd, mode); - sys_ftruncate(wfd, body_len); + if (body_len) + sys_ftruncate(wfd, body_len); vcollected = kstrdup(collected, GFP_KERNEL); state = CopyFile; } @@ -412,7 +423,7 @@ static unsigned my_inptr; /* index of next byte to be processed in inbuf */ static char * __init unpack_to_rootfs(char *buf, unsigned len) { - int written; + int written, res; decompress_fn decompress; const char *compress_name; static __initdata char msg_buf[64]; @@ -444,17 +455,21 @@ static char * __init unpack_to_rootfs(char *buf, unsigned len) } this_header = 0; decompress = decompress_method(buf, len, &compress_name); - if (decompress) - decompress(buf, len, NULL, flush_buffer, NULL, + pr_debug("Detected %s compressed data\n", compress_name); + if (decompress) { + res = decompress(buf, len, NULL, flush_buffer, NULL, &my_inptr, error); - else if (compress_name) { + if (res) + error("decompressor failed"); + } else if (compress_name) { if (!message) { snprintf(msg_buf, sizeof msg_buf, "compression method %s not configured", compress_name); message = msg_buf; } - } + } else + error("junk in compressed archive"); if (state != Reset) error("junk in compressed archive"); this_header = saved_offset + my_inptr; @@ -479,7 +494,8 @@ static int __init retain_initrd_param(char *str) } __setup("retain_initrd", retain_initrd_param); -extern char __initramfs_start[], __initramfs_end[]; +extern char __initramfs_start[]; +extern unsigned long __initramfs_size; #include <linux/initrd.h> #include <linux/kexec.h> @@ -515,13 +531,14 @@ 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; + int num; fd = sys_open("/", O_RDONLY, 0); WARN_ON(fd < 0); @@ -535,9 +552,9 @@ static void __init clean_rootfs(void) } dirp = buf; - count = sys_getdents64(fd, dirp, BUF_SIZE); - while (count > 0) { - while (count > 0) { + num = sys_getdents64(fd, dirp, BUF_SIZE); + while (num > 0) { + while (num > 0) { struct stat st; int ret; @@ -550,60 +567,61 @@ static void __init clean_rootfs(void) sys_unlink(dirp->d_name); } - count -= dirp->d_reclen; + num -= dirp->d_reclen; dirp = (void *)dirp + dirp->d_reclen; } dirp = buf; memset(buf, 0, BUF_SIZE); - count = sys_getdents64(fd, dirp, BUF_SIZE); + num = 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); + char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size); if (err) - panic(err); /* Failed to decompress INTERNAL initramfs */ + panic("%s", err); /* Failed to decompress INTERNAL initramfs */ if (initrd_start) { #ifdef CONFIG_BLK_DEV_RAM int fd; - printk(KERN_INFO "checking if image is initramfs...\n"); + printk(KERN_INFO "Trying to unpack rootfs image as initramfs...\n"); err = unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start); if (!err) { - printk(KERN_INFO "rootfs image is initramfs; unpacking...\n"); free_initrd(); - return 0; + goto done; } else { clean_rootfs(); - unpack_to_rootfs(__initramfs_start, - __initramfs_end - __initramfs_start); + unpack_to_rootfs(__initramfs_start, __initramfs_size); } printk(KERN_INFO "rootfs image is not initramfs (%s)" "; looks like an initrd\n", err); - fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 0700); + fd = sys_open("/initrd.image", + O_WRONLY|O_CREAT, 0700); if (fd >= 0) { sys_write(fd, (char *)initrd_start, initrd_end - initrd_start); sys_close(fd); free_initrd(); } + done: #else - printk(KERN_INFO "Unpacking initramfs..."); + printk(KERN_INFO "Unpacking initramfs...\n"); err = unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start); - if (err) { - printk(" failed!\n"); - printk(KERN_EMERG "%s\n", err); - } else { - printk(" done\n"); - } + if (err) + printk(KERN_EMERG "Initramfs unpacking failed: %s\n", err); free_initrd(); #endif + /* + * Try loading default modules from initramfs. This gives + * us a chance to load before device_initcalls. + */ + load_default_modules(); } return 0; } |
