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