[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[UNIKRAFT/BALLOON v2 7/7] lib/ukallocbbuddy: Balloon API calls insertion



From: Cezar Craciunoiu <cezar.craciunoiu@xxxxxxxxx>

To call the balloon in a fashionable way, the calls were added to bbuddy.
The palloc function calls deflate, pfree and addmem call inflate.

The balloon is first started using the balloon_init function that is called
just once. In the case of KVM, because it does not currently need to
initialize itself by inflating the balloon, the calls to balloon_init and
ukplat_inflate are skipped.

As there might be a need in the future for balloon inflation for KVM, it was
not removed from the original implementation. If needed (for cleaner code),
it can be removed and replaced with a stub.

The balloon calls do not influence the behaviour of bbuddy in a visible way,
meaning that, if something fails in the balloon, it does not affect what
is in bbuddy. Except for the case where an unknown error happens.

Signed-off-by: Cezar Craciunoiu <cezar.craciunoiu@xxxxxxxxx>
---
 lib/ukallocbbuddy/Config.uk |   2 +
 lib/ukallocbbuddy/bbuddy.c  | 137 +++++++++++++++++++++++++++++++++++-
 2 files changed, 137 insertions(+), 2 deletions(-)

diff --git a/lib/ukallocbbuddy/Config.uk b/lib/ukallocbbuddy/Config.uk
index c5a3025..5b3f9d2 100644
--- a/lib/ukallocbbuddy/Config.uk
+++ b/lib/ukallocbbuddy/Config.uk
@@ -4,3 +4,5 @@ config LIBUKALLOCBBUDDY
        select LIBNOLIBC if !HAVE_LIBC
        select LIBUKDEBUG
        select LIBUKALLOC
+       select BALLOON if HAVE_KVM
+
diff --git a/lib/ukallocbbuddy/bbuddy.c b/lib/ukallocbbuddy/bbuddy.c
index 85f3e8d..becc36e 100644
--- a/lib/ukallocbbuddy/bbuddy.c
+++ b/lib/ukallocbbuddy/bbuddy.c
@@ -49,6 +49,8 @@
 #include <uk/assert.h>
 #include <uk/page.h>
 
+#include <uk/plat/balloon.h>
+
 typedef struct chunk_head_st chunk_head_t;
 typedef struct chunk_tail_st chunk_tail_t;
 
@@ -242,6 +244,51 @@ static inline unsigned long num_pages_to_order(unsigned 
long num_pages)
        return ukarch_flsl(num_pages - 1) + 1;
 }
 
+/*********************
+ * BALLOON SUPPORT
+ */
+
+static char using_balloon;
+
+/**
+ * Initializes the balloon once it is ready. Immediate for Xen,
+ * but later for KVM driver.
+ */
+static void balloon_init(struct uk_alloc *a)
+{
+       struct uk_bbpalloc *b;
+       size_t i;
+       int order;
+       chunk_head_t *chunk;
+       int r;
+
+       b = (struct uk_bbpalloc *)&a->priv;
+
+       ukplat_balloon_set(&using_balloon);
+
+       if (using_balloon != 0)
+               return;
+
+       for (i = 0; i < FREELIST_SIZE; i++) {
+               if (!FREELIST_EMPTY(b->free_head[i])) {
+                       chunk = b->free_head[i];
+                       order = chunk->level;
+
+                       r = ukplat_inflate((void *)chunk, order);
+                       if (r < 0) {
+                               /* The balloon is ready but
+                                * failed for another reason.
+                                */
+                               return;
+                       }
+               }
+
+       }
+       using_balloon = 1;
+}
+
+
+
 /*********************
  * BINARY BUDDY PAGE ALLOCATOR
  */
@@ -249,6 +296,7 @@ static void *bbuddy_palloc(struct uk_alloc *a, unsigned 
long num_pages)
 {
        struct uk_bbpalloc *b;
        size_t i;
+       int r;
        chunk_head_t *alloc_ch, *spare_ch;
        chunk_tail_t *spare_ct;
 
@@ -291,6 +339,31 @@ static void *bbuddy_palloc(struct uk_alloc *a, unsigned 
long num_pages)
        }
        map_alloc(b, (uintptr_t)alloc_ch, 1UL << order);
 
