diff options
Diffstat (limited to 'init/initramfs.c')
| -rw-r--r-- | init/initramfs.c | 60 | 
1 files changed, 45 insertions, 15 deletions
diff --git a/init/initramfs.c b/init/initramfs.c index a8497fab1c3d..bece48c3461e 100644 --- a/init/initramfs.c +++ b/init/initramfs.c @@ -19,6 +19,29 @@  #include <linux/syscalls.h>  #include <linux/utime.h> +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)  { @@ -174,7 +197,7 @@ static __initdata enum state {  } state, next_state;  static __initdata char *victim; -static __initdata unsigned count; +static unsigned long count __initdata;  static __initdata loff_t this_header, next_header;  static inline void __init eat(unsigned n) @@ -186,7 +209,7 @@ static inline void __init eat(unsigned 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) @@ -213,7 +236,7 @@ static int __init do_start(void)  static int __init do_collect(void)  { -	unsigned n = remains; +	unsigned long n = remains;  	if (count < n)  		n = count;  	memcpy(collect, victim, n); @@ -346,7 +369,8 @@ static int __init do_name(void)  static int __init do_copy(void)  {  	if (count >= body_len) { -		sys_write(wfd, victim, body_len); +		if (xwrite(wfd, victim, body_len) != body_len) +			error("write error");  		sys_close(wfd);  		do_utime(vcollected, mtime);  		kfree(vcollected); @@ -354,7 +378,8 @@ static int __init do_copy(void)  		state = SkipIt;  		return 0;  	} else { -		sys_write(wfd, victim, count); +		if (xwrite(wfd, victim, count) != count) +			error("write error");  		body_len -= count;  		eat(count);  		return 1; @@ -384,7 +409,7 @@ 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;  	victim = buf; @@ -394,11 +419,11 @@ static int __init write_buffer(char *buf, unsigned len)  	return len - 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) { @@ -417,13 +442,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 <linux/decompress/generic.h> -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]; @@ -457,7 +482,7 @@ static char * __init unpack_to_rootfs(char *buf, unsigned len)  		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"); @@ -603,8 +628,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();  		}  |