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