2005-10-16 18:33:22 +04:00
/*
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2011-08-11 21:29:04 +04:00
* Copyright ( C ) 2004 - 2011 Red Hat , Inc . All rights reserved .
2005-10-16 18:33:22 +04:00
*
* This file is part of the device - mapper userspace tools .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
2007-08-21 20:26:07 +04:00
* of the GNU Lesser General Public License v .2 .1 .
2005-10-16 18:33:22 +04:00
*
2007-08-21 20:26:07 +04:00
* You should have received a copy of the GNU Lesser General Public License
2005-10-16 18:33:22 +04:00
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2008-11-03 21:59:59 +03:00
# include "dmlib.h"
2011-08-11 21:29:04 +04:00
# include <sys/mman.h>
2008-11-03 21:59:59 +03:00
2009-04-10 13:56:58 +04:00
/* FIXME: thread unsafe */
static DM_LIST_INIT ( _dm_pools ) ;
void dm_pools_check_leaks ( void ) ;
2011-08-11 21:29:04 +04:00
# ifdef DEBUG_ENFORCE_POOL_LOCKING
# ifdef DEBUG_POOL
# error Do not use DEBUG_POOL with DEBUG_ENFORCE_POOL_LOCKING
# endif
/*
* Use mprotect system call to ensure all locked pages are not writable .
* Generates segmentation fault with write access to the locked pool .
*
* - Implementation is using posix_memalign ( ) to get page aligned
* memory blocks ( could be implemented also through malloc ) .
* - Only pool - fast is properly handled for now .
* - Checksum is slower compared to mprotect .
*/
static size_t pagesize = 0 ;
static size_t pagesize_mask = 0 ;
# define ALIGN_ON_PAGE(size) (((size) + (pagesize_mask)) & ~(pagesize_mask))
# endif
2005-10-16 18:33:22 +04:00
# ifdef DEBUG_POOL
# include "pool-debug.c"
# else
# include "pool-fast.c"
# endif
2005-10-17 02:57:20 +04:00
char * dm_pool_strdup ( struct dm_pool * p , const char * str )
2005-10-16 18:33:22 +04:00
{
2011-03-30 16:57:03 +04:00
char * ret = dm_pool_alloc_aligned ( p , strlen ( str ) + 1 , 2 ) ;
2005-10-16 18:33:22 +04:00
if ( ret )
strcpy ( ret , str ) ;
return ret ;
}
2005-10-17 02:57:20 +04:00
char * dm_pool_strndup ( struct dm_pool * p , const char * str , size_t n )
2005-10-16 18:33:22 +04:00
{
2011-03-30 16:57:03 +04:00
char * ret = dm_pool_alloc_aligned ( p , n + 1 , 2 ) ;
2005-10-16 18:33:22 +04:00
if ( ret ) {
strncpy ( ret , str , n ) ;
ret [ n ] = ' \0 ' ;
}
return ret ;
}
2005-10-17 02:57:20 +04:00
void * dm_pool_zalloc ( struct dm_pool * p , size_t s )
2005-10-16 18:33:22 +04:00
{
2005-10-17 02:57:20 +04:00
void * ptr = dm_pool_alloc ( p , s ) ;
2005-10-16 18:33:22 +04:00
if ( ptr )
memset ( ptr , 0 , s ) ;
return ptr ;
}
2009-04-10 13:56:58 +04:00
void dm_pools_check_leaks ( void )
{
struct dm_pool * p ;
if ( dm_list_empty ( & _dm_pools ) )
return ;
log_error ( " You have a memory leak (not released memory pool): " ) ;
dm_list_iterate_items ( p , & _dm_pools ) {
# ifdef DEBUG_POOL
log_error ( " [%p] %s (%u bytes) " ,
p - > orig_pool ,
p - > name , p - > stats . bytes ) ;
# else
2011-03-10 17:49:01 +03:00
log_error ( " [%p] %s " , p , p - > name ) ;
2009-04-10 13:56:58 +04:00
# endif
}
2011-09-01 14:19:01 +04:00
log_error ( INTERNAL_ERROR " Unreleased memory pool(s) found. " ) ;
2009-04-10 13:56:58 +04:00
}
2011-08-11 21:29:04 +04:00
/**
* Status of locked pool .
*
* \ param p
* Pool to be tested for lock status .
*
* \ return
* 1 when the pool is locked , 0 otherwise .
*/
int dm_pool_locked ( struct dm_pool * p )
{
return p - > locked ;
}
/**
* Lock memory pool .
*
* \ param p
* Pool to be locked .
*
* \ param crc
* Bool specifies whether to store the pool crc / hash checksum .
*
* \ return
* 1 ( success ) when the pool was preperly locked , 0 otherwise .
*/
int dm_pool_lock ( struct dm_pool * p , int crc )
{
if ( p - > locked ) {
log_error ( INTERNAL_ERROR " Pool %s is already locked. " ,
p - > name ) ;
return 0 ;
}
if ( crc )
p - > crc = _pool_crc ( p ) ; /* Get crc for pool */
if ( ! _pool_protect ( p , PROT_READ ) ) {
_pool_protect ( p , PROT_READ | PROT_WRITE ) ;
return_0 ;
}
p - > locked = 1 ;
2013-01-08 02:30:29 +04:00
log_debug_mem ( " Pool %s is locked. " , p - > name ) ;
2011-08-11 21:29:04 +04:00
return 1 ;
}
/**
* Unlock memory pool .
*
* \ param p
* Pool to be unlocked .
*
* \ param crc
* Bool enables compare of the pool crc / hash with the stored value
* at pool lock . The pool is not properly unlocked if there is a mismatch .
*
* \ return
* 1 ( success ) when the pool was properly unlocked , 0 otherwise .
*/
int dm_pool_unlock ( struct dm_pool * p , int crc )
{
if ( ! p - > locked ) {
log_error ( INTERNAL_ERROR " Pool %s is already unlocked. " ,
p - > name ) ;
return 0 ;
}
p - > locked = 0 ;
if ( ! _pool_protect ( p , PROT_READ | PROT_WRITE ) )
return_0 ;
2013-01-08 02:30:29 +04:00
log_debug_mem ( " Pool %s is unlocked. " , p - > name ) ;
2011-08-11 21:29:04 +04:00
if ( crc & & ( p - > crc ! = _pool_crc ( p ) ) ) {
log_error ( INTERNAL_ERROR " Pool %s crc mismatch. " , p - > name ) ;
return 0 ;
}
return 1 ;
}