VMware balloon: Update balloon target on each lock/unlock.
authorXavier Deguillard <xdeguillard@vmware.com>
Thu, 6 Aug 2015 22:17:59 +0000 (15:17 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 4 Oct 2015 11:59:11 +0000 (12:59 +0100)
Instead of waiting for the next GET_TARGET command, we can react faster
by exploiting the fact that each hypervisor call also returns the
balloon target.

Signed-off-by: Xavier Deguillard <xdeguillard@vmware.com>
Acked-by: Dmitry Torokhov <dtor@vmware.com>
Signed-off-by: Philip P. Moltmann <moltmann@vmware.com>
Acked-by: Andy King <acking@vmware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/misc/vmw_balloon.c

index 64f275e..0b5aa93 100644 (file)
@@ -47,7 +47,7 @@
 
 MODULE_AUTHOR("VMware, Inc.");
 MODULE_DESCRIPTION("VMware Memory Control (Balloon) Driver");
-MODULE_VERSION("1.3.1.0-k");
+MODULE_VERSION("1.3.2.0-k");
 MODULE_ALIAS("dmi:*:svnVMware*:*");
 MODULE_ALIAS("vmware_vmmemctl");
 MODULE_LICENSE("GPL");
@@ -255,8 +255,10 @@ struct vmballoon;
 
 struct vmballoon_ops {
        void (*add_page)(struct vmballoon *b, int idx, struct page *p);
-       int (*lock)(struct vmballoon *b, unsigned int num_pages);
-       int (*unlock)(struct vmballoon *b, unsigned int num_pages);
+       int (*lock)(struct vmballoon *b, unsigned int num_pages,
+                                               unsigned int *target);
+       int (*unlock)(struct vmballoon *b, unsigned int num_pages,
+                                               unsigned int *target);
 };
 
 struct vmballoon {
@@ -413,7 +415,7 @@ static bool vmballoon_send_get_target(struct vmballoon *b, u32 *new_target)
  * check the return value and maybe submit a different page.
  */
 static int vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn,
-                                    unsigned int *hv_status)
+                               unsigned int *hv_status, unsigned int *target)
 {
        unsigned long status, dummy = 0;
        u32 pfn32;
@@ -424,7 +426,7 @@ static int vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn,
 
        STATS_INC(b->stats.lock);
 
-       *hv_status = status = VMWARE_BALLOON_CMD(LOCK, pfn, dummy, dummy);
+       *hv_status = status = VMWARE_BALLOON_CMD(LOCK, pfn, dummy, *target);
        if (vmballoon_check_status(b, status))
                return 0;
 
@@ -434,14 +436,14 @@ static int vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn,
 }
 
 static int vmballoon_send_batched_lock(struct vmballoon *b,
-                                       unsigned int num_pages)
+                               unsigned int num_pages, unsigned int *target)
 {
-       unsigned long status, dummy;
+       unsigned long status;
        unsigned long pfn = page_to_pfn(b->page);
 
        STATS_INC(b->stats.lock);
 
-       status = VMWARE_BALLOON_CMD(BATCHED_LOCK, pfn, num_pages, dummy);
+       status = VMWARE_BALLOON_CMD(BATCHED_LOCK, pfn, num_pages, *target);
        if (vmballoon_check_status(b, status))
                return 0;
 
@@ -454,7 +456,8 @@ static int vmballoon_send_batched_lock(struct vmballoon *b,
  * Notify the host that guest intends to release given page back into
  * the pool of available (to the guest) pages.
  */
-static bool vmballoon_send_unlock_page(struct vmballoon *b, unsigned long pfn)
+static bool vmballoon_send_unlock_page(struct vmballoon *b, unsigned long pfn,
+                                                       unsigned int *target)
 {
        unsigned long status, dummy = 0;
        u32 pfn32;
@@ -465,7 +468,7 @@ static bool vmballoon_send_unlock_page(struct vmballoon *b, unsigned long pfn)
 
        STATS_INC(b->stats.unlock);
 
-       status = VMWARE_BALLOON_CMD(UNLOCK, pfn, dummy, dummy);
+       status = VMWARE_BALLOON_CMD(UNLOCK, pfn, dummy, *target);
        if (vmballoon_check_status(b, status))
                return true;
 
@@ -475,14 +478,14 @@ static bool vmballoon_send_unlock_page(struct vmballoon *b, unsigned long pfn)
 }
 
 static bool vmballoon_send_batched_unlock(struct vmballoon *b,
-                                               unsigned int num_pages)
+                               unsigned int num_pages, unsigned int *target)
 {
-       unsigned long status, dummy;
+       unsigned long status;
        unsigned long pfn = page_to_pfn(b->page);
 
        STATS_INC(b->stats.unlock);
 
-       status = VMWARE_BALLOON_CMD(BATCHED_UNLOCK, pfn, num_pages, dummy);
+       status = VMWARE_BALLOON_CMD(BATCHED_UNLOCK, pfn, num_pages, *target);
        if (vmballoon_check_status(b, status))
                return true;
 
@@ -528,12 +531,14 @@ static void vmballoon_pop(struct vmballoon *b)
  * refuse list, those refused page are then released at the end of the
  * inflation cycle.
  */
-static int vmballoon_lock_page(struct vmballoon *b, unsigned int num_pages)
+static int vmballoon_lock_page(struct vmballoon *b, unsigned int num_pages,
+                                                       unsigned int *target)
 {
        int locked, hv_status;
        struct page *page = b->page;
 
-       locked = vmballoon_send_lock_page(b, page_to_pfn(page), &hv_status);
+       locked = vmballoon_send_lock_page(b, page_to_pfn(page), &hv_status,
+                                                               target);
        if (locked > 0) {
                STATS_INC(b->stats.refused_alloc);
 
@@ -567,11 +572,11 @@ static int vmballoon_lock_page(struct vmballoon *b, unsigned int num_pages)
 }
 
 static int vmballoon_lock_batched_page(struct vmballoon *b,
-                               unsigned int num_pages)
+                               unsigned int num_pages, unsigned int *target)
 {
        int locked, i;
 
-       locked = vmballoon_send_batched_lock(b, num_pages);
+       locked = vmballoon_send_batched_lock(b, num_pages, target);
        if (locked > 0) {
                for (i = 0; i < num_pages; i++) {
                        u64 pa = vmballoon_batch_get_pa(b->batch_page, i);
@@ -620,11 +625,12 @@ static int vmballoon_lock_batched_page(struct vmballoon *b,
  * the host so it can make sure the page will be available for the guest
  * to use, if needed.
  */
-static int vmballoon_unlock_page(struct vmballoon *b, unsigned int num_pages)
+static int vmballoon_unlock_page(struct vmballoon *b, unsigned int num_pages,
+                                                       unsigned int *target)
 {
        struct page *page = b->page;
 
-       if (!vmballoon_send_unlock_page(b, page_to_pfn(page))) {
+       if (!vmballoon_send_unlock_page(b, page_to_pfn(page), target)) {
                list_add(&page->lru, &b->pages);
                return -EIO;
        }
@@ -640,12 +646,12 @@ static int vmballoon_unlock_page(struct vmballoon *b, unsigned int num_pages)
 }
 
 static int vmballoon_unlock_batched_page(struct vmballoon *b,
-                                       unsigned int num_pages)
+                               unsigned int num_pages, unsigned int *target)
 {
        int locked, i, ret = 0;
        bool hv_success;
 
-       hv_success = vmballoon_send_batched_unlock(b, num_pages);
+       hv_success = vmballoon_send_batched_unlock(b, num_pages, target);
        if (!hv_success)
                ret = -EIO;
 
@@ -710,9 +716,7 @@ static void vmballoon_add_batched_page(struct vmballoon *b, int idx,
  */
 static void vmballoon_inflate(struct vmballoon *b)
 {
-       unsigned int goal;
        unsigned int rate;
-       unsigned int i;
        unsigned int allocations = 0;
        unsigned int num_pages = 0;
        int error = 0;
@@ -735,7 +739,6 @@ static void vmballoon_inflate(struct vmballoon *b)
         * slowdown page allocations considerably.
         */
 
-       goal = b->target - b->size;
        /*
         * Start with no sleep allocation rate which may be higher
         * than sleeping allocation rate.
@@ -744,16 +747,17 @@ static void vmballoon_inflate(struct vmballoon *b)
                        b->rate_alloc : VMW_BALLOON_NOSLEEP_ALLOC_MAX;
 
        pr_debug("%s - goal: %d, no-sleep rate: %d, sleep rate: %d\n",
-                __func__, goal, rate, b->rate_alloc);
+                __func__, b->target - b->size, rate, b->rate_alloc);
 
-       for (i = 0; i < goal; i++) {
-               struct page *page = alloc_page(flags);
+       while (b->size < b->target && num_pages < b->target - b->size) {
+               struct page *page;
 
                if (flags == VMW_PAGE_ALLOC_NOSLEEP)
                        STATS_INC(b->stats.alloc);
                else
                        STATS_INC(b->stats.sleep_alloc);
 
+               page = alloc_page(flags);
                if (!page) {
                        if (flags == VMW_PAGE_ALLOC_CANSLEEP) {
                                /*
@@ -778,7 +782,7 @@ static void vmballoon_inflate(struct vmballoon *b)
                         */
                        b->slow_allocation_cycles = VMW_BALLOON_SLOW_CYCLES;
 
-                       if (i >= b->rate_alloc)
+                       if (allocations >= b->rate_alloc)
                                break;
 
                        flags = VMW_PAGE_ALLOC_CANSLEEP;
@@ -789,7 +793,7 @@ static void vmballoon_inflate(struct vmballoon *b)
 
                b->ops->add_page(b, num_pages++, page);
                if (num_pages == b->batch_max_pages) {
-                       error = b->ops->lock(b, num_pages);
+                       error = b->ops->lock(b, num_pages, &b->target);
                        num_pages = 0;
                        if (error)
                                break;
@@ -800,21 +804,21 @@ static void vmballoon_inflate(struct vmballoon *b)
                        allocations = 0;
                }
 
-               if (i >= rate) {
+               if (allocations >= rate) {
                        /* We allocated enough pages, let's take a break. */
                        break;
                }
        }
 
        if (num_pages > 0)
-               b->ops->lock(b, num_pages);
+               b->ops->lock(b, num_pages, &b->target);
 
        /*
         * We reached our goal without failures so try increasing
         * allocation rate.
         */
-       if (error == 0 && i >= b->rate_alloc) {
-               unsigned int mult = i / b->rate_alloc;
+       if (error == 0 && allocations >= b->rate_alloc) {
+               unsigned int mult = allocations / b->rate_alloc;
 
                b->rate_alloc =
                        min(b->rate_alloc + mult * VMW_BALLOON_RATE_ALLOC_INC,
@@ -831,16 +835,11 @@ static void vmballoon_deflate(struct vmballoon *b)
 {
        struct page *page, *next;
        unsigned int i = 0;
-       unsigned int goal;
        unsigned int num_pages = 0;
        int error;
 
-       pr_debug("%s - size: %d, target %d\n", __func__, b->size, b->target);
-
-       /* limit deallocation rate */
-       goal = min(b->size - b->target, b->rate_free);
-
-       pr_debug("%s - goal: %d, rate: %d\n", __func__, goal, b->rate_free);
+       pr_debug("%s - size: %d, target %d, rate: %d\n", __func__, b->size,
+                                               b->target, b->rate_free);
 
        /* free pages to reach target */
        list_for_each_entry_safe(page, next, &b->pages, lru) {
@@ -848,7 +847,7 @@ static void vmballoon_deflate(struct vmballoon *b)
                b->ops->add_page(b, num_pages++, page);
 
                if (num_pages == b->batch_max_pages) {
-                       error = b->ops->unlock(b, num_pages);
+                       error = b->ops->unlock(b, num_pages, &b->target);
                        num_pages = 0;
                        if (error) {
                                /* quickly decrease rate in case of error */
@@ -858,12 +857,12 @@ static void vmballoon_deflate(struct vmballoon *b)
                        }
                }
 
-               if (++i >= goal)
+               if (++i >= b->size - b->target)
                        break;
        }
 
        if (num_pages > 0)
-               b->ops->unlock(b, num_pages);
+               b->ops->unlock(b, num_pages, &b->target);
 
        /* slowly increase rate if there were no errors */
        if (error == 0)