2005-10-16 18:33:22 +04:00
/*
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
* Copyright ( C ) 2004 - 2005 Red Hat , Inc . All rights reserved .
*
* 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"
2009-03-26 12:25:18 +03:00
# include <assert.h>
2005-10-16 18:33:22 +04:00
struct block {
struct block * next ;
size_t size ;
void * data ;
} ;
typedef struct {
unsigned block_serialno ; /* Non-decreasing serialno of block */
unsigned blocks_allocated ; /* Current number of blocks allocated */
unsigned blocks_max ; /* Max no of concurrently-allocated blocks */
unsigned int bytes , maxbytes ;
} pool_stats ;
2005-10-17 02:57:20 +04:00
struct dm_pool {
2009-04-10 13:56:58 +04:00
struct dm_list list ;
2005-10-16 18:33:22 +04:00
const char * name ;
2009-04-10 13:56:58 +04:00
void * orig_pool ; /* to pair it with first allocation call */
2011-08-11 21:29:04 +04:00
unsigned locked ;
long crc ;
2005-10-16 18:33:22 +04:00
int begun ;
struct block * object ;
struct block * blocks ;
struct block * tail ;
pool_stats stats ;
} ;
/* by default things come out aligned for doubles */
# define DEFAULT_ALIGNMENT __alignof__ (double)
2009-03-26 12:25:18 +03:00
struct dm_pool * dm_pool_create ( const char * name , size_t chunk_hint )
2005-10-16 18:33:22 +04:00
{
2011-03-30 16:16:15 +04:00
struct dm_pool * mem = dm_zalloc ( sizeof ( * mem ) ) ;
2005-10-16 18:33:22 +04:00
if ( ! mem ) {
log_error ( " Couldn't create memory pool %s (size % "
PRIsize_t " ) " , name , sizeof ( * mem ) ) ;
return NULL ;
}
mem - > name = name ;
2009-04-10 13:56:58 +04:00
mem - > orig_pool = mem ;
2005-10-16 18:33:22 +04:00
# ifdef DEBUG_POOL
2010-02-18 18:38:32 +03:00
log_debug_mem ( " Created mempool %s at %p " , name , mem ) ;
2005-10-16 18:33:22 +04:00
# endif
2009-04-10 13:56:58 +04:00
dm_list_add ( & _dm_pools , & mem - > list ) ;
2005-10-16 18:33:22 +04:00
return mem ;
}
2005-10-17 02:57:20 +04:00
static void _free_blocks ( struct dm_pool * p , struct block * b )
2005-10-16 18:33:22 +04:00
{
struct block * n ;
2011-08-11 21:29:04 +04:00
if ( p - > locked )
log_error ( INTERNAL_ERROR " _free_blocks from locked pool %s " ,
p - > name ) ;
2005-10-16 18:33:22 +04:00
while ( b ) {
p - > stats . bytes - = b - > size ;
p - > stats . blocks_allocated - - ;
n = b - > next ;
2005-10-17 02:57:20 +04:00
dm_free ( b - > data ) ;
dm_free ( b ) ;
2005-10-16 18:33:22 +04:00
b = n ;
}
}
2005-10-17 02:57:20 +04:00
static void _pool_stats ( struct dm_pool * p , const char * action )
2005-10-16 18:33:22 +04:00
{
# ifdef DEBUG_POOL
2010-02-18 18:38:32 +03:00
log_debug_mem ( " %s mempool %s at %p: %u/%u bytes, %u/%u blocks, "
" %u allocations) " , action , p - > name , p , p - > stats . bytes ,
2013-01-08 02:30:29 +04:00
p - > stats . maxbytes , p - > stats . blocks_allocated ,
p - > stats . blocks_max , p - > stats . block_serialno ) ;
2005-10-16 18:33:22 +04:00
# else
;
# endif
}
2005-10-17 02:57:20 +04:00
void dm_pool_destroy ( struct dm_pool * p )
2005-10-16 18:33:22 +04:00
{
_pool_stats ( p , " Destroying " ) ;
_free_blocks ( p , p - > blocks ) ;
2009-04-10 13:56:58 +04:00
dm_list_del ( & p - > list ) ;
2005-10-17 02:57:20 +04:00
dm_free ( p ) ;
2005-10-16 18:33:22 +04:00
}
2005-10-17 02:57:20 +04:00
void * dm_pool_alloc ( struct dm_pool * p , size_t s )
2005-10-16 18:33:22 +04:00
{
2005-10-17 02:57:20 +04:00
return dm_pool_alloc_aligned ( p , s , DEFAULT_ALIGNMENT ) ;
2005-10-16 18:33:22 +04:00
}
2005-10-17 02:57:20 +04:00
static void _append_block ( struct dm_pool * p , struct block * b )
2005-10-16 18:33:22 +04:00
{
2011-08-11 21:29:04 +04:00
if ( p - > locked )
log_error ( INTERNAL_ERROR " _append_blocks to locked pool %s " ,
p - > name ) ;
2005-10-16 18:33:22 +04:00
if ( p - > tail ) {
p - > tail - > next = b ;
p - > tail = b ;
} else
p - > blocks = p - > tail = b ;
p - > stats . block_serialno + + ;
p - > stats . blocks_allocated + + ;
if ( p - > stats . blocks_allocated > p - > stats . blocks_max )
p - > stats . blocks_max = p - > stats . blocks_allocated ;
p - > stats . bytes + = b - > size ;
if ( p - > stats . bytes > p - > stats . maxbytes )
p - > stats . maxbytes = p - > stats . bytes ;
}
static struct block * _new_block ( size_t s , unsigned alignment )
{
/* FIXME: I'm currently ignoring the alignment arg. */
size_t len = sizeof ( struct block ) + s ;
2005-10-17 02:57:20 +04:00
struct block * b = dm_malloc ( len ) ;
2005-10-16 18:33:22 +04:00
/*
* Too lazy to implement alignment for debug version , and
* I don ' t think LVM will use anything but default
* align .
*/
2011-03-30 16:57:03 +04:00
assert ( alignment < = DEFAULT_ALIGNMENT ) ;
2005-10-16 18:33:22 +04:00
if ( ! b ) {
2009-07-16 00:02:46 +04:00
log_error ( " Out of memory " ) ;
2005-10-16 18:33:22 +04:00
return NULL ;
}
2005-10-17 02:57:20 +04:00
if ( ! ( b - > data = dm_malloc ( s ) ) ) {
2009-07-16 00:02:46 +04:00
log_error ( " Out of memory " ) ;
2005-10-17 02:57:20 +04:00
dm_free ( b ) ;
2005-10-16 18:33:22 +04:00
return NULL ;
}
b - > next = NULL ;
b - > size = s ;
return b ;
}
2005-10-17 02:57:20 +04:00
void * dm_pool_alloc_aligned ( struct dm_pool * p , size_t s , unsigned alignment )
2005-10-16 18:33:22 +04:00
{
struct block * b = _new_block ( s , alignment ) ;
if ( ! b )
return NULL ;
_append_block ( p , b ) ;
return b - > data ;
}
2005-10-17 02:57:20 +04:00
void dm_pool_empty ( struct dm_pool * p )
2005-10-16 18:33:22 +04:00
{
_pool_stats ( p , " Emptying " ) ;
_free_blocks ( p , p - > blocks ) ;
p - > blocks = p - > tail = NULL ;
}
2005-10-17 02:57:20 +04:00
void dm_pool_free ( struct dm_pool * p , void * ptr )
2005-10-16 18:33:22 +04:00
{
struct block * b , * prev = NULL ;
_pool_stats ( p , " Freeing (before) " ) ;
for ( b = p - > blocks ; b ; b = b - > next ) {
if ( b - > data = = ptr )
break ;
prev = b ;
}
/*
* If this fires then you tried to free a
* pointer that either wasn ' t from this
* pool , or isn ' t the start of a block .
*/
assert ( b ) ;
_free_blocks ( p , b ) ;
if ( prev ) {
p - > tail = prev ;
prev - > next = NULL ;
} else
p - > blocks = p - > tail = NULL ;
_pool_stats ( p , " Freeing (after) " ) ;
}
2005-10-17 02:57:20 +04:00
int dm_pool_begin_object ( struct dm_pool * p , size_t init_size )
2005-10-16 18:33:22 +04:00
{
assert ( ! p - > begun ) ;
p - > begun = 1 ;
return 1 ;
}
2008-04-19 19:50:18 +04:00
int dm_pool_grow_object ( struct dm_pool * p , const void * extra , size_t delta )
2005-10-16 18:33:22 +04:00
{
struct block * new ;
2009-04-02 19:02:18 +04:00
size_t new_size ;
2011-08-11 21:29:04 +04:00
if ( p - > locked )
log_error ( INTERNAL_ERROR " Grow objects in locked pool %s " ,
p - > name ) ;
2009-04-02 19:02:18 +04:00
if ( ! delta )
delta = strlen ( extra ) ;
2005-10-16 18:33:22 +04:00
assert ( p - > begun ) ;
if ( p - > object )
2009-04-02 19:02:18 +04:00
new_size = delta + p - > object - > size ;
else
new_size = delta ;
2005-10-16 18:33:22 +04:00
2009-04-02 19:02:18 +04:00
if ( ! ( new = _new_block ( new_size , DEFAULT_ALIGNMENT ) ) ) {
2009-07-16 00:02:46 +04:00
log_error ( " Couldn't extend object. " ) ;
2005-10-16 18:33:22 +04:00
return 0 ;
}
if ( p - > object ) {
memcpy ( new - > data , p - > object - > data , p - > object - > size ) ;
2005-10-17 02:57:20 +04:00
dm_free ( p - > object - > data ) ;
dm_free ( p - > object ) ;
2005-10-16 18:33:22 +04:00
}
p - > object = new ;
2011-02-28 22:54:30 +03:00
memcpy ( ( char * ) new - > data + new_size - delta , extra , delta ) ;
2005-10-16 18:33:22 +04:00
return 1 ;
}
2005-10-17 02:57:20 +04:00
void * dm_pool_end_object ( struct dm_pool * p )
2005-10-16 18:33:22 +04:00
{
assert ( p - > begun ) ;
_append_block ( p , p - > object ) ;
p - > begun = 0 ;
p - > object = NULL ;
return p - > tail - > data ;
}
2005-10-17 02:57:20 +04:00
void dm_pool_abandon_object ( struct dm_pool * p )
2005-10-16 18:33:22 +04:00
{
assert ( p - > begun ) ;
2005-10-17 02:57:20 +04:00
dm_free ( p - > object ) ;
2005-10-16 18:33:22 +04:00
p - > begun = 0 ;
p - > object = NULL ;
}
2011-08-11 21:29:04 +04:00
static long _pool_crc ( const struct dm_pool * p )
{
# ifndef DEBUG_ENFORCE_POOL_LOCKING
# warning pool crc not implemented with pool debug
# endif
return 0 ;
}
static int _pool_protect ( struct dm_pool * p , int prot )
{
# ifdef DEBUG_ENFORCE_POOL_LOCKING
# warning pool mprotect not implemented with pool debug
# endif
return 1 ;
}