jffs2: implement mount option parsing and compression overriding
[pandora-kernel.git] / fs / jffs2 / compr.c
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 }