]> xenbits.xensource.com Git - people/liuw/linux.git/commitdiff
xen/balloon: rework increase_reservation
authorWei Liu <wei.liu2@citrix.com>
Tue, 4 Mar 2014 15:45:55 +0000 (15:45 +0000)
committerWei Liu <wei.liu2@citrix.com>
Wed, 15 Oct 2014 15:07:53 +0000 (16:07 +0100)
The original behavior of increase_reservation dequeues populated balloon
pages after hypercall, which doesn't quite comply with the logic of core
balloon compaction code, which expects driver to dequeue the pages
before doing any work.

In short, original logic:
1. prepare hypercall structure without grabbing the pages
2. issue hypercall
3. release populated pages to kernel

Change logic of increase_reservation to:
1. grab all pages from balloon driver and prepare hypercall structure
2. issue hypercall
3. release populated pages to kernel
4. add back any pages that are not populated to balloon driver

Note that balloon_retrieve's logic is changed as well -- the
accounting code is moved outside of that function and added to places
where appropriate.

This is in preparation for later patches that make use of the core
balloon compaction driver.

Signed-off-by: Wei Liu <wei.liu2@citrix.com>
drivers/xen/balloon.c

index 04e12b4e8b8fa5e1a43d5b30a53d271c867e1846..4f46545b390559803dbdaf0718418de09a613f37 100644 (file)
@@ -133,7 +133,11 @@ static void balloon_append(struct page *page)
        adjust_managed_page_count(page, -1);
 }
 
-/* balloon_retrieve: rescue a page from the balloon, if it is not empty. */
+/* balloon_retrieve: rescue a page from Xen balloon driver, if it is
+ * not empty. This function doesn't look at pages in generic balloon
+ * driver. Also the accouting is not updated as the page might be put
+ * back to the list.
+ */
 static struct page *balloon_retrieve(bool prefer_highmem)
 {
        struct page *page;
@@ -149,21 +153,9 @@ static struct page *balloon_retrieve(bool prefer_highmem)
                                  struct page, lru);
        list_del(&page->lru);
 
-       update_balloon_stats(page, -1);
-
-       adjust_managed_page_count(page, 1);
-
        return page;
 }
 
-static struct page *balloon_next_page(struct page *page)
-{
-       struct list_head *next = page->lru.next;
-       if (next == &xen_balloon.ballooned_pages)
-               return NULL;
-       return list_entry(next, struct page, lru);
-}
-
 static enum bp_state update_schedule(enum bp_state state)
 {
        if (state == BP_DONE) {
@@ -309,6 +301,7 @@ static enum bp_state increase_reservation(unsigned long nr_pages)
        int rc;
        unsigned long  pfn, i;
        struct page   *page;
+       LIST_HEAD(queue);
        struct xen_memory_reservation reservation = {
                .address_bits = 0,
                .extent_order = 0,
@@ -329,27 +322,34 @@ static enum bp_state increase_reservation(unsigned long nr_pages)
        if (nr_pages > ARRAY_SIZE(frame_list))
                nr_pages = ARRAY_SIZE(frame_list);
 
-       page = list_first_entry_or_null(&xen_balloon.ballooned_pages,
-                                       struct page, lru);
+       /* First step: grab all pages we need to balloon in */
        for (i = 0; i < nr_pages; i++) {
+               page = balloon_retrieve(false);
                if (!page) {
                        nr_pages = i;
                        break;
                }
                frame_list[i] = page_to_pfn(page);
-               page = balloon_next_page(page);
+               /* The order in queue must match the order in frame_list */
+               list_add_tail(&page->lru, &queue);
        }
 
+       /* Second step: issue hypercall */
        set_xen_guest_handle(reservation.extent_start, frame_list);
        reservation.nr_extents = nr_pages;
        rc = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation);
-       if (rc <= 0)
-               return BP_EAGAIN;
+       if (rc <= 0) {
+               rc = BP_EAGAIN;
+               goto move_pages_back;
+       }
 
+       /* Third step: free populated pages back to kernel allocator */
        for (i = 0; i < rc; i++) {
-               page = balloon_retrieve(false);
+               page = list_first_entry_or_null(&queue, struct page, lru);
+
                BUG_ON(page == NULL);
 
+               list_del(&page->lru);
                pfn = page_to_pfn(page);
 
 #ifdef CONFIG_XEN_HAVE_PVMMU
@@ -370,11 +370,19 @@ static enum bp_state increase_reservation(unsigned long nr_pages)
 
                /* Relinquish the page back to the allocator. */
                __free_reserved_page(page);
+
+               /* We only account for those pages that have been populated. */
+               update_balloon_stats(page, -1);
+               adjust_managed_page_count(page, 1);
        }
 
        xen_balloon.balloon_stats.current_pages += rc;
+       rc = BP_DONE;
 
-       return BP_DONE;
+move_pages_back:
+       /* Final step: move back any unpopulated pages to balloon driver */
+       list_splice_init(&queue, &xen_balloon.ballooned_pages);
+       return rc;
 }
 
 static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
@@ -545,6 +553,8 @@ int alloc_xenballooned_pages(int nr_pages, struct page **pages, bool highmem)
                page = balloon_retrieve(highmem);
                if (page && (highmem || !PageHighMem(page))) {
                        pages[pgno++] = page;
+                       update_balloon_stats(page, -1);
+                       adjust_managed_page_count(page, 1);
                } else {
                        enum bp_state st;
                        if (page)