source: rtems/cpukit/libfs/src/jffs2/src/compr_zlib.c @ 9da567b2

5
Last change on this file since 9da567b2 was 9da567b2, checked in by Yinghai Lu <yinghai@…>, on 08/08/14 at 21:23:14

initramfs: support initramfs that is bigger than 2GiB

Now with 64bit bzImage and kexec tools, we support ramdisk that size is
bigger than 2g, as we could put it above 4G.

Found compressed initramfs image could not be decompressed properly. It
turns out that image length is int during decompress detection, and it
will become < 0 when length is more than 2G. Furthermore, during
decompressing len as int is used for inbuf count, that has problem too.

Change len to long, that should be ok as on 32 bit platform long is
32bits.

Tested with following compressed initramfs image as root with kexec.

gzip, bzip2, xz, lzma, lzop, lz4.

run time for populate_rootfs():

size name Nehalem-EX Westmere-EX Ivybridge-EX

9034400256 root_img : 26s 24s 30s
3561095057 root_img.lz4 : 28s 27s 27s
3459554629 root_img.lzo : 29s 29s 28s
3219399480 root_img.gz : 64s 62s 49s
2251594592 root_img.xz : 262s 260s 183s
2226366598 root_img.lzma: 386s 376s 277s
2901482513 root_img.bz2 : 635s 599s

Signed-off-by: Yinghai Lu <yinghai@…>
Cc: "H. Peter Anvin" <hpa@…>
Cc: Ingo Molnar <mingo@…>
Cc: Rashika Kheria <rashika.kheria@…>
Cc: Josh Triplett <josh@…>
Cc: Kyungsik Lee <kyungsik.lee@…>
Cc: P J P <ppandit@…>
Cc: Al Viro <viro@…>
Cc: Tetsuo Handa <penguin-kernel@…>
Cc: "Daniel M. Weeks" <dan@…>
Cc: Alexandre Courbot <acourbot@…>
Cc: Jan Beulich <JBeulich@…>
Signed-off-by: Andrew Morton <akpm@…>
Signed-off-by: Linus Torvalds <torvalds@…>

  • Property mode set to 100644
