Messages in this thread Patch in this message | | | From | Yinghai Lu <> | Subject | [PATCH] initramfs: Support initrd that is bigger then 2G. | Date | Thu, 19 Jun 2014 19:12:16 -0700 |
| |
When initrd (compressed or not) is used, kernel report data corrupted with /dev/ram0.
The root cause: During initramfs checking, if it is initrd, it will be transferred to /initrd.image with sys_write. sys_write only support 2G-4K write, so if the initrd ram is more than that, /initrd.image will not complete at all.
Add local sys_write_large to loop calling sys_write to workaround the problem.
Also need to use that in write_buffer path for cpio that have file is more than file.
At the same time, we don't need to worry about sys_read/sys_write in do_mounts_rd.c::crd_load. As decompressor will have fill/flush that means it will allocate buffer and buffer is smaller than 2G.
Test with uncompressed initrd, and compressed with gz, bz2, lzma,xz, lzop.
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
--- init/initramfs.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-)
Index: linux-2.6/init/initramfs.c =================================================================== --- linux-2.6.orig/init/initramfs.c +++ linux-2.6/init/initramfs.c @@ -19,6 +19,26 @@ #include <linux/syscalls.h> #include <linux/utime.h> +static long __init sys_write_large(unsigned int fd, char *p, + size_t count) +{ + ssize_t left = count; + long written; + + /* sys_write only can write MAX_RW_COUNT aka 2G-4K bytes at most */ + while (left > 0) { + written = sys_write(fd, p, left); + + if (written <= 0) + break; + + left -= written; + p += written; + } + + return (written < 0) ? written : count; +} + static __initdata char *message; static void __init error(char *x) { @@ -346,7 +366,7 @@ static int __init do_name(void) static int __init do_copy(void) { if (count >= body_len) { - sys_write(wfd, victim, body_len); + sys_write_large(wfd, victim, body_len); sys_close(wfd); do_utime(vcollected, mtime); kfree(vcollected); @@ -354,7 +374,7 @@ static int __init do_copy(void) state = SkipIt; return 0; } else { - sys_write(wfd, victim, count); + sys_write_large(wfd, victim, count); body_len -= count; eat(count); return 1; @@ -604,8 +624,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); + long written = sys_write_large(fd, (char *)initrd_start, + initrd_end - initrd_start); + + if (written != initrd_end - initrd_start) + pr_err("/initrd.image: incomplete write (%ld != %ld)\n", + written, initrd_end - initrd_start); + sys_close(fd); free_initrd(); }
| |