X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=init%2Finitramfs.c;h=f8ce812ba43e9356fdf35393d6c6b423078514ba;hb=c3fb09b10003480d785d72d65d52daf73ca18efb;hp=43ae0cc9df48c1851a8611a247b26875430249a2;hpb=6cb6484943f28fffacb6bf00d912f1dfe00f9805;p=firefly-linux-kernel-4.4.55.git diff --git a/init/initramfs.c b/init/initramfs.c index 43ae0cc9df48..f8ce812ba43e 100644 --- a/init/initramfs.c +++ b/init/initramfs.c @@ -20,6 +20,29 @@ #include #include +static ssize_t __init xwrite(int fd, const char *p, size_t count) +{ + ssize_t out = 0; + + /* sys_write only can write MAX_RW_COUNT aka 2G-4K bytes at most */ + while (count) { + ssize_t rv = sys_write(fd, p, count); + + if (rv < 0) { + if (rv == -EINTR || rv == -EAGAIN) + continue; + return out ? out : rv; + } else if (rv == 0) + break; + + p += rv; + out += rv; + count -= rv; + } + + return out; +} + static __initdata char *message; static void __init error(char *x) { @@ -175,24 +198,24 @@ static __initdata enum state { } state, next_state; static __initdata char *victim; -static __initdata unsigned count; +static unsigned long byte_count __initdata; static __initdata loff_t this_header, next_header; static inline void __init eat(unsigned n) { victim += n; this_header += n; - count -= n; + byte_count -= n; } static __initdata char *vcollected; static __initdata char *collected; -static __initdata int remains; +static long remains __initdata; static __initdata char *collect; static void __init read_into(char *buf, unsigned size, enum state next) { - if (count >= size) { + if (byte_count >= size) { collected = victim; eat(size); state = next; @@ -214,9 +237,9 @@ static int __init do_start(void) static int __init do_collect(void) { - unsigned n = remains; - if (count < n) - n = count; + unsigned long n = remains; + if (byte_count < n) + n = byte_count; memcpy(collect, victim, n); eat(n); collect += n; @@ -258,8 +281,8 @@ static int __init do_header(void) static int __init do_skip(void) { - if (this_header + count < next_header) { - eat(count); + if (this_header + byte_count < next_header) { + eat(byte_count); return 1; } else { eat(next_header - this_header); @@ -270,9 +293,9 @@ static int __init do_skip(void) static int __init do_reset(void) { - while(count && *victim == '\0') + while (byte_count && *victim == '\0') eat(1); - if (count && (this_header & 3)) + if (byte_count && (this_header & 3)) error("broken padding"); return 1; } @@ -287,11 +310,11 @@ static int __init maybe_link(void) return 0; } -static void __init clean_path(char *path, umode_t mode) +static void __init clean_path(char *path, umode_t fmode) { struct stat st; - if (!sys_newlstat(path, &st) && (st.st_mode^mode) & S_IFMT) { + if (!sys_newlstat(path, &st) && (st.st_mode ^ fmode) & S_IFMT) { if (S_ISDIR(st.st_mode)) sys_rmdir(path); else @@ -346,8 +369,9 @@ static int __init do_name(void) static int __init do_copy(void) { - if (count >= body_len) { - sys_write(wfd, victim, body_len); + if (byte_count >= body_len) { + if (xwrite(wfd, victim, body_len) != body_len) + error("write error"); sys_close(wfd); do_utime(vcollected, mtime); kfree(vcollected); @@ -355,9 +379,10 @@ static int __init do_copy(void) state = SkipIt; return 0; } else { - sys_write(wfd, victim, count); - body_len -= count; - eat(count); + if (xwrite(wfd, victim, byte_count) != byte_count) + error("write error"); + body_len -= byte_count; + eat(byte_count); return 1; } } @@ -385,21 +410,21 @@ static __initdata int (*actions[])(void) = { [Reset] = do_reset, }; -static int __init write_buffer(char *buf, unsigned len) +static long __init write_buffer(char *buf, unsigned long len) { - count = len; + byte_count = len; victim = buf; while (!actions[state]()) ; - return len - count; + return len - byte_count; } -static int __init flush_buffer(void *bufv, unsigned len) +static long __init flush_buffer(void *bufv, unsigned long len) { char *buf = (char *) bufv; - int written; - int origLen = len; + long written; + long origLen = len; if (message) return -1; while ((written = write_buffer(buf, len)) < len && !message) { @@ -418,13 +443,13 @@ static int __init flush_buffer(void *bufv, unsigned len) return origLen; } -static unsigned my_inptr; /* index of next byte to be processed in inbuf */ +static unsigned long my_inptr; /* index of next byte to be processed in inbuf */ #include -static char * __init unpack_to_rootfs(char *buf, unsigned len) +static char * __init unpack_to_rootfs(char *buf, unsigned long len) { - int written, res; + long written; decompress_fn decompress; const char *compress_name; static __initdata char msg_buf[64]; @@ -456,8 +481,9 @@ static char * __init unpack_to_rootfs(char *buf, unsigned len) } this_header = 0; decompress = decompress_method(buf, len, &compress_name); + pr_debug("Detected %s compressed data\n", compress_name); if (decompress) { - res = decompress(buf, len, NULL, flush_buffer, NULL, + int res = decompress(buf, len, NULL, flush_buffer, NULL, &my_inptr, error); if (res) error("decompressor failed"); @@ -501,14 +527,14 @@ extern unsigned long __initramfs_size; static void __init free_initrd(void) { -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE unsigned long crashk_start = (unsigned long)__va(crashk_res.start); unsigned long crashk_end = (unsigned long)__va(crashk_res.end); #endif if (do_retain_initrd) goto skip; -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE /* * If the initrd region is overlapped with crashkernel reserved region, * free only memory that is not part of crashkernel region. @@ -600,7 +626,7 @@ static int __init populate_rootfs(void) 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; @@ -619,8 +645,13 @@ static int __init populate_rootfs(void) fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 0700); if (fd >= 0) { - sys_write(fd, (char *)initrd_start, - initrd_end - initrd_start); + ssize_t written = xwrite(fd, (char *)initrd_start, + initrd_end - initrd_start); + + if (written != initrd_end - initrd_start) + pr_err("/initrd.image: incomplete write (%zd != %ld)\n", + written, initrd_end - initrd_start); + sys_close(fd); free_initrd(); }