linux/fs/jffs2/compr_zlib.c
<<
>>
Prefs
   1/*
   2 * JFFS2 -- Journalling Flash File System, Version 2.
   3 *
   4 * Copyright © 2001-2007 Red Hat, Inc.
   5 * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
   6 *
   7 * Created by David Woodhouse <dwmw2@infradead.org>
   8 *
   9 * For licensing information, see the file 'LICENCE' in this directory.
  10 *
  11 */
  12
  13#if !defined(__KERNEL__) && !defined(__ECOS)
  14#error "The userspace support got too messy and was removed. Update your mkfs.jffs2"
  15#endif
  16
  17#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  18
  19#include <linux/kernel.h>
  20#include <linux/zlib.h>
  21#include <linux/zutil.h>
  22#include "nodelist.h"
  23#include "compr.h"
  24
  25        /* Plan: call deflate() with avail_in == *sourcelen,
  26                avail_out = *dstlen - 12 and flush == Z_FINISH.
  27                If it doesn't manage to finish, call it again with
  28                avail_in == 0 and avail_out set to the remaining 12
  29                bytes for it to clean up.
  30           Q: Is 12 bytes sufficient?
  31        */
  32#define STREAM_END_SPACE 12
  33
  34static DEFINE_MUTEX(deflate_mutex);
  35static DEFINE_MUTEX(inflate_mutex);
  36static z_stream inf_strm, def_strm;
  37
  38#ifdef __KERNEL__ /* Linux-only */
  39#include <linux/vmalloc.h>
  40#include <linux/init.h>
  41#include <linux/mutex.h>
  42
  43static int __init alloc_workspaces(void)
  44{
  45        def_strm.workspace = vmalloc(zlib_deflate_workspacesize(MAX_WBITS,
  46                                                        MAX_MEM_LEVEL));
  47        if (!def_strm.workspace)
  48                return -ENOMEM;
  49
  50        jffs2_dbg(1, "Allocated %d bytes for deflate workspace\n",
  51                  zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL));
  52        inf_strm.workspace = vmalloc(zlib_inflate_workspacesize());
  53        if (!inf_strm.workspace) {
  54                vfree(def_strm.workspace);
  55                return -ENOMEM;
  56        }
  57        jffs2_dbg(1, "Allocated %d bytes for inflate workspace\n",
  58                  zlib_inflate_workspacesize());
  59        return 0;
  60}
  61
  62static void free_workspaces(void)
  63{
  64        vfree(def_strm.workspace);
  65        vfree(inf_strm.workspace);
  66}
  67#else
  68#define alloc_workspaces() (0)
  69#define free_workspaces() do { } while(0)
  70#endif /* __KERNEL__ */
  71
  72static int jffs2_zlib_compress(unsigned char *data_in,
  73                               unsigned char *cpage_out,
  74                               uint32_t *sourcelen, uint32_t *dstlen)
  75{
  76        int ret;
  77
  78        if (*dstlen <= STREAM_END_SPACE)
  79                return -1;
  80
  81        mutex_lock(&deflate_mutex);
  82
  83        if (Z_OK != zlib_deflateInit(&def_strm, 3)) {
  84                pr_warn("deflateInit failed\n");
  85                mutex_unlock(&deflate_mutex);
  86                return -1;
  87        }
  88
  89        def_strm.next_in = data_in;
  90        def_strm.total_in = 0;
  91
  92        def_strm.next_out = cpage_out;
  93        def_strm.total_out = 0;
  94
  95        while (def_strm.total_out < *dstlen - STREAM_END_SPACE && def_strm.total_in < *sourcelen) {
  96                def_strm.avail_out = *dstlen - (def_strm.total_out + STREAM_END_SPACE);
  97                def_strm.avail_in = min_t(unsigned long,
  98                        (*sourcelen-def_strm.total_in), def_strm.avail_out);
  99                jffs2_dbg(1, "calling deflate with avail_in %ld, avail_out %ld\n",
 100                          def_strm.avail_in, def_strm.avail_out);
 101                ret = zlib_deflate(&def_strm, Z_PARTIAL_FLUSH);
 102                jffs2_dbg(1, "deflate returned with avail_in %ld, avail_out %ld, total_in %ld, total_out %ld\n",
 103                          def_strm.avail_in, def_strm.avail_out,
 104                          def_strm.total_in, def_strm.total_out);
 105                if (ret != Z_OK) {
 106                        jffs2_dbg(1, "deflate in loop returned %d\n", ret);
 107                        zlib_deflateEnd(&def_strm);
 108                        mutex_unlock(&deflate_mutex);
 109                        return -1;
 110                }
 111        }
 112        def_strm.avail_out += STREAM_END_SPACE;
 113        def_strm.avail_in = 0;
 114        ret = zlib_deflate(&def_strm, Z_FINISH);
 115        zlib_deflateEnd(&def_strm);
 116
 117        if (ret != Z_STREAM_END) {
 118                jffs2_dbg(1, "final deflate returned %d\n", ret);
 119                ret = -1;
 120                goto out;
 121        }
 122
 123        if (def_strm.total_out >= def_strm.total_in) {
 124                jffs2_dbg(1, "zlib compressed %ld bytes into %ld; failing\n",
 125                          def_strm.total_in, def_strm.total_out);
 126                ret = -1;
 127                goto out;
 128        }
 129
 130        jffs2_dbg(1, "zlib compressed %ld bytes into %ld\n",
 131                  def_strm.total_in, def_strm.total_out);
 132
 133        *dstlen = def_strm.total_out;
 134        *sourcelen = def_strm.total_in;
 135        ret = 0;
 136 out:
 137        mutex_unlock(&deflate_mutex);
 138        return ret;
 139}
 140
 141static int jffs2_zlib_decompress(unsigned char *data_in,
 142                                 unsigned char *cpage_out,
 143                                 uint32_t srclen, uint32_t destlen)
 144{
 145        int ret;
 146        int wbits = MAX_WBITS;
 147
 148        mutex_lock(&inflate_mutex);
 149
 150        inf_strm.next_in = data_in;
 151        inf_strm.avail_in = srclen;
 152        inf_strm.total_in = 0;
 153
 154        inf_strm.next_out = cpage_out;
 155        inf_strm.avail_out = destlen;
 156        inf_strm.total_out = 0;
 157
 158        /* If it's deflate, and it's got no preset dictionary, then
 159           we can tell zlib to skip the adler32 check. */
 160        if (srclen > 2 && !(data_in[1] & PRESET_DICT) &&
 161            ((data_in[0] & 0x0f) == Z_DEFLATED) &&
 162            !(((data_in[0]<<8) + data_in[1]) % 31)) {
 163
 164                jffs2_dbg(2, "inflate skipping adler32\n");
 165                wbits = -((data_in[0] >> 4) + 8);
 166                inf_strm.next_in += 2;
 167                inf_strm.avail_in -= 2;
 168        } else {
 169                /* Let this remain D1 for now -- it should never happen */
 170                jffs2_dbg(1, "inflate not skipping adler32\n");
 171        }
 172
 173
 174        if (Z_OK != zlib_inflateInit2(&inf_strm, wbits)) {
 175                pr_warn("inflateInit failed\n");
 176                mutex_unlock(&inflate_mutex);
 177                return 1;
 178        }
 179
 180        while((ret = zlib_inflate(&inf_strm, Z_FINISH)) == Z_OK)
 181                ;
 182        if (ret != Z_STREAM_END) {
 183                pr_notice("inflate returned %d\n", ret);
 184        }
 185        zlib_inflateEnd(&inf_strm);
 186        mutex_unlock(&inflate_mutex);
 187        return 0;
 188}
 189
 190static struct jffs2_compressor jffs2_zlib_comp = {
 191    .priority = JFFS2_ZLIB_PRIORITY,
 192    .name = "zlib",
 193    .compr = JFFS2_COMPR_ZLIB,
 194    .compress = &jffs2_zlib_compress,
 195    .decompress = &jffs2_zlib_decompress,
 196#ifdef JFFS2_ZLIB_DISABLED
 197    .disabled = 1,
 198#else
 199    .disabled = 0,
 200#endif
 201};
 202
 203int __init jffs2_zlib_init(void)
 204{
 205    int ret;
 206
 207    ret = alloc_workspaces();
 208    if (ret)
 209            return ret;
 210
 211    ret = jffs2_register_compressor(&jffs2_zlib_comp);
 212    if (ret)
 213            free_workspaces();
 214
 215    return ret;
 216}
 217
 218void jffs2_zlib_exit(void)
 219{
 220    jffs2_unregister_compressor(&jffs2_zlib_comp);
 221    free_workspaces();
 222}
 223