2008-07-14 20:08:37 +04:00
/*
* This file is part of UBIFS .
*
* Copyright ( C ) 2006 - 2008 Nokia Corporation .
* Copyright ( C ) 2006 , 2007 University of Szeged , Hungary
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License along with
* this program ; if not , write to the Free Software Foundation , Inc . , 51
* Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*
* Authors : Adrian Hunter
* Artem Bityutskiy ( Б и т ю ц к и й А р т ё м )
* Zoltan Sogor
*/
/*
* This file provides a single place to access to compression and
* decompression .
*/
# include <linux/crypto.h>
# include "ubifs.h"
/* Fake description object for the "none" compressor */
static struct ubifs_compressor none_compr = {
. compr_type = UBIFS_COMPR_NONE ,
. name = " no compression " ,
. capi_name = " " ,
} ;
# ifdef CONFIG_UBIFS_FS_LZO
static DEFINE_MUTEX ( lzo_mutex ) ;
static struct ubifs_compressor lzo_compr = {
. compr_type = UBIFS_COMPR_LZO ,
. comp_mutex = & lzo_mutex ,
. name = " LZO " ,
. capi_name = " lzo " ,
} ;
# else
static struct ubifs_compressor lzo_compr = {
. compr_type = UBIFS_COMPR_LZO ,
. name = " LZO " ,
} ;
# endif
# ifdef CONFIG_UBIFS_FS_ZLIB
static DEFINE_MUTEX ( deflate_mutex ) ;
static DEFINE_MUTEX ( inflate_mutex ) ;
static struct ubifs_compressor zlib_compr = {
. compr_type = UBIFS_COMPR_ZLIB ,
. comp_mutex = & deflate_mutex ,
. decomp_mutex = & inflate_mutex ,
. name = " zlib " ,
. capi_name = " deflate " ,
} ;
# else
static struct ubifs_compressor zlib_compr = {
. compr_type = UBIFS_COMPR_ZLIB ,
. name = " zlib " ,
} ;
# endif
/* All UBIFS compressors */
struct ubifs_compressor * ubifs_compressors [ UBIFS_COMPR_TYPES_CNT ] ;
/**
* ubifs_compress - compress data .
* @ in_buf : data to compress
* @ in_len : length of the data to compress
* @ out_buf : output buffer where compressed data should be stored
* @ out_len : output buffer length is returned here
* @ compr_type : type of compression to use on enter , actually used compression
* type on exit
*
* This function compresses input buffer @ in_buf of length @ in_len and stores
* the result in the output buffer @ out_buf and the resulting length in
* @ out_len . If the input buffer does not compress , it is just copied to the
* @ out_buf . The same happens if @ compr_type is % UBIFS_COMPR_NONE or if
* compression error occurred .
*
* Note , if the input buffer was not compressed , it is copied to the output
* buffer and % UBIFS_COMPR_NONE is returned in @ compr_type .
*/
void ubifs_compress ( const void * in_buf , int in_len , void * out_buf , int * out_len ,
int * compr_type )
{
int err ;
struct ubifs_compressor * compr = ubifs_compressors [ * compr_type ] ;
if ( * compr_type = = UBIFS_COMPR_NONE )
goto no_compr ;
/* If the input data is small, do not even try to compress it */
if ( in_len < UBIFS_MIN_COMPR_LEN )
goto no_compr ;
if ( compr - > comp_mutex )
mutex_lock ( compr - > comp_mutex ) ;
err = crypto_comp_compress ( compr - > cc , in_buf , in_len , out_buf ,
out_len ) ;
if ( compr - > comp_mutex )
mutex_unlock ( compr - > comp_mutex ) ;
if ( unlikely ( err ) ) {
ubifs_warn ( " cannot compress %d bytes, compressor %s, "
" error %d, leave data uncompressed " ,
in_len , compr - > name , err ) ;
goto no_compr ;
}
/*
2008-10-26 17:58:25 +03:00
* If the data compressed only slightly , it is better to leave it
* uncompressed to improve read speed .
2008-07-14 20:08:37 +04:00
*/
2008-10-26 17:58:25 +03:00
if ( in_len - * out_len < UBIFS_MIN_COMPRESS_DIFF )
2008-07-14 20:08:37 +04:00
goto no_compr ;
return ;
no_compr :
memcpy ( out_buf , in_buf , in_len ) ;
* out_len = in_len ;
* compr_type = UBIFS_COMPR_NONE ;
}
/**
* ubifs_decompress - decompress data .
* @ in_buf : data to decompress
* @ in_len : length of the data to decompress
* @ out_buf : output buffer where decompressed data should
* @ out_len : output length is returned here
* @ compr_type : type of compression
*
* This function decompresses data from buffer @ in_buf into buffer @ out_buf .
* The length of the uncompressed data is returned in @ out_len . This functions
* returns % 0 on success or a negative error code on failure .
*/
int ubifs_decompress ( const void * in_buf , int in_len , void * out_buf ,
int * out_len , int compr_type )
{
int err ;
struct ubifs_compressor * compr ;
if ( unlikely ( compr_type < 0 | | compr_type > = UBIFS_COMPR_TYPES_CNT ) ) {
ubifs_err ( " invalid compression type %d " , compr_type ) ;
return - EINVAL ;
}
compr = ubifs_compressors [ compr_type ] ;
if ( unlikely ( ! compr - > capi_name ) ) {
ubifs_err ( " %s compression is not compiled in " , compr - > name ) ;
return - EINVAL ;
}
if ( compr_type = = UBIFS_COMPR_NONE ) {
memcpy ( out_buf , in_buf , in_len ) ;
* out_len = in_len ;
return 0 ;
}
if ( compr - > decomp_mutex )
mutex_lock ( compr - > decomp_mutex ) ;
err = crypto_comp_decompress ( compr - > cc , in_buf , in_len , out_buf ,
out_len ) ;
if ( compr - > decomp_mutex )
mutex_unlock ( compr - > decomp_mutex ) ;
if ( err )
ubifs_err ( " cannot decompress %d bytes, compressor %s, "
" error %d " , in_len , compr - > name , err ) ;
return err ;
}
/**
* compr_init - initialize a compressor .
* @ compr : compressor description object
*
* This function initializes the requested compressor and returns zero in case
* of success or a negative error code in case of failure .
*/
static int __init compr_init ( struct ubifs_compressor * compr )
{
if ( compr - > capi_name ) {
compr - > cc = crypto_alloc_comp ( compr - > capi_name , 0 , 0 ) ;
if ( IS_ERR ( compr - > cc ) ) {
ubifs_err ( " cannot initialize compressor %s, error %ld " ,
compr - > name , PTR_ERR ( compr - > cc ) ) ;
return PTR_ERR ( compr - > cc ) ;
}
}
ubifs_compressors [ compr - > compr_type ] = compr ;
return 0 ;
}
/**
* compr_exit - de - initialize a compressor .
* @ compr : compressor description object
*/
static void compr_exit ( struct ubifs_compressor * compr )
{
if ( compr - > capi_name )
crypto_free_comp ( compr - > cc ) ;
return ;
}
/**
* ubifs_compressors_init - initialize UBIFS compressors .
*
* This function initializes the compressor which were compiled in . Returns
* zero in case of success and a negative error code in case of failure .
*/
int __init ubifs_compressors_init ( void )
{
int err ;
err = compr_init ( & lzo_compr ) ;
if ( err )
return err ;
err = compr_init ( & zlib_compr ) ;
if ( err )
goto out_lzo ;
ubifs_compressors [ UBIFS_COMPR_NONE ] = & none_compr ;
return 0 ;
out_lzo :
compr_exit ( & lzo_compr ) ;
return err ;
}
/**
* ubifs_compressors_exit - de - initialize UBIFS compressors .
*/
void __exit ubifs_compressors_exit ( void )
{
compr_exit ( & lzo_compr ) ;
compr_exit ( & zlib_compr ) ;
}