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((unsigned)(*sourcelen-def_strm.total_in), def_strm.avail_out);
  98                jffs2_dbg(1, "calling deflate with avail_in %d, avail_out %d\n",
  99                          def_strm.avail_in, def_strm.avail_out);
 100                ret = zlib_deflate(&def_strm, Z_PARTIAL_FLUSH);
 101                jffs2_dbg(1, "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n",
 102                          def_strm.avail_in, def_strm.avail_out,
 103                          def_strm.total_in, def_strm.total_out);
 104                if (ret != Z_OK) {
 105                        jffs2_dbg(1, "deflate in loop returned %d\n", ret);
 106                        zlib_deflateEnd(&def_strm);
 107                        mutex_unlock(&deflate_mutex);
 108                        return -1;
 109                }
 110        }
 111        def_strm.avail_out += STREAM_END_SPACE;
 112        def_strm.avail_in = 0;
 113        ret = zlib_deflate(&def_strm, Z_FINISH);
 114        zlib_deflateEnd(&def_strm);
 115
 116        if (ret != Z_STREAM_END) {
 117                jffs2_dbg(1, "final deflate returned %d\n", ret);
 118                ret = -1;
 119                goto out;
 120        }
 121
 122        if (def_strm.total_out >= def_strm.total_in) {
 123                jffs2_dbg(1, "zlib compressed %ld bytes into %ld; failing\n",
 124                          def_strm.total_in, def_strm.total_out);
 125                ret = -1;
 126                goto out;
 127        }
 128
 129        jffs2_dbg(1, "zlib compressed %ld bytes into %ld\n",
 130                  def_strm.total_in, def_strm.total_out);
 131
 132        *dstlen = def_strm.total_out;
 133        *sourcelen = def_strm.total_in;
 134        ret = 0;
 135 out:
 136        mutex_unlock(&deflate_mutex);
 137        return ret;
 138}
 139
 140static int jffs2_zlib_decompress(unsigned char *data_in,
 141                                 unsigned char *cpage_out,
 142                                 uint32_t srclen, uint32_t destlen)
 143{
 144        int ret;
 145        int wbits = MAX_WBITS;
 146
 147        mutex_lock(&inflate_mutex);
 148
 149        inf_strm.next_in = data_in;
 150        inf_strm.avail_in = srclen;
 151        inf_strm.total_in = 0;
 152
 153        inf_strm.next_out = cpage_out;
 154        inf_strm.avail_out = destlen;
 155        inf_strm.total_out = 0;
 156
 157        /* If it's deflate, and it's got no preset dictionary, then
 158           we can tell zlib to skip the adler32 check. */
 159        if (srclen > 2 && !(data_in[1] & PRESET_DICT) &&
 160            ((data_in[0] & 0x0f) == Z_DEFLATED) &&
 161            !(((data_in[0]<<8) + data_in[1]) % 31)) {
 162
 163                jffs2_dbg(2, "inflate skipping adler32\n");
 164                wbits = -((data_in[0] >> 4) + 8);
 165                inf_strm.next_in += 2;
 166                inf_strm.avail_in -= 2;
 167        } else {
 168                /* Let this remain D1 for now -- it should never happen */
 169                jffs2_dbg(1, "inflate not skipping adler32\n");
 170        }
 171
 172
 173        if (Z_OK != zlib_inflateInit2(&inf_strm, wbits)) {
 174                pr_warn("inflateInit failed\n");
 175                mutex_unlock(&inflate_mutex);
 176                return 1;
 177        }
 178
 179        while((ret = zlib_inflate(&inf_strm, Z_FINISH)) == Z_OK)
 180                ;
 181        if (ret != Z_STREAM_END) {
 182                pr_notice("inflate returned %d\n", ret);
 183        }
 184        zlib_inflateEnd(&inf_strm);
 185        mutex_unlock(&inflate_mutex);
 186        return 0;
 187}
 188
 189static struct jffs2_compressor jffs2_zlib_comp = {
 190    .priority = JFFS2_ZLIB_PRIORITY,
 191    .name = "zlib",
 192    .compr = JFFS2_COMPR_ZLIB,
 193    .compress = &jffs2_zlib_compress,
 194    .decompress = &jffs2_zlib_decompress,
 195#ifdef JFFS2_ZLIB_DISABLED
 196    .disabled = 1,
 197#else
 198    .disabled = 0,
 199#endif
 200};
 201
 202int __init jffs2_zlib_init(void)
 203{
 204    int ret;
 205
 206    ret = alloc_workspaces();
 207    if (ret)
 208            return ret;
 209
 210    ret = jffs2_register_compressor(&jffs2_zlib_comp);
 211    if (ret)
 212            free_workspaces();
 213
 214    return ret;
 215}
 216
 217void jffs2_zlib_exit(void)
 218{
 219    jffs2_unregister_compressor(&jffs2_zlib_comp);
 220    free_workspaces();
 221}
 222