Re: [PATCH] Add Zstandard support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Aug 25, 2020 at 11:29:43AM -0700, Lucas De Marchi wrote:
> On Tue, Aug 25, 2020 at 10:49 AM Dave Reisner <d@xxxxxxxxxxxxxx> wrote:
> >
> > On Tue, Aug 25, 2020 at 10:12:57AM -0700, Lucas De Marchi wrote:
> > > Hi,
> > >
> > > On Fri, Aug 21, 2020 at 3:46 PM Torge Matthies
> > > <openglfreak@xxxxxxxxxxxxxx> wrote:
> > > >
> > > > I was not able to find any existing zstd patch for kmod, so I wrote my own.
> > >
> > > thanks a lot for adding this.
> > >
> > > >
> > > > I was struggling to get the C code below the 80 character line length limit,
> > > > that's why I used gotos. I used descriptive label names, and it still looks
> > > > clean enough in my opinion.
> > >
> > > Humn.. I'd rather prefer not to be on 80 chars than using some of the gotos,
> > > but take a look below
> > >
> > > >
> > > > I changed the style of the hackargs variable in autogen.sh to multiline
> > > > because said line was becoming a bit long with the new --with-zstd arg
> > > > added.
> > >
> > > ok
> > >
> > > >
> > > > This patch has been running on my two Arch Linux installations (with an
> > > > accompanying mkinitcpio patch) for several months over many kernel updates
> > > > without any issues.
> > >
> > > great. Is Arch already using zstd for the kernel? Once this lands, is
> > > it going to
> > > zstd for modules?
> > >
> > > +Dave
> > >
> >
> > No plans that I'm aware of. We currently use CONFIG_MODULE_COMPRESS_XZ=y
> > to have Kbuild do the module compression for us at build time. Is Kbuild
> > being updated to support zstd if/when this patch lands in a kmod
> > release?
> >
> > Personally, I'd rather see less module compression, not more. This
> > "flavor of the week" compression stuff makes me tired, and the way
> > compression is implemented in userspace inhibits more important features
> > like secure module loading via finit_module.
> 
> zstd is being added to the kernel as well:
> http://lkml.iu.edu/hypermail/linux/kernel/1710.1/02783.html

Yes, there's upstream support for compressing the kernel images (and
soon initramfs) with zstd, but the Kbuild process allows for compressing
*modules* as part of modules_install:

https://github.com/torvalds/linux/blob/master/Makefile#L1053

Granted, distros could just do this after the fact in their packaging
process, but it seems weird to make zstd an outlier and not have an
associated CONFIG_MODULE_COMPRESS_ZSTD Kbuild option.

dR

