Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
compr.c
Go to the documentation of this file.
1 /*
2  * JFFS2 -- Journalling Flash File System, Version 2.
3  *
4  * Copyright © 2001-2007 Red Hat, Inc.
5  * Copyright © 2004-2010 David Woodhouse <[email protected]>
6  * Copyright © 2004 Ferenc Havasi <[email protected]>,
7  * University of Szeged, Hungary
8  *
9  * Created by Arjan van de Ven <[email protected]>
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) {
39  if (bestsize > size)
40  return 1;
41  return 0;
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  */
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) {
166  break;
168  ret = jffs2_selected_compress(0, data_in, cpage_out, datalen,
169  cdatalen);
170  break;
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;
233  ret = jffs2_selected_compress(JFFS2_COMPR_LZO, data_in,
234  cpage_out, datalen, cdatalen);
235  break;
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 
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 
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 
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 
366 {
367 /* Registering compressors */
368 #ifdef CONFIG_JFFS2_ZLIB
369  jffs2_zlib_init();
370 #endif
371 #ifdef CONFIG_JFFS2_RTIME
373 #endif
374 #ifdef CONFIG_JFFS2_RUBIN
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 
402 {
403 /* Unregistering compressors */
404 #ifdef CONFIG_JFFS2_LZO
405  jffs2_lzo_exit();
406 #endif
407 #ifdef CONFIG_JFFS2_RUBIN
410 #endif
411 #ifdef CONFIG_JFFS2_RTIME
413 #endif
414 #ifdef CONFIG_JFFS2_ZLIB
415  jffs2_zlib_exit();
416 #endif
417  return 0;
418 }