xref: /minix3/minix/servers/vm/slaballoc.c (revision 5f6c420586374d552d4a81aa129ada5aa46b797d)
1433d6423SLionel Sambuc 
2433d6423SLionel Sambuc #define _SYSTEM 1
3433d6423SLionel Sambuc 
4433d6423SLionel Sambuc #include <minix/callnr.h>
5433d6423SLionel Sambuc #include <minix/com.h>
6433d6423SLionel Sambuc #include <minix/config.h>
7433d6423SLionel Sambuc #include <minix/const.h>
8433d6423SLionel Sambuc #include <minix/ds.h>
9433d6423SLionel Sambuc #include <minix/endpoint.h>
10433d6423SLionel Sambuc #include <minix/minlib.h>
11433d6423SLionel Sambuc #include <minix/type.h>
12433d6423SLionel Sambuc #include <minix/ipc.h>
13433d6423SLionel Sambuc #include <minix/sysutil.h>
14433d6423SLionel Sambuc #include <minix/syslib.h>
15433d6423SLionel Sambuc #include <minix/bitmap.h>
16433d6423SLionel Sambuc #include <minix/debug.h>
17433d6423SLionel Sambuc 
18433d6423SLionel Sambuc #include <assert.h>
19433d6423SLionel Sambuc #include <errno.h>
20433d6423SLionel Sambuc #include <string.h>
21433d6423SLionel Sambuc 
22433d6423SLionel Sambuc #include <sys/param.h>
23433d6423SLionel Sambuc 
24433d6423SLionel Sambuc #include "glo.h"
25433d6423SLionel Sambuc #include "proto.h"
26433d6423SLionel Sambuc #include "util.h"
27433d6423SLionel Sambuc #include "sanitycheck.h"
28433d6423SLionel Sambuc 
29433d6423SLionel Sambuc #define SLABSIZES 200
30433d6423SLionel Sambuc 
31433d6423SLionel Sambuc #define ITEMSPERPAGE(bytes) (int)(DATABYTES / (bytes))
32433d6423SLionel Sambuc 
33433d6423SLionel Sambuc #define ELBITS		(sizeof(element_t)*8)
34433d6423SLionel Sambuc #define BITPAT(b)	(1UL << ((b) %  ELBITS))
35433d6423SLionel Sambuc #define BITEL(f, b)	(f)->sdh.usebits[(b)/ELBITS]
36433d6423SLionel Sambuc 
37433d6423SLionel Sambuc 
38433d6423SLionel Sambuc #define OFF(f, b) assert(!GETBIT(f, b))
39433d6423SLionel Sambuc #define ON(f, b)  assert(GETBIT(f, b))
40433d6423SLionel Sambuc 
41433d6423SLionel Sambuc #if MEMPROTECT
42433d6423SLionel Sambuc #define SLABDATAWRITABLE(data, wr) do {			\
43433d6423SLionel Sambuc 	assert(data->sdh.writable == WRITABLE_NONE);	\
44433d6423SLionel Sambuc 	assert(wr != WRITABLE_NONE);			\
45433d6423SLionel Sambuc 	vm_pagelock(data, 0);				\
46433d6423SLionel Sambuc 	data->sdh.writable = wr;			\
47433d6423SLionel Sambuc } while(0)
48433d6423SLionel Sambuc 
49433d6423SLionel Sambuc #define SLABDATAUNWRITABLE(data) do {			\
50433d6423SLionel Sambuc 	assert(data->sdh.writable != WRITABLE_NONE);	\
51433d6423SLionel Sambuc 	data->sdh.writable = WRITABLE_NONE;		\
52433d6423SLionel Sambuc 	vm_pagelock(data, 1);				\
53433d6423SLionel Sambuc } while(0)
54433d6423SLionel Sambuc 
55433d6423SLionel Sambuc #define SLABDATAUSE(data, code) do {			\
56433d6423SLionel Sambuc 	SLABDATAWRITABLE(data, WRITABLE_HEADER);	\
57433d6423SLionel Sambuc 	code						\
58433d6423SLionel Sambuc 	SLABDATAUNWRITABLE(data);			\
59433d6423SLionel Sambuc } while(0)
60433d6423SLionel Sambuc 
61433d6423SLionel Sambuc #else
62433d6423SLionel Sambuc 
63433d6423SLionel Sambuc #define SLABDATAWRITABLE(data, wr)
64433d6423SLionel Sambuc #define SLABDATAUNWRITABLE(data)
65433d6423SLionel Sambuc #define SLABDATAUSE(data, code) do { code } while(0)
66433d6423SLionel Sambuc 
67433d6423SLionel Sambuc #endif
68433d6423SLionel Sambuc 
69433d6423SLionel Sambuc #define GETBIT(f, b)	  (BITEL(f,b) &   BITPAT(b))
70433d6423SLionel Sambuc #define SETBIT(f, b)   {OFF(f,b); SLABDATAUSE(f, BITEL(f,b)|= BITPAT(b); (f)->sdh.nused++;); }
71433d6423SLionel Sambuc #define CLEARBIT(f, b) {ON(f, b); SLABDATAUSE(f, BITEL(f,b)&=~BITPAT(b); (f)->sdh.nused--; (f)->sdh.freeguess = (b);); }
72433d6423SLionel Sambuc 
73433d6423SLionel Sambuc #define OBJALIGN	8
74433d6423SLionel Sambuc 
75433d6423SLionel Sambuc #define MINSIZE 8
76433d6423SLionel Sambuc #define MAXSIZE (SLABSIZES-1+MINSIZE)
77433d6423SLionel Sambuc #define USEELEMENTS (1+(VM_PAGE_SIZE/MINSIZE/8))
78433d6423SLionel Sambuc 
79433d6423SLionel Sambuc static int pages = 0;
80433d6423SLionel Sambuc 
81433d6423SLionel Sambuc typedef u8_t element_t;
82433d6423SLionel Sambuc #define BITS_FULL (~(element_t)0)
83433d6423SLionel Sambuc typedef element_t elements_t[USEELEMENTS];
84433d6423SLionel Sambuc 
85433d6423SLionel Sambuc /* This file is too low-level to have global SANITYCHECKs everywhere,
86433d6423SLionel Sambuc  * as the (other) data structures are often necessarily in an
87433d6423SLionel Sambuc  * inconsistent state during a slaballoc() / slabfree(). So only do
88433d6423SLionel Sambuc  * our own sanity checks here, with SLABSANITYCHECK.
89433d6423SLionel Sambuc  */
90433d6423SLionel Sambuc 
91433d6423SLionel Sambuc 
92433d6423SLionel Sambuc /* Special writable values. */
93433d6423SLionel Sambuc #define WRITABLE_NONE	-2
94433d6423SLionel Sambuc #define WRITABLE_HEADER	-1
95433d6423SLionel Sambuc 
96433d6423SLionel Sambuc struct sdh {
97433d6423SLionel Sambuc #if SANITYCHECKS
98433d6423SLionel Sambuc 	u32_t magic1;
99433d6423SLionel Sambuc #endif
100433d6423SLionel Sambuc 	int freeguess;
101433d6423SLionel Sambuc 	struct slabdata *next, *prev;
102433d6423SLionel Sambuc 	elements_t usebits;
103433d6423SLionel Sambuc 	phys_bytes phys;
104433d6423SLionel Sambuc #if SANITYCHECKS
105433d6423SLionel Sambuc 	int writable;	/* data item number or WRITABLE_* */
106433d6423SLionel Sambuc 	u32_t magic2;
107433d6423SLionel Sambuc #endif
108433d6423SLionel Sambuc 	u16_t nused;	/* Number of data items used in this slab. */
109433d6423SLionel Sambuc };
110433d6423SLionel Sambuc 
111433d6423SLionel Sambuc #define DATABYTES	(VM_PAGE_SIZE-sizeof(struct sdh))
112433d6423SLionel Sambuc 
113433d6423SLionel Sambuc #define MAGIC1 0x1f5b842f
114433d6423SLionel Sambuc #define MAGIC2 0x8bb5a420
115433d6423SLionel Sambuc #define JUNK  0xdeadbeef
116433d6423SLionel Sambuc #define NOJUNK 0xc0ffee
117433d6423SLionel Sambuc 
118433d6423SLionel Sambuc struct slabdata {
119433d6423SLionel Sambuc 	u8_t 	data[DATABYTES];
120433d6423SLionel Sambuc 	struct	sdh sdh;
121*50b7f13fSCristiano Giuffrida };
122*50b7f13fSCristiano Giuffrida 
123*50b7f13fSCristiano Giuffrida static struct slabheader {
124*50b7f13fSCristiano Giuffrida 	struct slabdata *list_head;
125433d6423SLionel Sambuc } slabs[SLABSIZES];
126433d6423SLionel Sambuc 
127433d6423SLionel Sambuc static int objstats(void *, int, struct slabheader **, struct slabdata
128433d6423SLionel Sambuc 	**, int *);
129433d6423SLionel Sambuc 
130433d6423SLionel Sambuc #define GETSLAB(b, s) {			\
131433d6423SLionel Sambuc 	int _gsi;				\
132433d6423SLionel Sambuc 	assert((b) >= MINSIZE);	\
133433d6423SLionel Sambuc 	_gsi = (b) - MINSIZE;		\
134433d6423SLionel Sambuc 	assert((_gsi) < SLABSIZES);	\
135433d6423SLionel Sambuc 	assert((_gsi) >= 0);		\
136433d6423SLionel Sambuc 	s = &slabs[_gsi];			\
137433d6423SLionel Sambuc }
138433d6423SLionel Sambuc 
139433d6423SLionel Sambuc /* move slabdata nw to slabheader sl under list number l. */
140433d6423SLionel Sambuc #define ADDHEAD(nw, sl) {			\
141433d6423SLionel Sambuc 	SLABDATAUSE(nw,				\
142433d6423SLionel Sambuc 		(nw)->sdh.next = sl->list_head;	\
143433d6423SLionel Sambuc 		(nw)->sdh.prev = NULL;);	\
144433d6423SLionel Sambuc 	sl->list_head = nw;			\
145433d6423SLionel Sambuc 	if((nw)->sdh.next) {			\
146433d6423SLionel Sambuc 		SLABDATAUSE((nw)->sdh.next, \
147433d6423SLionel Sambuc 			(nw)->sdh.next->sdh.prev = (nw););	\
148433d6423SLionel Sambuc 	} \
149433d6423SLionel Sambuc }
150433d6423SLionel Sambuc 
151433d6423SLionel Sambuc #define UNLINKNODE(node)	{				\
152433d6423SLionel Sambuc 	struct slabdata *next, *prev;				\
153433d6423SLionel Sambuc 	prev = (node)->sdh.prev;				\
154433d6423SLionel Sambuc 	next = (node)->sdh.next;				\
155433d6423SLionel Sambuc 	if(prev) { SLABDATAUSE(prev, prev->sdh.next = next;); }	\
156433d6423SLionel Sambuc 	if(next) { SLABDATAUSE(next, next->sdh.prev = prev;); }	\
157433d6423SLionel Sambuc }
158433d6423SLionel Sambuc 
newslabdata(void)159433d6423SLionel Sambuc static struct slabdata *newslabdata(void)
160433d6423SLionel Sambuc {
161433d6423SLionel Sambuc 	struct slabdata *n;
162433d6423SLionel Sambuc 	phys_bytes p;
163433d6423SLionel Sambuc 
164433d6423SLionel Sambuc 	assert(sizeof(*n) == VM_PAGE_SIZE);
165433d6423SLionel Sambuc 
166433d6423SLionel Sambuc 	if(!(n = vm_allocpage(&p, VMP_SLAB))) {
167433d6423SLionel Sambuc 		printf("newslabdata: vm_allocpage failed\n");
168433d6423SLionel Sambuc 		return NULL;
169433d6423SLionel Sambuc 	}
170433d6423SLionel Sambuc 	memset(n->sdh.usebits, 0, sizeof(n->sdh.usebits));
171433d6423SLionel Sambuc 	pages++;
172433d6423SLionel Sambuc 
173433d6423SLionel Sambuc 	n->sdh.phys = p;
174433d6423SLionel Sambuc #if SANITYCHECKS
175433d6423SLionel Sambuc 	n->sdh.magic1 = MAGIC1;
176433d6423SLionel Sambuc 	n->sdh.magic2 = MAGIC2;
177433d6423SLionel Sambuc #endif
178433d6423SLionel Sambuc 	n->sdh.nused = 0;
179433d6423SLionel Sambuc 	n->sdh.freeguess = 0;
180433d6423SLionel Sambuc 
181433d6423SLionel Sambuc #if SANITYCHECKS
182433d6423SLionel Sambuc 	n->sdh.writable = WRITABLE_HEADER;
183433d6423SLionel Sambuc 	SLABDATAUNWRITABLE(n);
184433d6423SLionel Sambuc #endif
185433d6423SLionel Sambuc 
186433d6423SLionel Sambuc 	return n;
187433d6423SLionel Sambuc }
188433d6423SLionel Sambuc 
189433d6423SLionel Sambuc #if SANITYCHECKS
190433d6423SLionel Sambuc 
191433d6423SLionel Sambuc /*===========================================================================*
192433d6423SLionel Sambuc  *				checklist				     *
193433d6423SLionel Sambuc  *===========================================================================*/
checklist(const char * file,int line,struct slabheader * s,int bytes)194433d6423SLionel Sambuc static int checklist(const char *file, int line,
195433d6423SLionel Sambuc 	struct slabheader *s, int bytes)
196433d6423SLionel Sambuc {
197433d6423SLionel Sambuc 	struct slabdata *n = s->list_head;
198433d6423SLionel Sambuc 	int ch = 0;
199433d6423SLionel Sambuc 
200433d6423SLionel Sambuc 	while(n) {
201433d6423SLionel Sambuc 		int count = 0, i;
202433d6423SLionel Sambuc #if SANITYCHECKS
203433d6423SLionel Sambuc 		MYASSERT(n->sdh.magic1 == MAGIC1);
204433d6423SLionel Sambuc 		MYASSERT(n->sdh.magic2 == MAGIC2);
205433d6423SLionel Sambuc #endif
206433d6423SLionel Sambuc 		MYASSERT(usedpages_add(n->sdh.phys, VM_PAGE_SIZE) == OK);
207433d6423SLionel Sambuc 		if(n->sdh.prev)
208433d6423SLionel Sambuc 			MYASSERT(n->sdh.prev->sdh.next == n);
209433d6423SLionel Sambuc 		else
210433d6423SLionel Sambuc 			MYASSERT(s->list_head == n);
211433d6423SLionel Sambuc 		if(n->sdh.next) MYASSERT(n->sdh.next->sdh.prev == n);
212433d6423SLionel Sambuc 		for(i = 0; i < USEELEMENTS*8; i++)
213433d6423SLionel Sambuc 			if(i >= ITEMSPERPAGE(bytes))
214433d6423SLionel Sambuc 				MYASSERT(!GETBIT(n, i));
215433d6423SLionel Sambuc 			else
216433d6423SLionel Sambuc 				if(GETBIT(n,i))
217433d6423SLionel Sambuc 					count++;
218433d6423SLionel Sambuc 		MYASSERT(count == n->sdh.nused);
219433d6423SLionel Sambuc 		ch += count;
220433d6423SLionel Sambuc 		n = n->sdh.next;
221433d6423SLionel Sambuc 	}
222433d6423SLionel Sambuc 
223433d6423SLionel Sambuc 	return ch;
224433d6423SLionel Sambuc }
225433d6423SLionel Sambuc 
226433d6423SLionel Sambuc /*===========================================================================*
227433d6423SLionel Sambuc  *				void slab_sanitycheck			     *
228433d6423SLionel Sambuc  *===========================================================================*/
slab_sanitycheck(const char * file,int line)229433d6423SLionel Sambuc void slab_sanitycheck(const char *file, int line)
230433d6423SLionel Sambuc {
231433d6423SLionel Sambuc 	int s;
232433d6423SLionel Sambuc 	for(s = 0; s < SLABSIZES; s++) {
233433d6423SLionel Sambuc 		checklist(file, line, &slabs[s], s + MINSIZE);
234433d6423SLionel Sambuc 	}
235433d6423SLionel Sambuc }
236433d6423SLionel Sambuc 
237433d6423SLionel Sambuc /*===========================================================================*
238433d6423SLionel Sambuc  *				int slabsane				     *
239433d6423SLionel Sambuc  *===========================================================================*/
slabsane_f(const char * file,int line,void * mem,int bytes)240433d6423SLionel Sambuc int slabsane_f(const char *file, int line, void *mem, int bytes)
241433d6423SLionel Sambuc {
242433d6423SLionel Sambuc 	struct slabheader *s;
243433d6423SLionel Sambuc 	struct slabdata *f;
244433d6423SLionel Sambuc 	int i;
245433d6423SLionel Sambuc 
246433d6423SLionel Sambuc 	bytes = roundup(bytes, OBJALIGN);
247433d6423SLionel Sambuc 
248433d6423SLionel Sambuc 	return (objstats(mem, bytes, &s, &f, &i) == OK);
249433d6423SLionel Sambuc }
250433d6423SLionel Sambuc #endif
251433d6423SLionel Sambuc 
252433d6423SLionel Sambuc #if SANITYCHECKS
253433d6423SLionel Sambuc static int nojunkwarning = 0;
254433d6423SLionel Sambuc #endif
255433d6423SLionel Sambuc 
256433d6423SLionel Sambuc /*===========================================================================*
257433d6423SLionel Sambuc  *				void *slaballoc				     *
258433d6423SLionel Sambuc  *===========================================================================*/
slaballoc(int bytes)259433d6423SLionel Sambuc void *slaballoc(int bytes)
260433d6423SLionel Sambuc {
261433d6423SLionel Sambuc 	int i;
262433d6423SLionel Sambuc 	int count = 0;
263433d6423SLionel Sambuc 	struct slabheader *s;
264433d6423SLionel Sambuc 	struct slabdata *newslab;
265433d6423SLionel Sambuc 	char *ret;
266433d6423SLionel Sambuc 
267433d6423SLionel Sambuc 	bytes = roundup(bytes, OBJALIGN);
268433d6423SLionel Sambuc 
269433d6423SLionel Sambuc 	SLABSANITYCHECK(SCL_FUNCTIONS);
270433d6423SLionel Sambuc 
271433d6423SLionel Sambuc 	/* Retrieve entry in slabs[]. */
272433d6423SLionel Sambuc 	GETSLAB(bytes, s);
273433d6423SLionel Sambuc 	assert(s);
274433d6423SLionel Sambuc 
275433d6423SLionel Sambuc 	if(!(newslab = s->list_head)) {
276433d6423SLionel Sambuc 		/* Make sure there is something on the freelist. */
277433d6423SLionel Sambuc 		newslab = newslabdata();
278433d6423SLionel Sambuc 		if(!newslab) return NULL;
279433d6423SLionel Sambuc 		ADDHEAD(newslab, s);
280433d6423SLionel Sambuc 		assert(newslab->sdh.nused == 0);
281433d6423SLionel Sambuc 	} else	assert(newslab->sdh.nused > 0);
282433d6423SLionel Sambuc 	assert(newslab->sdh.nused < ITEMSPERPAGE(bytes));
283433d6423SLionel Sambuc 
284433d6423SLionel Sambuc 	SLABSANITYCHECK(SCL_DETAIL);
285433d6423SLionel Sambuc 
286433d6423SLionel Sambuc #if SANITYCHECKS
287433d6423SLionel Sambuc 	assert(newslab->sdh.magic1 == MAGIC1);
288433d6423SLionel Sambuc 	assert(newslab->sdh.magic2 == MAGIC2);
289433d6423SLionel Sambuc #endif
290433d6423SLionel Sambuc 
291433d6423SLionel Sambuc 	for(i = newslab->sdh.freeguess;
292433d6423SLionel Sambuc 		count < ITEMSPERPAGE(bytes); count++, i++) {
293433d6423SLionel Sambuc 		i = i % ITEMSPERPAGE(bytes);
294433d6423SLionel Sambuc 
295433d6423SLionel Sambuc 		if(!GETBIT(newslab, i))
296433d6423SLionel Sambuc 			break;
297433d6423SLionel Sambuc 	}
298433d6423SLionel Sambuc 
299433d6423SLionel Sambuc 	SLABSANITYCHECK(SCL_FUNCTIONS);
300433d6423SLionel Sambuc 
301433d6423SLionel Sambuc 	assert(count < ITEMSPERPAGE(bytes));
302433d6423SLionel Sambuc 	assert(i >= 0 && i < ITEMSPERPAGE(bytes));
303433d6423SLionel Sambuc 
304433d6423SLionel Sambuc 	SETBIT(newslab, i);
305433d6423SLionel Sambuc 	if(newslab->sdh.nused == ITEMSPERPAGE(bytes)) {
306433d6423SLionel Sambuc 		UNLINKNODE(newslab);
307433d6423SLionel Sambuc 		s->list_head = newslab->sdh.next;
308433d6423SLionel Sambuc 	}
309433d6423SLionel Sambuc 
310433d6423SLionel Sambuc 	ret = ((char *) newslab) + i*bytes;
311433d6423SLionel Sambuc 
312433d6423SLionel Sambuc #if SANITYCHECKS
313433d6423SLionel Sambuc #if MEMPROTECT
314433d6423SLionel Sambuc 	nojunkwarning++;
315433d6423SLionel Sambuc 	slabunlock(ret, bytes);
316433d6423SLionel Sambuc 	nojunkwarning--;
317433d6423SLionel Sambuc 	assert(!nojunkwarning);
318433d6423SLionel Sambuc #endif
319433d6423SLionel Sambuc 	*(u32_t *) ret = NOJUNK;
320433d6423SLionel Sambuc #if MEMPROTECT
321433d6423SLionel Sambuc 	slablock(ret, bytes);
322433d6423SLionel Sambuc #endif
323433d6423SLionel Sambuc #endif
324433d6423SLionel Sambuc 
325433d6423SLionel Sambuc 	SLABDATAUSE(newslab, newslab->sdh.freeguess = i+1;);
326433d6423SLionel Sambuc 
327433d6423SLionel Sambuc #if SANITYCHECKS
328433d6423SLionel Sambuc 	if(bytes >= SLABSIZES+MINSIZE) {
329433d6423SLionel Sambuc 		printf("slaballoc: odd, bytes %d?\n", bytes);
330433d6423SLionel Sambuc 	}
331433d6423SLionel Sambuc 
332433d6423SLionel Sambuc 	if(!slabsane_f(__FILE__, __LINE__, ret, bytes))
333433d6423SLionel Sambuc 		panic("slaballoc: slabsane failed");
334433d6423SLionel Sambuc #endif
335433d6423SLionel Sambuc 
336433d6423SLionel Sambuc 	assert(!((vir_bytes) ret % OBJALIGN));
337433d6423SLionel Sambuc 
338433d6423SLionel Sambuc 	return ret;
339433d6423SLionel Sambuc }
340433d6423SLionel Sambuc 
341433d6423SLionel Sambuc /*===========================================================================*
342433d6423SLionel Sambuc  *				int objstats				     *
343433d6423SLionel Sambuc  *===========================================================================*/
objstats(void * mem,int bytes,struct slabheader ** sp,struct slabdata ** fp,int * ip)344433d6423SLionel Sambuc static inline int objstats(void *mem, int bytes,
345433d6423SLionel Sambuc 	struct slabheader **sp, struct slabdata **fp, int *ip)
346433d6423SLionel Sambuc {
347433d6423SLionel Sambuc #if SANITYCHECKS
348433d6423SLionel Sambuc #define OBJSTATSCHECK(cond) \
349433d6423SLionel Sambuc 	if(!(cond)) { \
350433d6423SLionel Sambuc 		printf("VM: objstats: %s failed for ptr %p, %d bytes\n", \
351433d6423SLionel Sambuc 			#cond, mem, bytes); \
352433d6423SLionel Sambuc 		return EINVAL; \
353433d6423SLionel Sambuc 	}
354433d6423SLionel Sambuc #else
355433d6423SLionel Sambuc #define OBJSTATSCHECK(cond)
356433d6423SLionel Sambuc #endif
357433d6423SLionel Sambuc 
358433d6423SLionel Sambuc 	struct slabheader *s;
359433d6423SLionel Sambuc 	struct slabdata *f;
360433d6423SLionel Sambuc 	int i;
361433d6423SLionel Sambuc 
362433d6423SLionel Sambuc 	assert(!(bytes % OBJALIGN));
363433d6423SLionel Sambuc 
364433d6423SLionel Sambuc 	OBJSTATSCHECK((char *) mem >= (char *) VM_PAGE_SIZE);
365433d6423SLionel Sambuc 
366433d6423SLionel Sambuc #if SANITYCHECKS
367433d6423SLionel Sambuc 	if(*(u32_t *) mem == JUNK && !nojunkwarning) {
368433d6423SLionel Sambuc 		util_stacktrace();
369433d6423SLionel Sambuc 		printf("VM: WARNING: JUNK seen in slab object, likely freed\n");
370433d6423SLionel Sambuc 	}
371433d6423SLionel Sambuc #endif
372433d6423SLionel Sambuc 	/* Retrieve entry in slabs[]. */
373433d6423SLionel Sambuc 	GETSLAB(bytes, s);
374433d6423SLionel Sambuc 
375433d6423SLionel Sambuc 	/* Round address down to VM_PAGE_SIZE boundary to get header. */
376433d6423SLionel Sambuc 	f = (struct slabdata *) ((char *) mem - (vir_bytes) mem % VM_PAGE_SIZE);
377433d6423SLionel Sambuc 
378433d6423SLionel Sambuc #if SANITYCHECKS
379433d6423SLionel Sambuc 	OBJSTATSCHECK(f->sdh.magic1 == MAGIC1);
380433d6423SLionel Sambuc 	OBJSTATSCHECK(f->sdh.magic2 == MAGIC2);
381433d6423SLionel Sambuc #endif
382433d6423SLionel Sambuc 
383433d6423SLionel Sambuc 	/* Make sure it's in range. */
384433d6423SLionel Sambuc 	OBJSTATSCHECK((char *) mem >= (char *) f->data);
385433d6423SLionel Sambuc 	OBJSTATSCHECK((char *) mem < (char *) f->data + sizeof(f->data));
386433d6423SLionel Sambuc 
387433d6423SLionel Sambuc 	/* Get position. */
388433d6423SLionel Sambuc 	i = (char *) mem - (char *) f->data;
389433d6423SLionel Sambuc 	OBJSTATSCHECK(!(i % bytes));
390433d6423SLionel Sambuc 	i = i / bytes;
391433d6423SLionel Sambuc 
392433d6423SLionel Sambuc 	/* Make sure it is marked as allocated. */
393433d6423SLionel Sambuc 	OBJSTATSCHECK(GETBIT(f, i));
394433d6423SLionel Sambuc 
395433d6423SLionel Sambuc 	/* return values */
396433d6423SLionel Sambuc 	*ip = i;
397433d6423SLionel Sambuc 	*fp = f;
398433d6423SLionel Sambuc 	*sp = s;
399433d6423SLionel Sambuc 
400433d6423SLionel Sambuc 	return OK;
401433d6423SLionel Sambuc }
402433d6423SLionel Sambuc 
403433d6423SLionel Sambuc /*===========================================================================*
404433d6423SLionel Sambuc  *				void *slabfree				     *
405433d6423SLionel Sambuc  *===========================================================================*/
slabfree(void * mem,int bytes)406433d6423SLionel Sambuc void slabfree(void *mem, int bytes)
407433d6423SLionel Sambuc {
408433d6423SLionel Sambuc 	int i;
409433d6423SLionel Sambuc 	struct slabheader *s;
410433d6423SLionel Sambuc 	struct slabdata *f;
411433d6423SLionel Sambuc 
412433d6423SLionel Sambuc 	bytes = roundup(bytes, OBJALIGN);
413433d6423SLionel Sambuc 
414433d6423SLionel Sambuc 	SLABSANITYCHECK(SCL_FUNCTIONS);
415433d6423SLionel Sambuc 
416433d6423SLionel Sambuc 	if(objstats(mem, bytes, &s, &f, &i) != OK) {
417433d6423SLionel Sambuc 		panic("slabfree objstats failed");
418433d6423SLionel Sambuc 	}
419433d6423SLionel Sambuc 
420433d6423SLionel Sambuc #if SANITYCHECKS
421433d6423SLionel Sambuc 	if(*(u32_t *) mem == JUNK) {
422433d6423SLionel Sambuc 		printf("VM: WARNING: likely double free, JUNK seen\n");
423433d6423SLionel Sambuc 	}
424433d6423SLionel Sambuc #endif
425433d6423SLionel Sambuc 
426433d6423SLionel Sambuc #if SANITYCHECKS
427433d6423SLionel Sambuc #if MEMPROTECT
428433d6423SLionel Sambuc 	slabunlock(mem, bytes);
429433d6423SLionel Sambuc #endif
430433d6423SLionel Sambuc #if JUNKFREE
431433d6423SLionel Sambuc 	memset(mem, 0xa6, bytes);
432433d6423SLionel Sambuc #endif
433433d6423SLionel Sambuc 	*(u32_t *) mem = JUNK;
434433d6423SLionel Sambuc 	nojunkwarning++;
435433d6423SLionel Sambuc #if MEMPROTECT
436433d6423SLionel Sambuc 	slablock(mem, bytes);
437433d6423SLionel Sambuc #endif
438433d6423SLionel Sambuc 	nojunkwarning--;
439433d6423SLionel Sambuc 	assert(!nojunkwarning);
440433d6423SLionel Sambuc #endif
441433d6423SLionel Sambuc 
442433d6423SLionel Sambuc 	/* Free this data. */
443433d6423SLionel Sambuc 	CLEARBIT(f, i);
444433d6423SLionel Sambuc 
445433d6423SLionel Sambuc 	/* Check if this slab changes lists. */
446433d6423SLionel Sambuc 	if(f->sdh.nused == 0) {
447433d6423SLionel Sambuc 		UNLINKNODE(f);
448433d6423SLionel Sambuc 		if(f == s->list_head) s->list_head = f->sdh.next;
449433d6423SLionel Sambuc 		vm_freepages((vir_bytes) f, 1);
450433d6423SLionel Sambuc 		SLABSANITYCHECK(SCL_DETAIL);
451433d6423SLionel Sambuc 	} else if(f->sdh.nused == ITEMSPERPAGE(bytes)-1) {
452433d6423SLionel Sambuc 		ADDHEAD(f, s);
453433d6423SLionel Sambuc 	}
454433d6423SLionel Sambuc 
455433d6423SLionel Sambuc 	SLABSANITYCHECK(SCL_FUNCTIONS);
456433d6423SLionel Sambuc 
457433d6423SLionel Sambuc 	return;
458433d6423SLionel Sambuc }
459433d6423SLionel Sambuc 
460433d6423SLionel Sambuc #if MEMPROTECT
461433d6423SLionel Sambuc /*===========================================================================*
462433d6423SLionel Sambuc  *				void *slablock				     *
463433d6423SLionel Sambuc  *===========================================================================*/
slablock(void * mem,int bytes)464433d6423SLionel Sambuc void slablock(void *mem, int bytes)
465433d6423SLionel Sambuc {
466433d6423SLionel Sambuc 	int i;
467433d6423SLionel Sambuc 	struct slabheader *s;
468433d6423SLionel Sambuc 	struct slabdata *f;
469433d6423SLionel Sambuc 
470433d6423SLionel Sambuc 	bytes = roundup(bytes, OBJALIGN);
471433d6423SLionel Sambuc 
472433d6423SLionel Sambuc 	if(objstats(mem, bytes, &s, &f, &i) != OK)
473433d6423SLionel Sambuc 		panic("slablock objstats failed");
474433d6423SLionel Sambuc 
475433d6423SLionel Sambuc 	SLABDATAUNWRITABLE(f);
476433d6423SLionel Sambuc 
477433d6423SLionel Sambuc 	return;
478433d6423SLionel Sambuc }
479433d6423SLionel Sambuc 
480433d6423SLionel Sambuc /*===========================================================================*
481433d6423SLionel Sambuc  *				void *slabunlock			     *
482433d6423SLionel Sambuc  *===========================================================================*/
slabunlock(void * mem,int bytes)483433d6423SLionel Sambuc void slabunlock(void *mem, int bytes)
484433d6423SLionel Sambuc {
485433d6423SLionel Sambuc 	int i;
486433d6423SLionel Sambuc 	struct slabheader *s;
487433d6423SLionel Sambuc 	struct slabdata *f;
488433d6423SLionel Sambuc 
489433d6423SLionel Sambuc 	bytes = roundup(bytes, OBJALIGN);
490433d6423SLionel Sambuc 
491433d6423SLionel Sambuc 	if(objstats(mem, bytes, &s, &f, &i) != OK)
492433d6423SLionel Sambuc 		panic("slabunlock objstats failed");
493433d6423SLionel Sambuc 
494433d6423SLionel Sambuc 	SLABDATAWRITABLE(f, i);
495433d6423SLionel Sambuc 
496433d6423SLionel Sambuc 	return;
497433d6423SLionel Sambuc }
498433d6423SLionel Sambuc #endif
499433d6423SLionel Sambuc 
500433d6423SLionel Sambuc #if SANITYCHECKS
501433d6423SLionel Sambuc /*===========================================================================*
502433d6423SLionel Sambuc  *				void slabstats				     *
503433d6423SLionel Sambuc  *===========================================================================*/
slabstats(void)504433d6423SLionel Sambuc void slabstats(void)
505433d6423SLionel Sambuc {
506433d6423SLionel Sambuc 	int s, totalbytes = 0;
507433d6423SLionel Sambuc 	static int n;
508433d6423SLionel Sambuc 	n++;
509433d6423SLionel Sambuc 	if(n%1000) return;
510433d6423SLionel Sambuc 	for(s = 0; s < SLABSIZES; s++) {
511433d6423SLionel Sambuc 		int b, t;
512433d6423SLionel Sambuc 		b = s + MINSIZE;
513433d6423SLionel Sambuc 		t = checklist(__FILE__, __LINE__, &slabs[s], b);
514433d6423SLionel Sambuc 
515433d6423SLionel Sambuc 		if(t > 0) {
516433d6423SLionel Sambuc 			int bytes = t * b;
517433d6423SLionel Sambuc 			printf("VMSTATS: %2d slabs: %d (%dkB)\n", b, t, bytes/1024);
518433d6423SLionel Sambuc 			totalbytes += bytes;
519433d6423SLionel Sambuc 		}
520433d6423SLionel Sambuc 	}
521433d6423SLionel Sambuc 
522433d6423SLionel Sambuc 	if(pages > 0) {
523433d6423SLionel Sambuc 		printf("VMSTATS: %dK net used in slab objects in %d pages (%dkB): %d%% utilization\n",
524433d6423SLionel Sambuc 			totalbytes/1024, pages, pages*VM_PAGE_SIZE/1024,
525433d6423SLionel Sambuc 				100 * totalbytes / (pages*VM_PAGE_SIZE));
526433d6423SLionel Sambuc 	}
527433d6423SLionel Sambuc }
528433d6423SLionel Sambuc #endif
529