> I don't mind having the userspace implementation in kmod - adding any
> compression
> to the kernel has stalled over the years and IMO shouldn't prevent
> this going in.
> Most of distros are already using compressed modules, so it's not that
> adding another
> one would do any harm. It may even help to allow them to switch between formats
> without worrying about supporting older kernels since there would be a
> fallback in
> userspace if they are not willing to back port the kernel changs when
> that happens
> 
> Lucas De Marchi
> 
> >
> > dR
> >
> > > > Any additional testing and/or patch review would of course be appreciated.
> > > >
> > > > Signed-off-by: Torge Matthies <openglfreak@xxxxxxxxxxxxxx>
> > > > ---
> > > >  .semaphore/semaphore.yml     |   4 +-
> > > >  .travis.yml                  |   1 +
> > > >  Makefile.am                  |   4 +-
> > > >  autogen.sh                   |   9 ++-
> > > >  configure.ac                 |  13 +++-
> > > >  libkmod/libkmod-file.c       | 119 +++++++++++++++++++++++++++++++++++
> > > >  libkmod/libkmod.pc.in        |   2 +-
> > > >  shared/util.c                |   3 +
> > > >  testsuite/mkosi/mkosi.fedora |   1 +
> > > >  testsuite/test-util.c        |   3 +
> > > >  10 files changed, 153 insertions(+), 6 deletions(-)
> > > >
> > > > diff --git a/.semaphore/semaphore.yml b/.semaphore/semaphore.yml
> > > > index db47ca1..fe1d78a 100644
> > > > --- a/.semaphore/semaphore.yml
> > > > +++ b/.semaphore/semaphore.yml
> > > > @@ -22,7 +22,7 @@ blocks:
> > > >        prologue:
> > > >          commands:
> > > >            - sudo apt update
> > > > -          - sudo apt --yes install docbook-xsl liblzma-dev zlib1g-dev cython linux-headers-generic libssl-dev
> > > > +          - sudo apt --yes install docbook-xsl libzstd-dev liblzma-dev zlib1g-dev cython linux-headers-generic libssl-dev
> > > >            - checkout
> > > >
> > > >        epilogue:
> > > > @@ -42,5 +42,5 @@ blocks:
> > > >        prologue:
> > > >          commands:
> > > >            - sudo apt update
> > > > -          - sudo apt --yes install docbook-xsl liblzma-dev zlib1g-dev cython linux-headers-generic libssl-dev
> > > > +          - sudo apt --yes install docbook-xsl libzstd-dev liblzma-dev zlib1g-dev cython linux-headers-generic libssl-dev
> > > >            - checkout
> > > > diff --git a/.travis.yml b/.travis.yml
> > > > index 02c753e..0fcce14 100644
> > > > --- a/.travis.yml
> > > > +++ b/.travis.yml
> > > > @@ -14,6 +14,7 @@ matrix:
> > > >  before_install:
> > > >    - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
> > > >    - sudo apt-get update -qq
> > > > +  - sudo apt-get install -qq libzstd-dev
> > > >    - sudo apt-get install -qq liblzma-dev
> > > >    - sudo apt-get install -qq zlib1g-dev
> > > >    - sudo apt-get install -qq xsltproc docbook-xsl
> > > > diff --git a/Makefile.am b/Makefile.am
> > > > index 8eadb99..37d840b 100644
> > > > --- a/Makefile.am
> > > > +++ b/Makefile.am
> > > > @@ -31,6 +31,8 @@ SED_PROCESS = \
> > > >         -e 's,@exec_prefix\@,$(exec_prefix),g' \
> > > >         -e 's,@libdir\@,$(libdir),g' \
> > > >         -e 's,@includedir\@,$(includedir),g' \
> > > > +       -e 's,@libzstd_CFLAGS\@,${libzstd_CFLAGS},g' \
> > > > +       -e 's,@libzstd_LIBS\@,${libzstd_LIBS},g' \
> > > >         -e 's,@liblzma_CFLAGS\@,${liblzma_CFLAGS},g' \
> > > >         -e 's,@liblzma_LIBS\@,${liblzma_LIBS},g' \
> > > >         -e 's,@zlib_CFLAGS\@,${zlib_CFLAGS},g' \
> > > > @@ -90,7 +92,7 @@ libkmod_libkmod_la_DEPENDENCIES = \
> > > >         ${top_srcdir}/libkmod/libkmod.sym
> > > >  libkmod_libkmod_la_LIBADD = \
> > > >         shared/libshared.la \
> > > > -       ${liblzma_LIBS} ${zlib_LIBS} ${libcrypto_LIBS}
> > > > +       ${libzstd_LIBS} ${liblzma_LIBS} ${zlib_LIBS} ${libcrypto_LIBS}
> > > >
> > > >  noinst_LTLIBRARIES += libkmod/libkmod-internal.la
> > > >  libkmod_libkmod_internal_la_SOURCES = $(libkmod_libkmod_la_SOURCES)
> > > > diff --git a/autogen.sh b/autogen.sh
> > > > index 67b119f..e4997c4 100755
> > > > --- a/autogen.sh
> > > > +++ b/autogen.sh
> > > > @@ -32,7 +32,14 @@ fi
> > > >
> > > >  cd $oldpwd
> > > >
> > > > -hackargs="--enable-debug --enable-python --with-xz --with-zlib --with-openssl"
> > > > +hackargs="\
> > > > +--enable-debug \
> > > > +--enable-python \
> > > > +--with-zstd \
> > > > +--with-xz \
> > > > +--with-zlib \
> > > > +--with-openssl \
> > > > +"
> > > >
> > > >  if [ "x$1" = "xc" ]; then
> > > >          shift
> > > > diff --git a/configure.ac b/configure.ac
> > > > index 4a65d6b..a49f6b9 100644
> > > > --- a/configure.ac
> > > > +++ b/configure.ac
> > > > @@ -83,6 +83,17 @@ AC_ARG_WITH([rootlibdir],
> > > >          [], [with_rootlibdir=$libdir])
> > > >  AC_SUBST([rootlibdir], [$with_rootlibdir])
> > > >
> > > > +AC_ARG_WITH([zstd],
> > > > +       AS_HELP_STRING([--with-zstd], [handle Zstandard-compressed modules @<:@default=disabled@:>@]),
> > > > +       [], [with_zstd=no])
> > > > +AS_IF([test "x$with_zstd" != "xno"], [
> > > > +       PKG_CHECK_MODULES([libzstd], [libzstd >= 1.4.4])
> > > > +       AC_DEFINE([ENABLE_ZSTD], [1], [Enable Zstandard for modules.])
> > > > +], [
> > > > +       AC_MSG_NOTICE([Zstandard support not requested])
> > > > +])
> > > > +CC_FEATURE_APPEND([with_features], [with_zstd], [ZSTD])
> > > > +
> > > >  AC_ARG_WITH([xz],
> > > >         AS_HELP_STRING([--with-xz], [handle Xz-compressed modules @<:@default=disabled@:>@]),
> > > >         [], [with_xz=no])
> > > > @@ -307,7 +318,7 @@ AC_MSG_RESULT([
> > > >         tools:                  ${enable_tools}
> > > >         python bindings:        ${enable_python}
> > > >         logging:                ${enable_logging}
> > > > -       compression:            xz=${with_xz}  zlib=${with_zlib}
> > > > +       compression:            zstd=${with_zstd}  xz=${with_xz}  zlib=${with_zlib}
> > > >         debug:                  ${enable_debug}
> > > >         coverage:               ${enable_coverage}
> > > >         doc:                    ${enable_gtk_doc}
> > > > diff --git a/libkmod/libkmod-file.c b/libkmod/libkmod-file.c
> > > > index 5eeba6a..1a2e753 100644
> > > > --- a/libkmod/libkmod-file.c
> > > > +++ b/libkmod/libkmod-file.c
> > > > @@ -26,6 +26,9 @@
> > > >  #include <sys/stat.h>
> > > >  #include <sys/types.h>
> > > >  #include <unistd.h>
> > > > +#ifdef ENABLE_ZSTD
> > > > +#include <zstd.h>
> > > > +#endif
> > > >  #ifdef ENABLE_XZ
> > > >  #include <lzma.h>
> > > >  #endif
> > > > @@ -45,6 +48,9 @@ struct file_ops {
> > > >  };
> > > >
> > > >  struct kmod_file {
> > > > +#ifdef ENABLE_ZSTD
> > > > +       bool zstd_used;
> > > > +#endif
> > > >  #ifdef ENABLE_XZ
> > > >         bool xz_used;
> > > >  #endif
> > > > @@ -60,6 +66,116 @@ struct kmod_file {
> > > >         struct kmod_elf *elf;
> > > >  };
> > > >
> > > > +#ifdef ENABLE_ZSTD
> > > > +static int load_zstd(struct kmod_file *file)
> > > > +{
> > > > +       ZSTD_DStream *dstr = NULL;
> > > > +       size_t in_buf_size, out_buf_min_size, out_buf_size;
> > > > +       uint8_t *in_buf = NULL, *out_buf = NULL;
> > > > +       ZSTD_inBuffer zst_input;
> > > > +       ZSTD_outBuffer zst_output;
> > > > +       int ret = -EINVAL;
> > > > +
> > > > +       dstr = ZSTD_createDStream();
> > > > +       if (dstr == NULL) {
> > > > +               ERR(file->ctx, "zstd: Failed to create decompression stream\n");
> > > > +               ret = -EINVAL;
> > > > +               goto out;
> > > > +       }
> > > > +
> > > > +       in_buf_size = ZSTD_initDStream(dstr);
> > > > +       in_buf = malloc(in_buf_size);
> > > > +       if (in_buf == NULL) {
> > > > +               ERR(file->ctx, "zstd: %s\n", strerror(ENOMEM));
> > >
> > > no big deal, but malloc() should set errno, so you could use
> > > ret = -errno before printing and then use %m in the message.
> > >
> > > Same thing in other places.
> > >
> > > > +               ret = -ENOMEM;
> > > > +               goto out;
> > > > +       }
> > > > +
> > > > +       out_buf_size = out_buf_min_size = ZSTD_DStreamOutSize();
> > > > +       out_buf = malloc(out_buf_size);
> > > > +       if (out_buf == NULL) {
> > > > +               ERR(file->ctx, "zstd: %s\n", strerror(ENOMEM));
> > > > +               ret = -ENOMEM;
> > > > +               goto out;
> > > > +       }
> > > > +
> > > > +       zst_input.src = in_buf;
> > > > +       zst_output.dst = out_buf;
> > > > +       zst_output.size = out_buf_size;
> > > > +       zst_output.pos = 0;
> > > > +       while (true) {
> > > > +               ssize_t rdret;
> > > > +               size_t dsret;
> > > > +               uint8_t *tmp;
> > > > +
> > > > +               rdret = read(file->fd, in_buf, in_buf_size);
> > > > +               if (rdret < 0) {
> > > > +                       ret = -errno;
> > > > +                       goto out;
> > > > +               }
> > > > +               if (rdret == 0)
> > > > +                       break;
> > > > +
> > > > +               zst_input.size = rdret;
> > > > +               zst_input.pos = 0;
> > > > +
> > > > +               if (zst_output.size - zst_output.pos < out_buf_min_size)
> > > > +                       goto realloc_buffer;
> > >
> > > this could be a helper function to realloc the buffer. It can even be shared
> > > for the first alloc if you initialize zst_output.size to 0.. Then you
> > > have something like:
> > >
> > > > +
> > > > +try_decompress:
> > > > +               dsret = ZSTD_decompressStream(dstr, &zst_output, &zst_input);
> > > > +               if (ZSTD_isError(dsret)) {
> > > > +                       ERR(file->ctx, "zstd: %s\n", ZSTD_getErrorName(dsret));
> > > > +                       ret = -EINVAL;
> > > > +                       goto out;
> > > > +               }
> > > > +
> > > > +               if (zst_output.pos < zst_output.size
> > > > +                       && zst_output.size - zst_output.pos
> > > > +                       >= out_buf_min_size) {
> > > > +                       if (zst_input.pos < zst_input.size)
> > > > +                               goto try_decompress;
> > >
> > > this looks like a while/for loop. Could even be in a helper function
> > >
> > >
> > > > +                       else
> > > > +                               continue;
> > > > +               }
> > > > +
> > > > +realloc_buffer:
> > > > +               tmp = realloc(out_buf, out_buf_size + out_buf_min_size);
> > > > +               if (tmp == NULL) {
> > > > +                       ret = -errno;
> > > > +                       goto out;
> > > > +               }
> > > > +               out_buf_size += out_buf_min_size;
> > > > +               out_buf = tmp;
> > > > +               zst_output.dst = out_buf;
> > > > +               zst_output.size = out_buf_size;
> > > > +               goto try_decompress;
> > > > +       }
> > > > +
> > > > +       ZSTD_freeDStream(dstr);
> > > > +       free(in_buf);
> > > > +       file->zstd_used = true;
> > > > +       file->memory = out_buf;
> > > > +       file->size = zst_output.pos;
> > > > +       return 0;
> > > > +out:
> > > > +       if (dstr != NULL)
> > > > +               ZSTD_freeDStream(dstr);
> > > > +       free(out_buf);
> > > > +       free(in_buf);
> > > > +       return ret;
> > > > +}
> > > > +
> > > > +static void unload_zstd(struct kmod_file *file)
> > > > +{
> > > > +       if (!file->zstd_used)
> > > > +               return;
> > > > +       free(file->memory);
> > > > +}
> > > > +
> > > > +static const char magic_zstd[] = {0x28, 0xB5, 0x2F, 0xFD};
> > > > +#endif
> > > > +
> > > >  #ifdef ENABLE_XZ
> > > >  static void xz_uncompress_belch(struct kmod_file *file, lzma_ret ret)
> > > >  {
> > > > @@ -238,6 +354,9 @@ static const struct comp_type {
> > > >         const char *magic_bytes;
> > > >         const struct file_ops ops;
> > > >  } comp_types[] = {
> > > > +#ifdef ENABLE_ZSTD
> > > > +       {sizeof(magic_zstd), magic_zstd, {load_zstd, unload_zstd}},
> > > > +#endif
> > > >  #ifdef ENABLE_XZ
> > > >         {sizeof(magic_xz), magic_xz, {load_xz, unload_xz}},
> > > >  #endif
> > > > diff --git a/libkmod/libkmod.pc.in b/libkmod/libkmod.pc.in
> > > > index e4fdf21..3acca6a 100644
> > > > --- a/libkmod/libkmod.pc.in
> > > > +++ b/libkmod/libkmod.pc.in
> > > > @@ -7,5 +7,5 @@ Name: libkmod
> > > >  Description: Library to deal with kernel modules
> > > >  Version: @VERSION@
> > > >  Libs: -L${libdir} -lkmod
> > > > -Libs.private: @liblzma_LIBS@ @zlib_LIBS@
> > > > +Libs.private: @libzstd_LIBS@ @liblzma_LIBS@ @zlib_LIBS@
> > > >  Cflags: -I${includedir}
> > > > diff --git a/shared/util.c b/shared/util.c
> > > > index fd2028d..b487b5f 100644
> > > > --- a/shared/util.c
> > > > +++ b/shared/util.c
> > > > @@ -45,6 +45,9 @@ static const struct kmod_ext {
> > > >  #endif
> > > >  #ifdef ENABLE_XZ
> > > >         {".ko.xz", sizeof(".ko.xz") - 1},
> > > > +#endif
> > > > +#ifdef ENABLE_ZSTD
> > > > +       {".ko.zst", sizeof(".ko.zst") - 1},
> > > >  #endif
> > > >         { }
> > > >  };
> > > > diff --git a/testsuite/mkosi/mkosi.fedora b/testsuite/mkosi/mkosi.fedora
> > > > index 5252f87..7a2ee5e 100644
> > > > --- a/testsuite/mkosi/mkosi.fedora
> > > > +++ b/testsuite/mkosi/mkosi.fedora
> > > > @@ -19,6 +19,7 @@ BuildPackages =
> > > >         make
> > > >         pkgconf-pkg-config
> > > >         xml-common
> > > > +       libzstd-devel
> > > >         xz-devel
> > > >         zlib-devel
> > > >         openssl-devel
> > > > diff --git a/testsuite/test-util.c b/testsuite/test-util.c
> > > > index 5e25e58..621446b 100644
> > > > --- a/testsuite/test-util.c
> > > > +++ b/testsuite/test-util.c
> > > > @@ -156,6 +156,9 @@ static int test_path_ends_with_kmod_ext(const struct test *t)
> > > >  #endif
> > > >  #ifdef ENABLE_XZ
> > > >                 { "/bla.ko.xz", true },
> > > > +#endif
> > > > +#ifdef ENABLE_ZSTD
> > > > +               { "/bla.ko.zst", true },
> > >
> > > I think we want a zstd-compressed module in the testsuite as well to test this.
> > >
> > > thanks
> > > Lucas De Marchi
> > >
> > > >  #endif
> > > >                 { "/bla.ko.x", false },
> > > >                 { "/bla.ko.", false },
> > > > --
> > > > 2.28.0
> > > >



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux