~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/jffs2/compr.c

Version: ~ [ linux-5.2-rc1 ] ~ [ linux-5.1.2 ] ~ [ linux-5.0.16 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.43 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.119 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.176 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.179 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.139 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.67 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 19 static DEFINE_SPINLOCK(jffs2_compressor_list_lock);
 20 
 21 /* Available compressors are on this list */
 22 static LIST_HEAD(jffs2_compressor_list);
 23 
 24 /* Actual compression mode */
 25 static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
 26 
 27 /* Statistics for blocks stored without compression */
 28 static 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  */
 34 static 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  */
 74 static 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  */
148 uint16_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 
253 int 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 
301 int 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);
327 out:
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 
337 int 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 
359 void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
360 {
361         if (orig != comprbuf)
362                 kfree(comprbuf);
363 }
364 
365 int __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 
401 int 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 }
419 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp