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