1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2011 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
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "device_mapper/misc/dmlib.h"
#include <sys/mman.h>
#include <pthread.h>
static DM_LIST_INIT(_dm_pools);
static pthread_mutex_t _dm_pools_mutex = PTHREAD_MUTEX_INITIALIZER;
void dm_pools_check_leaks(void);
#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
#ifdef DEBUG_POOL
#include "pool-debug.c"
#else
#include "pool-fast.c"
#endif
char *dm_pool_strdup(struct dm_pool *p, const char *str)
{
size_t len = strlen(str) + 1;
char *ret = dm_pool_alloc(p, len);
if (ret)
memcpy(ret, str, len);
return ret;
}
char *dm_pool_strndup(struct dm_pool *p, const char *str, size_t n)
{
size_t slen = strlen(str);
size_t len = (slen < n) ? slen : n;
char *ret = dm_pool_alloc(p, n + 1);
if (ret) {
ret[len] = '\0';
memcpy(ret, str, len);
}
return ret;
}
void *dm_pool_zalloc(struct dm_pool *p, size_t s)
{
void *ptr = dm_pool_alloc(p, s);
if (ptr)
memset(ptr, 0, s);
return ptr;
}
void dm_pools_check_leaks(void)
{
struct dm_pool *p;
pthread_mutex_lock(&_dm_pools_mutex);
if (dm_list_empty(&_dm_pools)) {
pthread_mutex_unlock(&_dm_pools_mutex);
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
log_error(" [%p] %s", (void *)p, p->name);
#endif
}
pthread_mutex_unlock(&_dm_pools_mutex);
log_error(INTERNAL_ERROR "Unreleased memory pool(s) found.");
}
/**
* 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 properly 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;
log_debug_mem("Pool %s is locked.", p->name);
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;
log_debug_mem("Pool %s is unlocked.", p->name);
if (crc && (p->crc != _pool_crc(p))) {
log_error(INTERNAL_ERROR "Pool %s crc mismatch.", p->name);
return 0;
}
return 1;
}
|