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