/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 | } |