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

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

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

~ [ 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