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