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 /* jffs2_compress: 57 * @data_in: Pointer to uncompressed data 58 * @cpage_out: Pointer to returned pointer to buffer for compressed data 59 * @datalen: On entry, holds the amount of data available for compression. 60 * On exit, expected to hold the amount of data actually compressed. 61 * @cdatalen: On entry, holds the amount of space available for compressed 62 * data. On exit, expected to hold the actual size of the compressed 63 * data. 64 * 65 * Returns: Lower byte to be stored with data indicating compression type used. 66 * Zero is used to show that the data could not be compressed - the 67 * compressed version was actually larger than the original. 68 * Upper byte will be used later. (soon) 69 * 70 * If the cdata buffer isn't large enough to hold all the uncompressed data, 71 * jffs2_compress should compress as much as will fit, and should set 72 * *datalen accordingly to show the amount of data which were compressed. 73 */ 74 uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, 75 unsigned char *data_in, unsigned char **cpage_out, 76 uint32_t *datalen, uint32_t *cdatalen) 77 { 78 int ret = JFFS2_COMPR_NONE; 79 int mode, compr_ret; 80 struct jffs2_compressor *this, *best=NULL; 81 unsigned char *output_buf = NULL, *tmp_buf; 82 uint32_t orig_slen, orig_dlen; 83 uint32_t best_slen=0, best_dlen=0; 84 85 if (c->mount_opts.override_compr) 86 mode = c->mount_opts.compr; 87 else 88 mode = jffs2_compression_mode; 89 90 switch (mode) { 91 case JFFS2_COMPR_MODE_NONE: 92 break; 93 case JFFS2_COMPR_MODE_PRIORITY: 94 output_buf = kmalloc(*cdatalen,GFP_KERNEL); 95 if (!output_buf) { 96 printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n"); 97 goto out; 98 } 99 orig_slen = *datalen; 100 orig_dlen = *cdatalen; 101 spin_lock(&jffs2_compressor_list_lock); 102 list_for_each_entry(this, &jffs2_compressor_list, list) { 103 /* Skip decompress-only backwards-compatibility and disabled modules */ 104 if ((!this->compress)||(this->disabled)) 105 continue; 106 107 this->usecount++; 108 spin_unlock(&jffs2_compressor_list_lock); 109 *datalen = orig_slen; 110 *cdatalen = orig_dlen; 111 compr_ret = this->compress(data_in, output_buf, datalen, cdatalen); 112 spin_lock(&jffs2_compressor_list_lock); 113 this->usecount--; 114 if (!compr_ret) { 115 ret = this->compr; 116 this->stat_compr_blocks++; 117 this->stat_compr_orig_size += *datalen; 118 this->stat_compr_new_size += *cdatalen; 119 break; 120 } 121 } 122 spin_unlock(&jffs2_compressor_list_lock); 123 if (ret == JFFS2_COMPR_NONE) 124 kfree(output_buf); 125 break; 126 case JFFS2_COMPR_MODE_SIZE: 127 case JFFS2_COMPR_MODE_FAVOURLZO: 128 orig_slen = *datalen; 129 orig_dlen = *cdatalen; 130 spin_lock(&jffs2_compressor_list_lock); 131 list_for_each_entry(this, &jffs2_compressor_list, list) { 132 /* Skip decompress-only backwards-compatibility and disabled modules */ 133 if ((!this->compress)||(this->disabled)) 134 continue; 135 /* Allocating memory for output buffer if necessary */ 136 if ((this->compr_buf_size < orig_slen) && (this->compr_buf)) { 137 spin_unlock(&jffs2_compressor_list_lock); 138 kfree(this->compr_buf); 139 spin_lock(&jffs2_compressor_list_lock); 140 this->compr_buf_size=0; 141 this->compr_buf=NULL; 142 } 143 if (!this->compr_buf) { 144 spin_unlock(&jffs2_compressor_list_lock); 145 tmp_buf = kmalloc(orig_slen, GFP_KERNEL); 146 spin_lock(&jffs2_compressor_list_lock); 147 if (!tmp_buf) { 148 printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n", orig_slen); 149 continue; 150 } 151 else { 152 this->compr_buf = tmp_buf; 153 this->compr_buf_size = orig_slen; 154 } 155 } 156 this->usecount++; 157 spin_unlock(&jffs2_compressor_list_lock); 158 *datalen = orig_slen; 159 *cdatalen = orig_dlen; 160 compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen); 161 spin_lock(&jffs2_compressor_list_lock); 162 this->usecount--; 163 if (!compr_ret) { 164 if (((!best_dlen) || jffs2_is_best_compression(this, best, *cdatalen, best_dlen)) 165 && (*cdatalen < *datalen)) { 166 best_dlen = *cdatalen; 167 best_slen = *datalen; 168 best = this; 169 } 170 } 171 } 172 if (best_dlen) { 173 *cdatalen = best_dlen; 174 *datalen = best_slen; 175 output_buf = best->compr_buf; 176 best->compr_buf = NULL; 177 best->compr_buf_size = 0; 178 best->stat_compr_blocks++; 179 best->stat_compr_orig_size += best_slen; 180 best->stat_compr_new_size += best_dlen; 181 ret = best->compr; 182 } 183 spin_unlock(&jffs2_compressor_list_lock); 184 break; 185 default: 186 printk(KERN_ERR "JFFS2: unknown compression mode.\n"); 187 } 188 out: 189 if (ret == JFFS2_COMPR_NONE) { 190 *cpage_out = data_in; 191 *datalen = *cdatalen; 192 none_stat_compr_blocks++; 193 none_stat_compr_size += *datalen; 194 } 195 else { 196 *cpage_out = output_buf; 197 } 198 return ret; 199 } 200 201 int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, 202 uint16_t comprtype, unsigned char *cdata_in, 203 unsigned char *data_out, uint32_t cdatalen, uint32_t datalen) 204 { 205 struct jffs2_compressor *this; 206 int ret; 207 208 /* Older code had a bug where it would write non-zero 'usercompr' 209 fields. Deal with it. */ 210 if ((comprtype & 0xff) <= JFFS2_COMPR_ZLIB) 211 comprtype &= 0xff; 212 213 switch (comprtype & 0xff) { 214 case JFFS2_COMPR_NONE: 215 /* This should be special-cased elsewhere, but we might as well deal with it */ 216 memcpy(data_out, cdata_in, datalen); 217 none_stat_decompr_blocks++; 218 break; 219 case JFFS2_COMPR_ZERO: 220 memset(data_out, 0, datalen); 221 break; 222 default: 223 spin_lock(&jffs2_compressor_list_lock); 224 list_for_each_entry(this, &jffs2_compressor_list, list) { 225 if (comprtype == this->compr) { 226 this->usecount++; 227 spin_unlock(&jffs2_compressor_list_lock); 228 ret = this->decompress(cdata_in, data_out, cdatalen, datalen); 229 spin_lock(&jffs2_compressor_list_lock); 230 if (ret) { 231 printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret); 232 } 233 else { 234 this->stat_decompr_blocks++; 235 } 236 this->usecount--; 237 spin_unlock(&jffs2_compressor_list_lock); 238 return ret; 239 } 240 } 241 printk(KERN_WARNING "JFFS2 compression type 0x%02x not available.\n", comprtype); 242 spin_unlock(&jffs2_compressor_list_lock); 243 return -EIO; 244 } 245 return 0; 246 } 247 248 int jffs2_register_compressor(struct jffs2_compressor *comp) 249 { 250 struct jffs2_compressor *this; 251 252 if (!comp->name) { 253 printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n"); 254 return -1; 255 } 256 comp->compr_buf_size=0; 257 comp->compr_buf=NULL; 258 comp->usecount=0; 259 comp->stat_compr_orig_size=0; 260 comp->stat_compr_new_size=0; 261 comp->stat_compr_blocks=0; 262 comp->stat_decompr_blocks=0; 263 D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name)); 264 265 spin_lock(&jffs2_compressor_list_lock); 266 267 list_for_each_entry(this, &jffs2_compressor_list, list) { 268 if (this->priority < comp->priority) { 269 list_add(&comp->list, this->list.prev); 270 goto out; 271 } 272 } 273 list_add_tail(&comp->list, &jffs2_compressor_list); 274 out: 275 D2(list_for_each_entry(this, &jffs2_compressor_list, list) { 276 printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority); 277 }) 278 279 spin_unlock(&jffs2_compressor_list_lock); 280 281 return 0; 282 } 283 284 int jffs2_unregister_compressor(struct jffs2_compressor *comp) 285 { 286 D2(struct jffs2_compressor *this;) 287 288 D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name)); 289 290 spin_lock(&jffs2_compressor_list_lock); 291 292 if (comp->usecount) { 293 spin_unlock(&jffs2_compressor_list_lock); 294 printk(KERN_WARNING "JFFS2: Compressor modul is in use. Unregister failed.\n"); 295 return -1; 296 } 297 list_del(&comp->list); 298 299 D2(list_for_each_entry(this, &jffs2_compressor_list, list) { 300 printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority); 301 }) 302 spin_unlock(&jffs2_compressor_list_lock); 303 return 0; 304 } 305 306 void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig) 307 { 308 if (orig != comprbuf) 309 kfree(comprbuf); 310 } 311 312 int __init jffs2_compressors_init(void) 313 { 314 /* Registering compressors */ 315 #ifdef CONFIG_JFFS2_ZLIB 316 jffs2_zlib_init(); 317 #endif 318 #ifdef CONFIG_JFFS2_RTIME 319 jffs2_rtime_init(); 320 #endif 321 #ifdef CONFIG_JFFS2_RUBIN 322 jffs2_rubinmips_init(); 323 jffs2_dynrubin_init(); 324 #endif 325 #ifdef CONFIG_JFFS2_LZO 326 jffs2_lzo_init(); 327 #endif 328 /* Setting default compression mode */ 329 #ifdef CONFIG_JFFS2_CMODE_NONE 330 jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; 331 D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");) 332 #else 333 #ifdef CONFIG_JFFS2_CMODE_SIZE 334 jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE; 335 D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");) 336 #else 337 #ifdef CONFIG_JFFS2_CMODE_FAVOURLZO 338 jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO; 339 D1(printk(KERN_INFO "JFFS2: default compression mode: favourlzo\n");) 340 #else 341 D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");) 342 #endif 343 #endif 344 #endif 345 return 0; 346 } 347 348 int jffs2_compressors_exit(void) 349 { 350 /* Unregistering compressors */ 351 #ifdef CONFIG_JFFS2_LZO 352 jffs2_lzo_exit(); 353 #endif 354 #ifdef CONFIG_JFFS2_RUBIN 355 jffs2_dynrubin_exit(); 356 jffs2_rubinmips_exit(); 357 #endif 358 #ifdef CONFIG_JFFS2_RTIME 359 jffs2_rtime_exit(); 360 #endif 361 #ifdef CONFIG_JFFS2_ZLIB 362 jffs2_zlib_exit(); 363 #endif 364 return 0; 365 } 366