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