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 ,
2016-01-21 13:49:46 +03:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2005-10-16 18:33:22 +04:00
*/
2018-05-14 12:30:20 +03:00
# include "libdm/misc/dmlib.h"
2011-08-11 21:29:04 +04:00
# include <sys/mman.h>
2013-10-10 00:19:06 +04:00
# include <pthread.h>
2008-11-03 21:59:59 +03:00
2009-04-10 13:56:58 +04:00
static DM_LIST_INIT ( _dm_pools ) ;
2013-10-10 00:19:06 +04:00
static pthread_mutex_t _dm_pools_mutex = PTHREAD_MUTEX_INITIALIZER ;
2009-04-10 13:56:58 +04:00
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 .
*/
2017-10-18 17:57:46 +03:00
static size_t _pagesize = 0 ;
static size_t _pagesize_mask = 0 ;
# define ALIGN_ON_PAGE(size) (((size) + (_pagesize_mask)) & ~(_pagesize_mask))
2011-08-11 21:29:04 +04:00
# 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
{
2016-02-11 14:00:28 +03:00
size_t len = strlen ( str ) + 1 ;
char * ret = dm_pool_alloc ( p , len ) ;
2005-10-16 18:33:22 +04:00
if ( ret )
2016-02-11 14:00:28 +03:00
memcpy ( ret , str , len ) ;
2005-10-16 18:33:22 +04:00
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
{
2018-12-01 02:35:41 +03:00
size_t slen = strlen ( str ) ;
size_t len = ( slen < n ) ? slen : n ;
2016-02-11 14:00:28 +03:00
char * ret = dm_pool_alloc ( p , n + 1 ) ;
2005-10-16 18:33:22 +04:00
if ( ret ) {
2018-12-01 02:35:41 +03:00
ret [ len ] = ' \0 ' ;
memcpy ( ret , str , len ) ;
2005-10-16 18:33:22 +04:00
}
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 ;
2013-10-10 00:19:06 +04:00
pthread_mutex_lock ( & _dm_pools_mutex ) ;
if ( dm_list_empty ( & _dm_pools ) ) {
pthread_mutex_unlock ( & _dm_pools_mutex ) ;
2009-04-10 13:56:58 +04:00
return ;
2013-10-10 00:19:06 +04:00
}
2009-04-10 13:56:58 +04:00
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
2020-08-28 20:35:25 +03:00
log_error ( " [%p] %s " , ( void * ) p , p - > name ) ;
2009-04-10 13:56:58 +04:00
# endif
}
2013-10-10 00:19:06 +04:00
pthread_mutex_unlock ( & _dm_pools_mutex ) ;
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 ;
}