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