Hello Simon,

Le mercredi 18 novembre 2009 04:55:18, Simon Horman a écrit :
> On Tue, Nov 17, 2009 at 03:23:15PM +0100, Florian Fainelli wrote:
> > On Tuesday 17 November 2009 15:08:29 Florian Fainelli wrote:
> > > Hello Simon,
> > >
> > > On Tuesday 17 November 2009 04:04:38 Simon Horman wrote:
> > > > On Mon, Nov 16, 2009 at 12:53:06AM +0100, Florian Fainelli wrote:
> > > > > Hi Eric,
> > > > >
> > > > > This patch allows one to load a lzma compressed kernel using kexec
> > > > > -l. As I wanted the lzma code to be very similar to the existing
> > > > > zlib slurp_decompress I took lzread and associated routines from
> > > > > the cpio lzma support. Tested on my x86 laptop using the following
> > > > > commands:
> > > > >
> > > > > lzma e bzImage bzImage.lzma
> > > > > kexec -l bzImage.lzma
> > > > >
> > > > > Having lzma support is particularly useful on some embedded
> > > > > systems on which we have the kernel already lzma compressed
> > > > > and available on a mtd partition.
> > > > >
> > > > > Signed-off-by: Florian Fainelli <[email protected]>
> > > >
> > > > Should lzma_code_ be lzma_code. The former doesn't seem to work with
> > > > liblzma 4.999.9beta+20091016-1 from Debian.
> > >
> > > You are right it's actually lzma_code (without the trailing _).
> > >
> > > > > +             AC_MSG_NOTICE([lzma support disabled])))
> > > >
> > > > The trailing "fi" line appears to be missing.
> > >
> > > Fixed too.
> > > [snip]
> > >
> > > > Does this imply that zlib compression isn't supported if
> > > > lzma compression support is enabled?
> > >
> > > Indeed, we might want to support both at runtime. Would you agree with
> > > the following proposal:
> > >
> > > - rename slurp_decompress_file to zlib/lzma_decompress_file
> > > - in case gzopen fails, do not die, but return NULL
> > > - test the return value of zlib_decompress_file and try
> > >  lzma_decompress_file
> 
>       Something along those lines sounds entirely reasonable to me.
> 
> > We would also have to modify the call sites of slurp_decompress file this
> > might become pretty heavy if we support more decompression algorithms.
> > What do you think?
> 
> Perhaps slurp_decompress could be a wrapper which tries each algorithm in
> turn as necessary?
> 
> Also, I'd like to get rid of the #ifdef around what is currently
> slurp_decompress_file() if possible. My idea would be to move
> zlib_decompress_file and lzma_decompress_file into, for instance
> zlib.c and lzma.c respectively and have zlib.h and lzma.h provide
> more-or-less null functions for the case where the algorithm
> in question isn't supported.

Please find below a version which should address your comments.
Thanks for reviewing the patch.
--
From: Florian Fainelli <[email protected]>
Subject: [PATCH] add support for loading lzma compressed kernels

This patch allows one to load a lzma compressed kernel using kexec -l.
As I wanted the lzma code to be very similar to the existing
zlib slurp_decompress I took lzread and associated routines
from the cpio lzma support. Tested on my x86 laptop using the
following commands:

lzma e bzImage bzImage.lzma
kexec -l bzImage.lzma

Having lzma support is particularly useful on some embedded
systems on which we have the kernel already lzma compressed
and available on a mtd partition.

Signed-off-by: Florian Fainelli <[email protected]>
---
diff -urN kexec-tools-2.0.1/configure.ac kexec-tools-2.0.1.lzma/configure.ac
--- kexec-tools-2.0.1/configure.ac      2009-11-18 23:11:36.000000000 +0100
+++ kexec-tools-2.0.1.lzma/configure.ac 2009-11-18 23:11:21.000000000 +0100
@@ -79,6 +79,9 @@
 AC_ARG_WITH([zlib], AC_HELP_STRING([--without-zlib],[disable zlib support]),
        [ with_zlib="$withval"], [ with_zlib=yes ] )
 
+AC_ARG_WITH([lzma], AC_HELP_STRING([--without-lzma],[disable lzma support]),
+       [ with_lzma="$withval"], [ with_lzma=yes ] )
+
 AC_ARG_WITH([xen], AC_HELP_STRING([--without-xen],
        [disable extended xen support]), [ with_xen="$withval"], [ with_xen=yes 
] )
 
@@ -142,6 +145,13 @@
                AC_MSG_NOTICE([zlib support disabled])))
 fi
 
+dnl See if I have a usable copy of lzma available
+if test "$with_lzma" = yes ; then
+       AC_CHECK_HEADER(lzma.h,
+               AC_CHECK_LIB(lzma, lzma_code, ,
+               AC_MSG_NOTICE([lzma support disabled])))
+fi
+
 dnl find Xen control stack libraries
 if test "$with_xen" = yes ; then
        AC_CHECK_HEADER(xenctrl.h,
diff -urN kexec-tools-2.0.1/kexec/Makefile kexec-tools-2.0.1.lzma/kexec/Makefile
--- kexec-tools-2.0.1/kexec/Makefile    2009-11-18 23:11:37.000000000 +0100
+++ kexec-tools-2.0.1.lzma/kexec/Makefile       2009-11-18 23:15:21.000000000 
+0100
@@ -22,6 +22,8 @@
 KEXEC_SRCS += kexec/crashdump.c
 KEXEC_SRCS += kexec/crashdump-xen.c
 KEXEC_SRCS += kexec/phys_arch.c
+KEXEC_SRCS += kexec/lzma.c
+KEXEC_SRCS += kexec/zlib.c
 
 KEXEC_GENERATED_SRCS += $(PURGATORY_HEX_C)
 
diff -urN kexec-tools-2.0.1/kexec/kexec-lzma.h 
kexec-tools-2.0.1.lzma/kexec/kexec-lzma.h
--- kexec-tools-2.0.1/kexec/kexec-lzma.h        1970-01-01 01:00:00.000000000 
+0100
+++ kexec-tools-2.0.1.lzma/kexec/kexec-lzma.h   2009-11-19 00:06:24.000000000 
+0100
@@ -0,0 +1,29 @@
+#ifndef __KEXEC_LZMA_H
+#define __KEXEC_LZMA_H
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <lzma.h>
+
+#include "config.h"
+
+#ifdef HAVE_LIBLZMA
+#define kBufferSize (1 << 15)
+
+typedef struct lzfile {
+       uint8_t buf[kBufferSize];
+       lzma_stream strm;
+       FILE *file;
+       int encoding;
+       int eof;
+} LZFILE;
+
+LZFILE *lzopen(const char *path, const char *mode);
+int lzclose(LZFILE *lzfile);
+ssize_t lzread(LZFILE *lzfile, void *buf, size_t len);
+#endif /* HAVE_LIBLZMA */
+
+char *lzma_decompress_file(const char *filename, off_t *r_size);
+#endif /* __KEXEC_LZMA_H */
diff -urN kexec-tools-2.0.1/kexec/kexec-zlib.h 
kexec-tools-2.0.1.lzma/kexec/kexec-zlib.h
--- kexec-tools-2.0.1/kexec/kexec-zlib.h        1970-01-01 01:00:00.000000000 
+0100
+++ kexec-tools-2.0.1.lzma/kexec/kexec-zlib.h   2009-11-19 00:04:38.000000000 
+0100
@@ -0,0 +1,10 @@
+#ifndef __KEXEC_ZLIB_H
+#define __KEXEC_ZLIB_H
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "config.h"
+
+char *zlib_decompress_file(const char *filename, off_t *r_size);
+#endif /* __KEXEC_ZLIB_H */
diff -urN kexec-tools-2.0.1/kexec/kexec.c kexec-tools-2.0.1.lzma/kexec/kexec.c
--- kexec-tools-2.0.1/kexec/kexec.c     2009-11-18 23:11:45.000000000 +0100
+++ kexec-tools-2.0.1.lzma/kexec/kexec.c        2009-11-18 23:19:46.000000000 
+0100
@@ -38,14 +38,13 @@
 
 #include "config.h"
 
-#ifdef HAVE_LIBZ
-#include <zlib.h>
-#endif
 #include <sha256.h>
 #include "kexec.h"
 #include "kexec-syscall.h"
 #include "kexec-elf.h"
 #include "kexec-sha256.h"
+#include "kexec-zlib.h"
+#include "kexec-lzma.h"
 #include <arch/options.h>
 
 unsigned long long mem_min = 0;
@@ -554,67 +553,18 @@
        return buf;
 }
 
