From 06f521d5d67a23d91add6f1beb73edc6f2b70d0c Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Tue, 8 Mar 2011 22:45:46 +0100 Subject: xen/balloon: Removal of driver_pages Removal of driver_pages (I do not have seen any references to it). Signed-off-by: Daniel Kiper Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/balloon.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/xen/balloon.c') diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 43f9f02..b4206fd 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -70,11 +70,6 @@ struct balloon_stats { /* We aim for 'current allocation' == 'target allocation'. */ unsigned long current_pages; unsigned long target_pages; - /* - * Drivers may alter the memory reservation independently, but they - * must inform the balloon driver so we avoid hitting the hard limit. - */ - unsigned long driver_pages; /* Number of pages in high- and low-memory balloons. */ unsigned long balloon_low; unsigned long balloon_high; @@ -404,7 +399,6 @@ static int __init balloon_init(void) balloon_stats.target_pages = balloon_stats.current_pages; balloon_stats.balloon_low = 0; balloon_stats.balloon_high = 0; - balloon_stats.driver_pages = 0UL; init_timer(&balloon_timer); balloon_timer.data = 0; @@ -462,7 +456,6 @@ module_exit(balloon_exit); BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages)); BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_low)); BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_high)); -BALLOON_SHOW(driver_kb, "%lu\n", PAGES2KB(balloon_stats.driver_pages)); static ssize_t show_target_kb(struct sys_device *dev, struct sysdev_attribute *attr, char *buf) @@ -531,7 +524,6 @@ static struct attribute *balloon_info_attrs[] = { &attr_current_kb.attr, &attr_low_kb.attr, &attr_high_kb.attr, - &attr_driver_kb.attr, NULL }; -- cgit v1.1 From 95170b2e23d4e98843b4833d27fae7bf0910e19c Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Tue, 8 Mar 2011 22:47:39 +0100 Subject: xen/balloon: Migration from mod_timer() to schedule_delayed_work() Migration from mod_timer() to schedule_delayed_work(). Signed-off-by: Daniel Kiper Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/balloon.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'drivers/xen/balloon.c') diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index b4206fd..9206ff7 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -99,8 +99,7 @@ static LIST_HEAD(ballooned_pages); /* Main work function, always executed in process context. */ static void balloon_process(struct work_struct *work); -static DECLARE_WORK(balloon_worker, balloon_process); -static struct timer_list balloon_timer; +static DECLARE_DELAYED_WORK(balloon_worker, balloon_process); /* When ballooning out (allocating memory to return to Xen) we don't really want the kernel to try too hard since that can trigger the oom killer. */ @@ -172,11 +171,6 @@ static struct page *balloon_next_page(struct page *page) return list_entry(next, struct page, lru); } -static void balloon_alarm(unsigned long unused) -{ - schedule_work(&balloon_worker); -} - static unsigned long current_target(void) { unsigned long target = balloon_stats.target_pages; @@ -333,7 +327,7 @@ static void balloon_process(struct work_struct *work) /* Schedule more work if there is some still to be done. */ if (current_target() != balloon_stats.current_pages) - mod_timer(&balloon_timer, jiffies + HZ); + schedule_delayed_work(&balloon_worker, HZ); mutex_unlock(&balloon_mutex); } @@ -343,7 +337,7 @@ static void balloon_set_new_target(unsigned long target) { /* No need for lock. Not read-modify-write updates. */ balloon_stats.target_pages = target; - schedule_work(&balloon_worker); + schedule_delayed_work(&balloon_worker, 0); } static struct xenbus_watch target_watch = @@ -400,10 +394,6 @@ static int __init balloon_init(void) balloon_stats.balloon_low = 0; balloon_stats.balloon_high = 0; - init_timer(&balloon_timer); - balloon_timer.data = 0; - balloon_timer.function = balloon_alarm; - register_balloon(&balloon_sysdev); /* -- cgit v1.1 From 95d2ac4a0c904942a4fecf815781ebd4171e7a30 Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Tue, 8 Mar 2011 22:48:24 +0100 Subject: xen/balloon: Protect against CPU exhaust by event/x process Protect against CPU exhaust by event/x process during errors by adding some delays in scheduling next event and retry count limit. Signed-off-by: Daniel Kiper Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/balloon.c | 107 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 90 insertions(+), 17 deletions(-) (limited to 'drivers/xen/balloon.c') diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 9206ff7..6cd2530 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -66,6 +66,22 @@ #define BALLOON_CLASS_NAME "xen_memory" +/* + * balloon_process() state: + * + * BP_DONE: done or nothing to do, + * BP_EAGAIN: error, go to sleep, + * BP_ECANCELED: error, balloon operation canceled. + */ + +enum bp_state { + BP_DONE, + BP_EAGAIN, + BP_ECANCELED +}; + +#define RETRY_UNLIMITED 0 + struct balloon_stats { /* We aim for 'current allocation' == 'target allocation'. */ unsigned long current_pages; @@ -73,6 +89,10 @@ struct balloon_stats { /* Number of pages in high- and low-memory balloons. */ unsigned long balloon_low; unsigned long balloon_high; + unsigned long schedule_delay; + unsigned long max_schedule_delay; + unsigned long retry_count; + unsigned long max_retry_count; }; static DEFINE_MUTEX(balloon_mutex); @@ -171,6 +191,36 @@ static struct page *balloon_next_page(struct page *page) return list_entry(next, struct page, lru); } +static enum bp_state update_schedule(enum bp_state state) +{ + if (state == BP_DONE) { + balloon_stats.schedule_delay = 1; + balloon_stats.retry_count = 1; + return BP_DONE; + } + + pr_info("xen_balloon: Retry count: %lu/%lu\n", balloon_stats.retry_count, + balloon_stats.max_retry_count); + + ++balloon_stats.retry_count; + + if (balloon_stats.max_retry_count != RETRY_UNLIMITED && + balloon_stats.retry_count > balloon_stats.max_retry_count) { + pr_info("xen_balloon: Retry count limit exceeded\n" + "xen_balloon: Balloon operation canceled\n"); + balloon_stats.schedule_delay = 1; + balloon_stats.retry_count = 1; + return BP_ECANCELED; + } + + balloon_stats.schedule_delay <<= 1; + + if (balloon_stats.schedule_delay > balloon_stats.max_schedule_delay) + balloon_stats.schedule_delay = balloon_stats.max_schedule_delay; + + return BP_EAGAIN; +} + static unsigned long current_target(void) { unsigned long target = balloon_stats.target_pages; @@ -183,11 +233,11 @@ static unsigned long current_target(void) return target; } -static int increase_reservation(unsigned long nr_pages) +static enum bp_state increase_reservation(unsigned long nr_pages) { + int rc; unsigned long pfn, i; struct page *page; - long rc; struct xen_memory_reservation reservation = { .address_bits = 0, .extent_order = 0, @@ -199,7 +249,10 @@ static int increase_reservation(unsigned long nr_pages) page = balloon_first_page(); for (i = 0; i < nr_pages; i++) { - BUG_ON(page == NULL); + if (!page) { + nr_pages = i; + break; + } frame_list[i] = page_to_pfn(page); page = balloon_next_page(page); } @@ -207,8 +260,10 @@ static int increase_reservation(unsigned long nr_pages) 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) - goto out; + if (rc <= 0) { + pr_info("xen_balloon: %s: Cannot allocate memory\n", __func__); + return BP_EAGAIN; + } for (i = 0; i < rc; i++) { page = balloon_retrieve(); @@ -238,15 +293,14 @@ static int increase_reservation(unsigned long nr_pages) balloon_stats.current_pages += rc; - out: - return rc < 0 ? rc : rc != nr_pages; + return BP_DONE; } -static int decrease_reservation(unsigned long nr_pages) +static enum bp_state decrease_reservation(unsigned long nr_pages) { + enum bp_state state = BP_DONE; unsigned long pfn, i; struct page *page; - int need_sleep = 0; int ret; struct xen_memory_reservation reservation = { .address_bits = 0, @@ -259,8 +313,9 @@ static int decrease_reservation(unsigned long nr_pages) for (i = 0; i < nr_pages; i++) { if ((page = alloc_page(GFP_BALLOON)) == NULL) { + pr_info("xen_balloon: %s: Cannot allocate memory\n", __func__); nr_pages = i; - need_sleep = 1; + state = BP_EAGAIN; break; } @@ -296,7 +351,7 @@ static int decrease_reservation(unsigned long nr_pages) balloon_stats.current_pages -= nr_pages; - return need_sleep; + return state; } /* @@ -307,27 +362,31 @@ static int decrease_reservation(unsigned long nr_pages) */ static void balloon_process(struct work_struct *work) { - int need_sleep = 0; + enum bp_state state = BP_DONE; long credit; mutex_lock(&balloon_mutex); do { credit = current_target() - balloon_stats.current_pages; + if (credit > 0) - need_sleep = (increase_reservation(credit) != 0); + state = increase_reservation(credit); + if (credit < 0) - need_sleep = (decrease_reservation(-credit) != 0); + state = decrease_reservation(-credit); + + state = update_schedule(state); #ifndef CONFIG_PREEMPT if (need_resched()) schedule(); #endif - } while ((credit != 0) && !need_sleep); + } while (credit && state == BP_DONE); /* Schedule more work if there is some still to be done. */ - if (current_target() != balloon_stats.current_pages) - schedule_delayed_work(&balloon_worker, HZ); + if (state == BP_EAGAIN) + schedule_delayed_work(&balloon_worker, balloon_stats.schedule_delay * HZ); mutex_unlock(&balloon_mutex); } @@ -394,6 +453,11 @@ static int __init balloon_init(void) balloon_stats.balloon_low = 0; balloon_stats.balloon_high = 0; + balloon_stats.schedule_delay = 1; + balloon_stats.max_schedule_delay = 32; + balloon_stats.retry_count = 1; + balloon_stats.max_retry_count = 16; + register_balloon(&balloon_sysdev); /* @@ -447,6 +511,11 @@ BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages)); BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_low)); BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_high)); +static SYSDEV_ULONG_ATTR(schedule_delay, 0444, balloon_stats.schedule_delay); +static SYSDEV_ULONG_ATTR(max_schedule_delay, 0644, balloon_stats.max_schedule_delay); +static SYSDEV_ULONG_ATTR(retry_count, 0444, balloon_stats.retry_count); +static SYSDEV_ULONG_ATTR(max_retry_count, 0644, balloon_stats.max_retry_count); + static ssize_t show_target_kb(struct sys_device *dev, struct sysdev_attribute *attr, char *buf) { @@ -508,6 +577,10 @@ static SYSDEV_ATTR(target, S_IRUGO | S_IWUSR, static struct sysdev_attribute *balloon_attrs[] = { &attr_target_kb, &attr_target, + &attr_schedule_delay.attr, + &attr_max_schedule_delay.attr, + &attr_retry_count.attr, + &attr_max_retry_count.attr }; static struct attribute *balloon_info_attrs[] = { -- cgit v1.1 From 40095de1f9082f058970b985a96d2fbef43f94f4 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Mon, 14 Mar 2011 11:42:40 -0400 Subject: xen/balloon: Remove pr_info's and don't alter retry_count In the past the retry_count (in other form of this code) was zero. Meaning retry forever. Do the same thing here without changing it to the value 16. Also remove some of the pr_info as there is no need to spam the user. Acked-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/balloon.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers/xen/balloon.c') diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 6cd2530..77e6ad3 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -199,15 +199,10 @@ static enum bp_state update_schedule(enum bp_state state) return BP_DONE; } - pr_info("xen_balloon: Retry count: %lu/%lu\n", balloon_stats.retry_count, - balloon_stats.max_retry_count); - ++balloon_stats.retry_count; if (balloon_stats.max_retry_count != RETRY_UNLIMITED && balloon_stats.retry_count > balloon_stats.max_retry_count) { - pr_info("xen_balloon: Retry count limit exceeded\n" - "xen_balloon: Balloon operation canceled\n"); balloon_stats.schedule_delay = 1; balloon_stats.retry_count = 1; return BP_ECANCELED; @@ -260,10 +255,8 @@ static enum bp_state increase_reservation(unsigned long nr_pages) 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) { - pr_info("xen_balloon: %s: Cannot allocate memory\n", __func__); + if (rc <= 0) return BP_EAGAIN; - } for (i = 0; i < rc; i++) { page = balloon_retrieve(); @@ -313,7 +306,6 @@ static enum bp_state decrease_reservation(unsigned long nr_pages) for (i = 0; i < nr_pages; i++) { if ((page = alloc_page(GFP_BALLOON)) == NULL) { - pr_info("xen_balloon: %s: Cannot allocate memory\n", __func__); nr_pages = i; state = BP_EAGAIN; break; @@ -456,7 +448,7 @@ static int __init balloon_init(void) balloon_stats.schedule_delay = 1; balloon_stats.max_schedule_delay = 32; balloon_stats.retry_count = 1; - balloon_stats.max_retry_count = 16; + balloon_stats.max_retry_count = RETRY_UNLIMITED; register_balloon(&balloon_sysdev); -- cgit v1.1 From 803eb047a28d239809fff1f87274cdaa94e0d8ea Mon Sep 17 00:00:00 2001 From: Daniel De Graaf Date: Mon, 14 Mar 2011 11:29:37 -0400 Subject: xen-balloon: Move core balloon functionality out of module The basic functionality of ballooning pages is useful for Xen drivers in general. Rather than require a dependency on the balloon module, split the functionality that is reused into the core. The balloon module is still required to follow ballooning requests from xenstore or to view balloon statistics in sysfs. Acked-by: Ian Campbell Signed-off-by: Daniel De Graaf Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/balloon.c | 229 ++------------------------------------------------ 1 file changed, 6 insertions(+), 223 deletions(-) (limited to 'drivers/xen/balloon.c') diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 77e6ad3..7497041 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -1,6 +1,4 @@ /****************************************************************************** - * balloon.c - * * Xen balloon driver - enables returning/claiming memory to/from Xen. * * Copyright (c) 2003, B Dragovic @@ -33,7 +31,6 @@ */ #include -#include #include #include #include @@ -42,13 +39,11 @@ #include #include #include -#include #include #include #include #include -#include #include #include @@ -58,14 +53,10 @@ #include #include #include -#include +#include #include #include -#define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10)) - -#define BALLOON_CLASS_NAME "xen_memory" - /* * balloon_process() state: * @@ -80,28 +71,11 @@ enum bp_state { BP_ECANCELED }; -#define RETRY_UNLIMITED 0 - -struct balloon_stats { - /* We aim for 'current allocation' == 'target allocation'. */ - unsigned long current_pages; - unsigned long target_pages; - /* Number of pages in high- and low-memory balloons. */ - unsigned long balloon_low; - unsigned long balloon_high; - unsigned long schedule_delay; - unsigned long max_schedule_delay; - unsigned long retry_count; - unsigned long max_retry_count; -}; static DEFINE_MUTEX(balloon_mutex); -static struct sys_device balloon_sysdev; - -static int register_balloon(struct sys_device *sysdev); - -static struct balloon_stats balloon_stats; +struct balloon_stats balloon_stats; +EXPORT_SYMBOL_GPL(balloon_stats); /* We increase/decrease in batches which fit in a page */ static unsigned long frame_list[PAGE_SIZE / sizeof(unsigned long)]; @@ -384,51 +358,13 @@ static void balloon_process(struct work_struct *work) } /* Resets the Xen limit, sets new target, and kicks off processing. */ -static void balloon_set_new_target(unsigned long target) +void balloon_set_new_target(unsigned long target) { /* No need for lock. Not read-modify-write updates. */ balloon_stats.target_pages = target; schedule_delayed_work(&balloon_worker, 0); } - -static struct xenbus_watch target_watch = -{ - .node = "memory/target" -}; - -/* React to a change in the target key */ -static void watch_target(struct xenbus_watch *watch, - const char **vec, unsigned int len) -{ - unsigned long long new_target; - int err; - - err = xenbus_scanf(XBT_NIL, "memory", "target", "%llu", &new_target); - if (err != 1) { - /* This is ok (for domain0 at least) - so just return */ - return; - } - - /* The given memory/target value is in KiB, so it needs converting to - * pages. PAGE_SHIFT converts bytes to pages, hence PAGE_SHIFT - 10. - */ - balloon_set_new_target(new_target >> (PAGE_SHIFT - 10)); -} - -static int balloon_init_watcher(struct notifier_block *notifier, - unsigned long event, - void *data) -{ - int err; - - err = register_xenbus_watch(&target_watch); - if (err) - printk(KERN_ERR "Failed to set balloon watcher\n"); - - return NOTIFY_DONE; -} - -static struct notifier_block xenstore_notifier; +EXPORT_SYMBOL_GPL(balloon_set_new_target); static int __init balloon_init(void) { @@ -438,7 +374,7 @@ static int __init balloon_init(void) if (!xen_pv_domain()) return -ENODEV; - pr_info("xen_balloon: Initialising balloon driver.\n"); + pr_info("xen/balloon: Initialising balloon driver.\n"); balloon_stats.current_pages = min(xen_start_info->nr_pages, max_pfn); balloon_stats.target_pages = balloon_stats.current_pages; @@ -450,8 +386,6 @@ static int __init balloon_init(void) balloon_stats.retry_count = 1; balloon_stats.max_retry_count = RETRY_UNLIMITED; - register_balloon(&balloon_sysdev); - /* * Initialise the balloon with excess memory space. We need * to make sure we don't add memory which doesn't exist or @@ -472,160 +406,9 @@ static int __init balloon_init(void) __balloon_append(page); } - target_watch.callback = watch_target; - xenstore_notifier.notifier_call = balloon_init_watcher; - - register_xenstore_notifier(&xenstore_notifier); - return 0; } subsys_initcall(balloon_init); -static void balloon_exit(void) -{ - /* XXX - release balloon here */ - return; -} - -module_exit(balloon_exit); - -#define BALLOON_SHOW(name, format, args...) \ - static ssize_t show_##name(struct sys_device *dev, \ - struct sysdev_attribute *attr, \ - char *buf) \ - { \ - return sprintf(buf, format, ##args); \ - } \ - static SYSDEV_ATTR(name, S_IRUGO, show_##name, NULL) - -BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages)); -BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_low)); -BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_high)); - -static SYSDEV_ULONG_ATTR(schedule_delay, 0444, balloon_stats.schedule_delay); -static SYSDEV_ULONG_ATTR(max_schedule_delay, 0644, balloon_stats.max_schedule_delay); -static SYSDEV_ULONG_ATTR(retry_count, 0444, balloon_stats.retry_count); -static SYSDEV_ULONG_ATTR(max_retry_count, 0644, balloon_stats.max_retry_count); - -static ssize_t show_target_kb(struct sys_device *dev, struct sysdev_attribute *attr, - char *buf) -{ - return sprintf(buf, "%lu\n", PAGES2KB(balloon_stats.target_pages)); -} - -static ssize_t store_target_kb(struct sys_device *dev, - struct sysdev_attribute *attr, - const char *buf, - size_t count) -{ - char *endchar; - unsigned long long target_bytes; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - target_bytes = simple_strtoull(buf, &endchar, 0) * 1024; - - balloon_set_new_target(target_bytes >> PAGE_SHIFT); - - return count; -} - -static SYSDEV_ATTR(target_kb, S_IRUGO | S_IWUSR, - show_target_kb, store_target_kb); - - -static ssize_t show_target(struct sys_device *dev, struct sysdev_attribute *attr, - char *buf) -{ - return sprintf(buf, "%llu\n", - (unsigned long long)balloon_stats.target_pages - << PAGE_SHIFT); -} - -static ssize_t store_target(struct sys_device *dev, - struct sysdev_attribute *attr, - const char *buf, - size_t count) -{ - char *endchar; - unsigned long long target_bytes; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - target_bytes = memparse(buf, &endchar); - - balloon_set_new_target(target_bytes >> PAGE_SHIFT); - - return count; -} - -static SYSDEV_ATTR(target, S_IRUGO | S_IWUSR, - show_target, store_target); - - -static struct sysdev_attribute *balloon_attrs[] = { - &attr_target_kb, - &attr_target, - &attr_schedule_delay.attr, - &attr_max_schedule_delay.attr, - &attr_retry_count.attr, - &attr_max_retry_count.attr -}; - -static struct attribute *balloon_info_attrs[] = { - &attr_current_kb.attr, - &attr_low_kb.attr, - &attr_high_kb.attr, - NULL -}; - -static struct attribute_group balloon_info_group = { - .name = "info", - .attrs = balloon_info_attrs, -}; - -static struct sysdev_class balloon_sysdev_class = { - .name = BALLOON_CLASS_NAME, -}; - -static int register_balloon(struct sys_device *sysdev) -{ - int i, error; - - error = sysdev_class_register(&balloon_sysdev_class); - if (error) - return error; - - sysdev->id = 0; - sysdev->cls = &balloon_sysdev_class; - - error = sysdev_register(sysdev); - if (error) { - sysdev_class_unregister(&balloon_sysdev_class); - return error; - } - - for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++) { - error = sysdev_create_file(sysdev, balloon_attrs[i]); - if (error) - goto fail; - } - - error = sysfs_create_group(&sysdev->kobj, &balloon_info_group); - if (error) - goto fail; - - return 0; - - fail: - while (--i >= 0) - sysdev_remove_file(sysdev, balloon_attrs[i]); - sysdev_unregister(sysdev); - sysdev_class_unregister(&balloon_sysdev_class); - return error; -} - MODULE_LICENSE("GPL"); -- cgit v1.1 From b6f3067985f12d514187059fb10fe3c877f87cb2 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Tue, 15 Mar 2011 10:23:57 -0400 Subject: xen-balloon: Add interface to retrieve ballooned pages Pages that have been ballooned are useful for other Xen drivers doing grant table actions, because these pages have valid struct page/PFNs but have no valid MFN so are available for remapping. Acked-by: Ian Campbell Signed-off-by: Daniel De Graaf [v2: Deal with rebasing on top of modified balloon code] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/balloon.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 6 deletions(-) (limited to 'drivers/xen/balloon.c') diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 7497041..8c81cd2 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -128,14 +128,17 @@ static void balloon_append(struct page *page) } /* balloon_retrieve: rescue a page from the balloon, if it is not empty. */ -static struct page *balloon_retrieve(void) +static struct page *balloon_retrieve(bool prefer_highmem) { struct page *page; if (list_empty(&ballooned_pages)) return NULL; - page = list_entry(ballooned_pages.next, struct page, lru); + if (prefer_highmem) + page = list_entry(ballooned_pages.prev, struct page, lru); + else + page = list_entry(ballooned_pages.next, struct page, lru); list_del(&page->lru); if (PageHighMem(page)) { @@ -233,7 +236,7 @@ static enum bp_state increase_reservation(unsigned long nr_pages) return BP_EAGAIN; for (i = 0; i < rc; i++) { - page = balloon_retrieve(); + page = balloon_retrieve(false); BUG_ON(page == NULL); pfn = page_to_pfn(page); @@ -263,7 +266,7 @@ static enum bp_state increase_reservation(unsigned long nr_pages) return BP_DONE; } -static enum bp_state decrease_reservation(unsigned long nr_pages) +static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp) { enum bp_state state = BP_DONE; unsigned long pfn, i; @@ -279,7 +282,7 @@ static enum bp_state decrease_reservation(unsigned long nr_pages) nr_pages = ARRAY_SIZE(frame_list); for (i = 0; i < nr_pages; i++) { - if ((page = alloc_page(GFP_BALLOON)) == NULL) { + if ((page = alloc_page(gfp)) == NULL) { nr_pages = i; state = BP_EAGAIN; break; @@ -340,7 +343,7 @@ static void balloon_process(struct work_struct *work) state = increase_reservation(credit); if (credit < 0) - state = decrease_reservation(-credit); + state = decrease_reservation(-credit, GFP_BALLOON); state = update_schedule(state); @@ -366,6 +369,64 @@ void balloon_set_new_target(unsigned long target) } EXPORT_SYMBOL_GPL(balloon_set_new_target); +/** + * alloc_xenballooned_pages - get pages that have been ballooned out + * @nr_pages: Number of pages to get + * @pages: pages returned + * @return 0 on success, error otherwise + */ +int alloc_xenballooned_pages(int nr_pages, struct page** pages) +{ + int pgno = 0; + struct page* page; + mutex_lock(&balloon_mutex); + while (pgno < nr_pages) { + page = balloon_retrieve(true); + if (page) { + pages[pgno++] = page; + } else { + enum bp_state st; + st = decrease_reservation(nr_pages - pgno, GFP_HIGHUSER); + if (st != BP_DONE) + goto out_undo; + } + } + mutex_unlock(&balloon_mutex); + return 0; + out_undo: + while (pgno) + balloon_append(pages[--pgno]); + /* Free the memory back to the kernel soon */ + schedule_delayed_work(&balloon_worker, 0); + mutex_unlock(&balloon_mutex); + return -ENOMEM; +} +EXPORT_SYMBOL(alloc_xenballooned_pages); + +/** + * free_xenballooned_pages - return pages retrieved with get_ballooned_pages + * @nr_pages: Number of pages + * @pages: pages to return + */ +void free_xenballooned_pages(int nr_pages, struct page** pages) +{ + int i; + + mutex_lock(&balloon_mutex); + + for (i = 0; i < nr_pages; i++) { + if (pages[i]) + balloon_append(pages[i]); + } + + /* The balloon may be too large now. Shrink it if needed. */ + if (current_target() != balloon_stats.current_pages) + schedule_delayed_work(&balloon_worker, 0); + + mutex_unlock(&balloon_mutex); +} +EXPORT_SYMBOL(free_xenballooned_pages); + static int __init balloon_init(void) { unsigned long pfn, extra_pfn_end; -- cgit v1.1