source: rtems/cpukit/libfs/src/jffs2/src/compr.c @ 0c0f128

4.11
Last change on this file since 0c0f128 was 0c0f128, checked in by Sebastian Huber <sebastian.huber@…>, on Sep 12, 2013 at 1:57:47 PM

JFFS2: Import from Linux

Import of Journalling Flash File System, Version 2 from Linux 3.11.
This part of the Linux kernel is under a separate license which is
similar to the RTEMS license.

The file "cpukit/libfs/src/jffs2/include/linux/jffs2.h" is a copy of
"linux-3.11/include/uapi/linux/jffs2.h".

The file "LICENSE.JFFS2" is a copy of "linux-3.11/fs/jffs2/LICENCE".

The files

"linux-3.11/fs/jffs2/LICENCE",
"linux-3.11/fs/jffs2/acl.h",
"linux-3.11/fs/jffs2/build.c",
"linux-3.11/fs/jffs2/compr.c",
"linux-3.11/fs/jffs2/compr.h",
"linux-3.11/fs/jffs2/compr_rtime.c",
"linux-3.11/fs/jffs2/compr_rubin.c",
"linux-3.11/fs/jffs2/compr_zlib.c",
"linux-3.11/fs/jffs2/debug.c",
"linux-3.11/fs/jffs2/debug.h",
"linux-3.11/fs/jffs2/erase.c",
"linux-3.11/fs/jffs2/gc.c",
"linux-3.11/fs/jffs2/jffs2_fs_i.h",
"linux-3.11/fs/jffs2/jffs2_fs_sb.h",
"linux-3.11/fs/jffs2/nodelist.c",
"linux-3.11/fs/jffs2/nodelist.h",
"linux-3.11/fs/jffs2/nodemgmt.c",
"linux-3.11/fs/jffs2/read.c",
"linux-3.11/fs/jffs2/readinode.c",
"linux-3.11/fs/jffs2/scan.c",
"linux-3.11/fs/jffs2/summary.h",
"linux-3.11/fs/jffs2/write.c", and
"linux-3.11/fs/jffs2/xattr.h"

are copied to "cpukit/libfs/src/jffs2/src".

  • Property mode set to 100644
