[JFFS2] Add LZO compression support.
[safe/jmp/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 /* jffs2_compress:
28  * @data: Pointer to uncompressed data
29  * @cdata: Pointer to returned pointer to buffer for compressed data
30  * @datalen: On entry, holds the amount of data available for compression.
31  *      On exit, expected to hold the amount of data actually compressed.
32  * @cdatalen: On entry, holds the amount of space available for compressed
33  *      data. On exit, expected to hold the actual size of the compressed
34  *      data.
35  *
36  * Returns: Lower byte to be stored with data indicating compression type used.
37  * Zero is used to show that the data could not be compressed - the
38  * compressed version was actually larger than the original.
39  * Upper byte will be used later. (soon)
40  *
41  * If the cdata buffer isn't large enough to hold all the uncompressed data,
42  * jffs2_compress should compress as much as will fit, and should set
43  * *datalen accordingly to show the amount of data which were compressed.
44  */
45 uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
46                         unsigned char *data_in, unsigned char **cpage_out,
47                         uint32_t *datalen, uint32_t *cdatalen)
48 {
49         int ret = JFFS2_COMPR_NONE;
50         int compr_ret;
51         struct jffs2_compressor *this, *best=NULL;
52         unsigned char *output_buf = NULL, *tmp_buf;
53         uint32_t orig_slen, orig_dlen;
54         uint32_t best_slen=0, best_dlen=0;
55
56         switch (jffs2_compression_mode) {
57         case JFFS2_COMPR_MODE_NONE:
58                 break;
59         case JFFS2_COMPR_MODE_PRIORITY:
60                 output_buf = kmalloc(*cdatalen,GFP_KERNEL);
61                 if (!output_buf) {
62                         printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n");
63                         goto out;
64                 }
65                 orig_slen = *datalen;
66                 orig_dlen = *cdatalen;
67                 spin_lock(&jffs2_compressor_list_lock);
68                 list_for_each_entry(this, &jffs2_compressor_list, list) {
69                         /* Skip decompress-only backwards-compatibility and disabled modules */
70                         if ((!this->compress)||(this->disabled))
71                                 continue;
72
73                         this->usecount++;
74                         spin_unlock(&jffs2_compressor_list_lock);
75                         *datalen  = orig_slen;
76                         *cdatalen = orig_dlen;
77                         compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL);
78                         spin_lock(&jffs2_compressor_list_lock);
79                         this->usecount--;
80                         if (!compr_ret) {
81                                 ret = this->compr;
82                                 this->stat_compr_blocks++;
83                                 this->stat_compr_orig_size += *datalen;
84                                 this->stat_compr_new_size  += *cdatalen;
85                                 break;
86                         }
87                 }
88                 spin_unlock(&jffs2_compressor_list_lock);
89                 if (ret == JFFS2_COMPR_NONE)
90                         kfree(output_buf);
91                 break;
92         case JFFS2_COMPR_MODE_SIZE:
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                         /* Allocating memory for output buffer if necessary */
101                         if ((this->compr_buf_size<orig_dlen)&&(this->compr_buf)) {
102                                 spin_unlock(&jffs2_compressor_list_lock);
103                                 kfree(this->compr_buf);
104                                 spin_lock(&jffs2_compressor_list_lock);
105                                 this->compr_buf_size=0;
106                                 this->compr_buf=NULL;
107                         }
108                         if (!this->compr_buf) {
109                                 spin_unlock(&jffs2_compressor_list_lock);
110                                 tmp_buf = kmalloc(orig_dlen,GFP_KERNEL);
111                                 spin_lock(&jffs2_compressor_list_lock);
112                                 if (!tmp_buf) {
113                                         printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n",orig_dlen);
114                                         continue;
115                                 }
116                                 else {
117                                         this->compr_buf = tmp_buf;
118                                         this->compr_buf_size = orig_dlen;
119                                 }
120                         }
121                         this->usecount++;
122                         spin_unlock(&jffs2_compressor_list_lock);
123                         *datalen  = orig_slen;
124                         *cdatalen = orig_dlen;
125                         compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL);
126                         spin_lock(&jffs2_compressor_list_lock);
127                         this->usecount--;
128                         if (!compr_ret) {
129                                 if ((!best_dlen)||(best_dlen>*cdatalen)) {
130                                         best_dlen = *cdatalen;
131                                         best_slen = *datalen;
132                                         best = this;
133                                 }
134                         }
135                 }
136                 if (best_dlen) {
137                         *cdatalen = best_dlen;
138                         *datalen  = best_slen;
139                         output_buf = best->compr_buf;
140                         best->compr_buf = NULL;
141                         best->compr_buf_size = 0;
142                         best->stat_compr_blocks++;
143                         best->stat_compr_orig_size += best_slen;
144                         best->stat_compr_new_size  += best_dlen;
145                         ret = best->compr;
146                 }
147                 spin_unlock(&jffs2_compressor_list_lock);
148                 break;
149         default:
150                 printk(KERN_ERR "JFFS2: unknow compression mode.\n");
151         }
152  out:
153         if (ret == JFFS2_COMPR_NONE) {
154                 *cpage_out = data_in;
155                 *datalen = *cdatalen;
156                 none_stat_compr_blocks++;
157                 none_stat_compr_size += *datalen;
158         }
159         else {
160                 *cpage_out = output_buf;
161         }
162         return ret;
163 }
164
165 int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
166                      uint16_t comprtype, unsigned char *cdata_in,
167                      unsigned char *data_out, uint32_t cdatalen, uint32_t datalen)
168 {
169         struct jffs2_compressor *this;
170         int ret;
171
172         /* Older code had a bug where it would write non-zero 'usercompr'
173            fields. Deal with it. */
174         if ((comprtype & 0xff) <= JFFS2_COMPR_ZLIB)
175                 comprtype &= 0xff;
176
177         switch (comprtype & 0xff) {
178         case JFFS2_COMPR_NONE:
179                 /* This should be special-cased elsewhere, but we might as well deal with it */
180                 memcpy(data_out, cdata_in, datalen);
181                 none_stat_decompr_blocks++;
182                 break;
183         case JFFS2_COMPR_ZERO:
184                 memset(data_out, 0, datalen);
185                 break;
186         default:
187                 spin_lock(&jffs2_compressor_list_lock);
188                 list_for_each_entry(this, &jffs2_compressor_list, list) {
189                         if (comprtype == this->compr) {
190                                 this->usecount++;
191                                 spin_unlock(&jffs2_compressor_list_lock);
192                                 ret = this->decompress(cdata_in, data_out, cdatalen, datalen, NULL);
193                                 spin_lock(&jffs2_compressor_list_lock);
194                                 if (ret) {
195                                         printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret);
196                                 }
197                                 else {
198                                         this->stat_decompr_blocks++;
199                                 }
200                                 this->usecount--;
201                                 spin_unlock(&jffs2_compressor_list_lock);
202                                 return ret;
203                         }
204                 }
205                 printk(KERN_WARNING "JFFS2 compression type 0x%02x not available.\n", comprtype);
206                 spin_unlock(&jffs2_compressor_list_lock);
207                 return -EIO;
208         }
209         return 0;
210 }
211
212 int jffs2_register_compressor(struct jffs2_compressor *comp)
213 {
214         struct jffs2_compressor *this;
215
216         if (!comp->name) {
217                 printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n");
218                 return -1;
219         }
220         comp->compr_buf_size=0;
221         comp->compr_buf=NULL;
222         comp->usecount=0;
223         comp->stat_compr_orig_size=0;
224         comp->stat_compr_new_size=0;
225         comp->stat_compr_blocks=0;
226         comp->stat_decompr_blocks=0;
227         D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name));
228
229         spin_lock(&jffs2_compressor_list_lock);
230
231         list_for_each_entry(this, &jffs2_compressor_list, list) {
232                 if (this->priority < comp->priority) {
233                         list_add(&comp->list, this->list.prev);
234                         goto out;
235                 }
236         }
237         list_add_tail(&comp->list, &jffs2_compressor_list);
238 out:
239         D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
240                 printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
241         })
242
243         spin_unlock(&jffs2_compressor_list_lock);
244
245         return 0;
246 }
247
248 int jffs2_unregister_compressor(struct jffs2_compressor *comp)
249 {
250         D2(struct jffs2_compressor *this;)
251
252         D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name));
253
254         spin_lock(&jffs2_compressor_list_lock);
255
256         if (comp->usecount) {
257                 spin_unlock(&jffs2_compressor_list_lock);
258                 printk(KERN_WARNING "JFFS2: Compressor modul is in use. Unregister failed.\n");
259                 return -1;
260         }
261         list_del(&comp->list);
262
263         D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
264                 printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
265         })
266         spin_unlock(&jffs2_compressor_list_lock);
267         return 0;
268 }
269
270 void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
271 {
272         if (orig != comprbuf)
273                 kfree(comprbuf);
274 }
275
276 int __init jffs2_compressors_init(void)
277 {
278 /* Registering compressors */
279 #ifdef CONFIG_JFFS2_ZLIB
280         jffs2_zlib_init();
281 #endif
282 #ifdef CONFIG_JFFS2_RTIME
283         jffs2_rtime_init();
284 #endif
285 #ifdef CONFIG_JFFS2_RUBIN
286         jffs2_rubinmips_init();
287         jffs2_dynrubin_init();
288 #endif
289 #ifdef CONFIG_JFFS2_LZO
290         jffs2_lzo_init();
291 #endif
292 /* Setting default compression mode */
293 #ifdef CONFIG_JFFS2_CMODE_NONE
294         jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
295         D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");)
296 #else
297 #ifdef CONFIG_JFFS2_CMODE_SIZE
298         jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
299         D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");)
300 #else
301         D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");)
302 #endif
303 #endif
304         return 0;
305 }
306
307 int jffs2_compressors_exit(void)
308 {
309 /* Unregistering compressors */
310 #ifdef CONFIG_JFFS2_LZO
311         jffs2_lzo_exit();
312 #endif
313 #ifdef CONFIG_JFFS2_RUBIN
314         jffs2_dynrubin_exit();
315         jffs2_rubinmips_exit();
316 #endif
317 #ifdef CONFIG_JFFS2_RTIME
318         jffs2_rtime_exit();
319 #endif
320 #ifdef CONFIG_JFFS2_ZLIB
321         jffs2_zlib_exit();
322 #endif
323         return 0;
324 }