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 17 static DEFINE_SPINLOCK(jffs2_compressor_list_lock); 18 19 /* Available compressors are on this list */ 20 static LIST_HEAD(jffs2_compressor_list); 21 22 /* Actual compression mode */ 23 static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY; 24 25 /* Statistics for blocks stored without compression */ 26 static 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 */ 32 static 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 */ 72 static 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 */ 146 uint16_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 250 int 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 297 int 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); 323 out: 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 333 int 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 355 void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig) 356 { 357 if (orig != comprbuf) 358 kfree(comprbuf); 359 } 360 361 int __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 397 int 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