[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] Fix the balloon driver to do work in smaller batches, and
# HG changeset patch # User kaf24@xxxxxxxxxxxxxxxxxxxx # Node ID d5bd2c583cb01e1442827d5565b1cc19398b3f32 # Parent 0856c511a83ec51fc37aa22ab98257470e20b4fb Fix the balloon driver to do work in smaller batches, and not use a vmalloc'ed mfn list which may not be mapped into all page tables. Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx> diff -r 0856c511a83e -r d5bd2c583cb0 linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c --- a/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c Mon Sep 5 17:21:08 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c Mon Sep 5 17:51:55 2005 @@ -58,6 +58,12 @@ static struct proc_dir_entry *balloon_pde; static DECLARE_MUTEX(balloon_mutex); + +/* + * Protects atomic reservation decrease/increase against concurrent increases. + * Also protects non-atomic updates of current_pages and driver_pages, and + * balloon lists. + */ spinlock_t balloon_lock = SPIN_LOCK_UNLOCKED; /* We aim for 'current allocation' == 'target allocation'. */ @@ -157,6 +163,146 @@ return target; } +static int increase_reservation(unsigned long nr_pages) +{ + unsigned long *mfn_list, pfn, i, flags; + struct page *page; + long rc; + struct xen_memory_reservation reservation = { + .address_bits = 0, + .extent_order = 0, + .domid = DOMID_SELF + }; + + if (nr_pages > (PAGE_SIZE / sizeof(unsigned long))) + nr_pages = PAGE_SIZE / sizeof(unsigned long); + + mfn_list = (unsigned long *)__get_free_page(GFP_KERNEL); + if (mfn_list == NULL) + return -ENOMEM; + + balloon_lock(flags); + + reservation.extent_start = mfn_list; + reservation.nr_extents = nr_pages; + rc = HYPERVISOR_memory_op( + XENMEM_increase_reservation, &reservation); + if (rc < nr_pages) { + /* We hit the Xen hard limit: reprobe. */ + reservation.extent_start = mfn_list; + reservation.nr_extents = rc; + BUG_ON(HYPERVISOR_memory_op( + XENMEM_decrease_reservation, + &reservation) != rc); + hard_limit = current_pages + rc - driver_pages; + goto out; + } + + for (i = 0; i < nr_pages; i++) { + page = balloon_retrieve(); + BUG_ON(page == NULL); + + pfn = page - mem_map; + BUG_ON(phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY); + + /* Update P->M and M->P tables. */ + phys_to_machine_mapping[pfn] = mfn_list[i]; + xen_machphys_update(mfn_list[i], pfn); + + /* Link back into the page tables if not highmem. */ + if (pfn < max_low_pfn) + BUG_ON(HYPERVISOR_update_va_mapping( + (unsigned long)__va(pfn << PAGE_SHIFT), + pfn_pte_ma(mfn_list[i], PAGE_KERNEL), + 0)); + + /* Relinquish the page back to the allocator. */ + ClearPageReserved(page); + set_page_count(page, 1); + __free_page(page); + } + + current_pages += nr_pages; + + out: + balloon_unlock(flags); + + free_page((unsigned long)mfn_list); + + return 0; +} + +static int decrease_reservation(unsigned long nr_pages) +{ + unsigned long *mfn_list, pfn, i, flags; + struct page *page; + void *v; + int need_sleep = 0; + struct xen_memory_reservation reservation = { + .address_bits = 0, + .extent_order = 0, + .domid = DOMID_SELF + }; + + if (nr_pages > (PAGE_SIZE / sizeof(unsigned long))) + nr_pages = PAGE_SIZE / sizeof(unsigned long); + + mfn_list = (unsigned long *)__get_free_page(GFP_KERNEL); + if (mfn_list == NULL) + return -ENOMEM; + + for (i = 0; i < nr_pages; i++) { + if ((page = alloc_page(GFP_HIGHUSER)) == NULL) { + nr_pages = i; + need_sleep = 1; + break; + } + + pfn = page - mem_map; + mfn_list[i] = phys_to_machine_mapping[pfn]; + + if (!PageHighMem(page)) { + v = phys_to_virt(pfn << PAGE_SHIFT); + scrub_pages(v, 1); + BUG_ON(HYPERVISOR_update_va_mapping( + (unsigned long)v, __pte_ma(0), 0)); + } +#ifdef CONFIG_XEN_SCRUB_PAGES + else { + v = kmap(page); + scrub_pages(v, 1); + kunmap(page); + } +#endif + } + + /* Ensure that ballooned highmem pages don't have kmaps. */ + kmap_flush_unused(); + flush_tlb_all(); + + balloon_lock(flags); + + /* No more mappings: invalidate P2M and add to balloon. */ + for (i = 0; i < nr_pages; i++) { + pfn = mfn_to_pfn(mfn_list[i]); + phys_to_machine_mapping[pfn] = INVALID_P2M_ENTRY; + balloon_append(pfn_to_page(pfn)); + } + + reservation.extent_start = mfn_list; + reservation.nr_extents = nr_pages; + BUG_ON(HYPERVISOR_memory_op( + XENMEM_decrease_reservation, &reservation) != nr_pages); + + current_pages -= nr_pages; + + balloon_unlock(flags); + + free_page((unsigned long)mfn_list); + + return need_sleep; +} + /* * We avoid multiple worker processes conflicting via the balloon mutex. * We may of course race updates of the target counts (which are protected @@ -165,123 +311,23 @@ */ static void balloon_process(void *unused) { - unsigned long *mfn_list, pfn, i, flags; - struct page *page; - long credit, debt, rc; - void *v; - struct xen_memory_reservation reservation = { - .address_bits = 0, - .extent_order = 0, - .domid = DOMID_SELF - }; + int need_sleep = 0; + long credit; down(&balloon_mutex); - retry: - mfn_list = NULL; - - if ((credit = current_target() - current_pages) > 0) { - mfn_list = vmalloc(credit * sizeof(*mfn_list)); - if (mfn_list == NULL) - goto out; - - balloon_lock(flags); - reservation.extent_start = mfn_list; - reservation.nr_extents = credit; - rc = HYPERVISOR_memory_op( - XENMEM_increase_reservation, &reservation); - balloon_unlock(flags); - if (rc < credit) { - /* We hit the Xen hard limit: reprobe. */ - reservation.extent_start = mfn_list; - reservation.nr_extents = rc; - BUG_ON(HYPERVISOR_memory_op( - XENMEM_decrease_reservation, - &reservation) != rc); - hard_limit = current_pages + rc - driver_pages; - vfree(mfn_list); - goto retry; - } - - for (i = 0; i < credit; i++) { - page = balloon_retrieve(); - BUG_ON(page == NULL); - - pfn = page - mem_map; - if (phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY) - BUG(); - - /* Update P->M and M->P tables. */ - phys_to_machine_mapping[pfn] = mfn_list[i]; - xen_machphys_update(mfn_list[i], pfn); - - /* Link back into the page tables if not highmem. */ - if (pfn < max_low_pfn) - BUG_ON(HYPERVISOR_update_va_mapping( - (unsigned long)__va(pfn << PAGE_SHIFT), - pfn_pte_ma(mfn_list[i], PAGE_KERNEL), - 0)); - - /* Relinquish the page back to the allocator. */ - ClearPageReserved(page); - set_page_count(page, 1); - __free_page(page); - } - - current_pages += credit; - } else if (credit < 0) { - debt = -credit; - - mfn_list = vmalloc(debt * sizeof(*mfn_list)); - if (mfn_list == NULL) - goto out; - - for (i = 0; i < debt; i++) { - if ((page = alloc_page(GFP_HIGHUSER)) == NULL) { - debt = i; - break; - } - - pfn = page - mem_map; - mfn_list[i] = phys_to_machine_mapping[pfn]; - - if (!PageHighMem(page)) { - v = phys_to_virt(pfn << PAGE_SHIFT); - scrub_pages(v, 1); - BUG_ON(HYPERVISOR_update_va_mapping( - (unsigned long)v, __pte_ma(0), 0)); - } -#ifdef CONFIG_XEN_SCRUB_PAGES - else { - v = kmap(page); - scrub_pages(v, 1); - kunmap(page); - } + do { + credit = current_target() - current_pages; + if (credit > 0) + need_sleep = (increase_reservation(credit) != 0); + if (credit < 0) + need_sleep = (decrease_reservation(-credit) != 0); + +#ifndef CONFIG_PREEMPT + if (need_resched()) + schedule(); #endif - } - - /* Ensure that ballooned highmem pages don't have kmaps. */ - kmap_flush_unused(); - flush_tlb_all(); - - /* No more mappings: invalidate P2M and add to balloon. */ - for (i = 0; i < debt; i++) { - pfn = mfn_to_pfn(mfn_list[i]); - phys_to_machine_mapping[pfn] = INVALID_P2M_ENTRY; - balloon_append(pfn_to_page(pfn)); - } - - reservation.extent_start = mfn_list; - reservation.nr_extents = debt; - BUG_ON(HYPERVISOR_memory_op( - XENMEM_decrease_reservation, &reservation) != debt); - - current_pages -= debt; - } - - out: - if (mfn_list != NULL) - vfree(mfn_list); + } while ((credit != 0) && !need_sleep); /* Schedule more work if there is some still to be done. */ if (current_target() != current_pages) @@ -441,8 +487,9 @@ void balloon_update_driver_allowance(long delta) { unsigned long flags; + balloon_lock(flags); - driver_pages += delta; /* non-atomic update */ + driver_pages += delta; balloon_unlock(flags); } @@ -475,9 +522,10 @@ scrub_pages(vstart, 1 << order); - balloon_lock(flags); BUG_ON(generic_page_range( &init_mm, vstart, PAGE_SIZE << order, dealloc_pte_fn, NULL)); + + balloon_lock(flags); current_pages -= 1UL << order; balloon_unlock(flags); _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |