root/fs/jffs2/compr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. jffs2_is_best_compression
  2. jffs2_selected_compress
  3. jffs2_compress
  4. jffs2_decompress
  5. jffs2_register_compressor
  6. jffs2_unregister_compressor
  7. jffs2_free_comprbuf
  8. jffs2_compressors_init
  9. jffs2_compressors_exit

   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 
  19 static DEFINE_SPINLOCK(jffs2_compressor_list_lock);
  20 
  21 /* Available compressors are on this list */
  22 static LIST_HEAD(jffs2_compressor_list);
  23 
  24 /* Actual compression mode */
  25 static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
  26 
  27 /* Statistics for blocks stored without compression */
  28 static 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  */
  34 static 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  */
  74 static 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  */
 148 uint16_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 
 253 int 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 
 301 int 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);
 327 out:
 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 
 337 int 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 
 359 void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
 360 {
 361         if (orig != comprbuf)
 362                 kfree(comprbuf);
 363 }
 364 
 365 int __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 
 401 int 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 }

/* [<][>][^][v][top][bottom][index][help] */