File size: 11.6 KB
Line 
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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16
17#include "compr.h"
18
19static DEFINE_SPINLOCK(jffs2_compressor_list_lock);
20
21/* Available compressors are on this list */
22static LIST_HEAD(jffs2_compressor_list);
23
24/* Actual compression mode */
25static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
26
27/* Statistics for blocks stored without compression */
28static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0;
29
30
31/*
32 * Return 1 to use this compression
33 */
34static int jffs2_is_best_compression(struct jffs2_compressor *this,
35                struct jffs2_compressor *best, uint32_t size, uint32_t bestsize)
36{
37        switch (jffs2_compression_mode) {
38        case JFFS2_COMPR_MODE_SIZE:
39                if (bestsize > size)
40                        return 1;
41                return 0;
42        case JFFS2_COMPR_MODE_FAVOURLZO:
43                if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > size))
44                        return 1;
45                if ((best->compr != JFFS2_COMPR_LZO) && (bestsize > size))
46                        return 1;
47                if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > (size * FAVOUR_LZO_PERCENT / 100)))
48                        return 1;
49                if ((bestsize * FAVOUR_LZO_PERCENT / 100) > size)
50                        return 1;
51
52                return 0;
53        }
54        /* Shouldn't happen */
55        return 0;
56}
57
58/*
59 * jffs2_selected_compress:
60 * @compr: Explicit compression type to use (ie, JFFS2_COMPR_ZLIB).
61 *      If 0, just take the first available compression mode.
62 * @data_in: Pointer to uncompressed data
63 * @cpage_out: Pointer to returned pointer to buffer for compressed data
64 * @datalen: On entry, holds the amount of data available for compression.
65 *      On exit, expected to hold the amount of data actually compressed.
66 * @cdatalen: On entry, holds the amount of space available for compressed
67 *      data. On exit, expected to hold the actual size of the compressed
68 *      data.
69 *
70 * Returns: the compression type used.  Zero is used to show that the data
71 * could not be compressed; probably because we couldn't find the requested
72 * compression mode.
73 */
74static int jffs2_selected_compress(u8 compr, unsigned char *data_in,
75                unsigned char **cpage_out, u32 *datalen, u32 *cdatalen)
76{
77        struct jffs2_compressor *this;
78        int err, ret = JFFS2_COMPR_NONE;
79        uint32_t orig_slen, orig_dlen;
80        char *output_buf;
81
82        output_buf = kmalloc(*cdatalen, GFP_KERNEL);
83        if (!output_buf) {
84                pr_warn("No memory for compressor allocation. Compression failed.\n");
85                return ret;
86        }
87        orig_slen = *datalen;
88        orig_dlen = *cdatalen;
89        spin_lock(&jffs2_compressor_list_lock);
90        list_for_each_entry(this, &jffs2_compressor_list, list) {
91                /* Skip decompress-only and disabled modules */
92                if (!this->compress || this->disabled)
93                        continue;
94
95                /* Skip if not the desired compression type */
96                if (compr && (compr != this->compr))
97                        continue;
98
99                /*
100                 * Either compression type was unspecified, or we found our
101                 * compressor; either way, we're good to go.
102                 */
103                this->usecount++;
104                spin_unlock(&jffs2_compressor_list_lock);
105
106                *datalen  = orig_slen;
107                *cdatalen = orig_dlen;
108                err = this->compress(data_in, output_buf, datalen, cdatalen);
109
110                spin_lock(&jffs2_compressor_list_lock);
111                this->usecount--;
112                if (!err) {
113                        /* Success */
114                        ret = this->compr;
115                        this->stat_compr_blocks++;
116                        this->stat_compr_orig_size += *datalen;
117                        this->stat_compr_new_size += *cdatalen;
118                        break;
119                }
120        }
121        spin_unlock(&jffs2_compressor_list_lock);
122        if (ret == JFFS2_COMPR_NONE)
123                kfree(output_buf);
124        else
125                *cpage_out = output_buf;
126
127        return ret;
128}
129
130/* jffs2_compress:
131 * @data_in: Pointer to uncompressed data
132 * @cpage_out: Pointer to returned pointer to buffer for compressed data
133 * @datalen: On entry, holds the amount of data available for compression.
134 *      On exit, expected to hold the amount of data actually compressed.
135 * @cdatalen: On entry, holds the amount of space available for compressed
136 *      data. On exit, expected to hold the actual size of the compressed
137 *      data.
138 *
139 * Returns: Lower byte to be stored with data indicating compression type used.
140 * Zero is used to show that the data could not be compressed - the
141 * compressed version was actually larger than the original.
142 * Upper byte will be used later. (soon)
143 *
144 * If the cdata buffer isn't large enough to hold all the uncompressed data,
145 * jffs2_compress should compress as much as will fit, and should set
146 * *datalen accordingly to show the amount of data which were compressed.
147 */
148uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
149                        unsigned char *data_in, unsigned char **cpage_out,
150                        uint32_t *datalen, uint32_t *cdatalen)
151{
152        int ret = JFFS2_COMPR_NONE;
153        int mode, compr_ret;
154        struct jffs2_compressor *this, *best=NULL;
155        unsigned char *output_buf = NULL, *tmp_buf;
156        uint32_t orig_slen, orig_dlen;
157        uint32_t best_slen=0, best_dlen=0;
158
159        if (c->mount_opts.override_compr)
160                mode = c->mount_opts.compr;
161        else
162                mode = jffs2_compression_mode;
163
164        switch (mode) {
165        case JFFS2_COMPR_MODE_NONE:
166                break;
167        case JFFS2_COMPR_MODE_PRIORITY:
168                ret = jffs2_selected_compress(0, data_in, cpage_out, datalen,
169                                cdatalen);
170                break;
171        case JFFS2_COMPR_MODE_SIZE:
172        case JFFS2_COMPR_MODE_FAVOURLZO:
173                orig_slen = *datalen;
174                orig_dlen = *cdatalen;
175                spin_lock(&jffs2_compressor_list_lock);
176                list_for_each_entry(this, &jffs2_compressor_list, list) {
177                        /* Skip decompress-only backwards-compatibility and disabled modules */
178                        if ((!this->compress)||(this->disabled))
179                                continue;
180                        /* Allocating memory for output buffer if necessary */
181                        if ((this->compr_buf_size < orig_slen) && (this->compr_buf)) {
182                                spin_unlock(&jffs2_compressor_list_lock);
183                                kfree(this->compr_buf);
184                                spin_lock(&jffs2_compressor_list_lock);
185                                this->compr_buf_size=0;
186                                this->compr_buf=NULL;
187                        }
188                        if (!this->compr_buf) {
189                                spin_unlock(&jffs2_compressor_list_lock);
190                                tmp_buf = kmalloc(orig_slen, GFP_KERNEL);
191                                spin_lock(&jffs2_compressor_list_lock);
192                                if (!tmp_buf) {
193                                        pr_warn("No memory for compressor allocation. (%d bytes)\n",
194                                                orig_slen);
195                                        continue;
196                                }
197                                else {
198                                        this->compr_buf = tmp_buf;
199                                        this->compr_buf_size = orig_slen;
200                                }
201                        }
202                        this->usecount++;
203                        spin_unlock(&jffs2_compressor_list_lock);
204                        *datalen  = orig_slen;
205                        *cdatalen = orig_dlen;
206                        compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen);
207                        spin_lock(&jffs2_compressor_list_lock);
208                        this->usecount--;
209                        if (!compr_ret) {
210                                if (((!best_dlen) || jffs2_is_best_compression(this, best, *cdatalen, best_dlen))
211                                                && (*cdatalen < *datalen)) {
212                                        best_dlen = *cdatalen;
213                                        best_slen = *datalen;
214                                        best = this;
215                                }
216                        }
217                }
218                if (best_dlen) {
219                        *cdatalen = best_dlen;
220                        *datalen  = best_slen;
221                        output_buf = best->compr_buf;
222                        best->compr_buf = NULL;
223                        best->compr_buf_size = 0;
224                        best->stat_compr_blocks++;
225                        best->stat_compr_orig_size += best_slen;
226                        best->stat_compr_new_size  += best_dlen;
227                        ret = best->compr;
228                        *cpage_out = output_buf;
229                }
230                spin_unlock(&jffs2_compressor_list_lock);
231                break;
232        case JFFS2_COMPR_MODE_FORCELZO:
233                ret = jffs2_selected_compress(JFFS2_COMPR_LZO, data_in,
234                                cpage_out, datalen, cdatalen);
235                break;
236        case JFFS2_COMPR_MODE_FORCEZLIB:
237                ret = jffs2_selected_compress(JFFS2_COMPR_ZLIB, data_in,
238                                cpage_out, datalen, cdatalen);
239                break;
240        default:
241                pr_err("unknown compression mode\n");
242        }
243
244        if (ret == JFFS2_COMPR_NONE) {
245                *cpage_out = data_in;
246                *datalen = *cdatalen;
247                none_stat_compr_blocks++;
248                none_stat_compr_size += *datalen;
249        }
250        return ret;
251}
252
253int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
254                     uint16_t comprtype, unsigned char *cdata_in,
255                     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen)
256{
257        struct jffs2_compressor *this;
258        int ret;
259
260        /* Older code had a bug where it would write non-zero 'usercompr'
261           fields. Deal with it. */
262        if ((comprtype & 0xff) <= JFFS2_COMPR_ZLIB)
263                comprtype &= 0xff;
264
265        switch (comprtype & 0xff) {
266        case JFFS2_COMPR_NONE:
267                /* This should be special-cased elsewhere, but we might as well deal with it */
268                memcpy(data_out, cdata_in, datalen);
269                none_stat_decompr_blocks++;
270                break;
271        case JFFS2_COMPR_ZERO:
272                memset(data_out, 0, datalen);
273                break;
274        default:
275                spin_lock(&jffs2_compressor_list_lock);
276                list_for_each_entry(this, &jffs2_compressor_list, list) {
277                        if (comprtype == this->compr) {
278                                this->usecount++;
279                                spin_unlock(&jffs2_compressor_list_lock);
280                                ret = this->decompress(cdata_in, data_out, cdatalen, datalen);
281                                spin_lock(&jffs2_compressor_list_lock);
282                                if (ret) {
283                                        pr_warn("Decompressor \"%s\" returned %d\n",
284                                                this->name, ret);
285                                }
286                                else {
287                                        this->stat_decompr_blocks++;
288                                }
289                                this->usecount--;
290                                spin_unlock(&jffs2_compressor_list_lock);
291                                return ret;
292                        }
293                }
294                pr_warn("compression type 0x%02x not available\n", comprtype);
295                spin_unlock(&jffs2_compressor_list_lock);
296                return -EIO;
297        }
298        return 0;
299}
300
301int jffs2_register_compressor(struct jffs2_compressor *comp)
302{
303        struct jffs2_compressor *this;
304
305        if (!comp->name) {
306                pr_warn("NULL compressor name at registering JFFS2 compressor. Failed.\n");
307                return -1;
308        }
309        comp->compr_buf_size=0;
310        comp->compr_buf=NULL;
311        comp->usecount=0;
312        comp->stat_compr_orig_size=0;
313        comp->stat_compr_new_size=0;
314        comp->stat_compr_blocks=0;
315        comp->stat_decompr_blocks=0;
316        jffs2_dbg(1, "Registering JFFS2 compressor \"%s\"\n", comp->name);
317
318        spin_lock(&jffs2_compressor_list_lock);
319
320        list_for_each_entry(this, &jffs2_compressor_list, list) {
321                if (this->priority < comp->priority) {
322                        list_add(&comp->list, this->list.prev);
323                        goto out;
324                }
325        }
326        list_add_tail(&comp->list, &jffs2_compressor_list);
327out:
328        D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
329                printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
330        })
331
332        spin_unlock(&jffs2_compressor_list_lock);
333
334        return 0;
335}
336
337int jffs2_unregister_compressor(struct jffs2_compressor *comp)
338{
339        D2(struct jffs2_compressor *this);
340
341        jffs2_dbg(1, "Unregistering JFFS2 compressor \"%s\"\n", comp->name);
342
343        spin_lock(&jffs2_compressor_list_lock);
344
345        if (comp->usecount) {
346                spin_unlock(&jffs2_compressor_list_lock);
347                pr_warn("Compressor module is in use. Unregister failed.\n");
348                return -1;
349        }
350        list_del(&comp->list);
351
352        D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
353                printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
354        })
355        spin_unlock(&jffs2_compressor_list_lock);
356        return 0;
357}
358
359void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
360{
361        if (orig != comprbuf)
362                kfree(comprbuf);
363}
364
365int __init jffs2_compressors_init(void)
366{
367/* Registering compressors */
368#ifdef CONFIG_JFFS2_ZLIB
369        jffs2_zlib_init();
370#endif
371#ifdef CONFIG_JFFS2_RTIME
372        jffs2_rtime_init();
373#endif
374#ifdef CONFIG_JFFS2_RUBIN
375        jffs2_rubinmips_init();
376        jffs2_dynrubin_init();
377#endif
378#ifdef CONFIG_JFFS2_LZO
379        jffs2_lzo_init();
380#endif
381/* Setting default compression mode */
382#ifdef CONFIG_JFFS2_CMODE_NONE
383        jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
384        jffs2_dbg(1, "default compression mode: none\n");
385#else
386#ifdef CONFIG_JFFS2_CMODE_SIZE
387        jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
388        jffs2_dbg(1, "default compression mode: size\n");
389#else
390#ifdef CONFIG_JFFS2_CMODE_FAVOURLZO
391        jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO;
392        jffs2_dbg(1, "default compression mode: favourlzo\n");
393#else
394        jffs2_dbg(1, "default compression mode: priority\n");
395#endif
396#endif
397#endif
398        return 0;
399}
400
401int jffs2_compressors_exit(void)
402{
403/* Unregistering compressors */
404#ifdef CONFIG_JFFS2_LZO
405        jffs2_lzo_exit();
406#endif
407#ifdef CONFIG_JFFS2_RUBIN
408        jffs2_dynrubin_exit();
409        jffs2_rubinmips_exit();
410#endif
411#ifdef CONFIG_JFFS2_RTIME
412        jffs2_rtime_exit();
413#endif
414#ifdef CONFIG_JFFS2_ZLIB
415        jffs2_zlib_exit();
416#endif
417        return 0;
418}
Note: See TracBrowser for help on using the repository browser.