Split up the balloon module, similar to how grants and events are handled. This allow gntdev to use ballooned pages without adding a dependency on the balloon module. The interface is slightly different from that exposed in 2.6.32; the page vector is allocated by the caller, not by the balloon driver. This allows more freedom in how the returned pages are used, since they do not all have to be returned to the balloon driver at the same time. It also tries to reuse already ballooned pages rather than always ballooning new pages to ensure they are in low memory as the 2.6.32 version did. [PATCH 1/3] xen-balloon: Move core balloon functionality out of module [PATCH 2/3] xen-balloon: Add interface to retrieve ballooned pages [PATCH 3/3] xen-gntdev: Use ballooned pages for grant mappings _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel De Graaf
2011-Mar-07 18:06 UTC
[Xen-devel] [PATCH 1/3] 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. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- drivers/xen/Makefile | 4 +- drivers/xen/balloon.c | 220 +-------------------------------------- drivers/xen/xen-balloon.c | 249 +++++++++++++++++++++++++++++++++++++++++++++ include/xen/balloon.h | 21 ++++ 4 files changed, 278 insertions(+), 216 deletions(-) create mode 100644 drivers/xen/xen-balloon.c create mode 100644 include/xen/balloon.h diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index ad8c450..aa3ef62 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -1,4 +1,4 @@ -obj-y += grant-table.o features.o events.o manage.o +obj-y += grant-table.o features.o events.o manage.o balloon.o obj-y += xenbus/ nostackp := $(call cc-option, -fno-stack-protector) @@ -7,7 +7,7 @@ CFLAGS_features.o := $(nostackp) obj-$(CONFIG_BLOCK) += biomerge.o obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o obj-$(CONFIG_XEN_XENCOMM) += xencomm.o -obj-$(CONFIG_XEN_BALLOON) += balloon.o +obj-$(CONFIG_XEN_BALLOON) += xen-balloon.o obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/ obj-$(CONFIG_XEN_BLKDEV_BACKEND) += blkback/ diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 718050a..b0a7a92 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 <linux/kernel.h> -#include <linux/module.h> #include <linux/sched.h> #include <linux/errno.h> #include <linux/mm.h> @@ -42,13 +39,11 @@ #include <linux/highmem.h> #include <linux/mutex.h> #include <linux/list.h> -#include <linux/sysdev.h> #include <linux/gfp.h> #include <asm/page.h> #include <asm/pgalloc.h> #include <asm/pgtable.h> -#include <asm/uaccess.h> #include <asm/tlb.h> #include <asm/e820.h> @@ -58,35 +53,16 @@ #include <xen/xen.h> #include <xen/interface/xen.h> #include <xen/interface/memory.h> -#include <xen/xenbus.h> +#include <xen/balloon.h> #include <xen/features.h> #include <xen/page.h> #define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10)) -#define BALLOON_CLASS_NAME "xen_memory" - -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; -}; - 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)]; @@ -344,51 +320,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_work(&balloon_worker); } - -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) { @@ -398,7 +336,7 @@ static int __init balloon_init(void) if (!xen_domain()) return -ENODEV; - pr_info("xen_balloon: Initialising balloon driver.\n"); + pr_info("xen/balloon: Initialising balloon driver.\n"); if (xen_pv_domain()) nr_pages = xen_start_info->nr_pages; @@ -414,8 +352,6 @@ static int __init balloon_init(void) balloon_timer.data = 0; balloon_timer.function = balloon_alarm; - 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 @@ -436,153 +372,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)); -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) -{ - 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, -}; - -static struct attribute *balloon_info_attrs[] = { - &attr_current_kb.attr, - &attr_low_kb.attr, - &attr_high_kb.attr, - &attr_driver_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"); diff --git a/drivers/xen/xen-balloon.c b/drivers/xen/xen-balloon.c new file mode 100644 index 0000000..59dfd79 --- /dev/null +++ b/drivers/xen/xen-balloon.c @@ -0,0 +1,249 @@ +/****************************************************************************** + * Xen balloon driver - enables returning/claiming memory to/from Xen. + * + * Copyright (c) 2003, B Dragovic + * Copyright (c) 2003-2004, M Williamson, K Fraser + * Copyright (c) 2005 Dan M. Smith, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/sysdev.h> +#include <linux/capability.h> + +#include <xen/xen.h> +#include <xen/interface/xen.h> +#include <xen/balloon.h> +#include <xen/xenbus.h> +#include <xen/features.h> +#include <xen/page.h> + +#define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10)) + +#define BALLOON_CLASS_NAME "xen_memory" + +static struct sys_device balloon_sysdev; + +static int register_balloon(struct sys_device *sysdev); + +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; + +static int __init balloon_init(void) +{ + if (!xen_domain()) + return -ENODEV; + + pr_info("xen-balloon: Initialising balloon driver.\n"); + + register_balloon(&balloon_sysdev); + + 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 unregister? */ + 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)); +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) +{ + 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, +}; + +static struct attribute *balloon_info_attrs[] = { + &attr_current_kb.attr, + &attr_low_kb.attr, + &attr_high_kb.attr, + &attr_driver_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"); diff --git a/include/xen/balloon.h b/include/xen/balloon.h new file mode 100644 index 0000000..b2b7c21 --- /dev/null +++ b/include/xen/balloon.h @@ -0,0 +1,21 @@ +/****************************************************************************** + * Xen balloon functionality + */ + +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; +}; + +extern struct balloon_stats balloon_stats; + +void balloon_set_new_target(unsigned long target); -- 1.7.3.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel De Graaf
2011-Mar-07 18:06 UTC
[Xen-devel] [PATCH 2/3] 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. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- drivers/xen/balloon.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ include/xen/balloon.h | 3 ++ 2 files changed, 57 insertions(+), 0 deletions(-) diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index b0a7a92..be53596 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -328,6 +328,60 @@ void balloon_set_new_target(unsigned long target) } EXPORT_SYMBOL_GPL(balloon_set_new_target); +/** + * get_ballooned_pages - get pages that have been ballooned out + * @nr_pages: Number of pages to get + * @pages: pages returned + * @force: Try to balloon out more pages if needed + * @return number of pages retrieved + */ +int get_ballooned_pages(int nr_pages, struct page** pages, int force) +{ + int rv = 0; + struct page* page; + mutex_lock(&balloon_mutex); + /* Pages are pulled off the back of the queue to prefer highmem */ + while (rv < nr_pages) { + if (list_empty(&ballooned_pages)) { + if (!force) + break; + if (decrease_reservation(nr_pages - rv)) + force = 0; + } else { + page = list_entry(ballooned_pages.prev, + struct page, lru); + list_del(&page->lru); + pages[rv++] = page; + } + } + mutex_unlock(&balloon_mutex); + return rv; +} +EXPORT_SYMBOL(get_ballooned_pages); + +/** + * put_ballooned_pages - return pages retrieved with get_ballooned_pages + * @nr_pages: Number of pages + * @pages: pages to return + */ +void put_ballooned_pages(int nr_pages, struct page** pages) +{ + int i; + + mutex_lock(&balloon_mutex); + + for (i = 0; i < nr_pages; i++) { + if (PageHighMem(pages[i])) { + list_add_tail(&pages[i]->lru, &ballooned_pages); + } else { + list_add(&pages[i]->lru, &ballooned_pages); + } + } + + mutex_unlock(&balloon_mutex); +} +EXPORT_SYMBOL(put_ballooned_pages); + static int __init balloon_init(void) { unsigned long pfn, nr_pages, extra_pfn_end; diff --git a/include/xen/balloon.h b/include/xen/balloon.h index b2b7c21..5fc25fa 100644 --- a/include/xen/balloon.h +++ b/include/xen/balloon.h @@ -19,3 +19,6 @@ struct balloon_stats { extern struct balloon_stats balloon_stats; void balloon_set_new_target(unsigned long target); + +int get_ballooned_pages(int nr_pages, struct page** pages, int force); +void put_ballooned_pages(int nr_pages, struct page** pages); -- 1.7.3.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel De Graaf
2011-Mar-07 18:06 UTC
[Xen-devel] [PATCH 3/3] xen-gntdev: Use ballooned pages for grant mappings
Grant mappings cause the PFN<->MFN mapping to be lost on the pages used for the mapping. Instead of leaking memory, use pages that have already been ballooned out and so have no valid mapping. This removes the need for the bad-page leak workaround as pages are repopulated by the balloon driver. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- drivers/xen/gntdev.c | 41 ++++++++--------------------------------- 1 files changed, 8 insertions(+), 33 deletions(-) diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index d43ff30..2faf797 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -36,6 +36,7 @@ #include <xen/xen.h> #include <xen/grant_table.h> +#include <xen/balloon.h> #include <xen/gntdev.h> #include <xen/events.h> #include <asm/xen/hypervisor.h> @@ -122,10 +123,12 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) NULL == add->pages) goto err; + i = get_ballooned_pages(count, add->pages, 1); + if (i != count) { + put_ballooned_pages(i, add->pages); + goto err; + } for (i = 0; i < count; i++) { - add->pages[i] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM); - if (add->pages[i] == NULL) - goto err; add->map_ops[i].handle = -1; add->unmap_ops[i].handle = -1; } @@ -137,11 +140,6 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) return add; err: - if (add->pages) - for (i = 0; i < count; i++) { - if (add->pages[i]) - __free_page(add->pages[i]); - } kfree(add->pages); kfree(add->grants); kfree(add->map_ops); @@ -184,8 +182,6 @@ static struct grant_map *gntdev_find_map_index(struct gntdev_priv *priv, static void gntdev_put_map(struct grant_map *map) { - int i; - if (!map) return; @@ -202,29 +198,7 @@ static void gntdev_put_map(struct grant_map *map) if (!use_ptemod) unmap_grant_pages(map, 0, map->count); - for (i = 0; i < map->count; i++) { - uint32_t check, *tmp; - if (!map->pages[i]) - continue; - /* XXX When unmapping in an HVM domain, Xen will - * sometimes end up mapping the GFN to an invalid MFN. - * In this case, writes will be discarded and reads will - * return all 0xFF bytes. Leak these unusable GFNs - * until Xen supports fixing their p2m mapping. - * - * Confirmed present in Xen 4.1-RC3 with HVM source - */ - tmp = kmap(map->pages[i]); - *tmp = 0xdeaddead; - mb(); - check = *tmp; - kunmap(map->pages[i]); - if (check == 0xdeaddead) - __free_page(map->pages[i]); - else - pr_debug("Discard page %d=%ld\n", i, - page_to_pfn(map->pages[i])); - } + put_ballooned_pages(map->count, map->pages); } kfree(map->pages); kfree(map->grants); @@ -324,6 +298,7 @@ static int __unmap_grant_pages(struct grant_map *map, int offset, int pages) map->unmap_ops[offset+i].status); map->unmap_ops[offset+i].handle = -1; } + return err; } -- 1.7.3.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Campbell
2011-Mar-08 10:13 UTC
[Xen-devel] Re: [PATCH 2/3] xen-balloon: Add interface to retrieve ballooned pages
On Mon, 2011-03-07 at 18:06 +0000, Daniel De Graaf wrote:> 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. > > Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> > --- > drivers/xen/balloon.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ > include/xen/balloon.h | 3 ++ > 2 files changed, 57 insertions(+), 0 deletions(-) > > diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c > index b0a7a92..be53596 100644 > --- a/drivers/xen/balloon.c > +++ b/drivers/xen/balloon.c > @@ -328,6 +328,60 @@ void balloon_set_new_target(unsigned long target) > } > EXPORT_SYMBOL_GPL(balloon_set_new_target); > > +/** > + * get_ballooned_pages - get pages that have been ballooned outSince this is exported it should probably have "xen" somewhere in the name. A "get"/"put" naming scheme usually implies some sort of reference count manipulation when used in the kernel. "alloc"/"free" might be better here? Or maybe "take"/"return"? (I don''t really like that one)> + * @nr_pages: Number of pages to get > + * @pages: pages returned > + * @force: Try to balloon out more pages if neededIs there any case where this isn''t passed in as true?> + * @return number of pages retrieved > + */ > +int get_ballooned_pages(int nr_pages, struct page** pages, int force) > +{ > + int rv = 0; > + struct page* page; > + mutex_lock(&balloon_mutex); > + /* Pages are pulled off the back of the queue to prefer highmem */ > + while (rv < nr_pages) { > + if (list_empty(&ballooned_pages)) { > + if (!force) > + break; > + if (decrease_reservation(nr_pages - rv)) > + force = 0; > + } else { > + page = list_entry(ballooned_pages.prev, > + struct page, lru); > + list_del(&page->lru); > + pages[rv++] = page; > + } > + } > + mutex_unlock(&balloon_mutex); > + return rv; > +} > +EXPORT_SYMBOL(get_ballooned_pages); > + > +/** > + * put_ballooned_pages - return pages retrieved with get_ballooned_pages > + * @nr_pages: Number of pages > + * @pages: pages to return > + */ > +void put_ballooned_pages(int nr_pages, struct page** pages) > +{ > + int i; > + > + mutex_lock(&balloon_mutex); > + > + for (i = 0; i < nr_pages; i++) { > + if (PageHighMem(pages[i])) { > + list_add_tail(&pages[i]->lru, &ballooned_pages); > + } else { > + list_add(&pages[i]->lru, &ballooned_pages); > + } > + }Maybe we should kick the balloon worker thread here if current < target or some such? e.g. to reverse the effect of a force==1 in the getter.> + > + mutex_unlock(&balloon_mutex); > +} > +EXPORT_SYMBOL(put_ballooned_pages); > + > static int __init balloon_init(void) > { > unsigned long pfn, nr_pages, extra_pfn_end; > diff --git a/include/xen/balloon.h b/include/xen/balloon.h > index b2b7c21..5fc25fa 100644 > --- a/include/xen/balloon.h > +++ b/include/xen/balloon.h > @@ -19,3 +19,6 @@ struct balloon_stats { > extern struct balloon_stats balloon_stats; > > void balloon_set_new_target(unsigned long target); > + > +int get_ballooned_pages(int nr_pages, struct page** pages, int force); > +void put_ballooned_pages(int nr_pages, struct page** pages);_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Campbell
2011-Mar-08 10:18 UTC
[Xen-devel] Re: [PATCH 1/3] xen-balloon: Move core balloon functionality out of module
On Mon, 2011-03-07 at 18:06 +0000, Daniel De Graaf wrote:> 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. > > Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>balloon vs xen-balloon is a bit non-obvious but then events vs xen-evtchn and grant-table vs xen-gntdev are arguably even worse. At least you didn''t go for xen-blndev ;-) Acked-by: Ian Campbell <ian.campbell@citrix.com>> --- > drivers/xen/Makefile | 4 +- > drivers/xen/balloon.c | 220 +-------------------------------------- > drivers/xen/xen-balloon.c | 249 +++++++++++++++++++++++++++++++++++++++++++++ > include/xen/balloon.h | 21 ++++ > 4 files changed, 278 insertions(+), 216 deletions(-) > create mode 100644 drivers/xen/xen-balloon.c > create mode 100644 include/xen/balloon.h > > diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile > index ad8c450..aa3ef62 100644 > --- a/drivers/xen/Makefile > +++ b/drivers/xen/Makefile > @@ -1,4 +1,4 @@ > -obj-y += grant-table.o features.o events.o manage.o > +obj-y += grant-table.o features.o events.o manage.o balloon.o > obj-y += xenbus/ > > nostackp := $(call cc-option, -fno-stack-protector) > @@ -7,7 +7,7 @@ CFLAGS_features.o := $(nostackp) > obj-$(CONFIG_BLOCK) += biomerge.o > obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o > obj-$(CONFIG_XEN_XENCOMM) += xencomm.o > -obj-$(CONFIG_XEN_BALLOON) += balloon.o > +obj-$(CONFIG_XEN_BALLOON) += xen-balloon.o > obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o > obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/ > obj-$(CONFIG_XEN_BLKDEV_BACKEND) += blkback/ > diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c > index 718050a..b0a7a92 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 <linux/kernel.h> > -#include <linux/module.h> > #include <linux/sched.h> > #include <linux/errno.h> > #include <linux/mm.h> > @@ -42,13 +39,11 @@ > #include <linux/highmem.h> > #include <linux/mutex.h> > #include <linux/list.h> > -#include <linux/sysdev.h> > #include <linux/gfp.h> > > #include <asm/page.h> > #include <asm/pgalloc.h> > #include <asm/pgtable.h> > -#include <asm/uaccess.h> > #include <asm/tlb.h> > #include <asm/e820.h> > > @@ -58,35 +53,16 @@ > #include <xen/xen.h> > #include <xen/interface/xen.h> > #include <xen/interface/memory.h> > -#include <xen/xenbus.h> > +#include <xen/balloon.h> > #include <xen/features.h> > #include <xen/page.h> > > #define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10)) > > -#define BALLOON_CLASS_NAME "xen_memory" > - > -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; > -}; > - > 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)]; > @@ -344,51 +320,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_work(&balloon_worker); > } > - > -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) > { > @@ -398,7 +336,7 @@ static int __init balloon_init(void) > if (!xen_domain()) > return -ENODEV; > > - pr_info("xen_balloon: Initialising balloon driver.\n"); > + pr_info("xen/balloon: Initialising balloon driver.\n"); > > if (xen_pv_domain()) > nr_pages = xen_start_info->nr_pages; > @@ -414,8 +352,6 @@ static int __init balloon_init(void) > balloon_timer.data = 0; > balloon_timer.function = balloon_alarm; > > - 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 > @@ -436,153 +372,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)); > -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) > -{ > - 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, > -}; > - > -static struct attribute *balloon_info_attrs[] = { > - &attr_current_kb.attr, > - &attr_low_kb.attr, > - &attr_high_kb.attr, > - &attr_driver_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"); > diff --git a/drivers/xen/xen-balloon.c b/drivers/xen/xen-balloon.c > new file mode 100644 > index 0000000..59dfd79 > --- /dev/null > +++ b/drivers/xen/xen-balloon.c > @@ -0,0 +1,249 @@ > +/****************************************************************************** > + * Xen balloon driver - enables returning/claiming memory to/from Xen. > + * > + * Copyright (c) 2003, B Dragovic > + * Copyright (c) 2003-2004, M Williamson, K Fraser > + * Copyright (c) 2005 Dan M. Smith, IBM Corporation > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License version 2 > + * as published by the Free Software Foundation; or, when distributed > + * separately from the Linux kernel or incorporated into other > + * software packages, subject to the following license: > + * > + * Permission is hereby granted, free of charge, to any person obtaining a copy > + * of this source file (the "Software"), to deal in the Software without > + * restriction, including without limitation the rights to use, copy, modify, > + * merge, publish, distribute, sublicense, and/or sell copies of the Software, > + * and to permit persons to whom the Software is furnished to do so, subject to > + * the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE > + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS > + * IN THE SOFTWARE. > + */ > + > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/sysdev.h> > +#include <linux/capability.h> > + > +#include <xen/xen.h> > +#include <xen/interface/xen.h> > +#include <xen/balloon.h> > +#include <xen/xenbus.h> > +#include <xen/features.h> > +#include <xen/page.h> > + > +#define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10)) > + > +#define BALLOON_CLASS_NAME "xen_memory" > + > +static struct sys_device balloon_sysdev; > + > +static int register_balloon(struct sys_device *sysdev); > + > +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; > + > +static int __init balloon_init(void) > +{ > + if (!xen_domain()) > + return -ENODEV; > + > + pr_info("xen-balloon: Initialising balloon driver.\n"); > + > + register_balloon(&balloon_sysdev); > + > + 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 unregister? */ > + 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)); > +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) > +{ > + 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, > +}; > + > +static struct attribute *balloon_info_attrs[] = { > + &attr_current_kb.attr, > + &attr_low_kb.attr, > + &attr_high_kb.attr, > + &attr_driver_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"); > diff --git a/include/xen/balloon.h b/include/xen/balloon.h > new file mode 100644 > index 0000000..b2b7c21 > --- /dev/null > +++ b/include/xen/balloon.h > @@ -0,0 +1,21 @@ > +/****************************************************************************** > + * Xen balloon functionality > + */ > + > +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; > +}; > + > +extern struct balloon_stats balloon_stats; > + > +void balloon_set_new_target(unsigned long target); > -- > 1.7.3.4 >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Campbell
2011-Mar-08 10:18 UTC
[Xen-devel] Re: [PATCH 3/3] xen-gntdev: Use ballooned pages for grant mappings
On Mon, 2011-03-07 at 18:06 +0000, Daniel De Graaf wrote:> Grant mappings cause the PFN<->MFN mapping to be lost on the pages used > for the mapping. Instead of leaking memory, use pages that have already > been ballooned out and so have no valid mapping. This removes the need > for the bad-page leak workaround as pages are repopulated by the balloon > driver. > > Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>Acked-by: Ian Campbell <ian.campbell@citrix.com>> --- > drivers/xen/gntdev.c | 41 ++++++++--------------------------------- > 1 files changed, 8 insertions(+), 33 deletions(-) > > diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c > index d43ff30..2faf797 100644 > --- a/drivers/xen/gntdev.c > +++ b/drivers/xen/gntdev.c > @@ -36,6 +36,7 @@ > > #include <xen/xen.h> > #include <xen/grant_table.h> > +#include <xen/balloon.h> > #include <xen/gntdev.h> > #include <xen/events.h> > #include <asm/xen/hypervisor.h> > @@ -122,10 +123,12 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) > NULL == add->pages) > goto err; > > + i = get_ballooned_pages(count, add->pages, 1); > + if (i != count) { > + put_ballooned_pages(i, add->pages); > + goto err; > + } > for (i = 0; i < count; i++) { > - add->pages[i] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM); > - if (add->pages[i] == NULL) > - goto err; > add->map_ops[i].handle = -1; > add->unmap_ops[i].handle = -1; > } > @@ -137,11 +140,6 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) > return add; > > err: > - if (add->pages) > - for (i = 0; i < count; i++) { > - if (add->pages[i]) > - __free_page(add->pages[i]); > - } > kfree(add->pages); > kfree(add->grants); > kfree(add->map_ops); > @@ -184,8 +182,6 @@ static struct grant_map *gntdev_find_map_index(struct gntdev_priv *priv, > > static void gntdev_put_map(struct grant_map *map) > { > - int i; > - > if (!map) > return; > > @@ -202,29 +198,7 @@ static void gntdev_put_map(struct grant_map *map) > if (!use_ptemod) > unmap_grant_pages(map, 0, map->count); > > - for (i = 0; i < map->count; i++) { > - uint32_t check, *tmp; > - if (!map->pages[i]) > - continue; > - /* XXX When unmapping in an HVM domain, Xen will > - * sometimes end up mapping the GFN to an invalid MFN. > - * In this case, writes will be discarded and reads will > - * return all 0xFF bytes. Leak these unusable GFNs > - * until Xen supports fixing their p2m mapping. > - * > - * Confirmed present in Xen 4.1-RC3 with HVM source > - */ > - tmp = kmap(map->pages[i]); > - *tmp = 0xdeaddead; > - mb(); > - check = *tmp; > - kunmap(map->pages[i]); > - if (check == 0xdeaddead) > - __free_page(map->pages[i]); > - else > - pr_debug("Discard page %d=%ld\n", i, > - page_to_pfn(map->pages[i])); > - } > + put_ballooned_pages(map->count, map->pages); > } > kfree(map->pages); > kfree(map->grants); > @@ -324,6 +298,7 @@ static int __unmap_grant_pages(struct grant_map *map, int offset, int pages) > map->unmap_ops[offset+i].status); > map->unmap_ops[offset+i].handle = -1; > } > + > return err; > } >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel De Graaf
2011-Mar-08 16:24 UTC
[Xen-devel] [PATCH 2/3 v2] 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. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- drivers/xen/balloon.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ include/xen/balloon.h | 3 ++ 2 files changed, 63 insertions(+), 0 deletions(-) diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index b0a7a92..ec75f26 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -328,6 +328,66 @@ 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 number of pages retrieved + */ +int alloc_xenballooned_pages(int nr_pages, struct page** pages) +{ + int rv = 0; + int alloc_failed = 0; + struct page* page; + mutex_lock(&balloon_mutex); + /* Pages are pulled off the back of the queue to prefer highmem */ + while (rv < nr_pages) { + if (list_empty(&ballooned_pages)) { + if (alloc_failed) + break; + if (decrease_reservation(nr_pages - rv)) + alloc_failed = 1; + } else { + page = list_entry(ballooned_pages.prev, + struct page, lru); + list_del(&page->lru); + pages[rv++] = page; + } + } + mutex_unlock(&balloon_mutex); + return rv; +} +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]) + continue; + if (PageHighMem(pages[i])) { + list_add_tail(&pages[i]->lru, &ballooned_pages); + } else { + list_add(&pages[i]->lru, &ballooned_pages); + } + } + + /* The balloon may be too large now. Shrink it if needed. */ + if (current_target() != balloon_stats.current_pages) + schedule_work(&balloon_worker); + + mutex_unlock(&balloon_mutex); +} +EXPORT_SYMBOL(free_xenballooned_pages); + static int __init balloon_init(void) { unsigned long pfn, nr_pages, extra_pfn_end; diff --git a/include/xen/balloon.h b/include/xen/balloon.h index b2b7c21..72a6927 100644 --- a/include/xen/balloon.h +++ b/include/xen/balloon.h @@ -19,3 +19,6 @@ struct balloon_stats { extern struct balloon_stats balloon_stats; void balloon_set_new_target(unsigned long target); + +int alloc_xenballooned_pages(int nr_pages, struct page** pages); +void free_xenballooned_pages(int nr_pages, struct page** pages); -- 1.7.3.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel De Graaf
2011-Mar-08 16:24 UTC
[Xen-devel] [PATCH 3/3 v2] xen-gntdev: Use ballooned pages for grant mappings
Grant mappings cause the PFN<->MFN mapping to be lost on the pages used for the mapping. Instead of leaking memory, use pages that have already been ballooned out and so have no valid mapping. This removes the need for the bad-page leak workaround as pages are repopulated by the balloon driver. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- drivers/xen/gntdev.c | 40 +++++++--------------------------------- 1 files changed, 7 insertions(+), 33 deletions(-) diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index fdb805d..6cb4c68 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -36,6 +36,7 @@ #include <xen/xen.h> #include <xen/grant_table.h> +#include <xen/balloon.h> #include <xen/gntdev.h> #include <xen/events.h> #include <asm/xen/hypervisor.h> @@ -122,10 +123,12 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) NULL == add->pages) goto err; + i = alloc_xenballooned_pages(count, add->pages); + if (i != count) { + free_xenballooned_pages(i, add->pages); + goto err; + } for (i = 0; i < count; i++) { - add->pages[i] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM); - if (add->pages[i] == NULL) - goto err; add->map_ops[i].handle = -1; add->unmap_ops[i].handle = -1; } @@ -137,11 +140,6 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) return add; err: - if (add->pages) - for (i = 0; i < count; i++) { - if (add->pages[i]) - __free_page(add->pages[i]); - } kfree(add->pages); kfree(add->grants); kfree(add->map_ops); @@ -184,8 +182,6 @@ static struct grant_map *gntdev_find_map_index(struct gntdev_priv *priv, static void gntdev_put_map(struct grant_map *map) { - int i; - if (!map) return; @@ -202,29 +198,7 @@ static void gntdev_put_map(struct grant_map *map) if (!use_ptemod) unmap_grant_pages(map, 0, map->count); - for (i = 0; i < map->count; i++) { - uint32_t check, *tmp; - if (!map->pages[i]) - continue; - /* XXX When unmapping in an HVM domain, Xen will - * sometimes end up mapping the GFN to an invalid MFN. - * In this case, writes will be discarded and reads will - * return all 0xFF bytes. Leak these unusable GFNs - * until Xen supports fixing their p2m mapping. - * - * Confirmed present in Xen 4.1-RC3 with HVM source - */ - tmp = kmap(map->pages[i]); - *tmp = 0xdeaddead; - mb(); - check = *tmp; - kunmap(map->pages[i]); - if (check == 0xdeaddead) - __free_page(map->pages[i]); - else - pr_debug("Discard page %d=%ld\n", i, - page_to_pfn(map->pages[i])); - } + free_xenballooned_pages(map->count, map->pages); } kfree(map->pages); kfree(map->grants); -- 1.7.3.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel De Graaf
2011-Mar-08 16:24 UTC
[Xen-devel] Re: [PATCH 2/3] xen-balloon: Add interface to retrieve ballooned pages
On 03/08/2011 05:13 AM, Ian Campbell wrote:> On Mon, 2011-03-07 at 18:06 +0000, Daniel De Graaf wrote: >> 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. >> >> Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> >> --- >> drivers/xen/balloon.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ >> include/xen/balloon.h | 3 ++ >> 2 files changed, 57 insertions(+), 0 deletions(-) >> >> diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c >> index b0a7a92..be53596 100644 >> --- a/drivers/xen/balloon.c >> +++ b/drivers/xen/balloon.c >> @@ -328,6 +328,60 @@ void balloon_set_new_target(unsigned long target) >> } >> EXPORT_SYMBOL_GPL(balloon_set_new_target); >> >> +/** >> + * get_ballooned_pages - get pages that have been ballooned out > > Since this is exported it should probably have "xen" somewhere in the > name. > > A "get"/"put" naming scheme usually implies some sort of reference count > manipulation when used in the kernel. "alloc"/"free" might be better > here? Or maybe "take"/"return"? (I don''t really like that one)I think "alloc_xenballooned_pages" and "free_xenballooned_pages" would be good names; they do avoid confusion with the get/put convention which I hadn''t considered, and also imply the potential alloc/free of memory if the balloon is not inflated.>> + * @nr_pages: Number of pages to get >> + * @pages: pages returned >> + * @force: Try to balloon out more pages if needed > > Is there any case where this isn''t passed in as true?No; it''s probably best to remove it. The name change to "alloc" implies that it will touch allocation which is the use I had thought of for force==0.>> + * @return number of pages retrieved >> + */ >> +int get_ballooned_pages(int nr_pages, struct page** pages, int force) >> +{ >> + int rv = 0; >> + struct page* page; >> + mutex_lock(&balloon_mutex); >> + /* Pages are pulled off the back of the queue to prefer highmem */ >> + while (rv < nr_pages) { >> + if (list_empty(&ballooned_pages)) { >> + if (!force) >> + break; >> + if (decrease_reservation(nr_pages - rv)) >> + force = 0; >> + } else { >> + page = list_entry(ballooned_pages.prev, >> + struct page, lru); >> + list_del(&page->lru); >> + pages[rv++] = page; >> + } >> + } >> + mutex_unlock(&balloon_mutex); >> + return rv; >> +} >> +EXPORT_SYMBOL(get_ballooned_pages); >> + >> +/** >> + * put_ballooned_pages - return pages retrieved with get_ballooned_pages >> + * @nr_pages: Number of pages >> + * @pages: pages to return >> + */ >> +void put_ballooned_pages(int nr_pages, struct page** pages) >> +{ >> + int i; >> + >> + mutex_lock(&balloon_mutex); >> + >> + for (i = 0; i < nr_pages; i++) { >> + if (PageHighMem(pages[i])) { >> + list_add_tail(&pages[i]->lru, &ballooned_pages); >> + } else { >> + list_add(&pages[i]->lru, &ballooned_pages); >> + } >> + } > > Maybe we should kick the balloon worker thread here if current < target > or some such? e.g. to reverse the effect of a force==1 in the getter.Kicking the worker thread is a good idea: if the balloon module is not loaded, the pages will never be returned to the kernel allocator (although they will be reused for later balloon requests).>> + >> + mutex_unlock(&balloon_mutex); >> +} >> +EXPORT_SYMBOL(put_ballooned_pages); >> + >> static int __init balloon_init(void) >> { >> unsigned long pfn, nr_pages, extra_pfn_end; >> diff --git a/include/xen/balloon.h b/include/xen/balloon.h >> index b2b7c21..5fc25fa 100644 >> --- a/include/xen/balloon.h >> +++ b/include/xen/balloon.h >> @@ -19,3 +19,6 @@ struct balloon_stats { >> extern struct balloon_stats balloon_stats; >> >> void balloon_set_new_target(unsigned long target); >> + >> +int get_ballooned_pages(int nr_pages, struct page** pages, int force); >> +void put_ballooned_pages(int nr_pages, struct page** pages); > >-- Daniel De Graaf National Security Agency _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Campbell
2011-Mar-08 16:36 UTC
[Xen-devel] Re: [PATCH 2/3 v2] xen-balloon: Add interface to retrieve ballooned pages
On Tue, 2011-03-08 at 16:24 +0000, Daniel De Graaf wrote:> 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.The new functions duplicate parts of balloon_retrieve and balloon_append but without adjusting the various stats, I''m not sure that''s right. I think you should probably just use those functions. Ian.> > Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> > --- > drivers/xen/balloon.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ > include/xen/balloon.h | 3 ++ > 2 files changed, 63 insertions(+), 0 deletions(-) > > diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c > index b0a7a92..ec75f26 100644 > --- a/drivers/xen/balloon.c > +++ b/drivers/xen/balloon.c > @@ -328,6 +328,66 @@ 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 number of pages retrieved > + */ > +int alloc_xenballooned_pages(int nr_pages, struct page** pages) > +{ > + int rv = 0; > + int alloc_failed = 0; > + struct page* page; > + mutex_lock(&balloon_mutex); > + /* Pages are pulled off the back of the queue to prefer highmem */ > + while (rv < nr_pages) { > + if (list_empty(&ballooned_pages)) { > + if (alloc_failed) > + break; > + if (decrease_reservation(nr_pages - rv)) > + alloc_failed = 1; > + } else { > + page = list_entry(ballooned_pages.prev, > + struct page, lru); > + list_del(&page->lru); > + pages[rv++] = page; > + } > + } > + mutex_unlock(&balloon_mutex); > + return rv; > +} > +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]) > + continue; > + if (PageHighMem(pages[i])) { > + list_add_tail(&pages[i]->lru, &ballooned_pages); > + } else { > + list_add(&pages[i]->lru, &ballooned_pages); > + } > + } > + > + /* The balloon may be too large now. Shrink it if needed. */ > + if (current_target() != balloon_stats.current_pages) > + schedule_work(&balloon_worker); > + > + mutex_unlock(&balloon_mutex); > +} > +EXPORT_SYMBOL(free_xenballooned_pages); > + > static int __init balloon_init(void) > { > unsigned long pfn, nr_pages, extra_pfn_end; > diff --git a/include/xen/balloon.h b/include/xen/balloon.h > index b2b7c21..72a6927 100644 > --- a/include/xen/balloon.h > +++ b/include/xen/balloon.h > @@ -19,3 +19,6 @@ struct balloon_stats { > extern struct balloon_stats balloon_stats; > > void balloon_set_new_target(unsigned long target); > + > +int alloc_xenballooned_pages(int nr_pages, struct page** pages); > +void free_xenballooned_pages(int nr_pages, struct page** pages);_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel De Graaf
2011-Mar-08 16:55 UTC
[Xen-devel] [PATCH 2/3 v3] 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. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- drivers/xen/balloon.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++-- include/xen/balloon.h | 3 ++ 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index b0a7a92..53deaec 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -116,14 +116,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(int 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)) { @@ -198,7 +201,7 @@ static int increase_reservation(unsigned long nr_pages) goto out; for (i = 0; i < rc; i++) { - page = balloon_retrieve(); + page = balloon_retrieve(0); BUG_ON(page == NULL); pfn = page_to_pfn(page); @@ -328,6 +331,58 @@ 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 number of pages retrieved + */ +int alloc_xenballooned_pages(int nr_pages, struct page** pages) +{ + int rv = 0; + int alloc_failed = 0; + struct page* page; + mutex_lock(&balloon_mutex); + while (rv < nr_pages) { + page = balloon_retrieve(1); + if (page) { + pages[rv++] = page; + } else { + if (alloc_failed) + break; + if (decrease_reservation(nr_pages - rv)) + alloc_failed = 1; + } + } + mutex_unlock(&balloon_mutex); + return rv; +} +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_work(&balloon_worker); + + mutex_unlock(&balloon_mutex); +} +EXPORT_SYMBOL(free_xenballooned_pages); + static int __init balloon_init(void) { unsigned long pfn, nr_pages, extra_pfn_end; diff --git a/include/xen/balloon.h b/include/xen/balloon.h index b2b7c21..72a6927 100644 --- a/include/xen/balloon.h +++ b/include/xen/balloon.h @@ -19,3 +19,6 @@ struct balloon_stats { extern struct balloon_stats balloon_stats; void balloon_set_new_target(unsigned long target); + +int alloc_xenballooned_pages(int nr_pages, struct page** pages); +void free_xenballooned_pages(int nr_pages, struct page** pages); -- 1.7.3.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Campbell
2011-Mar-08 17:11 UTC
[Xen-devel] Re: [PATCH 2/3 v3] xen-balloon: Add interface to retrieve ballooned pages
On Tue, 2011-03-08 at 16:55 +0000, Daniel De Graaf wrote:> 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. > > Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> > --- > drivers/xen/balloon.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++-- > include/xen/balloon.h | 3 ++ > 2 files changed, 61 insertions(+), 3 deletions(-) > > diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c > index b0a7a92..53deaec 100644 > --- a/drivers/xen/balloon.c > +++ b/drivers/xen/balloon.c > @@ -116,14 +116,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(int prefer_highmem)bool?> { > 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)) { > @@ -198,7 +201,7 @@ static int increase_reservation(unsigned long nr_pages) > goto out; > > for (i = 0; i < rc; i++) { > - page = balloon_retrieve(); > + page = balloon_retrieve(0); > BUG_ON(page == NULL); > > pfn = page_to_pfn(page); > @@ -328,6 +331,58 @@ 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 number of pages retrieved > + */ > +int alloc_xenballooned_pages(int nr_pages, struct page** pages) > +{ > + int rv = 0; > + int alloc_failed = 0; > + struct page* page; > + mutex_lock(&balloon_mutex); > + while (rv < nr_pages) { > + page = balloon_retrieve(1); > + if (page) { > + pages[rv++] = page; > + } else { > + if (alloc_failed) > + break; > + if (decrease_reservation(nr_pages - rv)) > + alloc_failed = 1;This loop and the "alloc_failed" thing seems pretty subtle. If I''m reading correctly then if decrease_reservation didn''t manage to return the number of pages we asked for then we have a few more turns of the handle to retrieve whatever we can, but we already know it''s not going to be everything we asked for, or decrease_reservation would have succeeded). The only caller of this is your 3/3 which just returns what it got and fails if it didn''t get everything it asked for. At least until we have a second caller which requires otherwise (and I don''t think we will) I think this function should either return all or nothing and should clean up after itself in the latter case, which saves the caller a job too. Ian.> + } > + } > + mutex_unlock(&balloon_mutex); > + return rv; > +} > +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_work(&balloon_worker); > + > + mutex_unlock(&balloon_mutex); > +} > +EXPORT_SYMBOL(free_xenballooned_pages); > + > static int __init balloon_init(void) > { > unsigned long pfn, nr_pages, extra_pfn_end; > diff --git a/include/xen/balloon.h b/include/xen/balloon.h > index b2b7c21..72a6927 100644 > --- a/include/xen/balloon.h > +++ b/include/xen/balloon.h > @@ -19,3 +19,6 @@ struct balloon_stats { > extern struct balloon_stats balloon_stats; > > void balloon_set_new_target(unsigned long target); > + > +int alloc_xenballooned_pages(int nr_pages, struct page** pages); > +void free_xenballooned_pages(int nr_pages, struct page** pages);_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel De Graaf
2011-Mar-08 19:49 UTC
[Xen-devel] [PATCH 2/3 v4] 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. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- drivers/xen/balloon.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++-- include/xen/balloon.h | 3 ++ 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index b0a7a92..d187fce 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -116,14 +116,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)) { @@ -198,7 +201,7 @@ static int increase_reservation(unsigned long nr_pages) goto out; for (i = 0; i < rc; i++) { - page = balloon_retrieve(); + page = balloon_retrieve(0); BUG_ON(page == NULL); pfn = page_to_pfn(page); @@ -328,6 +331,62 @@ 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(1); + if (page) { + pages[pgno++] = page; + } else { + if (decrease_reservation(nr_pages - pgno)) + 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_work(&balloon_worker); + 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_work(&balloon_worker); + + mutex_unlock(&balloon_mutex); +} +EXPORT_SYMBOL(free_xenballooned_pages); + static int __init balloon_init(void) { unsigned long pfn, nr_pages, extra_pfn_end; diff --git a/include/xen/balloon.h b/include/xen/balloon.h index b2b7c21..72a6927 100644 --- a/include/xen/balloon.h +++ b/include/xen/balloon.h @@ -19,3 +19,6 @@ struct balloon_stats { extern struct balloon_stats balloon_stats; void balloon_set_new_target(unsigned long target); + +int alloc_xenballooned_pages(int nr_pages, struct page** pages); +void free_xenballooned_pages(int nr_pages, struct page** pages); -- 1.7.3.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel De Graaf
2011-Mar-08 19:49 UTC
[Xen-devel] [PATCH 3/3 v4] xen-gntdev: Use ballooned pages for grant mappings
Grant mappings cause the PFN<->MFN mapping to be lost on the pages used for the mapping. Instead of leaking memory, use pages that have already been ballooned out and so have no valid mapping. This removes the need for the bad-page leak workaround as pages are repopulated by the balloon driver. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- drivers/xen/gntdev.c | 38 +++++--------------------------------- 1 files changed, 5 insertions(+), 33 deletions(-) diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index fdb805d..f60c409 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -36,6 +36,7 @@ #include <xen/xen.h> #include <xen/grant_table.h> +#include <xen/balloon.h> #include <xen/gntdev.h> #include <xen/events.h> #include <asm/xen/hypervisor.h> @@ -122,10 +123,10 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) NULL == add->pages) goto err; + if (alloc_xenballooned_pages(count, add->pages)) + goto err; + for (i = 0; i < count; i++) { - add->pages[i] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM); - if (add->pages[i] == NULL) - goto err; add->map_ops[i].handle = -1; add->unmap_ops[i].handle = -1; } @@ -137,11 +138,6 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) return add; err: - if (add->pages) - for (i = 0; i < count; i++) { - if (add->pages[i]) - __free_page(add->pages[i]); - } kfree(add->pages); kfree(add->grants); kfree(add->map_ops); @@ -184,8 +180,6 @@ static struct grant_map *gntdev_find_map_index(struct gntdev_priv *priv, static void gntdev_put_map(struct grant_map *map) { - int i; - if (!map) return; @@ -202,29 +196,7 @@ static void gntdev_put_map(struct grant_map *map) if (!use_ptemod) unmap_grant_pages(map, 0, map->count); - for (i = 0; i < map->count; i++) { - uint32_t check, *tmp; - if (!map->pages[i]) - continue; - /* XXX When unmapping in an HVM domain, Xen will - * sometimes end up mapping the GFN to an invalid MFN. - * In this case, writes will be discarded and reads will - * return all 0xFF bytes. Leak these unusable GFNs - * until Xen supports fixing their p2m mapping. - * - * Confirmed present in Xen 4.1-RC3 with HVM source - */ - tmp = kmap(map->pages[i]); - *tmp = 0xdeaddead; - mb(); - check = *tmp; - kunmap(map->pages[i]); - if (check == 0xdeaddead) - __free_page(map->pages[i]); - else - pr_debug("Discard page %d=%ld\n", i, - page_to_pfn(map->pages[i])); - } + free_xenballooned_pages(map->count, map->pages); } kfree(map->pages); kfree(map->grants); -- 1.7.3.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Campbell
2011-Mar-09 10:30 UTC
[Xen-devel] Re: [PATCH 2/3 v4] xen-balloon: Add interface to retrieve ballooned pages
On Tue, 2011-03-08 at 19:49 +0000, Daniel De Graaf wrote:> 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. > > Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> > --- > drivers/xen/balloon.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++-- > include/xen/balloon.h | 3 ++ > 2 files changed, 65 insertions(+), 3 deletions(-) > > diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c > index b0a7a92..d187fce 100644 > --- a/drivers/xen/balloon.c > +++ b/drivers/xen/balloon.c > @@ -116,14 +116,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)) { > @@ -198,7 +201,7 @@ static int increase_reservation(unsigned long nr_pages) > goto out; > > for (i = 0; i < rc; i++) { > - page = balloon_retrieve(); > + page = balloon_retrieve(0);You can use "true" and "false" with bools. Otherwise this and patch 3/3 v4 look good to me.> BUG_ON(page == NULL); > > pfn = page_to_pfn(page); > @@ -328,6 +331,62 @@ 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(1); > + if (page) { > + pages[pgno++] = page; > + } else { > + if (decrease_reservation(nr_pages - pgno)) > + 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_work(&balloon_worker); > + 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_work(&balloon_worker); > + > + mutex_unlock(&balloon_mutex); > +} > +EXPORT_SYMBOL(free_xenballooned_pages); > + > static int __init balloon_init(void) > { > unsigned long pfn, nr_pages, extra_pfn_end; > diff --git a/include/xen/balloon.h b/include/xen/balloon.h > index b2b7c21..72a6927 100644 > --- a/include/xen/balloon.h > +++ b/include/xen/balloon.h > @@ -19,3 +19,6 @@ struct balloon_stats { > extern struct balloon_stats balloon_stats; > > void balloon_set_new_target(unsigned long target); > + > +int alloc_xenballooned_pages(int nr_pages, struct page** pages); > +void free_xenballooned_pages(int nr_pages, struct page** pages);_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Konrad Rzeszutek Wilk
2011-Mar-09 21:03 UTC
Re: [Xen-devel] [PATCH 2/3] xen-balloon: Add interface to retrieve ballooned pages
On Mon, Mar 07, 2011 at 01:06:47PM -0500, Daniel De Graaf wrote:> 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. > > Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> > --- > drivers/xen/balloon.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ > include/xen/balloon.h | 3 ++ > 2 files changed, 57 insertions(+), 0 deletions(-) > > diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c > index b0a7a92..be53596 100644 > --- a/drivers/xen/balloon.c > +++ b/drivers/xen/balloon.c > @@ -328,6 +328,60 @@ void balloon_set_new_target(unsigned long target) > } > EXPORT_SYMBOL_GPL(balloon_set_new_target); > > +/** > + * get_ballooned_pages - get pages that have been ballooned out > + * @nr_pages: Number of pages to get > + * @pages: pages returned > + * @force: Try to balloon out more pages if needed > + * @return number of pages retrieved > + */ > +int get_ballooned_pages(int nr_pages, struct page** pages, int force) > +{ > + int rv = 0; > + struct page* page; > + mutex_lock(&balloon_mutex); > + /* Pages are pulled off the back of the queue to prefer highmem */ > + while (rv < nr_pages) { > + if (list_empty(&ballooned_pages)) { > + if (!force) > + break; > + if (decrease_reservation(nr_pages - rv))I am looking at the implementation of decrease_reservation with Daniel''s Kipper patches ("xen/balloon: Protect against CPU exhaust by event/x process") and his code will the functionality of trying to balloon out the amount of pages you want. But if it can''t balloon out all, it will try the best it can. Meaning if nr_pages is 256 and rv is 0, and we only say get 100 of them, this particular loop would keep on going forever.. until it got the rest of those 156 pages which it might not. Perhaps rebasing on top of Daniel''s patch and utilize the BP_EAGAIN logic to back-off, or just return -EBUSY with the amount returned?> + force = 0; > + } else { > + page = list_entry(ballooned_pages.prev, > + struct page, lru); > + list_del(&page->lru); > + pages[rv++] = page; > + } > + } > + mutex_unlock(&balloon_mutex); > + return rv; > +} > +EXPORT_SYMBOL(get_ballooned_pages); > + > +/** > + * put_ballooned_pages - return pages retrieved with get_ballooned_pages > + * @nr_pages: Number of pages > + * @pages: pages to return > + */ > +void put_ballooned_pages(int nr_pages, struct page** pages) > +{ > + int i; > + > + mutex_lock(&balloon_mutex); > + > + for (i = 0; i < nr_pages; i++) { > + if (PageHighMem(pages[i])) { > + list_add_tail(&pages[i]->lru, &ballooned_pages); > + } else { > + list_add(&pages[i]->lru, &ballooned_pages); > + } > + } > + > + mutex_unlock(&balloon_mutex); > +} > +EXPORT_SYMBOL(put_ballooned_pages); > + > static int __init balloon_init(void) > { > unsigned long pfn, nr_pages, extra_pfn_end; > diff --git a/include/xen/balloon.h b/include/xen/balloon.h > index b2b7c21..5fc25fa 100644 > --- a/include/xen/balloon.h > +++ b/include/xen/balloon.h > @@ -19,3 +19,6 @@ struct balloon_stats { > extern struct balloon_stats balloon_stats; > > void balloon_set_new_target(unsigned long target); > + > +int get_ballooned_pages(int nr_pages, struct page** pages, int force); > +void put_ballooned_pages(int nr_pages, struct page** pages); > -- > 1.7.3.4 > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xensource.com > http://lists.xensource.com/xen-devel_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel De Graaf
2011-Mar-09 21:22 UTC
Re: [Xen-devel] [PATCH 2/3] xen-balloon: Add interface to retrieve ballooned pages
On 03/09/2011 04:03 PM, Konrad Rzeszutek Wilk wrote:> On Mon, Mar 07, 2011 at 01:06:47PM -0500, Daniel De Graaf wrote: >> 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. >> >> Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> >> --- >> drivers/xen/balloon.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ >> include/xen/balloon.h | 3 ++ >> 2 files changed, 57 insertions(+), 0 deletions(-) >> >> diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c >> index b0a7a92..be53596 100644 >> --- a/drivers/xen/balloon.c >> +++ b/drivers/xen/balloon.c >> @@ -328,6 +328,60 @@ void balloon_set_new_target(unsigned long target) >> } >> EXPORT_SYMBOL_GPL(balloon_set_new_target); >> >> +/** >> + * get_ballooned_pages - get pages that have been ballooned out >> + * @nr_pages: Number of pages to get >> + * @pages: pages returned >> + * @force: Try to balloon out more pages if needed >> + * @return number of pages retrieved >> + */ >> +int get_ballooned_pages(int nr_pages, struct page** pages, int force) >> +{ >> + int rv = 0; >> + struct page* page; >> + mutex_lock(&balloon_mutex); >> + /* Pages are pulled off the back of the queue to prefer highmem */ >> + while (rv < nr_pages) { >> + if (list_empty(&ballooned_pages)) { >> + if (!force) >> + break; >> + if (decrease_reservation(nr_pages - rv)) > > I am looking at the implementation of decrease_reservation with > Daniel''s Kipper patches ("xen/balloon: Protect against CPU exhaust by event/x process") > and his code will the functionality of trying to balloon out the amount of > pages you want. But if it can''t balloon out all, it will try the best it > can. Meaning if nr_pages is 256 and rv is 0, and we only say get 100 of them, > this particular loop would keep on going forever.. until it got the rest > of those 156 pages which it might not. > > Perhaps rebasing on top of Daniel''s patch and utilize the BP_EAGAIN logic > to back-off, or just return -EBUSY with the amount returned? >I think adding a parameter to decrease_reservation specifying what GFP_* flags will be used in allocation might be useful. The correct rebase of my most recent patch on top of Daniel Kiper''s patch would be to return -ENOMEM when decrease_reservation returns BP_EAGAIN. Since GFP_BALLOON does not try very hard in the memory allocation, this might produce memory errors more often than it should, whereas the alloc_xenballooned_pages call may wish to just use GFP_HIGHUSER and risk invoking the OOM killer if required. Would you prefer I submitted all three patches rebased on top of Daniel Kipper''s R4 patches (or do you have a git tree with those already included)?>> + force = 0; >> + } else { >> + page = list_entry(ballooned_pages.prev, >> + struct page, lru); >> + list_del(&page->lru); >> + pages[rv++] = page; >> + } >> + } >> + mutex_unlock(&balloon_mutex); >> + return rv; >> +} >> +EXPORT_SYMBOL(get_ballooned_pages); >> + >> +/** >> + * put_ballooned_pages - return pages retrieved with get_ballooned_pages >> + * @nr_pages: Number of pages >> + * @pages: pages to return >> + */ >> +void put_ballooned_pages(int nr_pages, struct page** pages) >> +{ >> + int i; >> + >> + mutex_lock(&balloon_mutex); >> + >> + for (i = 0; i < nr_pages; i++) { >> + if (PageHighMem(pages[i])) { >> + list_add_tail(&pages[i]->lru, &ballooned_pages); >> + } else { >> + list_add(&pages[i]->lru, &ballooned_pages); >> + } >> + } >> + >> + mutex_unlock(&balloon_mutex); >> +} >> +EXPORT_SYMBOL(put_ballooned_pages); >> + >> static int __init balloon_init(void) >> { >> unsigned long pfn, nr_pages, extra_pfn_end; >> diff --git a/include/xen/balloon.h b/include/xen/balloon.h >> index b2b7c21..5fc25fa 100644 >> --- a/include/xen/balloon.h >> +++ b/include/xen/balloon.h >> @@ -19,3 +19,6 @@ struct balloon_stats { >> extern struct balloon_stats balloon_stats; >> >> void balloon_set_new_target(unsigned long target); >> + >> +int get_ballooned_pages(int nr_pages, struct page** pages, int force); >> +void put_ballooned_pages(int nr_pages, struct page** pages); >> -- >> 1.7.3.4 >> >> >> _______________________________________________ >> Xen-devel mailing list >> Xen-devel@lists.xensource.com >> http://lists.xensource.com/xen-devel >-- Daniel De Graaf National Security Agency _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Konrad Rzeszutek Wilk
2011-Mar-09 21:59 UTC
Re: [Xen-devel] [PATCH 2/3] xen-balloon: Add interface to retrieve ballooned pages
On Wed, Mar 09, 2011 at 04:22:04PM -0500, Daniel De Graaf wrote:> On 03/09/2011 04:03 PM, Konrad Rzeszutek Wilk wrote: > > On Mon, Mar 07, 2011 at 01:06:47PM -0500, Daniel De Graaf wrote: > >> 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. > >> > >> Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> > >> --- > >> drivers/xen/balloon.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ > >> include/xen/balloon.h | 3 ++ > >> 2 files changed, 57 insertions(+), 0 deletions(-) > >> > >> diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c > >> index b0a7a92..be53596 100644 > >> --- a/drivers/xen/balloon.c > >> +++ b/drivers/xen/balloon.c > >> @@ -328,6 +328,60 @@ void balloon_set_new_target(unsigned long target) > >> } > >> EXPORT_SYMBOL_GPL(balloon_set_new_target); > >> > >> +/** > >> + * get_ballooned_pages - get pages that have been ballooned out > >> + * @nr_pages: Number of pages to get > >> + * @pages: pages returned > >> + * @force: Try to balloon out more pages if needed > >> + * @return number of pages retrieved > >> + */ > >> +int get_ballooned_pages(int nr_pages, struct page** pages, int force) > >> +{ > >> + int rv = 0; > >> + struct page* page; > >> + mutex_lock(&balloon_mutex); > >> + /* Pages are pulled off the back of the queue to prefer highmem */ > >> + while (rv < nr_pages) { > >> + if (list_empty(&ballooned_pages)) { > >> + if (!force) > >> + break; > >> + if (decrease_reservation(nr_pages - rv)) > > > > I am looking at the implementation of decrease_reservation with > > Daniel''s Kipper patches ("xen/balloon: Protect against CPU exhaust by event/x process") > > and his code will the functionality of trying to balloon out the amount of > > pages you want. But if it can''t balloon out all, it will try the best it > > can. Meaning if nr_pages is 256 and rv is 0, and we only say get 100 of them, > > this particular loop would keep on going forever.. until it got the rest > > of those 156 pages which it might not. > > > > Perhaps rebasing on top of Daniel''s patch and utilize the BP_EAGAIN logic > > to back-off, or just return -EBUSY with the amount returned? > > > > I think adding a parameter to decrease_reservation specifying what GFP_* flags > will be used in allocation might be useful. The correct rebase of my most recent > patch on top of Daniel Kiper''s patch would be to return -ENOMEM when > decrease_reservation returns BP_EAGAIN. Since GFP_BALLOON does not try very hard<nods>> in the memory allocation, this might produce memory errors more often than it > should, whereas the alloc_xenballooned_pages call may wish to just use GFP_HIGHUSER > and risk invoking the OOM killer if required.OK. Looking forward to the patches.> > Would you prefer I submitted all three patches rebased on top of Daniel Kipper''s > R4 patches (or do you have ak git tree with those already included)?#devel/balloon-hotplug (jsut pushed it so it might take 10 minutes for it to show up). _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel