[Libguestfs] [PATCH supermin v2 1/4] init: Uncompress modules before adding them to the mini initrd.
Pino Toscano
ptoscano at redhat.com
Wed Feb 17 15:54:21 UTC 2016
On Wednesday 17 February 2016 14:22:31 Richard W.M. Jones wrote:
> When building the mini initrd, previously we copied the modules into
> the initrd as-is, so for example if the module was xz-compressed, we
> copied the foo.ko.xz file to the initrd. This requires that the mini
> init binary is linked to zlib & lzma, so that it knows how to
> uncompress these modules when insmoding them at boot time. Also since
> the init is statically linked, it required _static_ versions of these
> libraries.
>
> This changes things so that the modules are uncompressed in the mini
> initrd, so they are a little bit larger, but the init binary no longer
> needs to be statically linked to zlib & lzma.
>
> The init binary is smaller (966K -> 837K), but because we are storing
> uncompressed modules in the mini initrd, the initrd as a whole becomes
> larger (1.4M -> 2.6M)
>
> However there are benefits to this change:
>
> - The code in the init binary is much simpler.
>
> - Removes the dependency on static zlib & lzma.
>
> - We can use an alternate libc to make a much smaller init binary
> (see following commits).
LGTM, just one note below.
> ---
> README | 4 +-
> configure.ac | 74 ++-------------------------
> src/Makefile.am | 1 -
> src/config.ml.in | 2 +
> src/ext2_initrd.ml | 28 ++++++++++-
> src/init.c | 145 -----------------------------------------------------
> 6 files changed, 34 insertions(+), 220 deletions(-)
>
> diff --git a/README b/README
> index 34949a2..56a28f6 100644
> --- a/README
> +++ b/README
> @@ -97,9 +97,9 @@ are building:
> qemu >= 0.13
> kernel >= 2.6.36
>
> - zlib (statically linked) - if your kernel uses gzipped modules
> + gunzip (command) - if your kernel uses gzipped modules
>
> - xz (statically linked) - if your kernel uses xz-compressed modules
> + unxz (command) - if your kernel uses xz-compressed modules
>
> Building and installing
> -----------------------
> diff --git a/configure.ac b/configure.ac
> index 126366b..0fe88c7 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -127,77 +127,11 @@ dnl Check for fakeroot, only used a few drivers where the host package
> dnl manager contains broken/unnecessary tests for root privs.
> AC_PATH_PROG(FAKEROOT,[fakeroot],[no])
>
> -dnl Support for compressed input files, gzipped kernel modules.
> -AC_CHECK_HEADER([zlib.h],[
> - AC_CHECK_LIB([z],[gzopen],[
> - zlib=yes
> - ZLIB_LIBS=-lz
> +dnl Check for gunzip, only needed if you have gzip-compressed kernel modules.
> +AC_PATH_PROG(GUNZIP,[gunzip],[no])
>
> - AC_MSG_CHECKING([for gzip static library])
> - old_CFLAGS="$CFLAGS"
> - old_LDFLAGS="$LDFLAGS"
> - old_LIBS="$LIBS"
> - CFLAGS="$CFLAGS -static"
> - LDFLAGS="$LDFLAGS -static"
> - LIBS="$LIBS -lz"
> - AC_LINK_IFELSE([
> - #include <stdio.h>
> - #include <stdlib.h>
> - #include <zlib.h>
> - int main () { gzFile g = gzopen ("test", "rb"); exit (g ? 1 : 0); }
> - ],[
> - zlib_static=yes
> - ZLIB_STATIC_LIBS="$ZLIB_LIBS"
> - AC_MSG_RESULT([yes])
> - ],[
> - AC_MSG_RESULT([no])
> - ])
> - CFLAGS="$old_CFLAGS"
> - LDFLAGS="$old_LDFLAGS"
> - LIBS="$old_LIBS"
> - ])
> -])
> -if test "x$zlib" = "xyes"; then
> - AC_DEFINE([HAVE_ZLIB],[1],[Define if you have zlib])
> - AC_SUBST([ZLIB_LIBS])
> -fi
> -if test "x$zlib_static" = "xyes"; then
> - AC_DEFINE([HAVE_ZLIB_STATIC],[1],[Define if you have static zlib])
> - AC_SUBST([ZLIB_STATIC_LIBS])
> -fi
> -
> -dnl Support for xzed kernel modules.
> -AC_CHECK_HEADER([lzma.h],[
> - AC_CHECK_LIB([lzma],[lzma_code],[
> - AC_MSG_CHECKING([for xz static library])
> - old_CFLAGS="$CFLAGS"
> - old_LDFLAGS="$LDFLAGS"
> - old_LIBS="$LIBS"
> - CFLAGS="$CFLAGS -static"
> - LDFLAGS="$LDFLAGS -static"
> - LIBS="$LIBS -llzma"
> - AC_LINK_IFELSE([
> - #include <stdio.h>
> - #include <stdlib.h>
> - #include <lzma.h>
> - int main () { lzma_stream s = LZMA_STREAM_INIT;
> - exit (s.next_in == NULL ? 1 : 0); }
> - ],[
> - lzma_static=yes
> - LZMA_STATIC_LIBS="-llzma"
> - AC_MSG_RESULT([yes])
> - ],[
> - AC_MSG_RESULT([no])
> - ])
> - CFLAGS="$old_CFLAGS"
> - LDFLAGS="$old_LDFLAGS"
> - LIBS="$old_LIBS"
> - ])
> -])
> -if test "x$lzma_static" = "xyes"; then
> - AC_DEFINE([HAVE_LZMA_STATIC],[1],[Define if you have static lzma])
> - AC_SUBST([LZMA_STATIC_LIBS])
> -fi
> +dnl Check for unxz, only needed if you have xz-compressed kernel modules.
> +AC_PATH_PROG(UNXZ,[unxz],[no])
>
> dnl mke2fs.
> AC_PATH_PROG([MKE2FS],[mke2fs],[no],
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 6261c86..5a601fe 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -143,7 +143,6 @@ noinst_PROGRAMS = init
> init_SOURCES = init.c
> init_CFLAGS = -static
> init_LDFLAGS = -static
> -init_LDADD = $(ZLIB_STATIC_LIBS) $(LZMA_STATIC_LIBS)
>
> CLEANFILES += ext2init-bin.S
>
> diff --git a/src/config.ml.in b/src/config.ml.in
> index 42cf833..19545b6 100644
> --- a/src/config.ml.in
> +++ b/src/config.ml.in
> @@ -29,12 +29,14 @@ let dpkg_deb = "@DPKG_DEB@"
> let dpkg_query = "@DPKG_QUERY@"
> let dpkg_divert = "@DPKG_DIVERT@"
> let fakeroot = "@FAKEROOT@"
> +let gunzip = "@GUNZIP@"
> let makepkg = "@MAKEPKG@"
> let pacman = "@PACMAN@"
> let pactree = "@PACTREE@"
> let pacman_g2 = "@PACMAN_G2@"
> let rpm = "@RPM@"
> let rpm2cpio = "@RPM2CPIO@"
> +let unxz = "@UNXZ@"
> let urpmi = "@URPMI@"
> let yumdownloader = "@YUMDOWNLOADER@"
> let zypper = "@ZYPPER@"
> diff --git a/src/ext2_initrd.ml b/src/ext2_initrd.ml
> index b34f0e6..e49a19d 100644
> --- a/src/ext2_initrd.ml
> +++ b/src/ext2_initrd.ml
> @@ -1,5 +1,5 @@
> (* supermin 5
> - * Copyright (C) 2009-2014 Red Hat Inc.
> + * Copyright (C) 2009-2016 Red Hat Inc.
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of the GNU General Public License as published by
> @@ -105,8 +105,32 @@ let rec build_initrd debug tmpdir modpath initrd =
> sprintf "cp -t %s %s" (quote initdir) (quote (modpath // modl)) in
> run_command cmd;
>
> + (* Uncompress the module, if the name ends in .xz or .gz. *)
> + let basename = Filename.basename modl in
> + let basename =
> + let len = String.length basename in
> + if Config.unxz <> "no" && Filename.check_suffix basename ".xz"
> + then (
> + let cmd = sprintf "%s %s"
> + (quote Config.unxz)
> + (quote (initdir // basename)) in
> + run_command cmd;
> + String.sub basename 0 (len-3)
> + )
> + else if Config.gunzip <> "no" &&
> + Filename.check_suffix basename ".gz"
> + then (
> + let cmd = sprintf "%s %s"
> + (quote Config.gunzip)
> + (quote (initdir // basename)) in
> + run_command cmd;
> + String.sub basename 0 (len-3)
> + )
> + else
> + basename in
An optimization here could be use xz/gunzip -c instead of cp+xz/gunzip,
which would avoid I/O during the appliance (re)build.
> +
> (* Write module name to 'modules' file. *)
> - fprintf chan "%s\n" (Filename.basename modl);
> + fprintf chan "%s\n" basename;
> incr loaded
> )
> ) set
> diff --git a/src/init.c b/src/init.c
> index 814243a..25d6bc6 100644
> --- a/src/init.c
> +++ b/src/init.c
> @@ -42,14 +42,6 @@
>
> #include <asm/unistd.h>
>
> -#ifdef HAVE_ZLIB_STATIC
> -#include <zlib.h>
> -#endif
> -
> -#ifdef HAVE_LZMA_STATIC
> -#include <lzma.h>
> -#endif
> -
> /* Maximum time to wait for the root device to appear (seconds).
> *
> * On slow machines with lots of disks (Koji running the 255 disk test
> @@ -102,12 +94,6 @@ main ()
> print_uptime ();
> fprintf (stderr, "supermin: ext2 mini initrd starting up: "
> PACKAGE_VERSION
> -#ifdef HAVE_ZLIB_STATIC
> - " zlib"
> -#endif
> -#ifdef HAVE_LZMA_STATIC
> - " xz"
> -#endif
> "\n");
>
> read_cmdline ();
> @@ -283,20 +269,6 @@ main ()
> exit (EXIT_FAILURE);
> }
>
> -#if HAVE_LZMA_STATIC
> -static int
> -ends_with (const char *str, const char *suffix)
> -{
> - if (!str || !suffix)
> - return 0;
> - size_t lenstr = strlen (str);
> - size_t lensuffix = strlen (suffix);
> - if (lensuffix > lenstr)
> - return 0;
> - return strncmp (str + lenstr - lensuffix, suffix, lensuffix) == 0;
> -}
> -#endif
> -
> static void
> insmod (const char *filename)
> {
> @@ -305,118 +277,6 @@ insmod (const char *filename)
> if (verbose)
> fprintf (stderr, "supermin: internal insmod %s\n", filename);
>
> -#ifdef HAVE_ZLIB_STATIC
> - int capacity = 64*1024;
> - char *buf = (char *) malloc (capacity);
> - int tmpsize = 8 * 1024;
> - char tmp[tmpsize];
> - int num;
> -
> - errno = 0;
> - size = 0;
> -
> - if (!buf) {
> - perror("malloc");
> - exit (EXIT_FAILURE);
> - }
> -
> -#ifdef HAVE_LZMA_STATIC
> - if (ends_with(filename, ".xz")) {
> - lzma_stream strm = LZMA_STREAM_INIT;
> - lzma_ret ret = lzma_stream_decoder(&strm, UINT64_MAX,
> - LZMA_CONCATENATED);
> - if (verbose)
> - fprintf (stderr, "supermin: running xz\n");
> - FILE *fd = fopen (filename, "r");
> - if (!fd) {
> - perror("popen failed");
> - exit (EXIT_FAILURE);
> - }
> - char tmp_out[tmpsize];
> - strm.avail_in = 0;
> - strm.next_out = tmp_out;
> - strm.avail_out = tmpsize;
> -
> - lzma_action action = LZMA_RUN;
> -
> - while (1) {
> - if (strm.avail_in == 0) {
> - strm.next_in = tmp;
> - strm.avail_in = fread(tmp, 1, tmpsize, fd);
> -
> - if (ferror(fd)) {
> - // POSIX says that fread() sets errno if
> - // an error occurred. ferror() doesn't
> - // touch errno.
> - perror("Error reading input file");
> - exit (EXIT_FAILURE);
> - }
> - if (feof(fd)) action = LZMA_FINISH;
> - }
> -
> - ret = lzma_code(&strm, action);
> -
> - // Write and check write error before checking decoder error.
> - // This way as much data as possible gets written to output
> - // even if decoder detected an error.
> - if (strm.avail_out == 0 || ret != LZMA_OK) {
> - const size_t num = tmpsize - strm.avail_out;
> - if (num > capacity) {
> - buf = (char*) realloc (buf, size*2);
> - if (!buf) {
> - perror("realloc");
> - exit (EXIT_FAILURE);
> - }
> - capacity = size;
> - }
> - memcpy (buf+size, tmp_out, num);
> - capacity -= num;
> - size += num;
> - strm.next_out = tmp_out;
> - strm.avail_out = tmpsize;
> - }
> - if (ret != LZMA_OK) {
> - if (ret == LZMA_STREAM_END) {
> - break;
> - } else {
> - perror("internal error");
> - exit(EXIT_FAILURE);
> - }
> - }
> - }
> - fclose (fd);
> - if (verbose)
> - fprintf (stderr, "done with xz %d read\n", size);
> - } else {
> -#endif
> - gzFile gzfp = gzopen (filename, "rb");
> - if (gzfp == NULL) {
> - fprintf (stderr, "insmod: gzopen failed: %s", filename);
> - exit (EXIT_FAILURE);
> - }
> - while ((num = gzread (gzfp, tmp, tmpsize)) > 0) {
> - if (num > capacity) {
> - buf = (char*) realloc (buf, size*2);
> - if (!buf) {
> - perror("realloc");
> - exit (EXIT_FAILURE);
> - }
> - capacity = size;
> - }
> - memcpy (buf+size, tmp, num);
> - capacity -= num;
> - size += num;
> - }
> - if (num == -1) {
> - perror ("insmod: gzread");
> - exit (EXIT_FAILURE);
> - }
> - gzclose (gzfp);
> -#ifdef HAVE_LZMA_STATIC
> -}
> -#endif
> -
> -#else
> int fd = open (filename, O_RDONLY);
> if (fd == -1) {
> fprintf (stderr, "insmod: open: %s: %m\n", filename);
> @@ -439,7 +299,6 @@ insmod (const char *filename)
> offset += rc;
> } while (offset < size);
> close (fd);
> -#endif
>
> if (init_module (buf, size, "") != 0) {
> fprintf (stderr, "insmod: init_module: %s: %s\n", filename, moderror (errno));
> @@ -447,10 +306,6 @@ insmod (const char *filename)
> * of a missing device.
> */
> }
> -
> -#ifdef HAVE_ZLIB_STATIC
> - free (buf);
> -#endif
> }
>
> /* Mount /proc unless it's mounted already. */
>
--
Pino Toscano
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part.
URL: <http://listman.redhat.com/archives/libguestfs/attachments/20160217/105a1b35/attachment.sig>
More information about the Libguestfs
mailing list