-#if HAVE_LIBZ
 char *slurp_decompress_file(const char *filename, off_t *r_size)
 {
-       gzFile fp;
-       int errnum;
-       const char *msg;
-       char *buf;
-       off_t size, allocated;
-       ssize_t result;
-
-       if (!filename) {
-               *r_size = 0;
-               return 0;
-       }
-       fp = gzopen(filename, "rb");
-       if (fp == 0) {
-               msg = gzerror(fp, &errnum);
-               if (errnum == Z_ERRNO) {
-                       msg = strerror(errno);
-               }
-               die("Cannot open `%s': %s\n", filename, msg);
-       }
-       size = 0;
-       allocated = 65536;
-       buf = xmalloc(allocated);
-       do {
-               if (size == allocated) {
-                       allocated <<= 1;
-                       buf = xrealloc(buf, allocated);
-               }
-               result = gzread(fp, buf + size, allocated - size);
-               if (result < 0) {
-                       if ((errno == EINTR) || (errno == EAGAIN))
-                               continue;
+       char *kernel_buf;
 
-                       msg = gzerror(fp, &errnum);
-                       if (errnum == Z_ERRNO) {
-                               msg = strerror(errno);
-                       }
-                       die ("read on %s of %ld bytes failed: %s\n",
-                               filename, (allocated - size) + 0UL, msg);
-               }
-               size += result;
-       } while(result > 0);
-       result = gzclose(fp);
-       if (result != Z_OK) {
-               msg = gzerror(fp, &errnum);
-               if (errnum == Z_ERRNO) {
-                       msg = strerror(errno);
-               }
-               die ("Close of %s failed: %s\n", filename, msg);
+       kernel_buf = zlib_decompress_file(filename, r_size);
+       if (!kernel_buf) {
+               kernel_buf = lzma_decompress_file(filename, r_size);
+               if (!kernel_buf)
+                       return slurp_file(filename, r_size);
        }
-       *r_size =  size;
-       return buf;
+       return kernel_buf;
 }
-#else
-char *slurp_decompress_file(const char *filename, off_t *r_size)
-{
-       return slurp_file(filename, r_size);
-}
-#endif
 
 static void update_purgatory(struct kexec_info *info)
 {
diff -urN kexec-tools-2.0.1/kexec/lzma.c kexec-tools-2.0.1.lzma/kexec/lzma.c
--- kexec-tools-2.0.1/kexec/lzma.c      1970-01-01 01:00:00.000000000 +0100
+++ kexec-tools-2.0.1.lzma/kexec/lzma.c 2009-11-19 00:03:54.000000000 +0100
@@ -0,0 +1,187 @@
+#include "kexec-lzma.h"
+#ifdef HAVE_LIBLZMA
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <lzma.h>
+
+#include "kexec.h"
+
+static LZFILE *lzopen_internal(const char *path, const char *mode, int fd)
+{
+       int level = 5;
+       int encoding = 0;
+       FILE *fp;
+       LZFILE *lzfile;
+       lzma_ret ret;
+       lzma_stream lzma_strm_tmp = LZMA_STREAM_INIT;
+
+       for (; *mode; mode++) {
+               if (*mode == 'w')
+                       encoding = 1;
+               else if (*mode == 'r')
+                       encoding = 0;
+               else if (*mode >= '1' && *mode <= '9')
+                       level = *mode - '0';
+       }
+       if (fd != -1)
+               fp = fdopen(fd, encoding ? "w" : "r");
+       else
+               fp = fopen(path, encoding ? "w" : "r");
+       if (!fp)
+               return NULL;
+
+       lzfile = calloc(1, sizeof(*lzfile));
+
+       if (!lzfile) {
+               fclose(fp);
+               return NULL;
+       }
+
+       lzfile->file = fp;
+       lzfile->encoding = encoding;
+       lzfile->eof = 0;
+       lzfile->strm = lzma_strm_tmp;
+       if (encoding) {
+               lzma_options_lzma opt_lzma;
+               if (lzma_lzma_preset(&opt_lzma, level - 1))
+                       return NULL;
+               ret = lzma_alone_encoder(&lzfile->strm, &opt_lzma);
+       } else {
+               ret = lzma_auto_decoder(&lzfile->strm,
+                                       UINT64_C(64) * 1024 * 1024, 0);
+       }
+       if (ret != LZMA_OK) {
+               fclose(fp);
+               free(lzfile);
+               return NULL;
+       }
+       return lzfile;
+}
+
+LZFILE *lzopen(const char *path, const char *mode)
+{
+       return lzopen_internal(path, mode, -1);
+}
+
+int lzclose(LZFILE *lzfile)
+{
+       lzma_ret ret;
+       int n;
+
+       if (!lzfile)
+               return -1;
+
+       if (lzfile->encoding) {
+               for (;;) {
+                       lzfile->strm.avail_out = kBufferSize;
+                       lzfile->strm.next_out = lzfile->buf;
+                       ret = lzma_code(&lzfile->strm, LZMA_FINISH);
+                       if (ret != LZMA_OK && ret != LZMA_STREAM_END)
+                               return -1;
+                       n = kBufferSize - lzfile->strm.avail_out;
+                       if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n)
+                               return -1;
+                       if (ret == LZMA_STREAM_END)
+                               break;
+               }
+       }
+       lzma_end(&lzfile->strm);
+
+       return fclose(lzfile->file);
+       free(lzfile);
+}
+
+ssize_t lzread(LZFILE *lzfile, void *buf, size_t len)
+{
+       lzma_ret ret;
+       int eof = 0;
+
+       if (!lzfile || lzfile->encoding)
+               return -1;
+
+       if (lzfile->eof)
+               return 0;
+
+       lzfile->strm.next_out = buf;
+       lzfile->strm.avail_out = len;
+
+       for (;;) {
+               if (!lzfile->strm.avail_in) {
+                       lzfile->strm.next_in = lzfile->buf;
+                       lzfile->strm.avail_in = fread(lzfile->buf, 1, 
kBufferSize, lzfile->file);
+                       if (!lzfile->strm.avail_in)
+                               eof = 1;
+               }
+
+               ret = lzma_code(&lzfile->strm, LZMA_RUN);
+               if (ret == LZMA_STREAM_END) {
+                       lzfile->eof = 1;
+                       return len - lzfile->strm.avail_out;
+               }
+
+               if (ret != LZMA_OK)
+                       return -1;
+
+               if (!lzfile->strm.avail_out)
+                       return len;
+
+               if (eof)
+                       return -1;
+       }
+}
+
+char *lzma_decompress_file(const char *filename, off_t *r_size)
+{
+       LZFILE *fp;
+       char *buf;
+       off_t size, allocated;
+       ssize_t result;
+
+       if (!filename) {
+               *r_size = 0;
+               return 0;
+       }
+       fp = lzopen(filename, "rb");
+       if (fp == 0) {
+               die("Cannot open `%s': %s\n", filename);
+       }
+       size = 0;
+       allocated = 65536;
+       buf = xmalloc(allocated);
+       do {
+               if (size == allocated) {
+                       allocated <<= 1;
+                       buf = xrealloc(buf, allocated);
+               }
+               result = lzread(fp, buf + size, allocated - size);
+               if (result < 0) {
+                       if ((errno == EINTR) || (errno == EAGAIN))
+                               continue;
+
+                       die ("read on %s of %ld bytes failed\n",
+                               filename, (allocated - size) + 0UL);
+               }
+               size += result;
+       } while(result > 0);
+       result = lzclose(fp);
+       if (result != LZMA_OK) {
+               die ("Close of %s failed\n", filename);
+       }
+       *r_size =  size;
+       return buf;
+}
+#else
+char *lzma_decompress_file(const char *filename, off_t *r_size)
+{
+       return NULL;
+}
+#endif /* HAVE_LIBLZMA */
diff -urN kexec-tools-2.0.1/kexec/zlib.c kexec-tools-2.0.1.lzma/kexec/zlib.c
--- kexec-tools-2.0.1/kexec/zlib.c      1970-01-01 01:00:00.000000000 +0100
+++ kexec-tools-2.0.1.lzma/kexec/zlib.c 2009-11-19 00:05:28.000000000 +0100
@@ -0,0 +1,78 @@
+#include "kexec-zlib.h"
+#ifdef HAVE_LIBZ
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <zlib.h>
+
+#include "kexec.h"
+
+char *zlib_decompress_file(const char *filename, off_t *r_size)
+{
+       gzFile fp;
+       int errnum;
+       const char *msg;
+       char *buf;
+       off_t size, allocated;
+       ssize_t result;
+
+       if (!filename) {
+               *r_size = 0;
+               return 0;
+       }
+       fp = gzopen(filename, "rb");
+       if (fp == 0) {
+               msg = gzerror(fp, &errnum);
+               if (errnum == Z_ERRNO) {
+                       msg = strerror(errno);
+               }
+               fprintf(stderr, "Cannot open `%s': %s\n", filename, msg);
+               return NULL;
+       }
+       size = 0;
+       allocated = 65536;
+       buf = xmalloc(allocated);
+       do {
+               if (size == allocated) {
+                       allocated <<= 1;
+                       buf = xrealloc(buf, allocated);
+               }
+               result = gzread(fp, buf + size, allocated - size);
+               if (result < 0) {
+                       if ((errno == EINTR) || (errno == EAGAIN))
+                               continue;
+
+                       msg = gzerror(fp, &errnum);
+                       if (errnum == Z_ERRNO) {
+                               msg = strerror(errno);
+                       }
+                       die ("read on %s of %ld bytes failed: %s\n",
+                               filename, (allocated - size) + 0UL, msg);
+               }
+               size += result;
+       } while(result > 0);
+       result = gzclose(fp);
+       if (result != Z_OK) {
+               msg = gzerror(fp, &errnum);
+               if (errnum == Z_ERRNO) {
+                       msg = strerror(errno);
+               }
+               die ("Close of %s failed: %s\n", filename, msg);
+       }
+       *r_size =  size;
+       return buf;
+}
+#else
+char *zlib_decompress_file(const char *filename, off_t *r_size)
+{
+       return NULL;
+}
+#endif /* HAVE_ZLIB */

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

Reply via email to