linux/fs/jffs2/compr.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 * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
   7 *                  University of Szeged, Hungary
   8 *
   9 * Created by Arjan van de Ven <arjan@infradead.org>
  10 *
  11 * For licensing information, see the file 'LICENCE' in this directory.
  12 *
  13 */
  14
  15#include "compr.h"
  16
  17static DEFINE_SPINLOCK(jffs2_compressor_list_lock);
  18
  19/* Available compressors are on this list */
  20static LIST_HEAD(jffs2_compressor_list);
  21
  22/* Actual compression mode */
  23static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
  24
  25/* Statistics for blocks stored without compression */
  26static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0;
  27
  28
  29/*
  30 * Return 1 to use this compression
  31 */
  32static int jffs2_is_best_compression(struct jffs2_compressor *this,
  33                struct jffs2_compressor *best, uint32_t size, uint32_t bestsize)
  34{
  35        switch (jffs2_compression_mode) {
  36        case JFFS2_COMPR_MODE_SIZE:
  37                if (bestsize > size)
  38                        return 1;
  39                return 0;
  40        case JFFS2_COMPR_MODE_FAVOURLZO:
  41                if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > size))
  42                        return 1;
  43                if ((best->compr != JFFS2_COMPR_LZO) && (bestsize > size))
  44                        return 1;
  45                if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > (size * FAVOUR_LZO_PERCENT / 100)))
  46                        return 1;
  47                if ((bestsize * FAVOUR_LZO_PERCENT / 100) > size)
  48                        return 1;
  49
  50                return 0;
  51        }
  52        /* Shouldn't happen */
  53        return 0;
  54}
  55
  56/*
  57 * jffs2_selected_compress:
  58 * @compr: Explicit compression type to use (ie, JFFS2_COMPR_ZLIB).
  59 *      If 0, just take the first available compression mode.
  60 * @data_in: Pointer to uncompressed data
  61 * @cpage_out: Pointer to returned pointer to buffer for compressed data
  62 * @datalen: On entry, holds the amount of data available for compression.
  63 *      On exit, expected to hold the amount of data actually compressed.
  64 * @cdatalen: On entry, holds the amount of space available for compressed
  65 *      data. On exit, expected to hold the actual size of the compressed
  66 *      data.
  67 *
  68 * Returns: the compression type used.  Zero is used to show that the data
  69 * could not be compressed; probably because we couldn't find the requested
  70 * compression mode.
  71 */
  72static int jffs2_selected_compress(u8 compr, unsigned char *data_in,
  73                unsigned char **cpage_out, u32 *datalen, u32 *cdatalen)
  74{
  75        struct jffs2_compressor *this;
  76        int err, ret = JFFS2_COMPR_NONE;
  77        uint32_t orig_slen, orig_dlen;
  78        char *output_buf;
  79
  80        output_buf = kmalloc(*cdatalen, GFP_KERNEL);
  81        if (!output_buf) {
  82                printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n");
  83                return ret;
  84        }
  85        orig_slen = *datalen;
  86        orig_dlen = *cdatalen;
  87        spin_lock(&jffs2_compressor_list_lock);
  88        list_for_each_entry(this, &jffs2_compressor_list, list) {
  89                /* Skip decompress-only and disabled modules */
  90                if (!this->compress || this->disabled)
  91                        continue;
  92
  93                /* Skip if not the desired compression type */
  94                if (compr && (compr != this->compr))
  95                        continue;
  96
  97                /*
  98                 * Either compression type was unspecified, or we found our
  99                 * compressor; either way, we're good to go.
 100                 */
 101                this->usecount++;
 102                spin_unlock(&jffs2_compressor_list_lock);
 103
 104                *datalen  = orig_slen;
 105                *cdatalen = orig_dlen;
 106                err = this->compress(data_in, output_buf, datalen, cdatalen);
 107
 108                spin_lock(&jffs2_compressor_list_lock);
 109                this->usecount--;
 110                if (!err) {
 111                        /* Success */
 112                        ret = this->compr;
 113                        this->stat_compr_blocks++;
 114                        this->stat_compr_orig_size += *datalen;
 115                        this->stat_compr_new_size += *cdatalen;
 116                        break;
 117                }
 118        }
 119        spin_unlock(&jffs2_compressor_list_lock);
 120        if (ret == JFFS2_COMPR_NONE)
 121                kfree(output_buf);
 122        else
 123                *cpage_out = output_buf;
 124
 125        return ret;
 126}
 127
 128/* jffs2_compress:
 129 * @data_in: Pointer to uncompressed data
 130 * @cpage_out: Pointer to returned pointer to buffer for compressed data
 131 * @datalen: On entry, holds the amount of data available for compression.
 132 *      On exit, expected to hold the amount of data actually compressed.
 133 * @cdatalen: On entry, holds the amount of space available for compressed
 134 *      data. On exit, expected to hold the actual size of the compressed
 135 *      data.
 136 *
 137 * Returns: Lower byte to be stored with data indicating compression type used.
 138 * Zero is used to show that the data could not be compressed - the
 139 * compressed version was actually larger than the original.
 140 * Upper byte will be used later. (soon)
 141 *
 142 * If the cdata buffer isn't large enough to hold all the uncompressed data,
 143 * jffs2_compress should compress as much as will fit, and should set
 144 * *datalen accordingly to show the amount of data which were compressed.
 145 */
 146uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
 147                        unsigned char *data_in, unsigned char **cpage_out,
 148                        uint32_t *datalen, uint32_t *cdatalen)
 149{
 150        int ret = JFFS2_COMPR_NONE;
 151        int mode, compr_ret;
 152        struct jffs2_compressor *this, *best=NULL;
 153        unsigned char *output_buf = NULL, *tmp_buf;
 154        uint32_t orig_slen, orig_dlen;
 155        uint32_t best_slen=0, best_dlen=0;
 156
 157        if (c->mount_opts.override_compr)
 158                mode = c->mount_opts.compr;
 159        else
 160                mode = jffs2_compression_mode;
 161
 162        switch (mode) {
 163        case JFFS2_COMPR_MODE_NONE:
 164                break;
 165        case JFFS2_COMPR_MODE_PRIORITY:
 166                ret = jffs2_selected_compress(0, data_in, cpage_out, datalen,
 167                                cdatalen);
 168                break;
 169        case JFFS2_COMPR_MODE_SIZE:
 170        case JFFS2_COMPR_MODE_FAVOURLZO:
 171                orig_slen = *datalen;
 172                orig_dlen = *cdatalen;
 173                spin_lock(&jffs2_compressor_list_lock);
 174                list_for_each_entry(this, &jffs2_compressor_list, list) {
 175                        /* Skip decompress-only backwards-compatibility and disabled modules */
 176                        if ((!this->compress)||(this->disabled))
 177                                continue;
 178                        /* Allocating memory for output buffer if necessary */
 179                        if ((this->compr_buf_size < orig_slen) && (this->compr_buf)) {
 180                                spin_unlock(&jffs2_compressor_list_lock);
 181                                kfree(this->compr_buf);
 182                                spin_lock(&jffs2_compressor_list_lock);
 183                                this->compr_buf_size=0;
 184                                this->compr_buf=NULL;
 185                        }
 186                        if (!this->compr_buf) {
 187                                spin_unlock(&jffs2_compressor_list_lock);
 188                                tmp_buf = kmalloc(orig_slen, GFP_KERNEL);
 189                                spin_lock(&jffs2_compressor_list_lock);
 190                                if (!tmp_buf) {
 191                                        printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n", orig_slen);
 192                                        continue;
 193                                }
 194                                else {
 195                                        this->compr_buf = tmp_buf;
 196                                        this->compr_buf_size = orig_slen;
 197                                }
 198                        }
 199                        this->usecount++;
 200                        spin_unlock(&jffs2_compressor_list_lock);
 201                        *datalen  = orig_slen;
 202                        *cdatalen = orig_dlen;
 203                        compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen);
 204                        spin_lock(&jffs2_compressor_list_lock);
 205                        this->usecount--;
 206                        if (!compr_ret) {
 207                                if (((!best_dlen) || jffs2_is_best_compression(this, best, *cdatalen, best_dlen))
 208                                                && (*cdatalen < *datalen)) {
 209                                        best_dlen = *cdatalen;
 210                                        best_slen = *datalen;
 211                                        best = this;
 212                                }
 213                        }
 214                }
 215                if (best_dlen) {
 216                        *cdatalen = best_dlen;
 217                        *datalen  = best_slen;
 218                        output_buf = best->compr_buf;
 219                        best->compr_buf = NULL;
 220                        best->compr_buf_size = 0;
 221                        best->stat_compr_blocks++;
 222                        best->stat_compr_orig_size += best_slen;
 223                        best->stat_compr_new_size  += best_dlen;
 224                        ret = best->compr;
 225                        *cpage_out = output_buf;
 226                }
 227                spin_unlock(&jffs2_compressor_list_lock);
 228                break;
 229        case JFFS2_COMPR_MODE_FORCELZO:
 230                ret = jffs2_selected_compress(JFFS2_COMPR_LZO, data_in,
 231                                cpage_out, datalen, cdatalen);
 232                break;
 233        case JFFS2_COMPR_MODE_FORCEZLIB:
 234                ret = jffs2_selected_compress(JFFS2_COMPR_ZLIB, data_in,
 235                                cpage_out, datalen, cdatalen);
 236                break;
 237        default:
 238                printk(KERN_ERR "JFFS2: unknown compression mode.\n");
 239        }
 240
 241        if (ret == JFFS2_COMPR_NONE) {
 242                *cpage_out = data_in;
 243                *datalen = *cdatalen;
 244                none_stat_compr_blocks++;
 245                none_stat_compr_size += *datalen;
 246        }
 247        return ret;
 248}
 249
 250int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
 251                     uint16_t comprtype, unsigned char *cdata_in,
 252                     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen)
 253{
 254        struct jffs2_compressor *this;
 255        int ret;
 256
 257        /* Older code had a bug where it would write non-zero 'usercompr'
 258           fields. Deal with it. */
 259        if ((comprtype & 0xff) <= JFFS2_COMPR_ZLIB)
 260                comprtype &= 0xff;
 261
 262        switch (comprtype & 0xff) {
 263        case JFFS2_COMPR_NONE:
 264                /* This should be special-cased elsewhere, but we might as well deal with it */
 265                memcpy(data_out, cdata_in, datalen);
 266                none_stat_decompr_blocks++;
 267                break;
 268        case JFFS2_COMPR_ZERO:
 269                memset(data_out, 0, datalen);
 270                break;
 271        default:
 272                spin_lock(&jffs2_compressor_list_lock);
 273                list_for_each_entry(this, &jffs2_compressor_list, list) {
 274                        if (comprtype == this->compr) {
 275                                this->usecount++;
 276                                spin_unlock(&jffs2_compressor_list_lock);
 277                                ret = this->decompress(cdata_in, data_out, cdatalen, datalen);
 278                                spin_lock(&jffs2_compressor_list_lock);
 279                                if (ret) {
 280                                        printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret);
 281                                }
 282                                else {
 283                                        this->stat_decompr_blocks++;
 284                                }
 285                                this->usecount--;
 286                                spin_unlock(&jffs2_compressor_list_lock);
 287                                return ret;
 288                        }
 289                }
 290                printk(KERN_WARNING "JFFS2 compression type 0x%02x not available.\n", comprtype);
 291                spin_unlock(&jffs2_compressor_list_lock);
 292                return -EIO;
 293        }
 294        return 0;
 295}
 296
 297int jffs2_register_compressor(struct jffs2_compressor *comp)
 298{
 299        struct jffs2_compressor *this;
 300
 301        if (!comp->name) {
 302                printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n");
 303                return -1;
 304        }
 305        comp->compr_buf_size=0;
 306        comp->compr_buf=NULL;
 307        comp->usecount=0;
 308        comp->stat_compr_orig_size=0;
 309        comp->stat_compr_new_size=0;
 310        comp->stat_compr_blocks=0;
 311        comp->stat_decompr_blocks=0;
 312        D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name));
 313
 314        spin_lock(&jffs2_compressor_list_lock);
 315
 316        list_for_each_entry(this, &jffs2_compressor_list, list) {
 317                if (this->priority < comp->priority) {
 318                        list_add(&comp->list, this->list.prev);
 319                        goto out;
 320                }
 321        }
 322        list_add_tail(&comp->list, &jffs2_compressor_list);
 323out:
 324        D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
 325                printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
 326        })
 327
 328        spin_unlock(&jffs2_compressor_list_lock);
 329
 330        return 0;
 331}
 332
 333int jffs2_unregister_compressor(struct jffs2_compressor *comp)
 334{
 335        D2(struct jffs2_compressor *this;)
 336
 337        D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name));
 338
 339        spin_lock(&jffs2_compressor_list_lock);
 340
 341        if (comp->usecount) {
 342                spin_unlock(&jffs2_compressor_list_lock);
 343                printk(KERN_WARNING "JFFS2: Compressor modul is in use. Unregister failed.\n");
 344                return -1;
 345        }
 346        list_del(&comp->list);
 347
 348        D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
 349                printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
 350        })
 351        spin_unlock(&jffs2_compressor_list_lock);
 352        return 0;
 353}
 354
 355void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
 356{
 357        if (orig != comprbuf)
 358                kfree(comprbuf);
 359}
 360
 361int __init jffs2_compressors_init(void)
 362{
 363/* Registering compressors */
 364#ifdef CONFIG_JFFS2_ZLIB
 365        jffs2_zlib_init();
 366#endif
 367#ifdef CONFIG_JFFS2_RTIME
 368        jffs2_rtime_init();
 369#endif
 370#ifdef CONFIG_JFFS2_RUBIN
 371        jffs2_rubinmips_init();
 372        jffs2_dynrubin_init();
 373#endif
 374#ifdef CONFIG_JFFS2_LZO
 375        jffs2_lzo_init();
 376#endif
 377/* Setting default compression mode */
 378#ifdef CONFIG_JFFS2_CMODE_NONE
 379        jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
 380        D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");)
 381#else
 382#ifdef CONFIG_JFFS2_CMODE_SIZE
 383        jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
 384        D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");)
 385#else
 386#ifdef CONFIG_JFFS2_CMODE_FAVOURLZO
 387        jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO;
 388        D1(printk(KERN_INFO "JFFS2: default compression mode: favourlzo\n");)
 389#else
 390        D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");)
 391#endif
 392#endif
 393#endif
 394        return 0;
 395}
 396
 397int jffs2_compressors_exit(void)
 398{
 399/* Unregistering compressors */
 400#ifdef CONFIG_JFFS2_LZO
 401        jffs2_lzo_exit();
 402#endif
 403#ifdef CONFIG_JFFS2_RUBIN
 404        jffs2_dynrubin_exit();
 405        jffs2_rubinmips_exit();
 406#endif
 407#ifdef CONFIG_JFFS2_RTIME
 408        jffs2_rtime_exit();
 409#endif
 410#ifdef CONFIG_JFFS2_ZLIB
 411        jffs2_zlib_exit();
 412#endif
 413        return 0;
 414}
 415