Branch data Line data Source code
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 : 0 : static int jffs2_is_best_compression(struct jffs2_compressor *this,
35 : : struct jffs2_compressor *best, uint32_t size, uint32_t bestsize)
36 : : {
37 [ # # # ]: 0 : switch (jffs2_compression_mode) {
38 : : case JFFS2_COMPR_MODE_SIZE:
39 [ # # ]: 0 : if (bestsize > size)
40 : : return 1;
41 : : return 0;
42 : : case JFFS2_COMPR_MODE_FAVOURLZO:
43 [ # # ][ # # ]: 0 : if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > size))
44 : : return 1;
45 [ # # ][ # # ]: 0 : if ((best->compr != JFFS2_COMPR_LZO) && (bestsize > size))
46 : : return 1;
47 [ # # ][ # # ]: 0 : if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > (size * FAVOUR_LZO_PERCENT / 100)))
48 : : return 1;
49 [ # # ]: 0 : 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 : 0 : 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 : 0 : output_buf = kmalloc(*cdatalen, GFP_KERNEL);
83 [ # # ]: 0 : if (!output_buf) {
84 : 0 : pr_warn("No memory for compressor allocation. Compression failed.\n");
85 : 0 : return ret;
86 : : }
87 : 0 : orig_slen = *datalen;
88 : 0 : orig_dlen = *cdatalen;
89 : : spin_lock(&jffs2_compressor_list_lock);
90 [ # # ]: 0 : list_for_each_entry(this, &jffs2_compressor_list, list) {
91 : : /* Skip decompress-only and disabled modules */
92 [ # # ][ # # ]: 0 : if (!this->compress || this->disabled)
93 : 0 : continue;
94 : :
95 : : /* Skip if not the desired compression type */
96 [ # # ][ # # ]: 0 : if (compr && (compr != this->compr))
97 : 0 : continue;
98 : :
99 : : /*
100 : : * Either compression type was unspecified, or we found our
101 : : * compressor; either way, we're good to go.
102 : : */
103 : 0 : this->usecount++;
104 : : spin_unlock(&jffs2_compressor_list_lock);
105 : :
106 : 0 : *datalen = orig_slen;
107 : 0 : *cdatalen = orig_dlen;
108 : 0 : err = this->compress(data_in, output_buf, datalen, cdatalen);
109 : :
110 : : spin_lock(&jffs2_compressor_list_lock);
111 : 0 : this->usecount--;
112 [ # # ]: 0 : if (!err) {
113 : : /* Success */
114 : 0 : ret = this->compr;
115 : 0 : this->stat_compr_blocks++;
116 : 0 : this->stat_compr_orig_size += *datalen;
117 : 0 : this->stat_compr_new_size += *cdatalen;
118 : 0 : break;
119 : : }
120 : : }
121 : : spin_unlock(&jffs2_compressor_list_lock);
122 [ # # ]: 0 : if (ret == JFFS2_COMPR_NONE)
123 : 0 : kfree(output_buf);
124 : : else
125 : 0 : *cpage_out = output_buf;
126 : :
127 : 0 : 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 : 0 : 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 [ # # ]: 0 : if (c->mount_opts.override_compr)
160 : 0 : mode = c->mount_opts.compr;
161 : : else
162 : 0 : mode = jffs2_compression_mode;
163 : :
164 [ # # # # : 0 : switch (mode) {
# # ]
165 : : case JFFS2_COMPR_MODE_NONE:
166 : : break;
167 : : case JFFS2_COMPR_MODE_PRIORITY:
168 : 0 : ret = jffs2_selected_compress(0, data_in, cpage_out, datalen,
169 : : cdatalen);
170 : 0 : break;
171 : : case JFFS2_COMPR_MODE_SIZE:
172 : : case JFFS2_COMPR_MODE_FAVOURLZO:
173 : 0 : orig_slen = *datalen;
174 : 0 : orig_dlen = *cdatalen;
175 : : spin_lock(&jffs2_compressor_list_lock);
176 [ # # ]: 0 : list_for_each_entry(this, &jffs2_compressor_list, list) {
177 : : /* Skip decompress-only backwards-compatibility and disabled modules */
178 [ # # ][ # # ]: 0 : if ((!this->compress)||(this->disabled))
179 : 0 : continue;
180 : : /* Allocating memory for output buffer if necessary */
181 [ # # ][ # # ]: 0 : if ((this->compr_buf_size < orig_slen) && (this->compr_buf)) {
182 : : spin_unlock(&jffs2_compressor_list_lock);
183 : 0 : kfree(this->compr_buf);
184 : : spin_lock(&jffs2_compressor_list_lock);
185 : 0 : this->compr_buf_size=0;
186 : 0 : this->compr_buf=NULL;
187 : : }
188 [ # # ]: 0 : 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 [ # # ]: 0 : if (!tmp_buf) {
193 : 0 : pr_warn("No memory for compressor allocation. (%d bytes)\n",
194 : : orig_slen);
195 : 0 : continue;
196 : : }
197 : : else {
198 : 0 : this->compr_buf = tmp_buf;
199 : 0 : this->compr_buf_size = orig_slen;
200 : : }
201 : : }
202 : 0 : this->usecount++;
203 : : spin_unlock(&jffs2_compressor_list_lock);
204 : 0 : *datalen = orig_slen;
205 : 0 : *cdatalen = orig_dlen;
206 : 0 : compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen);
207 : : spin_lock(&jffs2_compressor_list_lock);
208 : 0 : this->usecount--;
209 [ # # ]: 0 : if (!compr_ret) {
210 [ # # ][ # # ]: 0 : if (((!best_dlen) || jffs2_is_best_compression(this, best, *cdatalen, best_dlen))
211 [ # # ]: 0 : && (*cdatalen < *datalen)) {
212 : : best_dlen = *cdatalen;
213 : : best_slen = *datalen;
214 : : best = this;
215 : : }
216 : : }
217 : : }
218 [ # # ]: 0 : if (best_dlen) {
219 : 0 : *cdatalen = best_dlen;
220 : 0 : *datalen = best_slen;
221 : 0 : output_buf = best->compr_buf;
222 : 0 : best->compr_buf = NULL;
223 : 0 : best->compr_buf_size = 0;
224 : 0 : best->stat_compr_blocks++;
225 : 0 : best->stat_compr_orig_size += best_slen;
226 : 0 : best->stat_compr_new_size += best_dlen;
227 : 0 : ret = best->compr;
228 : 0 : *cpage_out = output_buf;
229 : : }
230 : : spin_unlock(&jffs2_compressor_list_lock);
231 : : break;
232 : : case JFFS2_COMPR_MODE_FORCELZO:
233 : 0 : ret = jffs2_selected_compress(JFFS2_COMPR_LZO, data_in,
234 : : cpage_out, datalen, cdatalen);
235 : 0 : break;
236 : : case JFFS2_COMPR_MODE_FORCEZLIB:
237 : 0 : ret = jffs2_selected_compress(JFFS2_COMPR_ZLIB, data_in,
238 : : cpage_out, datalen, cdatalen);
239 : 0 : break;
240 : : default:
241 : 0 : pr_err("unknown compression mode\n");
242 : : }
243 : :
244 [ # # ]: 0 : if (ret == JFFS2_COMPR_NONE) {
245 : 0 : *cpage_out = data_in;
246 : 0 : *datalen = *cdatalen;
247 : 0 : none_stat_compr_blocks++;
248 : 0 : none_stat_compr_size += *datalen;
249 : : }
250 : 0 : return ret;
251 : : }
252 : :
253 : 0 : 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 [ # # ]: 0 : if ((comprtype & 0xff) <= JFFS2_COMPR_ZLIB)
263 : : comprtype &= 0xff;
264 : :
265 [ # # # ]: 0 : switch (comprtype & 0xff) {
266 : : case JFFS2_COMPR_NONE:
267 : : /* This should be special-cased elsewhere, but we might as well deal with it */
268 : 0 : memcpy(data_out, cdata_in, datalen);
269 : 0 : none_stat_decompr_blocks++;
270 : 0 : break;
271 : : case JFFS2_COMPR_ZERO:
272 [ # # ]: 0 : memset(data_out, 0, datalen);
273 : : break;
274 : : default:
275 : : spin_lock(&jffs2_compressor_list_lock);
276 [ # # ]: 0 : list_for_each_entry(this, &jffs2_compressor_list, list) {
277 [ # # ]: 0 : if (comprtype == this->compr) {
278 : 0 : this->usecount++;
279 : : spin_unlock(&jffs2_compressor_list_lock);
280 : 0 : ret = this->decompress(cdata_in, data_out, cdatalen, datalen);
281 : : spin_lock(&jffs2_compressor_list_lock);
282 [ # # ]: 0 : if (ret) {
283 : 0 : pr_warn("Decompressor \"%s\" returned %d\n",
284 : : this->name, ret);
285 : : }
286 : : else {
287 : 0 : this->stat_decompr_blocks++;
288 : : }
289 : 0 : this->usecount--;
290 : : spin_unlock(&jffs2_compressor_list_lock);
291 : 0 : return ret;
292 : : }
293 : : }
294 : 0 : pr_warn("compression type 0x%02x not available\n", comprtype);
295 : : spin_unlock(&jffs2_compressor_list_lock);
296 : 0 : return -EIO;
297 : : }
298 : : return 0;
299 : : }
300 : :
301 : 0 : int jffs2_register_compressor(struct jffs2_compressor *comp)
302 : : {
303 : : struct jffs2_compressor *this;
304 : :
305 [ # # ]: 0 : if (!comp->name) {
306 : 0 : pr_warn("NULL compressor name at registering JFFS2 compressor. Failed.\n");
307 : 0 : return -1;
308 : : }
309 : 0 : comp->compr_buf_size=0;
310 : 0 : comp->compr_buf=NULL;
311 : 0 : comp->usecount=0;
312 : 0 : comp->stat_compr_orig_size=0;
313 : 0 : comp->stat_compr_new_size=0;
314 : 0 : comp->stat_compr_blocks=0;
315 : 0 : 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 [ # # ]: 0 : list_for_each_entry(this, &jffs2_compressor_list, list) {
321 [ # # ]: 0 : if (this->priority < comp->priority) {
322 : 0 : list_add(&comp->list, this->list.prev);
323 : : goto out;
324 : : }
325 : : }
326 : 0 : 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 : 0 : return 0;
335 : : }
336 : :
337 : 0 : 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 [ # # ]: 0 : if (comp->usecount) {
346 : : spin_unlock(&jffs2_compressor_list_lock);
347 : 0 : pr_warn("Compressor module is in use. Unregister failed.\n");
348 : 0 : 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 : 0 : return 0;
357 : : }
358 : :
359 : 0 : void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
360 : : {
361 [ # # ]: 0 : if (orig != comprbuf)
362 : 0 : kfree(comprbuf);
363 : 0 : }
364 : :
365 : 0 : int __init jffs2_compressors_init(void)
366 : : {
367 : : /* Registering compressors */
368 : : #ifdef CONFIG_JFFS2_ZLIB
369 : 0 : jffs2_zlib_init();
370 : : #endif
371 : : #ifdef CONFIG_JFFS2_RTIME
372 : 0 : jffs2_rtime_init();
373 : : #endif
374 : : #ifdef CONFIG_JFFS2_RUBIN
375 : 0 : jffs2_rubinmips_init();
376 : 0 : jffs2_dynrubin_init();
377 : : #endif
378 : : #ifdef CONFIG_JFFS2_LZO
379 : 0 : 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 : 0 : return 0;
399 : : }
400 : :
401 : 0 : int jffs2_compressors_exit(void)
402 : : {
403 : : /* Unregistering compressors */
404 : : #ifdef CONFIG_JFFS2_LZO
405 : 0 : jffs2_lzo_exit();
406 : : #endif
407 : : #ifdef CONFIG_JFFS2_RUBIN
408 : 0 : jffs2_dynrubin_exit();
409 : 0 : jffs2_rubinmips_exit();
410 : : #endif
411 : : #ifdef CONFIG_JFFS2_RTIME
412 : 0 : jffs2_rtime_exit();
413 : : #endif
414 : : #ifdef CONFIG_JFFS2_ZLIB
415 : 0 : jffs2_zlib_exit();
416 : : #endif
417 : 0 : return 0;
418 : : }
|