+       /* Remove the chunk from the balloon - not for KVM */
+       if (using_balloon != 2) {
+               r = ukplat_deflate((void *)alloc_ch, (int)order);
+               if (r < 0) {
+                       if (r == -ENXIO) {
+                               /* The balloon isn't ready yet!
+                                * We don't need to do anything.
+                                */
+                       } else if (r == -ENOSYS) {
+                               /* deflation not implemented */
+                       } else {
+                               /* The balloon is ready but
+                                * failed for another reason.
+                                */
+                               return NULL;
+                       }
+               } else if (using_balloon == 0) {
+                       /* Deflate succeeded for the first time.
+                        * The balloon driver is ready! We need to move
+                        * all of the freelist data to the balloon.
+                        */
+                       balloon_init(a);
+               }
+       }
+
        return ((void *)alloc_ch);
 
 no_memory:
@@ -306,6 +379,7 @@ static void bbuddy_pfree(struct uk_alloc *a, void *obj, 
unsigned long num_pages)
        chunk_head_t *freed_ch, *to_merge_ch;
        chunk_tail_t *freed_ct;
        unsigned long mask;
+       int r;
 
        UK_ASSERT(a != NULL);
        b = (struct uk_bbpalloc *)&a->priv;
@@ -318,6 +392,29 @@ static void bbuddy_pfree(struct uk_alloc *a, void *obj, 
unsigned long num_pages)
        /* First free the chunk */
        map_free(b, (uintptr_t)obj, 1UL << order);
 
+       /* Add the free chunk to the balloon */
+       r = ukplat_inflate((void *)obj, (int)order);
+       if (r < 0) {
+               if (r == -ENXIO) {
+                       /* The balloon isn't ready yet!
+                        * We don't need to do anything.
+                        */
+               } else if (r == -ENOSYS) {
+                       /* inflateion not implemented */
+               } else {
+                       /* The balloon is ready but
+                        * failed for another reason.
+                        */
+                       return;
+               }
+       } else if (using_balloon == 0) {
+               /* Inflate succeeded for the first time.
+                * The balloon driver is now ready!
+                * We need to move all of the free list data to the balloon.
+                */
+               balloon_init(a);
+       }
+
        /* Create free chunk */
        freed_ch = (chunk_head_t *)obj;
        freed_ct = (chunk_tail_t *)((char *)obj
@@ -371,6 +468,7 @@ static int bbuddy_addmem(struct uk_alloc *a, void *base, 
size_t len)
        chunk_head_t *ch;
        chunk_tail_t *ct;
        uintptr_t min, max, range;
+       int r;
 
        UK_ASSERT(a != NULL);
        UK_ASSERT(base != NULL);
@@ -431,8 +529,10 @@ static int bbuddy_addmem(struct uk_alloc *a, void *base, 
size_t len)
        memset(memr->mm_alloc_bitmap, (unsigned char) ~0,
                        memr->mm_alloc_bitmap_size);
 
-       /* free up the memory we've been given to play with */
-       map_free(b, min, memr->nr_pages);
+
+       /* Mock call to check if the balloon is implemented */
+       if (ukplat_inflate(NULL, 0) == -ENOSYS)
+               map_free(b, min, memr->nr_pages);
 
        count = 0;
        while (range != 0) {
@@ -448,6 +548,39 @@ static int bbuddy_addmem(struct uk_alloc *a, void *base, 
size_t len)
                            (uintptr_t)a, min, (uintptr_t)(min + (1UL << i)),
                            (i - __PAGE_SHIFT));
 
+               /*
+                * For each free block we attempt to add it to the balloon
+                * Afterwards, if successful, all of our usable memory will be
+                * in the balloon. It will become accessible by calling deflate
+                * in ukpalloc, or directly for KVM!
+                *
+                * If the balloon device has not yet been added then the
+                * allocator will proceed without ballooning support until
+                * the device has been added (KVM).
+                */
+               r = ukplat_inflate((void *)min, (int)(i - __PAGE_SHIFT));
+               if (r < 0) {
+                       if (r == -ENXIO) {
+                               /* The balloon isn't ready yet!
+                                * We don't need to do anything.
+                                */
+                       } else if (r == -ENOSYS) {
+                               /* inflation not implemented */
+                       } else {
+                               /* The balloon is ready but failed
+                                * for another reason.
+                                */
+                               return r;
+                       }
+               } else if (using_balloon == 0) {
+                       /* Inflate succeeded for the first time.
+                        * The balloon driver is now ready!
+                        * We need to move all of the free list
+                        * data to the balloon.
+                        */
+                       balloon_init(a);
+               }
+
                ch = (chunk_head_t *)min;
                min += 1UL << i;
                range -= 1UL << i;
-- 
2.20.1




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.