]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/mem_pool.c
Buffer overrun fixes
[bacula/bacula] / bacula / src / lib / mem_pool.c
1 /*
2  *  Bacula memory pool routines. 
3  *
4  *  The idea behind these routines is that there will be
5  *  pools of memory that are pre-allocated for quick
6  *  access. The pools will have a fixed memory size on allocation
7  *  but if need be, the size can be increased. This is 
8  *  particularly useful for filename
9  *  buffers where 256 bytes should be sufficient in 99.99%
10  *  of the cases, but when it isn't we want to be able to
11  *  increase the size.
12  *
13  *  A major advantage of the pool memory aside from the speed
14  *  is that the buffer carrys around its size, so to ensure that
15  *  there is enough memory, simply call the check_pool_memory_size()
16  *  with the desired size and it will adjust only if necessary.
17  *
18  *           Kern E. Sibbald
19  *
20  *   Version $Id$
21  */
22
23 /*
24    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
25
26    This program is free software; you can redistribute it and/or
27    modify it under the terms of the GNU General Public License as
28    published by the Free Software Foundation; either version 2 of
29    the License, or (at your option) any later version.
30
31    This program is distributed in the hope that it will be useful,
32    but WITHOUT ANY WARRANTY; without even the implied warranty of
33    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
34    General Public License for more details.
35
36    You should have received a copy of the GNU General Public
37    License along with this program; if not, write to the Free
38    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
39    MA 02111-1307, USA.
40
41  */
42
43 #include "bacula.h"
44
45 struct s_pool_ctl {
46    size_t size;                       /* default size */
47    size_t max_size;                   /* max allocated */
48    size_t max_used;                   /* max buffers used */
49    size_t in_use;                     /* number in use */
50    struct abufhead *free_buf;         /* pointer to free buffers */
51 };
52
53 static struct s_pool_ctl pool_ctl[] = {
54    {  256,  256, 0, 0, NULL },        /* PM_NOPOOL no pooling */
55    {  256,  256, 0, 0, NULL },        /* PM_FNAME filename buffers */
56    {  512,  512, 0, 0, NULL },        /* PM_MESSAGE message buffer */
57    { 1024, 1024, 0, 0, NULL }         /* PM_EMSG error message buffer */
58 };
59
60 /*  Memory allocation control structures and storage.  */
61 struct abufhead {
62    size_t ablen;                      /* Buffer length in bytes */
63    int32_t pool;                      /* pool */
64    struct abufhead *next;             /* pointer to next free buffer */
65 };
66
67 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
68
69
70 #ifdef SMARTALLOC
71
72 #define HEAD_SIZE BALIGN(sizeof(struct abufhead))
73
74 extern POOLMEM *sm_malloc(char *fname, int lineno, int nbytes);
75
76 POOLMEM *sm_get_pool_memory(char *fname, int lineno, int pool)
77 {
78    struct abufhead *buf;
79
80    sm_check(fname, lineno, True);
81    if (pool > PM_MAX) {
82       Emsg2(M_ABORT, 0, "MemPool index %d larger than max %d\n", pool, PM_MAX);
83    }
84    P(mutex);
85    if (pool_ctl[pool].free_buf) {
86       buf = pool_ctl[pool].free_buf;
87       pool_ctl[pool].free_buf = buf->next;
88       pool_ctl[pool].in_use++;
89       if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
90          pool_ctl[pool].max_used = pool_ctl[pool].in_use;
91       }
92       V(mutex);
93       Dmsg3(150, "sm_get_pool_memory reuse %x to %s:%d\n", buf, fname, lineno);
94       sm_new_owner(fname, lineno, (char *)buf);
95       return (POOLMEM *)((char *)buf+HEAD_SIZE);
96    }
97       
98    if ((buf = (struct abufhead *) sm_malloc(fname, lineno, pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
99       V(mutex);
100       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", pool_ctl[pool].size);
101    }
102    buf->ablen = pool_ctl[pool].size;
103    buf->pool = pool;
104    pool_ctl[pool].in_use++;
105    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
106       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
107    }
108    V(mutex);
109    Dmsg3(150, "sm_get_pool_memory give %x to %s:%d\n", buf, fname, lineno);
110    return (POOLMEM *)((char *)buf+HEAD_SIZE);
111 }
112
113 /* Get nonpool memory of size requested */
114 POOLMEM *sm_get_memory(char *fname, int lineno, size_t size)
115 {
116    struct abufhead *buf;
117    int pool = 0;
118
119    sm_check(fname, lineno, True);
120    if ((buf = (struct abufhead *) sm_malloc(fname, lineno, size+HEAD_SIZE)) == NULL) {
121       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
122    }
123    buf->ablen = size;
124    buf->pool = pool;
125    buf->next = NULL;
126    pool_ctl[pool].in_use++;
127    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used)
128       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
129    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
130 }
131
132
133 /* Return the size of a memory buffer */
134 size_t sm_sizeof_pool_memory(char *fname, int lineno, POOLMEM *obuf)
135 {
136    char *cp = (char *)obuf;
137
138    sm_check(fname, lineno, False);
139    ASSERT(obuf);
140    cp -= HEAD_SIZE;
141    return ((struct abufhead *)cp)->ablen;
142 }
143
144 /* Realloc pool memory buffer */
145 POOLMEM *sm_realloc_pool_memory(char *fname, int lineno, POOLMEM *obuf, size_t size)
146 {
147    char *cp = (char *)obuf;
148    void *buf;
149    int pool;
150
151    sm_check(fname, lineno, False);
152    ASSERT(obuf);
153    P(mutex);
154    cp -= HEAD_SIZE;
155    buf = realloc(cp, size+HEAD_SIZE);
156    if (buf == NULL) {
157       V(mutex);
158       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
159    }
160    ((struct abufhead *)buf)->ablen = size;
161    pool = ((struct abufhead *)buf)->pool;
162    if (size > pool_ctl[pool].max_size) {
163       pool_ctl[pool].max_size = size;
164    }
165    V(mutex);
166    sm_check(fname, lineno, False);
167    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
168 }
169
170 POOLMEM *sm_check_pool_memory_size(char *fname, int lineno, POOLMEM *obuf, size_t size)
171 {
172    sm_check(fname, lineno, False);
173    ASSERT(obuf);
174    if (size <= sizeof_pool_memory(obuf)) {
175       return obuf;
176    }
177    return realloc_pool_memory(obuf, size);
178 }
179
180 #else
181
182 POOLMEM *get_pool_memory(int pool)
183 {
184    struct abufhead *buf;
185
186    P(mutex);
187    if (pool_ctl[pool].free_buf) {
188       buf = pool_ctl[pool].free_buf;
189       pool_ctl[pool].free_buf = buf->next;
190       V(mutex);
191       return (POOLMEM *)((char *)buf+HEAD_SIZE);
192    }
193       
194    if ((buf=malloc(pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
195       V(mutex);
196       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", pool_ctl[pool].size);
197    }
198    buf->ablen = pool_ctl[pool].size;
199    buf->pool = pool;
200    buf->next = NULL;
201    pool_ctl[pool].in_use++;
202    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
203       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
204    }
205    V(mutex);
206    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
207 }
208
209 /* Get nonpool memory of size requested */
210 POOLMEM *get_memory(size_t size)
211 {
212    struct abufhead *buf;
213    int pool = 0;
214
215    if ((buf=malloc(size+HEAD_SIZE)) == NULL) {
216       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
217    }
218    buf->ablen = size;
219    buf->pool = pool;
220    buf->next = NULL;
221    pool_ctl[pool].in_use++;
222    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
223       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
224    }
225    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
226 }
227
228
229 /* Return the size of a memory buffer */
230 size_t sizeof_pool_memory(POOLMEM *obuf)
231 {
232    char *cp = (char *)obuf;
233
234    ASSERT(obuf);
235    cp -= HEAD_SIZE;
236    return ((struct abufhead *)cp)->ablen;
237 }
238
239 /* Realloc pool memory buffer */
240 POOLMEM *realloc_pool_memory(POOLMEM *obuf, size_t size)
241 {
242    char *cp = (char *)obuf;
243    void *buf;
244    int pool;
245
246    ASSERT(obuf);
247    P(mutex);
248    cp -= HEAD_SIZE;
249    buf = realloc(cp, size+HEAD_SIZE);
250    if (buf == NULL) {
251       V(mutex);
252       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
253    }
254    ((struct abufhead *)buf)->ablen = size;
255    pool = ((struct abufhead *)buf)->pool;
256    if (size > pool_ctl[pool].max_size) {
257       pool_ctl[pool].max_size = size;
258    }
259    V(mutex);
260    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
261 }
262
263 POOLMEM *check_pool_memory_size(POOLMEM *obuf, size_t size)
264 {
265    ASSERT(obuf);
266    if (size <= sizeof_pool_memory(obuf)) {
267       return obuf;
268    }
269    return realloc_pool_memory(obuf, size);
270 }
271
272 #endif /* SMARTALLOC */
273
274
275
276 /* Free a memory buffer */
277 void free_pool_memory(POOLMEM *obuf)
278 {
279    struct abufhead *buf;
280    int pool;
281
282    sm_check(__FILE__, __LINE__, False);
283    ASSERT(obuf);
284    P(mutex);
285    buf = (struct abufhead *)((char *)obuf - HEAD_SIZE);
286    pool = buf->pool;
287    pool_ctl[pool].in_use--;
288    if (pool == 0) {
289       free((char *)buf);              /* free nonpooled memory */
290    } else {                           /* otherwise link it to the free pool chain */
291 #ifdef DEBUG
292       struct abufhead *next;
293       /* Don't let him free the same buffer twice */
294       for (next=pool_ctl[pool].free_buf; next; next=next->next) {
295          ASSERT(next != buf);  /* attempt to free twice */
296       }
297 #endif
298       buf->next = pool_ctl[pool].free_buf;
299       pool_ctl[pool].free_buf = buf;
300    }
301    Dmsg2(150, "free_pool_memory %x pool=%d\n", buf, pool);
302    V(mutex);
303 }
304
305
306
307 /* Release all pooled memory */
308 void close_memory_pool()
309 {
310    struct abufhead *buf, *next;
311    int i;
312
313    sm_check(__FILE__, __LINE__, False);
314    P(mutex);
315    for (i=1; i<=PM_MAX; i++) {
316       buf = pool_ctl[i].free_buf;
317       while (buf) {
318          next = buf->next;
319          free((char *)buf);
320          buf = next;
321       }
322       pool_ctl[i].free_buf = NULL;
323    }
324    V(mutex);
325 }
326
327 #ifdef DEBUG
328
329 static char *pool_name(int pool)
330 {
331    static char *name[] = {"NoPool", "FNAME ", "MSG   ", "EMSG  "};
332    static char buf[30];
333
334    if (pool >= 0 && pool <= PM_MAX) {
335       return name[pool];
336    }
337    sprintf(buf, "%-6d", pool);
338    return buf;
339 }
340    
341 /* Print staticstics on memory pool usage   
342  */ 
343 void print_memory_pool_stats()
344 {
345    int i;
346
347    Dmsg0(-1, "Pool   Maxsize  Maxused  Inuse\n");
348    for (i=0; i<=PM_MAX; i++)
349       Dmsg4(-1, "%5s  %7d  %7d  %5d\n", pool_name(i), pool_ctl[i].max_size,
350          pool_ctl[i].max_used, pool_ctl[i].in_use);
351
352    Dmsg0(-1, "\n");
353 }
354
355 #else
356 void print_memory_pool_stats() {} 
357 #endif /* DEBUG */