Commit c62437a9 authored by Rusty Russell's avatar Rusty Russell

Remove redundant metalen from metadata header: we can use page bits.

parent f033b4f3
...@@ -35,8 +35,6 @@ ...@@ -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) ...@@ -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, ...@@ -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 free = 0, len, i, metalen;
unsigned long i;
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, ...@@ -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, ...@@ -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); /* We start on this page. */
assert(nextpage % getpagesize() == 0); 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()); memset((char *)pool + nextpage*getpagesize(), 0, getpagesize());
mh->metalen += getpagesize(); return alloc_metaspace(pool, poolsize, mh, bytes, type);
return alloc_metaspace(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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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; for (i = 0; i < metalen * CHAR_BIT / BITS_PER_PAGE; i += len) {
i < mh->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) ...@@ -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));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment