|
@@ -35,8 +35,6 @@
|
|
|
*/
|
|
*/
|
|
|
struct metaheader
|
|
struct metaheader
|
|
|
{
|
|
{
|
|
|
- /* Length (after this header). (FIXME: implied by page bits!). */
|
|
|
|
|
- unsigned long metalen;
|
|
|
|
|
/* Next meta header, or 0 */
|
|
/* Next meta header, or 0 */
|
|
|
unsigned long next;
|
|
unsigned long next;
|
|
|
/* Bits start here. */
|
|
/* Bits start here. */
|
|
@@ -149,9 +147,6 @@ void alloc_init(void *pool, unsigned long poolsize)
|
|
|
BUILD_ASSERT(FREE == 0);
|
|
BUILD_ASSERT(FREE == 0);
|
|
|
memset(pool, 0, len);
|
|
memset(pool, 0, len);
|
|
|
|
|
|
|
|
- /* Set up metalen */
|
|
|
|
|
- mh->metalen = len - pool_offset(pool, mh + 1);
|
|
|
|
|
-
|
|
|
|
|
/* Mark the pagestate and metadata page(s) allocated. */
|
|
/* Mark the pagestate and metadata page(s) allocated. */
|
|
|
set_page_state(pool, 0, TAKEN_START);
|
|
set_page_state(pool, 0, TAKEN_START);
|
|
|
for (i = 1; i < div_up(len, getpagesize()); i++)
|
|
for (i = 1; i < div_up(len, getpagesize()); i++)
|
|
@@ -244,15 +239,31 @@ static unsigned long sub_page_alloc(void *pool, unsigned long page,
|
|
|
return page*getpagesize() + (i-1)*BITMAP_GRANULARITY;
|
|
return page*getpagesize() + (i-1)*BITMAP_GRANULARITY;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static uint8_t *alloc_metaspace(struct metaheader *mh, unsigned long bytes,
|
|
|
|
|
|
|
+/* We look at the page states to figure out where the allocation for this
|
|
|
|
|
+ * metadata ends. */
|
|
|
|
|
+static unsigned long get_metalen(void *pool, unsigned long poolsize,
|
|
|
|
|
+ struct metaheader *mh)
|
|
|
|
|
+{
|
|
|
|
|
+ unsigned long i, first, pages = poolsize / getpagesize();
|
|
|
|
|
+
|
|
|
|
|
+ first = pool_offset(pool, mh + 1)/getpagesize();
|
|
|
|
|
+
|
|
|
|
|
+ for (i = first + 1; i < pages && get_page_state(pool,i) == TAKEN; i++);
|
|
|
|
|
+
|
|
|
|
|
+ return i * getpagesize() - pool_offset(pool, mh + 1);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static uint8_t *alloc_metaspace(void *pool, unsigned long poolsize,
|
|
|
|
|
+ struct metaheader *mh, unsigned long bytes,
|
|
|
enum sub_metadata_type type)
|
|
enum sub_metadata_type type)
|
|
|
{
|
|
{
|
|
|
uint8_t *meta = (uint8_t *)(mh + 1);
|
|
uint8_t *meta = (uint8_t *)(mh + 1);
|
|
|
- unsigned long free = 0, len;
|
|
|
|
|
- unsigned long i;
|
|
|
|
|
|
|
+ unsigned long free = 0, len, i, metalen;
|
|
|
|
|
+
|
|
|
|
|
+ metalen = get_metalen(pool, poolsize, mh);
|
|
|
|
|
|
|
|
/* TAKEN tags end a subpage alloc. */
|
|
/* TAKEN tags end a subpage alloc. */
|
|
|
- for (i = 0; i < mh->metalen * CHAR_BIT / BITS_PER_PAGE; i += len) {
|
|
|
|
|
|
|
+ for (i = 0; i < metalen * CHAR_BIT / BITS_PER_PAGE; i += len) {
|
|
|
switch (get_bit_pair(meta, i)) {
|
|
switch (get_bit_pair(meta, i)) {
|
|
|
case FREE:
|
|
case FREE:
|
|
|
len = 1;
|
|
len = 1;
|
|
@@ -285,7 +296,7 @@ static uint8_t *new_metadata(void *pool, unsigned long poolsize,
|
|
|
unsigned long page;
|
|
unsigned long page;
|
|
|
|
|
|
|
|
for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh)){
|
|
for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh)){
|
|
|
- uint8_t *meta = alloc_metaspace(mh, bytes, type);
|
|
|
|
|
|
|
+ uint8_t *meta = alloc_metaspace(pool, poolsize, mh, bytes,type);
|
|
|
|
|
|
|
|
if (meta)
|
|
if (meta)
|
|
|
return meta;
|
|
return meta;
|
|
@@ -293,22 +304,22 @@ static uint8_t *new_metadata(void *pool, unsigned long poolsize,
|
|
|
|
|
|
|
|
/* No room for metadata? Can we expand an existing one? */
|
|
/* No room for metadata? Can we expand an existing one? */
|
|
|
for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh)){
|
|
for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh)){
|
|
|
- /* It should end on a page boundary. */
|
|
|
|
|
unsigned long nextpage;
|
|
unsigned long nextpage;
|
|
|
|
|
|
|
|
- nextpage = pool_offset(pool, (char *)(mh + 1) + mh->metalen);
|
|
|
|
|
- assert(nextpage % getpagesize() == 0);
|
|
|
|
|
|
|
+ /* We start on this page. */
|
|
|
|
|
+ nextpage = pool_offset(pool, (char *)(mh+1))/getpagesize();
|
|
|
|
|
+ /* Iterate through any other pages we own. */
|
|
|
|
|
+ while (get_page_state(pool, ++nextpage) == TAKEN)
|
|
|
|
|
|
|
|
/* Now, can we grab that page? */
|
|
/* Now, can we grab that page? */
|
|
|
- if (get_page_state(pool, nextpage / getpagesize()) != FREE)
|
|
|
|
|
|
|
+ if (get_page_state(pool, nextpage) != FREE)
|
|
|
continue;
|
|
continue;
|
|
|
|
|
|
|
|
/* OK, expand metadata, do it again. */
|
|
/* OK, expand metadata, do it again. */
|
|
|
- set_page_state(pool, nextpage / getpagesize(), TAKEN);
|
|
|
|
|
|
|
+ set_page_state(pool, nextpage, TAKEN);
|
|
|
BUILD_ASSERT(FREE == 0);
|
|
BUILD_ASSERT(FREE == 0);
|
|
|
- memset((char *)pool + nextpage, 0, getpagesize());
|
|
|
|
|
- mh->metalen += getpagesize();
|
|
|
|
|
- return alloc_metaspace(mh, bytes, type);
|
|
|
|
|
|
|
+ memset((char *)pool + nextpage*getpagesize(), 0, getpagesize());
|
|
|
|
|
+ return alloc_metaspace(pool, poolsize, mh, bytes, type);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* No metadata left at all? */
|
|
/* No metadata left at all? */
|
|
@@ -317,16 +328,15 @@ static uint8_t *new_metadata(void *pool, unsigned long poolsize,
|
|
|
return NULL;
|
|
return NULL;
|
|
|
|
|
|
|
|
newmh = (struct metaheader *)((char *)pool + page * getpagesize());
|
|
newmh = (struct metaheader *)((char *)pool + page * getpagesize());
|
|
|
- newmh->metalen = getpagesize() - sizeof(*mh);
|
|
|
|
|
BUILD_ASSERT(FREE == 0);
|
|
BUILD_ASSERT(FREE == 0);
|
|
|
- memset(newmh + 1, 0, newmh->metalen);
|
|
|
|
|
|
|
+ memset(newmh + 1, 0, getpagesize() - sizeof(*mh));
|
|
|
|
|
|
|
|
/* Sew it into linked list */
|
|
/* Sew it into linked list */
|
|
|
mh = first_mheader(pool,poolsize);
|
|
mh = first_mheader(pool,poolsize);
|
|
|
newmh->next = mh->next;
|
|
newmh->next = mh->next;
|
|
|
mh->next = pool_offset(pool, newmh);
|
|
mh->next = pool_offset(pool, newmh);
|
|
|
|
|
|
|
|
- return alloc_metaspace(newmh, bytes, type);
|
|
|
|
|
|
|
+ return alloc_metaspace(pool, poolsize, newmh, bytes, type);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void alloc_free_pages(void *pool, unsigned long pagenum)
|
|
static void alloc_free_pages(void *pool, unsigned long pagenum)
|
|
@@ -412,15 +422,16 @@ static bool clean_metadata(void *pool, unsigned long poolsize)
|
|
|
for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh)){
|
|
for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh)){
|
|
|
uint8_t *meta;
|
|
uint8_t *meta;
|
|
|
long i;
|
|
long i;
|
|
|
|
|
+ unsigned long metalen = get_metalen(pool, poolsize, mh);
|
|
|
|
|
|
|
|
meta = (uint8_t *)(mh + 1);
|
|
meta = (uint8_t *)(mh + 1);
|
|
|
BUILD_ASSERT(FREE == 0);
|
|
BUILD_ASSERT(FREE == 0);
|
|
|
- for (i = mh->metalen - 1; i > 0; i--)
|
|
|
|
|
|
|
+ for (i = metalen - 1; i > 0; i--)
|
|
|
if (meta[i] != 0)
|
|
if (meta[i] != 0)
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
/* Completely empty? */
|
|
/* Completely empty? */
|
|
|
- if (prev_mh && i == mh->metalen) {
|
|
|
|
|
|
|
+ if (prev_mh && i == metalen) {
|
|
|
alloc_free_pages(pool,
|
|
alloc_free_pages(pool,
|
|
|
pool_offset(pool, mh)/getpagesize());
|
|
pool_offset(pool, mh)/getpagesize());
|
|
|
prev_mh->next = mh->next;
|
|
prev_mh->next = mh->next;
|
|
@@ -430,7 +441,7 @@ static bool clean_metadata(void *pool, unsigned long poolsize)
|
|
|
uint8_t *p;
|
|
uint8_t *p;
|
|
|
|
|
|
|
|
/* Some pages at end are free? */
|
|
/* Some pages at end are free? */
|
|
|
- for (p = (uint8_t *)(mh+1)+mh->metalen - getpagesize();
|
|
|
|
|
|
|
+ for (p = (uint8_t *)(mh+1) + metalen - getpagesize();
|
|
|
p > meta + i;
|
|
p > meta + i;
|
|
|
p -= getpagesize()) {
|
|
p -= getpagesize()) {
|
|
|
set_page_state(pool,
|
|
set_page_state(pool,
|
|
@@ -516,7 +527,7 @@ void alloc_free(void *pool, unsigned long poolsize, void *free)
|
|
|
assert(poolsize >= MIN_SIZE);
|
|
assert(poolsize >= MIN_SIZE);
|
|
|
|
|
|
|
|
mh = first_mheader(pool, poolsize);
|
|
mh = first_mheader(pool, poolsize);
|
|
|
- assert((char *)free >= (char *)(mh + 1) + mh->metalen);
|
|
|
|
|
|
|
+ assert((char *)free >= (char *)(mh + 1));
|
|
|
assert((char *)pool + poolsize > (char *)free);
|
|
assert((char *)pool + poolsize > (char *)free);
|
|
|
|
|
|
|
|
pagenum = pool_offset(pool, free) / getpagesize();
|
|
pagenum = pool_offset(pool, free) / getpagesize();
|
|
@@ -538,7 +549,8 @@ static bool is_metadata_page(void *pool, unsigned long poolsize,
|
|
|
unsigned long start, end;
|
|
unsigned long start, end;
|
|
|
|
|
|
|
|
start = pool_offset(pool, mh);
|
|
start = pool_offset(pool, mh);
|
|
|
- end = pool_offset(pool, (char *)(mh+1) + mh->metalen);
|
|
|
|
|
|
|
+ end = pool_offset(pool, (char *)(mh+1)
|
|
|
|
|
+ + get_metalen(pool, poolsize, mh));
|
|
|
if (page >= start/getpagesize() && page < end/getpagesize())
|
|
if (page >= start/getpagesize() && page < end/getpagesize())
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
@@ -608,7 +620,8 @@ bool alloc_check(void *pool, unsigned long poolsize)
|
|
|
if (start + sizeof(*mh) > poolsize)
|
|
if (start + sizeof(*mh) > poolsize)
|
|
|
return false;
|
|
return false;
|
|
|
|
|
|
|
|
- end = pool_offset(pool, (char *)(mh+1) + mh->metalen);
|
|
|
|
|
|
|
+ end = pool_offset(pool, (char *)(mh+1)
|
|
|
|
|
+ + get_metalen(pool, poolsize, mh));
|
|
|
if (end > poolsize)
|
|
if (end > poolsize)
|
|
|
return false;
|
|
return false;
|
|
|
|
|
|
|
@@ -676,14 +689,13 @@ void alloc_visualize(FILE *out, void *pool, unsigned long poolsize)
|
|
|
|
|
|
|
|
/* Now do each metadata page. */
|
|
/* Now do each metadata page. */
|
|
|
for (; mh; mh = next_mheader(pool,mh)) {
|
|
for (; mh; mh = next_mheader(pool,mh)) {
|
|
|
- unsigned long free = 0, subpageblocks = 0, len = 0;
|
|
|
|
|
|
|
+ unsigned long free = 0, subpageblocks = 0, len = 0, metalen;
|
|
|
uint8_t *meta = (uint8_t *)(mh + 1);
|
|
uint8_t *meta = (uint8_t *)(mh + 1);
|
|
|
|
|
|
|
|
- metadata_pages += (sizeof(*mh) + mh->metalen) / getpagesize();
|
|
|
|
|
|
|
+ metalen = get_metalen(pool, poolsize, mh);
|
|
|
|
|
+ metadata_pages += (sizeof(*mh) + metalen) / getpagesize();
|
|
|
|
|
|
|
|
- for (i = 0;
|
|
|
|
|
- i < mh->metalen * CHAR_BIT / BITS_PER_PAGE;
|
|
|
|
|
- i += len) {
|
|
|
|
|
|
|
+ for (i = 0; i < metalen * CHAR_BIT / BITS_PER_PAGE; i += len) {
|
|
|
switch (get_page_state(meta, i)) {
|
|
switch (get_page_state(meta, i)) {
|
|
|
case FREE:
|
|
case FREE:
|
|
|
len = 1;
|
|
len = 1;
|
|
@@ -701,7 +713,7 @@ void alloc_visualize(FILE *out, void *pool, unsigned long poolsize)
|
|
|
|
|
|
|
|
fprintf(out, "Metadata %lu-%lu: %lu free, %lu subpageblocks, %lu%% density\n",
|
|
fprintf(out, "Metadata %lu-%lu: %lu free, %lu subpageblocks, %lu%% density\n",
|
|
|
pool_offset(pool, mh),
|
|
pool_offset(pool, mh),
|
|
|
- pool_offset(pool, (char *)(mh+1) + mh->metalen),
|
|
|
|
|
|
|
+ pool_offset(pool, (char *)(mh+1) + metalen),
|
|
|
free, subpageblocks,
|
|
free, subpageblocks,
|
|
|
subpageblocks * BITMAP_METALEN * 100
|
|
subpageblocks * BITMAP_METALEN * 100
|
|
|
/ (free + subpageblocks * BITMAP_METALEN));
|
|
/ (free + subpageblocks * BITMAP_METALEN));
|