Root/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
16static DEFINE_SPINLOCK(jffs2_compressor_list_lock);
17
18/* Available compressors are on this list */
19static LIST_HEAD(jffs2_compressor_list);
20
21/* Actual compression mode */
22static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
23
24/* Statistics for blocks stored without compression */
25static 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 */
31static 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 */
73uint16_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
195int 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
242int 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);
268out:
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
278int 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
300void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
301{
302    if (orig != comprbuf)
303        kfree(comprbuf);
304}
305
306int __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
342int 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}
360

Archive Download this file



interactive