Mercurial > hvf > hvf-old
view cp/mm/slab.c @ 618:535aec703236
cp: define a FIXME macro that leaves a sclp message
There are far too many fixmes in the code. Sadly, the compiler simply
discards them. This usually isn't an issue until one accidentally hits a
"weird" bug which just turns out to be an unhandled (but documented) case in
another part of the code. Using a macro instead of a comment will let the
compiler string-ify the text, and then at runtime use SCLP to print it out.
This will immediatelly point at problem areas. So, keep an eye on SCLP from
now on :)
Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Tue, 13 Dec 2011 22:20:50 -0500 |
parents | 7d7bdce419ed |
children |
line wrap: on
line source
/* * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * * This file is released under the GPLv2. See the COPYING file for more * details. */ #include <magic.h> #include <buddy.h> #include <slab.h> #include <page.h> static struct slab *generic[7]; /* * Create slab caches for 16, 32, 64, 128, and 256 byte allocations */ int init_slab(void) { generic[0] = create_slab(16, 4); if (!generic[0]) goto out_err; generic[1] = create_slab(32, 4); if (!generic[1]) goto out_err; generic[2] = create_slab(64, 4); if (!generic[2]) goto out_err; generic[3] = create_slab(128, 4); if (!generic[3]) goto out_err; generic[4] = create_slab(256, 8); if (!generic[4]) goto out_err; generic[5] = create_slab(512, 8); if (!generic[5]) goto out_err; generic[6] = create_slab(1024, 8); if (!generic[6]) goto out_err; return 0; out_err: free_slab(generic[0]); free_slab(generic[1]); free_slab(generic[2]); free_slab(generic[3]); free_slab(generic[4]); free_slab(generic[5]); free_slab(generic[6]); return -ENOMEM; } /** * create_slab - Create a new slab * @objsize: object size in bytes * @align: object alignment in bytes (must be a power of two) */ struct slab *create_slab(u16 objsize, u8 align) { struct page *page; struct slab *slab; if (!objsize || !align) return NULL; page = alloc_pages(0, ZONE_NORMAL); if (!page) return NULL; slab = page_to_addr(page); memset(slab, 0, PAGE_SIZE); slab->magic = SLAB_MAGIC; slab->lock = SPIN_LOCK_UNLOCKED; INIT_LIST_HEAD(&slab->slab_pages); slab->first = slab; align--; /* turn into a mask */ /* actual object size */ if (objsize & align) objsize += align + 1 - (objsize & align); slab->objsize = objsize; /* number of objects in a page */ slab->count = 8 * (PAGE_SIZE - sizeof(struct slab)) / (8 * objsize + 1); /* offset of the first object */ slab->startoff = sizeof(struct slab) + (slab->count + 4) / 8; if (slab->startoff & align) { u16 tmp; slab->startoff += align + 1 - (slab->startoff & align); /* * TODO: there's got to be a better way to ensure that we * fit into a single page */ tmp = slab->startoff + slab->count * slab->objsize; if (tmp > PAGE_SIZE) slab->count--; } slab->used = 0; return slab; } void free_slab(struct slab *passed_slab) { struct slab *slab; if (!passed_slab) return; BUG_ON(passed_slab->magic != SLAB_MAGIC); BUG_ON(passed_slab->used != 0); list_for_each_entry(slab, &passed_slab->slab_pages, slab_pages) { BUG_ON(slab->magic != SLAB_CONT_MAGIC); BUG_ON(slab->used != 0); /* * Theoretically, we should remove the page from the list, * but no one _really_ cares */ free_pages(slab, 0); } free_pages(passed_slab, 0); } static inline void *__alloc_slab_obj_newpage(struct slab *slab, int type) { struct page *page; struct slab *new; page = alloc_pages(0, type); if (!page) return ERR_PTR(-ENOMEM); new = page_to_addr(page); memset(new, 0, PAGE_SIZE); new->magic = SLAB_CONT_MAGIC; new->first = slab; new->objsize = slab->objsize; new->startoff = slab->startoff; new->count = slab->count; /* add it to the current slab */ list_add_tail(&new->slab_pages, &slab->slab_pages); return new; } static void *alloc_slab_obj(struct slab *passed_slab, int type) { struct slab *slab = passed_slab; void *obj = NULL; int objidx; u8 *bits; u8 mask; unsigned long int_mask; if (!slab) return NULL; BUG_ON(passed_slab->magic != SLAB_MAGIC); spin_lock_intsave(&passed_slab->lock, &int_mask); /* * Does the first slab page have an unused object _AND_ is in the * right zone? */ if (slab->used < slab->count && ZONE_TYPE(addr_to_page(slab)) == type) goto alloc; /* * No. Find the first slab page that has unused objects */ list_for_each_entry(slab, &passed_slab->slab_pages, slab_pages) if (slab->used < slab->count && ZONE_TYPE(addr_to_page(slab)) == type) goto alloc; /* * None of the pages have an unused object. Let's allocate another * page */ slab = __alloc_slab_obj_newpage(passed_slab, type); if (IS_ERR(slab)) { FIXME("if we tried to get a ZONE_NORMAL and failed, " "shouldn't we retry with ZONE_LOW?"); goto out; } alloc: /* found a page */ for (objidx = 0; objidx < slab->count; objidx++) { bits = slab->bitmap + (objidx/8); mask = 1 << (7 - (objidx % 8)); if (*bits & mask) continue; slab->used++; *bits |= mask; obj = ((u8*) slab) + slab->startoff + slab->objsize * objidx; break; } out: spin_unlock_intrestore(&passed_slab->lock, int_mask); return obj; } static void free_slab_obj(void *ptr) { struct slab *slab; int objidx; u8 *bits; unsigned long int_mask; /* get the slab object ptr */ slab = (struct slab *) (((u64) ptr) & ~0xfff); spin_lock_intsave(&slab->first->lock, &int_mask); /* calculate the object number */ objidx = (((u64) ptr) - ((u64) slab) - slab->startoff) / slab->objsize; /* update the bitmap */ bits = slab->bitmap + (objidx/8); *bits &= ~(1 << (7 - (objidx % 8))); if (--slab->used) { FIXME("free the page?"); } spin_unlock_intrestore(&slab->first->lock, int_mask); } int allocsize(void *ptr) { struct slab *slab; /* get the slab object ptr */ slab = (struct slab *) (((u64) ptr) & ~0xfff); return slab->objsize; } void *malloc(int size, int type) { if (!size) return NULL; if (size <= 16) return alloc_slab_obj(generic[0], type); if (size <= 32) return alloc_slab_obj(generic[1], type); if (size <= 64) return alloc_slab_obj(generic[2], type); if (size <= 128) return alloc_slab_obj(generic[3], type); if (size <= 256) return alloc_slab_obj(generic[4], type); if (size <= 512) return alloc_slab_obj(generic[5], type); if (size <= 1024) return alloc_slab_obj(generic[6], type); return NULL; } void free(void *ptr) { if (ptr) free_slab_obj(ptr); }