2005-04-17 02:20:36 +04:00
/*
* JFFS2 - - Journalling Flash File System , Version 2.
*
2007-04-25 17:16:47 +04:00
* Copyright © 2001 - 2007 Red Hat , Inc .
2010-08-08 17:15:22 +04:00
* Copyright © 2004 - 2010 David Woodhouse < dwmw2 @ infradead . org >
2007-04-25 17:16:47 +04:00
* Copyright © 2004 Ferenc Havasi < havasi @ inf . u - szeged . hu > ,
2007-07-10 13:01:22 +04:00
* University of Szeged , Hungary
2005-04-17 02:20:36 +04:00
*
2010-08-08 17:15:22 +04:00
* Created by Arjan van de Ven < arjan @ infradead . org >
*
2005-04-17 02:20:36 +04:00
* For licensing information , see the file ' LICENCE ' in this directory .
*
*/
# include "compr.h"
static DEFINE_SPINLOCK ( jffs2_compressor_list_lock ) ;
/* Available compressors are on this list */
static LIST_HEAD ( jffs2_compressor_list ) ;
/* Actual compression mode */
static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY ;
/* Statistics for blocks stored without compression */
static uint32_t none_stat_compr_blocks = 0 , none_stat_decompr_blocks = 0 , none_stat_compr_size = 0 ;
2007-07-10 13:28:42 +04:00
/*
* Return 1 to use this compression
*/
static int jffs2_is_best_compression ( struct jffs2_compressor * this ,
struct jffs2_compressor * best , uint32_t size , uint32_t bestsize )
{
switch ( jffs2_compression_mode ) {
case JFFS2_COMPR_MODE_SIZE :
if ( bestsize > size )
return 1 ;
return 0 ;
case JFFS2_COMPR_MODE_FAVOURLZO :
if ( ( this - > compr = = JFFS2_COMPR_LZO ) & & ( bestsize > size ) )
return 1 ;
if ( ( best - > compr ! = JFFS2_COMPR_LZO ) & & ( bestsize > size ) )
return 1 ;
if ( ( this - > compr = = JFFS2_COMPR_LZO ) & & ( bestsize > ( size * FAVOUR_LZO_PERCENT / 100 ) ) )
return 1 ;
if ( ( bestsize * FAVOUR_LZO_PERCENT / 100 ) > size )
return 1 ;
return 0 ;
}
/* Shouldn't happen */
return 0 ;
}
2005-04-17 02:20:36 +04:00
/* jffs2_compress:
2008-10-17 18:19:45 +04:00
* @ data_in : Pointer to uncompressed data
* @ cpage_out : Pointer to returned pointer to buffer for compressed data
2005-04-17 02:20:36 +04:00
* @ datalen : On entry , holds the amount of data available for compression .
* On exit , expected to hold the amount of data actually compressed .
* @ cdatalen : On entry , holds the amount of space available for compressed
* data . On exit , expected to hold the actual size of the compressed
* data .
*
* Returns : Lower byte to be stored with data indicating compression type used .
2005-11-07 14:16:07 +03:00
* Zero is used to show that the data could not be compressed - the
2005-04-17 02:20:36 +04:00
* compressed version was actually larger than the original .
* Upper byte will be used later . ( soon )
*
* If the cdata buffer isn ' t large enough to hold all the uncompressed data ,
2005-11-07 14:16:07 +03:00
* jffs2_compress should compress as much as will fit , and should set
2005-04-17 02:20:36 +04:00
* * datalen accordingly to show the amount of data which were compressed .
*/
uint16_t jffs2_compress ( struct jffs2_sb_info * c , struct jffs2_inode_info * f ,
2007-07-10 13:01:22 +04:00
unsigned char * data_in , unsigned char * * cpage_out ,
uint32_t * datalen , uint32_t * cdatalen )
2005-04-17 02:20:36 +04:00
{
int ret = JFFS2_COMPR_NONE ;
2007-07-10 13:01:22 +04:00
int compr_ret ;
struct jffs2_compressor * this , * best = NULL ;
unsigned char * output_buf = NULL , * tmp_buf ;
uint32_t orig_slen , orig_dlen ;
uint32_t best_slen = 0 , best_dlen = 0 ;
2005-04-17 02:20:36 +04:00
2007-07-10 13:01:22 +04:00
switch ( jffs2_compression_mode ) {
case JFFS2_COMPR_MODE_NONE :
break ;
case JFFS2_COMPR_MODE_PRIORITY :
output_buf = kmalloc ( * cdatalen , GFP_KERNEL ) ;
if ( ! output_buf ) {
printk ( KERN_WARNING " JFFS2: No memory for compressor allocation. Compression failed. \n " ) ;
goto out ;
}
orig_slen = * datalen ;
orig_dlen = * cdatalen ;
spin_lock ( & jffs2_compressor_list_lock ) ;
list_for_each_entry ( this , & jffs2_compressor_list , list ) {
/* Skip decompress-only backwards-compatibility and disabled modules */
if ( ( ! this - > compress ) | | ( this - > disabled ) )
continue ;
2005-04-17 02:20:36 +04:00
2007-07-10 13:01:22 +04:00
this - > usecount + + ;
spin_unlock ( & jffs2_compressor_list_lock ) ;
* datalen = orig_slen ;
* cdatalen = orig_dlen ;
2010-09-23 06:52:33 +04:00
compr_ret = this - > compress ( data_in , output_buf , datalen , cdatalen ) ;
2007-07-10 13:01:22 +04:00
spin_lock ( & jffs2_compressor_list_lock ) ;
this - > usecount - - ;
if ( ! compr_ret ) {
ret = this - > compr ;
this - > stat_compr_blocks + + ;
this - > stat_compr_orig_size + = * datalen ;
this - > stat_compr_new_size + = * cdatalen ;
break ;
}
}
spin_unlock ( & jffs2_compressor_list_lock ) ;
if ( ret = = JFFS2_COMPR_NONE )
kfree ( output_buf ) ;
break ;
case JFFS2_COMPR_MODE_SIZE :
2007-07-10 13:28:42 +04:00
case JFFS2_COMPR_MODE_FAVOURLZO :
2007-07-10 13:01:22 +04:00
orig_slen = * datalen ;
orig_dlen = * cdatalen ;
spin_lock ( & jffs2_compressor_list_lock ) ;
list_for_each_entry ( this , & jffs2_compressor_list , list ) {
/* Skip decompress-only backwards-compatibility and disabled modules */
if ( ( ! this - > compress ) | | ( this - > disabled ) )
continue ;
/* Allocating memory for output buffer if necessary */
2007-07-10 13:28:42 +04:00
if ( ( this - > compr_buf_size < orig_slen ) & & ( this - > compr_buf ) ) {
2007-07-10 13:01:22 +04:00
spin_unlock ( & jffs2_compressor_list_lock ) ;
kfree ( this - > compr_buf ) ;
spin_lock ( & jffs2_compressor_list_lock ) ;
this - > compr_buf_size = 0 ;
this - > compr_buf = NULL ;
}
if ( ! this - > compr_buf ) {
spin_unlock ( & jffs2_compressor_list_lock ) ;
2007-07-10 13:28:42 +04:00
tmp_buf = kmalloc ( orig_slen , GFP_KERNEL ) ;
2007-07-10 13:01:22 +04:00
spin_lock ( & jffs2_compressor_list_lock ) ;
if ( ! tmp_buf ) {
2007-07-10 13:28:42 +04:00
printk ( KERN_WARNING " JFFS2: No memory for compressor allocation. (%d bytes) \n " , orig_slen ) ;
2007-07-10 13:01:22 +04:00
continue ;
}
else {
this - > compr_buf = tmp_buf ;
2007-07-10 13:28:42 +04:00
this - > compr_buf_size = orig_slen ;
2007-07-10 13:01:22 +04:00
}
}
this - > usecount + + ;
spin_unlock ( & jffs2_compressor_list_lock ) ;
* datalen = orig_slen ;
* cdatalen = orig_dlen ;
2010-09-23 06:52:33 +04:00
compr_ret = this - > compress ( data_in , this - > compr_buf , datalen , cdatalen ) ;
2007-07-10 13:01:22 +04:00
spin_lock ( & jffs2_compressor_list_lock ) ;
this - > usecount - - ;
if ( ! compr_ret ) {
2007-07-10 13:28:42 +04:00
if ( ( ( ! best_dlen ) | | jffs2_is_best_compression ( this , best , * cdatalen , best_dlen ) )
& & ( * cdatalen < * datalen ) ) {
2007-07-10 13:01:22 +04:00
best_dlen = * cdatalen ;
best_slen = * datalen ;
best = this ;
}
}
}
if ( best_dlen ) {
* cdatalen = best_dlen ;
* datalen = best_slen ;
output_buf = best - > compr_buf ;
best - > compr_buf = NULL ;
best - > compr_buf_size = 0 ;
best - > stat_compr_blocks + + ;
best - > stat_compr_orig_size + = best_slen ;
best - > stat_compr_new_size + = best_dlen ;
ret = best - > compr ;
}
spin_unlock ( & jffs2_compressor_list_lock ) ;
break ;
default :
tree-wide: fix assorted typos all over the place
That is "success", "unknown", "through", "performance", "[re|un]mapping"
, "access", "default", "reasonable", "[con]currently", "temperature"
, "channel", "[un]used", "application", "example","hierarchy", "therefore"
, "[over|under]flow", "contiguous", "threshold", "enough" and others.
Signed-off-by: André Goddard Rosa <andre.goddard@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
2009-11-14 18:09:05 +03:00
printk ( KERN_ERR " JFFS2: unknown compression mode. \n " ) ;
2007-07-10 13:01:22 +04:00
}
2005-04-17 02:20:36 +04:00
out :
2007-07-10 13:01:22 +04:00
if ( ret = = JFFS2_COMPR_NONE ) {
* cpage_out = data_in ;
* datalen = * cdatalen ;
none_stat_compr_blocks + + ;
none_stat_compr_size + = * datalen ;
}
else {
* cpage_out = output_buf ;
}
2005-04-17 02:20:36 +04:00
return ret ;
}
int jffs2_decompress ( struct jffs2_sb_info * c , struct jffs2_inode_info * f ,
2005-11-07 14:16:07 +03:00
uint16_t comprtype , unsigned char * cdata_in ,
2005-04-17 02:20:36 +04:00
unsigned char * data_out , uint32_t cdatalen , uint32_t datalen )
{
2007-07-10 13:01:22 +04:00
struct jffs2_compressor * this ;
int ret ;
2005-04-17 02:20:36 +04:00
/* Older code had a bug where it would write non-zero 'usercompr'
fields . Deal with it . */
if ( ( comprtype & 0xff ) < = JFFS2_COMPR_ZLIB )
comprtype & = 0xff ;
switch ( comprtype & 0xff ) {
case JFFS2_COMPR_NONE :
/* This should be special-cased elsewhere, but we might as well deal with it */
memcpy ( data_out , cdata_in , datalen ) ;
2007-07-10 13:01:22 +04:00
none_stat_decompr_blocks + + ;
2005-04-17 02:20:36 +04:00
break ;
case JFFS2_COMPR_ZERO :
memset ( data_out , 0 , datalen ) ;
break ;
default :
2007-07-10 13:01:22 +04:00
spin_lock ( & jffs2_compressor_list_lock ) ;
list_for_each_entry ( this , & jffs2_compressor_list , list ) {
if ( comprtype = = this - > compr ) {
this - > usecount + + ;
spin_unlock ( & jffs2_compressor_list_lock ) ;
2010-09-23 06:52:33 +04:00
ret = this - > decompress ( cdata_in , data_out , cdatalen , datalen ) ;
2007-07-10 13:01:22 +04:00
spin_lock ( & jffs2_compressor_list_lock ) ;
if ( ret ) {
printk ( KERN_WARNING " Decompressor \" %s \" returned %d \n " , this - > name , ret ) ;
}
else {
this - > stat_decompr_blocks + + ;
}
this - > usecount - - ;
spin_unlock ( & jffs2_compressor_list_lock ) ;
return ret ;
}
}
2005-04-17 02:20:36 +04:00
printk ( KERN_WARNING " JFFS2 compression type 0x%02x not available. \n " , comprtype ) ;
2007-07-10 13:01:22 +04:00
spin_unlock ( & jffs2_compressor_list_lock ) ;
2005-04-17 02:20:36 +04:00
return - EIO ;
}
return 0 ;
}
int jffs2_register_compressor ( struct jffs2_compressor * comp )
{
2007-07-10 13:01:22 +04:00
struct jffs2_compressor * this ;
2005-04-17 02:20:36 +04:00
2007-07-10 13:01:22 +04:00
if ( ! comp - > name ) {
printk ( KERN_WARNING " NULL compressor name at registering JFFS2 compressor. Failed. \n " ) ;
return - 1 ;
}
comp - > compr_buf_size = 0 ;
comp - > compr_buf = NULL ;
comp - > usecount = 0 ;
comp - > stat_compr_orig_size = 0 ;
comp - > stat_compr_new_size = 0 ;
comp - > stat_compr_blocks = 0 ;
comp - > stat_decompr_blocks = 0 ;
D1 ( printk ( KERN_DEBUG " Registering JFFS2 compressor \" %s \" \n " , comp - > name ) ) ;
2005-04-17 02:20:36 +04:00
2007-07-10 13:01:22 +04:00
spin_lock ( & jffs2_compressor_list_lock ) ;
2005-04-17 02:20:36 +04:00
2007-07-10 13:01:22 +04:00
list_for_each_entry ( this , & jffs2_compressor_list , list ) {
if ( this - > priority < comp - > priority ) {
list_add ( & comp - > list , this - > list . prev ) ;
goto out ;
}
}
list_add_tail ( & comp - > list , & jffs2_compressor_list ) ;
2005-04-17 02:20:36 +04:00
out :
2007-07-10 13:01:22 +04:00
D2 ( list_for_each_entry ( this , & jffs2_compressor_list , list ) {
printk ( KERN_DEBUG " Compressor \" %s \" , prio %d \n " , this - > name , this - > priority ) ;
} )
2005-04-17 02:20:36 +04:00
2007-07-10 13:01:22 +04:00
spin_unlock ( & jffs2_compressor_list_lock ) ;
2005-04-17 02:20:36 +04:00
2007-07-10 13:01:22 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
int jffs2_unregister_compressor ( struct jffs2_compressor * comp )
{
2007-07-10 13:01:22 +04:00
D2 ( struct jffs2_compressor * this ; )
2005-04-17 02:20:36 +04:00
2007-07-10 13:01:22 +04:00
D1 ( printk ( KERN_DEBUG " Unregistering JFFS2 compressor \" %s \" \n " , comp - > name ) ) ;
2005-04-17 02:20:36 +04:00
2007-07-10 13:01:22 +04:00
spin_lock ( & jffs2_compressor_list_lock ) ;
2005-04-17 02:20:36 +04:00
2007-07-10 13:01:22 +04:00
if ( comp - > usecount ) {
spin_unlock ( & jffs2_compressor_list_lock ) ;
printk ( KERN_WARNING " JFFS2: Compressor modul is in use. Unregister failed. \n " ) ;
return - 1 ;
}
list_del ( & comp - > list ) ;
2005-04-17 02:20:36 +04:00
2007-07-10 13:01:22 +04:00
D2 ( list_for_each_entry ( this , & jffs2_compressor_list , list ) {
printk ( KERN_DEBUG " Compressor \" %s \" , prio %d \n " , this - > name , this - > priority ) ;
} )
spin_unlock ( & jffs2_compressor_list_lock ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
void jffs2_free_comprbuf ( unsigned char * comprbuf , unsigned char * orig )
{
2007-07-10 13:01:22 +04:00
if ( orig ! = comprbuf )
kfree ( comprbuf ) ;
2005-04-17 02:20:36 +04:00
}
2006-05-16 19:08:10 +04:00
int __init jffs2_compressors_init ( void )
2005-04-17 02:20:36 +04:00
{
/* Registering compressors */
# ifdef CONFIG_JFFS2_ZLIB
2007-07-10 13:01:22 +04:00
jffs2_zlib_init ( ) ;
2005-04-17 02:20:36 +04:00
# endif
# ifdef CONFIG_JFFS2_RTIME
2007-07-10 13:01:22 +04:00
jffs2_rtime_init ( ) ;
2005-04-17 02:20:36 +04:00
# endif
# ifdef CONFIG_JFFS2_RUBIN
2007-07-10 13:01:22 +04:00
jffs2_rubinmips_init ( ) ;
jffs2_dynrubin_init ( ) ;
2005-04-17 02:20:36 +04:00
# endif
2007-07-10 13:28:36 +04:00
# ifdef CONFIG_JFFS2_LZO
jffs2_lzo_init ( ) ;
# endif
2005-04-17 02:20:36 +04:00
/* Setting default compression mode */
# ifdef CONFIG_JFFS2_CMODE_NONE
2007-07-10 13:01:22 +04:00
jffs2_compression_mode = JFFS2_COMPR_MODE_NONE ;
D1 ( printk ( KERN_INFO " JFFS2: default compression mode: none \n " ) ; )
2005-04-17 02:20:36 +04:00
# else
# ifdef CONFIG_JFFS2_CMODE_SIZE
2007-07-10 13:01:22 +04:00
jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE ;
D1 ( printk ( KERN_INFO " JFFS2: default compression mode: size \n " ) ; )
2007-07-10 13:28:42 +04:00
# else
# ifdef CONFIG_JFFS2_CMODE_FAVOURLZO
jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO ;
D1 ( printk ( KERN_INFO " JFFS2: default compression mode: favourlzo \n " ) ; )
2005-04-17 02:20:36 +04:00
# else
2007-07-10 13:01:22 +04:00
D1 ( printk ( KERN_INFO " JFFS2: default compression mode: priority \n " ) ; )
2005-04-17 02:20:36 +04:00
# endif
2007-07-10 13:28:42 +04:00
# endif
2005-04-17 02:20:36 +04:00
# endif
2007-07-10 13:01:22 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-06-03 03:25:50 +04:00
int jffs2_compressors_exit ( void )
2005-04-17 02:20:36 +04:00
{
/* Unregistering compressors */
2007-07-10 13:28:36 +04:00
# ifdef CONFIG_JFFS2_LZO
jffs2_lzo_exit ( ) ;
# endif
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_JFFS2_RUBIN
2007-07-10 13:01:22 +04:00
jffs2_dynrubin_exit ( ) ;
jffs2_rubinmips_exit ( ) ;
2005-04-17 02:20:36 +04:00
# endif
# ifdef CONFIG_JFFS2_RTIME
2007-07-10 13:01:22 +04:00
jffs2_rtime_exit ( ) ;
2005-04-17 02:20:36 +04:00
# endif
# ifdef CONFIG_JFFS2_ZLIB
2007-07-10 13:01:22 +04:00
jffs2_zlib_exit ( ) ;
2005-04-17 02:20:36 +04:00
# endif
2007-07-10 13:01:22 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}