summaryrefslogtreecommitdiff
path: root/drivers/xen/balloon.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/xen/balloon.c')
-rw-r--r--drivers/xen/balloon.c124
1 files changed, 61 insertions, 63 deletions
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index a2c4fc49c483..49c3f9926394 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -59,6 +59,7 @@
#include <linux/slab.h>
#include <linux/sysctl.h>
#include <linux/moduleparam.h>
+#include <linux/jiffies.h>
#include <asm/page.h>
#include <asm/tlb.h>
@@ -83,7 +84,7 @@ module_param(balloon_boot_timeout, uint, 0444);
#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
static int xen_hotplug_unpopulated;
-static struct ctl_table balloon_table[] = {
+static const struct ctl_table balloon_table[] = {
{
.procname = "hotplug_unpopulated",
.data = &xen_hotplug_unpopulated,
@@ -93,25 +94,6 @@ static struct ctl_table balloon_table[] = {
.extra1 = SYSCTL_ZERO,
.extra2 = SYSCTL_ONE,
},
- { }
-};
-
-static struct ctl_table balloon_root[] = {
- {
- .procname = "balloon",
- .mode = 0555,
- .child = balloon_table,
- },
- { }
-};
-
-static struct ctl_table xen_root[] = {
- {
- .procname = "xen",
- .mode = 0555,
- .child = balloon_root,
- },
- { }
};
#else
@@ -164,7 +146,8 @@ static DECLARE_WAIT_QUEUE_HEAD(balloon_wq);
/* balloon_append: add the given page to the balloon. */
static void balloon_append(struct page *page)
{
- __SetPageOffline(page);
+ if (!PageOffline(page))
+ __SetPageOffline(page);
/* Lowmem is re-populated first, so highmem pages go at list tail. */
if (PageHighMem(page)) {
@@ -174,6 +157,8 @@ static void balloon_append(struct page *page)
list_add(&page->lru, &ballooned_pages);
balloon_stats.balloon_low++;
}
+ inc_node_page_state(page, NR_BALLOON_PAGES);
+
wake_up(&balloon_wq);
}
@@ -196,6 +181,8 @@ static struct page *balloon_retrieve(bool require_lowmem)
balloon_stats.balloon_low--;
__ClearPageOffline(page);
+ dec_node_page_state(page, NR_BALLOON_PAGES);
+
return page;
}
@@ -315,7 +302,7 @@ static enum bp_state reserve_additional_memory(void)
* are not restored since this region is now known not to
* conflict with any devices.
*/
- if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+ if (xen_pv_domain()) {
unsigned long pfn, i;
pfn = PFN_DOWN(resource->start);
@@ -430,7 +417,11 @@ static enum bp_state increase_reservation(unsigned long nr_pages)
xenmem_reservation_va_mapping_update(1, &page, &frame_list[i]);
- /* Relinquish the page back to the allocator. */
+ /*
+ * Relinquish the page back to the allocator. Note that
+ * some pages, including ones added via xen_online_page(), might
+ * not be marked reserved; free_reserved_page() will handle that.
+ */
free_reserved_page(page);
}
@@ -635,7 +626,7 @@ int xen_alloc_ballooned_pages(unsigned int nr_pages, struct page **pages)
*/
BUILD_BUG_ON(XEN_PAGE_SIZE != PAGE_SIZE);
- if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+ if (xen_pv_domain()) {
ret = xen_alloc_p2m_entry(page_to_pfn(page));
if (ret < 0)
goto out_undo;
@@ -688,46 +679,64 @@ void xen_free_ballooned_pages(unsigned int nr_pages, struct page **pages)
}
EXPORT_SYMBOL(xen_free_ballooned_pages);
-#if defined(CONFIG_XEN_PV) && !defined(CONFIG_XEN_UNPOPULATED_ALLOC)
-static void __init balloon_add_region(unsigned long start_pfn,
- unsigned long pages)
+static int __init balloon_add_regions(void)
{
+ unsigned long start_pfn, pages;
unsigned long pfn, extra_pfn_end;
+ unsigned int i;
- /*
- * If the amount of usable memory has been limited (e.g., with
- * the 'mem' command line parameter), don't add pages beyond
- * this limit.
- */
- extra_pfn_end = min(max_pfn, start_pfn + pages);
+ for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) {
+ pages = xen_extra_mem[i].n_pfns;
+ if (!pages)
+ continue;
+
+ start_pfn = xen_extra_mem[i].start_pfn;
+
+ /*
+ * If the amount of usable memory has been limited (e.g., with
+ * the 'mem' command line parameter), don't add pages beyond
+ * this limit.
+ */
+ extra_pfn_end = min(max_pfn, start_pfn + pages);
+
+ for (pfn = start_pfn; pfn < extra_pfn_end; pfn++)
+ balloon_append(pfn_to_page(pfn));
- for (pfn = start_pfn; pfn < extra_pfn_end; pfn++) {
- /* totalram_pages and totalhigh_pages do not
- include the boot-time balloon extension, so
- don't subtract from it. */
- balloon_append(pfn_to_page(pfn));
+ /*
+ * Extra regions are accounted for in the physmap, but need
+ * decreasing from current_pages and target_pages to balloon
+ * down the initial allocation, because they are already
+ * accounted for in total_pages.
+ */
+ pages = extra_pfn_end - start_pfn;
+ if (pages >= balloon_stats.current_pages ||
+ pages >= balloon_stats.target_pages) {
+ WARN(1, "Extra pages underflow current target");
+ return -ERANGE;
+ }
+ balloon_stats.current_pages -= pages;
+ balloon_stats.target_pages -= pages;
}
- balloon_stats.total_pages += extra_pfn_end - start_pfn;
+ return 0;
}
-#endif
static int __init balloon_init(void)
{
struct task_struct *task;
+ int rc;
if (!xen_domain())
return -ENODEV;
pr_info("Initialising balloon driver\n");
-#ifdef CONFIG_XEN_PV
- balloon_stats.current_pages = xen_pv_domain()
- ? min(xen_start_info->nr_pages - xen_released_pages, max_pfn)
- : get_num_physpages();
-#else
- balloon_stats.current_pages = get_num_physpages();
-#endif
+ if (xen_released_pages >= get_num_physpages()) {
+ WARN(1, "Released pages underflow current target");
+ return -ERANGE;
+ }
+
+ balloon_stats.current_pages = get_num_physpages() - xen_released_pages;
balloon_stats.target_pages = balloon_stats.current_pages;
balloon_stats.balloon_low = 0;
balloon_stats.balloon_high = 0;
@@ -741,23 +750,12 @@ static int __init balloon_init(void)
#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
set_online_page_callback(&xen_online_page);
register_memory_notifier(&xen_memory_nb);
- register_sysctl_table(xen_root);
+ register_sysctl_init("xen/balloon", balloon_table);
#endif
-#if defined(CONFIG_XEN_PV) && !defined(CONFIG_XEN_UNPOPULATED_ALLOC)
- {
- int i;
-
- /*
- * Initialize the balloon with pages from the extra memory
- * regions (see arch/x86/xen/setup.c).
- */
- for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++)
- if (xen_extra_mem[i].n_pfns)
- balloon_add_region(xen_extra_mem[i].start_pfn,
- xen_extra_mem[i].n_pfns);
- }
-#endif
+ rc = balloon_add_regions();
+ if (rc)
+ return rc;
task = kthread_run(balloon_thread, NULL, "xen-balloon");
if (IS_ERR(task)) {
@@ -794,7 +792,7 @@ static int __init balloon_wait_finish(void)
if (balloon_state == BP_ECANCELED) {
pr_warn_once("Initial ballooning failed, %ld pages need to be freed.\n",
-credit);
- if (jiffies - last_changed >= HZ * balloon_boot_timeout)
+ if (time_is_before_eq_jiffies(last_changed + HZ * balloon_boot_timeout))
panic("Initial ballooning failed!\n");
}