[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