vserver 1.9.5.x5
[linux-2.6.git] / fs / jffs2 / compr.c
1 /*
2  * JFFS2 -- Journalling Flash File System, Version 2.
3  *
4  * Copyright (C) 2001-2003 Red Hat, Inc.
5  * Created by Arjan van de Ven <arjanv@redhat.com>
6  *
7  * Copyright (C) 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  * $Id: compr.c,v 1.42 2004/08/07 21:56:08 dwmw2 Exp $
13  *
14  */
15
16 #include "compr.h"
17
18 static DEFINE_SPINLOCK(jffs2_compressor_list_lock);
19
20 /* Available compressors are on this list */
21 static LIST_HEAD(jffs2_compressor_list);
22
23 /* Actual compression mode */
24 static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
25
26 void jffs2_set_compression_mode(int mode) 
27 {
28         jffs2_compression_mode = mode;
29 }
30
31 int jffs2_get_compression_mode(void)
32 {
33         return jffs2_compression_mode;
34 }
35
36 /* Statistics for blocks stored without compression */
37 static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0;
38
39 /* jffs2_compress:
40  * @data: Pointer to uncompressed data
41  * @cdata: Pointer to returned pointer to buffer for compressed data
42  * @datalen: On entry, holds the amount of data available for compression.
43  *      On exit, expected to hold the amount of data actually compressed.
44  * @cdatalen: On entry, holds the amount of space available for compressed
45  *      data. On exit, expected to hold the actual size of the compressed
46  *      data.
47  *
48  * Returns: Lower byte to be stored with data indicating compression type used.
49  * Zero is used to show that the data could not be compressed - the 
50  * compressed version was actually larger than the original.
51  * Upper byte will be used later. (soon)
52  *
53  * If the cdata buffer isn't large enough to hold all the uncompressed data,
54  * jffs2_compress should compress as much as will fit, and should set 
55  * *datalen accordingly to show the amount of data which were compressed.
56  */
57 uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
58                              unsigned char *data_in, unsigned char **cpage_out, 
59                              uint32_t *datalen, uint32_t *cdatalen)
60 {
61         int ret = JFFS2_COMPR_NONE;
62         int compr_ret;
63         struct jffs2_compressor *this, *best=NULL;
64         unsigned char *output_buf = NULL, *tmp_buf;
65         uint32_t orig_slen, orig_dlen;
66         uint32_t best_slen=0, best_dlen=0;
67
68         switch (jffs2_compression_mode) {
69         case JFFS2_COMPR_MODE_NONE:
70                 break;
71         case JFFS2_COMPR_MODE_PRIORITY:
72                 output_buf = kmalloc(*cdatalen,GFP_KERNEL);
73                 if (!output_buf) {
74                         printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n");
75                         goto out;
76                 }
77                 orig_slen = *datalen;
78                 orig_dlen = *cdatalen;
79                 spin_lock(&jffs2_compressor_list_lock);
80                 list_for_each_entry(this, &jffs2_compressor_list, list) {
81                         /* Skip decompress-only backwards-compatibility and disabled modules */
82                         if ((!this->compress)||(this->disabled))
83                                 continue;
84
85                         this->usecount++;
86                         spin_unlock(&jffs2_compressor_list_lock);
87                         *datalen  = orig_slen;
88                         *cdatalen = orig_dlen;
89                         compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL);
90                         spin_lock(&jffs2_compressor_list_lock);
91                         this->usecount--;
92                         if (!compr_ret) {
93                                 ret = this->compr;
94                                 this->stat_compr_blocks++;
95                                 this->stat_compr_orig_size += *datalen;
96                                 this->stat_compr_new_size  += *cdatalen;
97                                 break;
98                         }
99                 }
100                 spin_unlock(&jffs2_compressor_list_lock);
101                 if (ret == JFFS2_COMPR_NONE) kfree(output_buf);
102                 break;
103         case JFFS2_COMPR_MODE_SIZE:
104                 orig_slen = *datalen;
105                 orig_dlen = *cdatalen;
106                 spin_lock(&jffs2_compressor_list_lock);
107                 list_for_each_entry(this, &jffs2_compressor_list, list) {
108                         /* Skip decompress-only backwards-compatibility and disabled modules */
109                         if ((!this->compress)||(this->disabled))
110                                 continue;
111                         /* Allocating memory for output buffer if necessary */
112                         if ((this->compr_buf_size<orig_dlen)&&(this->compr_buf)) {
113                                 spin_unlock(&jffs2_compressor_list_lock);
114                                 kfree(this->compr_buf);
115                                 spin_lock(&jffs2_compressor_list_lock);
116                                 this->compr_buf_size=0;
117                                 this->compr_buf=NULL;
118                         }
119                         if (!this->compr_buf) {
120                                 spin_unlock(&jffs2_compressor_list_lock);
121                                 tmp_buf = kmalloc(orig_dlen,GFP_KERNEL);
122                                 spin_lock(&jffs2_compressor_list_lock);
123                                 if (!tmp_buf) {
124                                         printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n",orig_dlen);
125                                         continue;
126                                 }
127                                 else {
128                                         this->compr_buf = tmp_buf;
129                                         this->compr_buf_size = orig_dlen;
130                                 }
131                         }
132                         this->usecount++;
133                         spin_unlock(&jffs2_compressor_list_lock);
134                         *datalen  = orig_slen;
135                         *cdatalen = orig_dlen;
136                         compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL);
137                         spin_lock(&jffs2_compressor_list_lock);
138                         this->usecount--;
139                         if (!compr_ret) {
140                                 if ((!best_dlen)||(best_dlen>*cdatalen)) {
141                                         best_dlen = *cdatalen;
142                                         best_slen = *datalen;
143                                         best = this;
144                                 }
145                         }
146                 }
147                 if (best_dlen) {
148                         *cdatalen = best_dlen;
149                         *datalen  = best_slen;
150                         output_buf = best->compr_buf;
151                         best->compr_buf = NULL;
152                         best->compr_buf_size = 0;
153                         best->stat_compr_blocks++;
154                         best->stat_compr_orig_size += best_slen;
155                         best->stat_compr_new_size  += best_dlen;
156                         ret = best->compr;
157                 }
158                 spin_unlock(&jffs2_compressor_list_lock);
159                 break;
160         default:
161                 printk(KERN_ERR "JFFS2: unknow compression mode.\n");
162         }
163  out:
164         if (ret == JFFS2_COMPR_NONE) {
165                 *cpage_out = data_in;
166                 *datalen = *cdatalen;
167                 none_stat_compr_blocks++;
168                 none_stat_compr_size += *datalen;
169         }
170         else {
171                 *cpage_out = output_buf;
172         }
173         return ret;
174 }
175
176 int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
177                      uint16_t comprtype, unsigned char *cdata_in, 
178                      unsigned char *data_out, uint32_t cdatalen, uint32_t datalen)
179 {
180         struct jffs2_compressor *this;
181         int ret;
182
183         /* Older code had a bug where it would write non-zero 'usercompr'
184            fields. Deal with it. */
185         if ((comprtype & 0xff) <= JFFS2_COMPR_ZLIB)
186                 comprtype &= 0xff;
187
188         switch (comprtype & 0xff) {
189         case JFFS2_COMPR_NONE:
190                 /* This should be special-cased elsewhere, but we might as well deal with it */
191                 memcpy(data_out, cdata_in, datalen);
192                 none_stat_decompr_blocks++;
193                 break;
194         case JFFS2_COMPR_ZERO:
195                 memset(data_out, 0, datalen);
196                 break;
197         default:
198                 spin_lock(&jffs2_compressor_list_lock);
199                 list_for_each_entry(this, &jffs2_compressor_list, list) {
200                         if (comprtype == this->compr) {
201                                 this->usecount++;
202                                 spin_unlock(&jffs2_compressor_list_lock);
203                                 ret = this->decompress(cdata_in, data_out, cdatalen, datalen, NULL);
204                                 spin_lock(&jffs2_compressor_list_lock);
205                                 if (ret) {
206                                         printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret);
207                                 }
208                                 else {
209                                         this->stat_decompr_blocks++;
210                                 }
211                                 this->usecount--;
212                                 spin_unlock(&jffs2_compressor_list_lock);
213                                 return ret;
214                         }
215                 }
216                 printk(KERN_WARNING "JFFS2 compression type 0x%02x not available.\n", comprtype);
217                 spin_unlock(&jffs2_compressor_list_lock);
218                 return -EIO;
219         }
220         return 0;
221 }
222
223 int jffs2_register_compressor(struct jffs2_compressor *comp)
224 {
225         struct jffs2_compressor *this;
226
227         if (!comp->name) {
228                 printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n");
229                 return -1;
230         }
231         comp->compr_buf_size=0;
232         comp->compr_buf=NULL;
233         comp->usecount=0;
234         comp->stat_compr_orig_size=0;
235         comp->stat_compr_new_size=0;
236         comp->stat_compr_blocks=0;
237         comp->stat_decompr_blocks=0;
238         D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name));
239
240         spin_lock(&jffs2_compressor_list_lock);
241
242         list_for_each_entry(this, &jffs2_compressor_list, list) {
243                 if (this->priority < comp->priority) {
244                         list_add(&comp->list, this->list.prev);
245                         goto out;
246                 }
247         }
248         list_add_tail(&comp->list, &jffs2_compressor_list);
249 out:
250         D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
251                 printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
252         })
253
254         spin_unlock(&jffs2_compressor_list_lock);
255
256         return 0;
257 }
258
259 int jffs2_unregister_compressor(struct jffs2_compressor *comp)
260 {
261         D2(struct jffs2_compressor *this;)
262
263         D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name));
264
265         spin_lock(&jffs2_compressor_list_lock);
266
267         if (comp->usecount) {
268                 spin_unlock(&jffs2_compressor_list_lock);
269                 printk(KERN_WARNING "JFFS2: Compressor modul is in use. Unregister failed.\n");
270                 return -1;
271         }
272         list_del(&comp->list);
273
274         D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
275                 printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
276         })
277         spin_unlock(&jffs2_compressor_list_lock);
278         return 0;
279 }
280
281 #ifdef CONFIG_JFFS2_PROC
282
283 #define JFFS2_STAT_BUF_SIZE 16000
284
285 char *jffs2_list_compressors(void)
286 {
287         struct jffs2_compressor *this;
288         char *buf, *act_buf;
289
290         act_buf = buf = kmalloc(JFFS2_STAT_BUF_SIZE,GFP_KERNEL);
291         list_for_each_entry(this, &jffs2_compressor_list, list) {
292                 act_buf += sprintf(act_buf, "%10s priority:%d ", this->name, this->priority);
293                 if ((this->disabled)||(!this->compress))
294                         act_buf += sprintf(act_buf,"disabled");
295                 else
296                         act_buf += sprintf(act_buf,"enabled");
297                 act_buf += sprintf(act_buf,"\n");
298         }
299         return buf;
300 }
301
302 char *jffs2_stats(void)
303 {
304         struct jffs2_compressor *this;
305         char *buf, *act_buf;
306
307         act_buf = buf = kmalloc(JFFS2_STAT_BUF_SIZE,GFP_KERNEL);
308
309         act_buf += sprintf(act_buf,"JFFS2 compressor statistics:\n");
310         act_buf += sprintf(act_buf,"%10s   ","none");
311         act_buf += sprintf(act_buf,"compr: %d blocks (%d)  decompr: %d blocks\n", none_stat_compr_blocks, 
312                            none_stat_compr_size, none_stat_decompr_blocks);
313         spin_lock(&jffs2_compressor_list_lock);
314         list_for_each_entry(this, &jffs2_compressor_list, list) {
315                 act_buf += sprintf(act_buf,"%10s ",this->name);
316                 if ((this->disabled)||(!this->compress))
317                         act_buf += sprintf(act_buf,"- ");
318                 else
319                         act_buf += sprintf(act_buf,"+ ");
320                 act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d)  decompr: %d blocks ", this->stat_compr_blocks, 
321                                    this->stat_compr_new_size, this->stat_compr_orig_size, 
322                                    this->stat_decompr_blocks);
323                 act_buf += sprintf(act_buf,"\n");
324         }
325         spin_unlock(&jffs2_compressor_list_lock);
326
327         return buf;
328 }
329
330 char *jffs2_get_compression_mode_name(void) 
331 {
332         switch (jffs2_compression_mode) {
333         case JFFS2_COMPR_MODE_NONE:
334                 return "none";
335         case JFFS2_COMPR_MODE_PRIORITY:
336                 return "priority";
337         case JFFS2_COMPR_MODE_SIZE:
338                 return "size";
339         }
340         return "unkown";
341 }
342
343 int jffs2_set_compression_mode_name(const char *name) 
344 {
345         if (!strcmp("none",name)) {
346                 jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
347                 return 0;
348         }
349         if (!strcmp("priority",name)) {
350                 jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
351                 return 0;
352         }
353         if (!strcmp("size",name)) {
354                 jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
355                 return 0;
356         }
357         return 1;
358 }
359
360 static int jffs2_compressor_Xable(const char *name, int disabled)
361 {
362         struct jffs2_compressor *this;
363         spin_lock(&jffs2_compressor_list_lock);
364         list_for_each_entry(this, &jffs2_compressor_list, list) {
365                 if (!strcmp(this->name, name)) {
366                         this->disabled = disabled;
367                         spin_unlock(&jffs2_compressor_list_lock);
368                         return 0;                        
369                 }
370         }
371         spin_unlock(&jffs2_compressor_list_lock);
372         printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name);
373         return 1;
374 }
375
376 int jffs2_enable_compressor_name(const char *name)
377 {
378         return jffs2_compressor_Xable(name, 0);
379 }
380
381 int jffs2_disable_compressor_name(const char *name)
382 {
383         return jffs2_compressor_Xable(name, 1);
384 }
385
386 int jffs2_set_compressor_priority(const char *name, int priority)
387 {
388         struct jffs2_compressor *this,*comp;
389         spin_lock(&jffs2_compressor_list_lock);
390         list_for_each_entry(this, &jffs2_compressor_list, list) {
391                 if (!strcmp(this->name, name)) {
392                         this->priority = priority;
393                         comp = this;
394                         goto reinsert;
395                 }
396         }
397         spin_unlock(&jffs2_compressor_list_lock);
398         printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name);        
399         return 1;
400 reinsert:
401         /* list is sorted in the order of priority, so if
402            we change it we have to reinsert it into the
403            good place */
404         list_del(&comp->list);
405         list_for_each_entry(this, &jffs2_compressor_list, list) {
406                 if (this->priority < comp->priority) {
407                         list_add(&comp->list, this->list.prev);
408                         spin_unlock(&jffs2_compressor_list_lock);
409                         return 0;
410                 }
411         }
412         list_add_tail(&comp->list, &jffs2_compressor_list);
413         spin_unlock(&jffs2_compressor_list_lock);
414         return 0;
415 }
416
417 #endif
418
419 void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
420 {
421         if (orig != comprbuf)
422                 kfree(comprbuf);
423 }
424
425 int jffs2_compressors_init(void) 
426 {
427 /* Registering compressors */
428 #ifdef CONFIG_JFFS2_ZLIB
429         jffs2_zlib_init();
430 #endif
431 #ifdef CONFIG_JFFS2_RTIME
432         jffs2_rtime_init();
433 #endif
434 #ifdef CONFIG_JFFS2_RUBIN
435         jffs2_rubinmips_init();
436         jffs2_dynrubin_init();
437 #endif
438 #ifdef CONFIG_JFFS2_LZARI
439         jffs2_lzari_init();
440 #endif
441 #ifdef CONFIG_JFFS2_LZO
442         jffs2_lzo_init();
443 #endif
444 /* Setting default compression mode */
445 #ifdef CONFIG_JFFS2_CMODE_NONE
446         jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
447         D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");)
448 #else
449 #ifdef CONFIG_JFFS2_CMODE_SIZE
450         jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
451         D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");)
452 #else
453         D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");)
454 #endif
455 #endif
456         return 0;
457 }
458
459 int jffs2_compressors_exit(void) 
460 {
461 /* Unregistering compressors */
462 #ifdef CONFIG_JFFS2_LZO
463         jffs2_lzo_exit();
464 #endif
465 #ifdef CONFIG_JFFS2_LZARI
466         jffs2_lzari_exit();
467 #endif
468 #ifdef CONFIG_JFFS2_RUBIN
469         jffs2_dynrubin_exit();
470         jffs2_rubinmips_exit();
471 #endif
472 #ifdef CONFIG_JFFS2_RTIME
473         jffs2_rtime_exit();
474 #endif
475 #ifdef CONFIG_JFFS2_ZLIB
476         jffs2_zlib_exit();
477 #endif
478         return 0;
479 }