smalloc.c revision c08e194db676bd9dcd0f43bacf2051c7c91a62df
1572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams/*
2572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams * simple memory allocator, backed by mmap() so that it hands out memory
3572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams * that can be shared across processes and threads
4572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams */
5572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams#include <sys/mman.h>
6572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams#include <stdio.h>
7572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams#include <stdlib.h>
8572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams#include <assert.h>
9572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams#include <string.h>
10572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams#include <unistd.h>
11572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams#include <sys/types.h>
12572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams#include <limits.h>
13572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
14572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams#include "mutex.h"
15572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
16572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams#undef ENABLE_RESIZE		/* define to enable pool resizing */
17572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams#define MP_SAFE			/* define to made allocator thread safe */
18572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
19572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams#define INITIAL_SIZE	1048576	/* new pool size */
20572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams#define MAX_POOLS	32	/* maximum number of pools to setup */
21572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
22572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsunsigned int smalloc_pool_size = INITIAL_SIZE;
23572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
24572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams#ifdef ENABLE_RESIZE
25572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams#define MAX_SIZE	8 * smalloc_pool_size
26572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstatic unsigned int resize_error;
27572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams#endif
28572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
29572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstruct pool {
30572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	struct fio_mutex *lock;			/* protects this pool */
31572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	void *map;				/* map of blocks */
32572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	void *last;				/* next free block hint */
33572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	unsigned int size;			/* size of pool */
34572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	unsigned int room;			/* size left in pool */
35572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	unsigned int largest_block;		/* largest block free */
36572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	unsigned int free_since_compact;	/* sfree() since compact() */
37572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	int fd;					/* memory backing fd */
38572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	char file[PATH_MAX];			/* filename for fd */
39572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams};
40572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
41572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstatic struct pool mp[MAX_POOLS];
42572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstatic unsigned int nr_pools;
43572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstatic unsigned int last_pool;
44572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstatic struct fio_mutex *lock;
45572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
46572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstruct mem_hdr {
47572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	unsigned int size;
48572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams};
49572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
50572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstatic inline void pool_lock(struct pool *pool)
51572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams{
52572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	if (pool->lock)
53572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams		fio_mutex_down(pool->lock);
54572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams}
55572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
56572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstatic inline void pool_unlock(struct pool *pool)
57572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams{
58572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	if (pool->lock)
59572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams		fio_mutex_up(pool->lock);
60572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams}
61572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
62572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstatic inline void global_read_lock(void)
63572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams{
64572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	if (lock)
65572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams		fio_mutex_down_read(lock);
66572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams}
67572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
68572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstatic inline void global_read_unlock(void)
69572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams{
70572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	if (lock)
71572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams		fio_mutex_up_read(lock);
72572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams}
73572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
74572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstatic inline void global_write_lock(void)
75572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams{
76572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	if (lock)
77572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams		fio_mutex_down_write(lock);
78572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams}
79572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
80572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstatic inline void global_write_unlock(void)
81572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams{
82572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	if (lock)
83572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams		fio_mutex_up_write(lock);
84572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams}
85572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
86572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams#define hdr_free(hdr)		((hdr)->size & 0x80000000)
87572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams#define hdr_size(hdr)		((hdr)->size & ~0x80000000)
88572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams#define hdr_mark_free(hdr)	((hdr)->size |= 0x80000000)
89572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
90572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstatic inline int ptr_valid(struct pool *pool, void *ptr)
91572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams{
92572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	return (ptr >= pool->map) && (ptr < pool->map + pool->size);
93572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams}
94572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
95572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstatic inline int __hdr_valid(struct pool *pool, struct mem_hdr *hdr,
96572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams			      unsigned int size)
97572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams{
98572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	return ptr_valid(pool, hdr) && ptr_valid(pool, (void *) hdr + size - 1);
99572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams}
100572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
101572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstatic inline int hdr_valid(struct pool *pool, struct mem_hdr *hdr)
102572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams{
103572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	return __hdr_valid(pool, hdr, hdr_size(hdr));
104572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams}
105572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
1066a804605b99cab4ffa3cc55c691338fd4a5396eaJason Samsstatic inline int region_free(struct mem_hdr *hdr)
107572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams{
108572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	return hdr_free(hdr) || (!hdr_free(hdr) && !hdr_size(hdr));
109572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams}
110572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
111572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstatic inline struct mem_hdr *__hdr_nxt(struct pool *pool, struct mem_hdr *hdr,
112572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams					unsigned int size)
113572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams{
114572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	struct mem_hdr *nxt = (void *) hdr + size + sizeof(*hdr);
115572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
116572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	if (__hdr_valid(pool, nxt, size))
117572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams		return nxt;
118572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
119572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	return NULL;
120572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams}
121572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
122572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstatic inline struct mem_hdr *hdr_nxt(struct pool *pool, struct mem_hdr *hdr)
123572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams{
124572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	return __hdr_nxt(pool, hdr, hdr_size(hdr));
125572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams}
126572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
127572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstatic void merge(struct pool *pool, struct mem_hdr *hdr, struct mem_hdr *nxt)
128572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams{
129572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	unsigned int hfree = hdr_free(hdr);
130572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	unsigned int nfree = hdr_free(nxt);
131572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
132572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	hdr->size = hdr_size(hdr) + hdr_size(nxt) + sizeof(*nxt);
133572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	nxt->size = 0;
134572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
135572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	if (hfree)
136572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams		hdr_mark_free(hdr);
1376a804605b99cab4ffa3cc55c691338fd4a5396eaJason Sams	if (nfree)
1386a804605b99cab4ffa3cc55c691338fd4a5396eaJason Sams		hdr_mark_free(nxt);
1396a804605b99cab4ffa3cc55c691338fd4a5396eaJason Sams
1406a804605b99cab4ffa3cc55c691338fd4a5396eaJason Sams	if (pool->last == nxt)
1416a804605b99cab4ffa3cc55c691338fd4a5396eaJason Sams		pool->last = hdr;
1426a804605b99cab4ffa3cc55c691338fd4a5396eaJason Sams}
143572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
144f1d97e536561b4731997c85873dde3b3fb721cb2Stephen Hinesstatic int combine(struct pool *pool, struct mem_hdr *prv, struct mem_hdr *hdr)
145f1d97e536561b4731997c85873dde3b3fb721cb2Stephen Hines{
146572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	if (prv && hdr_free(prv) && hdr_free(hdr)) {
147572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams		merge(pool, prv, hdr);
148572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams		return 1;
149572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	}
150572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
151572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	return 0;
152572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams}
153572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
154572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstatic int compact_pool(struct pool *pool)
155572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams{
156572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	struct mem_hdr *hdr = pool->map, *nxt;
157572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	unsigned int compacted = 0;
158572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
159572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	if (pool->free_since_compact < 50)
160572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams		return 1;
161572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams
162572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams	while (hdr) {
163572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams		nxt = hdr_nxt(pool, hdr);
164572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams		if (!nxt)
165572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams			break;
166572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams		if (hdr_free(nxt) && hdr_free(hdr)) {
167572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams			merge(pool, hdr, nxt);
168			compacted++;
169			continue;
170		}
171		hdr = hdr_nxt(pool, hdr);
172	}
173
174	pool->free_since_compact = 0;
175	return !!compacted;
176}
177
178static int resize_pool(struct pool *pool)
179{
180#ifdef ENABLE_RESIZE
181	unsigned int new_size = pool->size << 1;
182	struct mem_hdr *hdr, *last_hdr;
183	void *ptr;
184
185	if (new_size >= MAX_SIZE || resize_error)
186		return 1;
187
188	if (ftruncate(pool->fd, new_size) < 0)
189		goto fail;
190
191	ptr = mremap(pool->map, pool->size, new_size, 0);
192	if (ptr == MAP_FAILED)
193		goto fail;
194
195	pool->map = ptr;
196	hdr = pool;
197	do {
198		last_hdr = hdr;
199	} while ((hdr = hdr_nxt(hdr)) != NULL);
200
201	if (hdr_free(last_hdr)) {
202		last_hdr->size = hdr_size(last_hdr) + new_size - pool_size;
203		hdr_mark_free(last_hdr);
204	} else {
205		struct mem_hdr *nxt;
206
207		nxt = (void *) last_hdr + hdr_size(last_hdr) + sizeof(*hdr);
208		nxt->size = new_size - pool_size - sizeof(*hdr);
209		hdr_mark_free(nxt);
210	}
211
212	pool_room += new_size - pool_size;
213	pool_size = new_size;
214	return 0;
215fail:
216	perror("resize");
217	resize_error = 1;
218#else
219	return 1;
220#endif
221}
222
223static int add_pool(struct pool *pool, unsigned int alloc_size)
224{
225	struct mem_hdr *hdr;
226	void *ptr;
227	int fd;
228
229	strcpy(pool->file, "/tmp/.fio_smalloc.XXXXXX");
230	fd = mkstemp(pool->file);
231	if (fd < 0)
232		goto out_close;
233
234	alloc_size += sizeof(*hdr);
235	if (alloc_size > smalloc_pool_size)
236		pool->size = alloc_size;
237	else
238		pool->size = smalloc_pool_size;
239
240	if (ftruncate(fd, pool->size) < 0)
241		goto out_unlink;
242
243	ptr = mmap(NULL, pool->size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
244	if (ptr == MAP_FAILED)
245		goto out_unlink;
246
247	memset(ptr, 0, pool->size);
248	pool->map = pool->last = ptr;
249
250#ifdef MP_SAFE
251	pool->lock = fio_mutex_init(1);
252	if (!pool->lock)
253		goto out_unlink;
254#endif
255
256	pool->fd = fd;
257
258	hdr = pool->map;
259	pool->room = hdr->size = pool->size - sizeof(*hdr);
260	pool->largest_block = pool->room;
261	hdr_mark_free(hdr);
262	global_write_lock();
263	nr_pools++;
264	global_write_unlock();
265	return 0;
266out_unlink:
267	if (pool->map)
268		munmap(pool->map, pool->size);
269	unlink(pool->file);
270out_close:
271	if (fd >= 0)
272		close(fd);
273	return 1;
274}
275
276void sinit(void)
277{
278	int ret;
279
280#ifdef MP_SAFE
281	lock = fio_mutex_rw_init();
282#endif
283	ret = add_pool(&mp[0], INITIAL_SIZE);
284	assert(!ret);
285}
286
287static void cleanup_pool(struct pool *pool)
288{
289	unlink(pool->file);
290	close(pool->fd);
291	munmap(pool->map, pool->size);
292
293	if (pool->lock)
294		fio_mutex_remove(pool->lock);
295}
296
297void scleanup(void)
298{
299	unsigned int i;
300
301	for (i = 0; i < nr_pools; i++)
302		cleanup_pool(&mp[i]);
303
304	if (lock)
305		fio_mutex_remove(lock);
306}
307
308static void sfree_pool(struct pool *pool, void *ptr)
309{
310	struct mem_hdr *hdr, *nxt;
311
312	if (!ptr)
313		return;
314
315	assert(ptr_valid(pool, ptr));
316
317	pool_lock(pool);
318	hdr = ptr - sizeof(*hdr);
319	assert(!hdr_free(hdr));
320	hdr_mark_free(hdr);
321	pool->room -= hdr_size(hdr);
322
323	nxt = hdr_nxt(pool, hdr);
324	if (nxt && hdr_free(nxt))
325		merge(pool, hdr, nxt);
326
327	if (hdr_size(hdr) > pool->largest_block)
328		pool->largest_block = hdr_size(hdr);
329
330	pool->free_since_compact++;
331	pool_unlock(pool);
332}
333
334void sfree(void *ptr)
335{
336	struct pool *pool = NULL;
337	unsigned int i;
338
339	global_read_lock();
340
341	for (i = 0; i < nr_pools; i++) {
342		if (ptr_valid(&mp[i], ptr)) {
343			pool = &mp[i];
344			break;
345		}
346	}
347
348	global_read_unlock();
349
350	assert(pool);
351	sfree_pool(pool, ptr);
352}
353
354static void *smalloc_pool(struct pool *pool, unsigned int size)
355{
356	struct mem_hdr *hdr, *prv;
357	int did_restart = 0;
358	void *ret;
359
360	/*
361	 * slight chance of race with sfree() here, but acceptable
362	 */
363	if (!size || size > pool->room + sizeof(*hdr) ||
364	    ((size > pool->largest_block) && pool->largest_block))
365		return NULL;
366
367	pool_lock(pool);
368restart:
369	hdr = pool->last;
370	prv = NULL;
371	do {
372		if (combine(pool, prv, hdr))
373			hdr = prv;
374
375		if (hdr_free(hdr) && hdr_size(hdr) >= size)
376			break;
377
378		prv = hdr;
379	} while ((hdr = hdr_nxt(pool, hdr)) != NULL);
380
381	if (!hdr)
382		goto fail;
383
384	/*
385	 * more room, adjust next header if any
386	 */
387	if (hdr_size(hdr) - size >= 2 * sizeof(*hdr)) {
388		struct mem_hdr *nxt = __hdr_nxt(pool, hdr, size);
389
390		if (nxt) {
391			nxt->size = hdr_size(hdr) - size - sizeof(*hdr);
392			if (hdr_size(hdr) == pool->largest_block)
393				pool->largest_block = hdr_size(nxt);
394			hdr_mark_free(nxt);
395		} else
396			size = hdr_size(hdr);
397	} else
398		size = hdr_size(hdr);
399
400	if (size == hdr_size(hdr) && size == pool->largest_block)
401		pool->largest_block = 0;
402
403	/*
404	 * also clears free bit
405	 */
406	hdr->size = size;
407	pool->last = hdr_nxt(pool, hdr);
408	if (!pool->last)
409		pool->last = pool->map;
410	pool->room -= size;
411	pool_unlock(pool);
412
413	ret = (void *) hdr + sizeof(*hdr);
414	memset(ret, 0, size);
415	return ret;
416fail:
417	/*
418	 * if we fail to allocate, first compact the entries that we missed.
419	 * if that also fails, increase the size of the pool
420	 */
421	++did_restart;
422	if (did_restart <= 1) {
423		if (!compact_pool(pool)) {
424			pool->last = pool->map;
425			goto restart;
426		}
427	}
428	++did_restart;
429	if (did_restart <= 2) {
430		if (!resize_pool(pool)) {
431			pool->last = pool->map;
432			goto restart;
433		}
434	}
435	pool_unlock(pool);
436	return NULL;
437}
438
439void *smalloc(unsigned int size)
440{
441	unsigned int i;
442
443	global_read_lock();
444	i = last_pool;
445
446	do {
447		for (; i < nr_pools; i++) {
448			void *ptr = smalloc_pool(&mp[i], size);
449
450			if (ptr) {
451				last_pool = i;
452				global_read_unlock();
453				return ptr;
454			}
455		}
456		if (last_pool) {
457			last_pool = 0;
458			continue;
459		}
460
461		if (nr_pools + 1 >= MAX_POOLS)
462			break;
463		else {
464			i = nr_pools;
465			global_read_unlock();
466			if (add_pool(&mp[nr_pools], size))
467				goto out;
468			global_read_lock();
469		}
470	} while (1);
471
472	global_read_unlock();
473out:
474	return NULL;
475}
476
477char *smalloc_strdup(const char *str)
478{
479	char *ptr;
480
481	ptr = smalloc(strlen(str) + 1);
482	strcpy(ptr, str);
483	return ptr;
484}
485