Coverage Report

Created: 2025-06-22 06:56

/src/lvm2/libdm/mm/pool.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.  
3
 * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
4
 *
5
 * This file is part of the device-mapper userspace tools.
6
 *
7
 * This copyrighted material is made available to anyone wishing to use,
8
 * modify, copy, or redistribute it subject to the terms and conditions
9
 * of the GNU Lesser General Public License v.2.1.
10
 *
11
 * You should have received a copy of the GNU Lesser General Public License
12
 * along with this program; if not, write to the Free Software Foundation,
13
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
14
 */
15
16
#include "libdm/misc/dmlib.h"
17
#include <sys/mman.h>
18
#include <pthread.h>
19
20
static DM_LIST_INIT(_dm_pools);
21
static pthread_mutex_t _dm_pools_mutex = PTHREAD_MUTEX_INITIALIZER;
22
void dm_pools_check_leaks(void);
23
24
#ifdef DEBUG_ENFORCE_POOL_LOCKING
25
#ifdef DEBUG_POOL
26
#error Do not use DEBUG_POOL with DEBUG_ENFORCE_POOL_LOCKING
27
#endif
28
29
/*
30
 * Use mprotect system call to ensure all locked pages are not writable.
31
 * Generates segmentation fault with write access to the locked pool.
32
 *
33
 * - Implementation is using posix_memalign() to get page aligned
34
 *   memory blocks (could be implemented also through malloc).
35
 * - Only pool-fast is properly handled for now.
36
 * - Checksum is slower compared to mprotect.
37
 */
38
static size_t _pagesize = 0;
39
static size_t _pagesize_mask = 0;
40
#define ALIGN_ON_PAGE(size) (((size) + (_pagesize_mask)) & ~(_pagesize_mask))
41
#endif
42
43
#ifdef DEBUG_POOL
44
#include "pool-debug.c"
45
#else
46
#include "pool-fast.c"
47
#endif
48
49
char *dm_pool_strdup(struct dm_pool *p, const char *str)
50
0
{
51
0
  size_t len = strlen(str) + 1;
52
0
  char *ret = dm_pool_alloc(p, len);
53
54
0
  if (ret)
55
0
    memcpy(ret, str, len);
56
57
0
  return ret;
58
0
}
59
60
char *dm_pool_strndup(struct dm_pool *p, const char *str, size_t n)
61
0
{
62
0
  size_t slen = strlen(str);
63
0
  size_t len = (slen < n) ? slen : n;
64
0
  char *ret = dm_pool_alloc(p, n + 1);
65
66
0
  if (ret) {
67
0
    ret[len] = '\0';
68
0
    memcpy(ret, str, len);
69
0
  }
70
71
0
  return ret;
72
0
}
73
74
void *dm_pool_zalloc(struct dm_pool *p, size_t s)
75
0
{
76
0
  void *ptr = dm_pool_alloc(p, s);
77
78
0
  if (ptr)
79
0
    memset(ptr, 0, s);
80
81
0
  return ptr;
82
0
}
83
84
void dm_pools_check_leaks(void)
85
0
{
86
0
  struct dm_pool *p;
87
88
0
  pthread_mutex_lock(&_dm_pools_mutex);
89
0
  if (dm_list_empty(&_dm_pools)) {
90
0
    pthread_mutex_unlock(&_dm_pools_mutex);
91
0
    return;
92
0
  }
93
94
0
  log_error("You have a memory leak (not released memory pool):");
95
0
  dm_list_iterate_items(p, &_dm_pools) {
96
#ifdef DEBUG_POOL
97
    log_error(" [%p] %s (%u bytes)",
98
        p->orig_pool,
99
        p->name, p->stats.bytes);
100
#else
101
0
    log_error(" [%p] %s", (void *)p, p->name);
102
0
#endif
103
0
  }
104
0
  pthread_mutex_unlock(&_dm_pools_mutex);
105
0
  log_error(INTERNAL_ERROR "Unreleased memory pool(s) found.");
106
0
}
107
108
/**
109
 * Status of locked pool.
110
 *
111
 * \param p
112
 * Pool to be tested for lock status.
113
 *
114
 * \return
115
 * 1 when the pool is locked, 0 otherwise.
116
 */
117
int dm_pool_locked(struct dm_pool *p)
118
0
{
119
0
  return p->locked;
120
0
}
121
122
/**
123
 * Lock memory pool.
124
 *
125
 * \param p
126
 * Pool to be locked.
127
 *
128
 * \param crc
129
 * Bool specifies whether to store the pool crc/hash checksum.
130
 *
131
 * \return
132
 * 1 (success) when the pool was properly locked, 0 otherwise.
133
 */
134
int dm_pool_lock(struct dm_pool *p, int crc)
135
0
{
136
0
  if (p->locked) {
137
0
    log_error(INTERNAL_ERROR "Pool %s is already locked.",
138
0
        p->name);
139
0
    return 0;
140
0
  }
141
142
0
  if (crc)
143
0
    p->crc = _pool_crc(p);  /* Get crc for pool */
144
145
0
  if (!_pool_protect(p, PROT_READ)) {
146
0
    _pool_protect(p, PROT_READ | PROT_WRITE);
147
0
    return_0;
148
0
  }
149
150
0
  p->locked = 1;
151
152
0
  log_debug_mem("Pool %s is locked.", p->name);
153
154
0
  return 1;
155
0
}
156
157
/**
158
 * Unlock memory pool.
159
 *
160
 * \param p
161
 * Pool to be unlocked.
162
 *
163
 * \param crc
164
 * Bool enables compare of the pool crc/hash with the stored value
165
 * at pool lock. The pool is not properly unlocked if there is a mismatch.
166
 *
167
 * \return
168
 * 1 (success) when the pool was properly unlocked, 0 otherwise.
169
 */
170
int dm_pool_unlock(struct dm_pool *p, int crc)
171
0
{
172
0
  if (!p->locked) {
173
0
    log_error(INTERNAL_ERROR "Pool %s is already unlocked.",
174
0
        p->name);
175
0
    return 0;
176
0
  }
177
178
0
  p->locked = 0;
179
180
0
  if (!_pool_protect(p, PROT_READ | PROT_WRITE))
181
0
    return_0;
182
183
0
  log_debug_mem("Pool %s is unlocked.", p->name);
184
185
0
  if (crc && (p->crc != _pool_crc(p))) {
186
0
    log_error(INTERNAL_ERROR "Pool %s crc mismatch.", p->name);
187
0
    return 0;
188
0
  }
189
190
0
  return 1;
191
0
}