File size: 4.7 KB
Line 
1#include "rtems-jffs2-config.h"
2
3/*
4 * JFFS2 -- Journalling Flash File System, Version 2.
5 *
6 * Copyright © 2001-2007 Red Hat, Inc.
7 * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
8 *
9 * Created by David Woodhouse <dwmw2@infradead.org>
10 *
11 * For licensing information, see the file 'LICENCE' in this directory.
12 *
13 */
14
15#if !defined(__KERNEL__) && !defined(__ECOS)
16#error "The userspace support got too messy and was removed. Update your mkfs.jffs2"
17#endif
18
19#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20
21#include <linux/kernel.h>
22#include <linux/zlib.h>
23#include <linux/zutil.h>
24#include "nodelist.h"
25#include "compr.h"
26
27        /* Plan: call deflate() with avail_in == *sourcelen,
28                avail_out = *dstlen - 12 and flush == Z_FINISH.
29                If it doesn't manage to finish, call it again with
30                avail_in == 0 and avail_out set to the remaining 12
31                bytes for it to clean up.
32           Q: Is 12 bytes sufficient?
33        */
34#define STREAM_END_SPACE 12
35
36static DEFINE_MUTEX(deflate_mutex);
37static DEFINE_MUTEX(inflate_mutex);
38
39static rtems_jffs2_compressor_zlib_control *get_zlib_control(
40        rtems_jffs2_compressor_control *super
41)
42{
43        return (rtems_jffs2_compressor_zlib_control *) super;
44}
45
46uint16_t rtems_jffs2_compressor_zlib_compress(
47        rtems_jffs2_compressor_control *super,
48        unsigned char *data_in,
49        unsigned char *cpage_out,
50        uint32_t *sourcelen,
51        uint32_t *dstlen
52)
53{
54        rtems_jffs2_compressor_zlib_control *self = get_zlib_control(super);
55        z_stream *def_strm = &self->stream;
56        int ret;
57
58        if (*dstlen <= STREAM_END_SPACE)
59                return JFFS2_COMPR_NONE;
60
61        mutex_lock(&deflate_mutex);
62
63        if (Z_OK != zlib_deflateInit(def_strm, 3)) {
64                pr_warn("deflateInit failed\n");
65                mutex_unlock(&deflate_mutex);
66                return JFFS2_COMPR_NONE;
67        }
68
69        def_strm->next_in = data_in;
70        def_strm->total_in = 0;
71
72        def_strm->next_out = cpage_out;
73        def_strm->total_out = 0;
74
75        while (def_strm->total_out < *dstlen - STREAM_END_SPACE && def_strm->total_in < *sourcelen) {
76                def_strm->avail_out = *dstlen - (def_strm->total_out + STREAM_END_SPACE);
77                def_strm->avail_in = min_t(unsigned long,
78                        (*sourcelen-def_strm->total_in), def_strm->avail_out);
79                jffs2_dbg(1, "calling deflate with avail_in %ld, avail_out %ld\n",
80                          def_strm->avail_in, def_strm->avail_out);
81                ret = zlib_deflate(def_strm, Z_PARTIAL_FLUSH);
82                jffs2_dbg(1, "deflate returned with avail_in %ld, avail_out %ld, total_in %ld, total_out %ld\n",
83                          def_strm->avail_in, def_strm->avail_out,
84                          def_strm->total_in, def_strm->total_out);
85                if (ret != Z_OK) {
86                        jffs2_dbg(1, "deflate in loop returned %d\n", ret);
87                        zlib_deflateEnd(def_strm);
88                        mutex_unlock(&deflate_mutex);
89                        return JFFS2_COMPR_NONE;
90                }
91        }
92        def_strm->avail_out += STREAM_END_SPACE;
93        def_strm->avail_in = 0;
94        ret = zlib_deflate(def_strm, Z_FINISH);
95        zlib_deflateEnd(def_strm);
96
97        if (ret != Z_STREAM_END) {
98                jffs2_dbg(1, "final deflate returned %d\n", ret);
99                ret = JFFS2_COMPR_NONE;
100                goto out;
101        }
102
103        if (def_strm->total_out >= def_strm->total_in) {
104                jffs2_dbg(1, "zlib compressed %ld bytes into %ld; failing\n",
105                          def_strm->total_in, def_strm->total_out);
106                ret = JFFS2_COMPR_NONE;
107                goto out;
108        }
109
110        jffs2_dbg(1, "zlib compressed %ld bytes into %ld\n",
111                  def_strm->total_in, def_strm->total_out);
112
113        *dstlen = def_strm->total_out;
114        *sourcelen = def_strm->total_in;
115        ret = JFFS2_COMPR_ZLIB;
116 out:
117        mutex_unlock(&deflate_mutex);
118        return ret;
119}
120
121int rtems_jffs2_compressor_zlib_decompress(
122        rtems_jffs2_compressor_control *super,
123        uint16_t comprtype,
124        unsigned char *data_in,
125        unsigned char *cpage_out,
126        uint32_t srclen,
127        uint32_t destlen
128)
129{
130        rtems_jffs2_compressor_zlib_control *self = get_zlib_control(super);
131        z_stream *inf_strm = &self->stream;
132        int ret;
133        int wbits = MAX_WBITS;
134
135        if (comprtype != JFFS2_COMPR_ZLIB) {
136                return -EIO;
137        }
138
139        mutex_lock(&inflate_mutex);
140
141        inf_strm->next_in = data_in;
142        inf_strm->avail_in = srclen;
143        inf_strm->total_in = 0;
144
145        inf_strm->next_out = cpage_out;
146        inf_strm->avail_out = destlen;
147        inf_strm->total_out = 0;
148
149        /* If it's deflate, and it's got no preset dictionary, then
150           we can tell zlib to skip the adler32 check. */
151        if (srclen > 2 && !(data_in[1] & PRESET_DICT) &&
152            ((data_in[0] & 0x0f) == Z_DEFLATED) &&
153            !(((data_in[0]<<8) + data_in[1]) % 31)) {
154
155                jffs2_dbg(2, "inflate skipping adler32\n");
156                wbits = -((data_in[0] >> 4) + 8);
157                inf_strm->next_in += 2;
158                inf_strm->avail_in -= 2;
159        } else {
160                /* Let this remain D1 for now -- it should never happen */
161                jffs2_dbg(1, "inflate not skipping adler32\n");
162        }
163
164
165        if (Z_OK != zlib_inflateInit2(inf_strm, wbits)) {
166                pr_warn("inflateInit failed\n");
167                mutex_unlock(&inflate_mutex);
168                return -EIO;
169        }
170
171        while((ret = zlib_inflate(inf_strm, Z_FINISH)) == Z_OK)
172                ;
173        if (ret != Z_STREAM_END) {
174                pr_notice("inflate returned %d\n", ret);
175        }
176        zlib_inflateEnd(inf_strm);
177        mutex_unlock(&inflate_mutex);
178        return 0;
179}
Note: See TracBrowser for help on using the repository browser.