/****************************************************************************** * 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 * Copyright (c) 2010 Daniel Kiper * * Memory hotplug support was written by Daniel Kiper. Work on * it was sponsored by Google under Google Summer of Code 2010 * program. Jeremy Fitzhardinge from Citrix was the mentor for * this project. * * 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. */ #define pr_fmt(fmt) … #include <linux/cpu.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/cred.h> #include <linux/errno.h> #include <linux/freezer.h> #include <linux/kthread.h> #include <linux/mm.h> #include <linux/memblock.h> #include <linux/pagemap.h> #include <linux/highmem.h> #include <linux/mutex.h> #include <linux/list.h> #include <linux/gfp.h> #include <linux/notifier.h> #include <linux/memory.h> #include <linux/memory_hotplug.h> #include <linux/percpu-defs.h> #include <linux/slab.h> #include <linux/sysctl.h> #include <linux/moduleparam.h> #include <linux/jiffies.h> #include <asm/page.h> #include <asm/tlb.h> #include <asm/xen/hypervisor.h> #include <asm/xen/hypercall.h> #include <xen/xen.h> #include <xen/interface/xen.h> #include <xen/interface/memory.h> #include <xen/balloon.h> #include <xen/features.h> #include <xen/page.h> #include <xen/mem-reservation.h> #undef MODULE_PARAM_PREFIX #define MODULE_PARAM_PREFIX … static uint __read_mostly balloon_boot_timeout = …; module_param(balloon_boot_timeout, uint, 0444); #ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG static int xen_hotplug_unpopulated; static struct ctl_table balloon_table[] = …; #else #define xen_hotplug_unpopulated … #endif /* * Use one extent per PAGE_SIZE to avoid to break down the page into * multiple frame. */ #define EXTENT_ORDER … /* * balloon_thread() state: * * BP_DONE: done or nothing to do, * BP_WAIT: wait to be rescheduled, * BP_EAGAIN: error, go to sleep, * BP_ECANCELED: error, balloon operation canceled. */ static enum bp_state { … } balloon_state = …; /* Main waiting point for xen-balloon thread. */ static DECLARE_WAIT_QUEUE_HEAD(balloon_thread_wq); static DEFINE_MUTEX(balloon_mutex); struct balloon_stats balloon_stats; EXPORT_SYMBOL_GPL(…); /* We increase/decrease in batches which fit in a page */ static xen_pfn_t frame_list[PAGE_SIZE / sizeof(xen_pfn_t)]; /* List of ballooned pages, threaded through the mem_map array. */ static LIST_HEAD(ballooned_pages); static DECLARE_WAIT_QUEUE_HEAD(balloon_wq); /* 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. */ #define GFP_BALLOON … /* balloon_append: add the given page to the balloon. */ 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(bool require_lowmem) { … } static struct page *balloon_next_page(struct page *page) { … } static void update_schedule(void) { … } #ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG static void release_memory_resource(struct resource *resource) { … } static struct resource *additional_memory_resource(phys_addr_t size) { … } static enum bp_state reserve_additional_memory(void) { … } static void xen_online_page(struct page *page, unsigned int order) { … } static int xen_memory_notifier(struct notifier_block *nb, unsigned long val, void *v) { … } static struct notifier_block xen_memory_nb = …; #else static enum bp_state reserve_additional_memory(void) { balloon_stats.target_pages = balloon_stats.current_pages + balloon_stats.target_unpopulated; return BP_ECANCELED; } #endif /* CONFIG_XEN_BALLOON_MEMORY_HOTPLUG */ static long current_credit(void) { … } static bool balloon_is_inflated(void) { … } static enum bp_state increase_reservation(unsigned long nr_pages) { … } static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp) { … } /* * Stop waiting if either state is BP_DONE and ballooning action is * needed, or if the credit has changed while state is not BP_DONE. */ static bool balloon_thread_cond(long credit) { … } /* * As this is a kthread it is guaranteed to run as a single instance only. * We may of course race updates of the target counts (which are protected * by the balloon lock), or with changes to the Xen hard limit, but we will * recover from these in time. */ static int balloon_thread(void *unused) { … } /* Resets the Xen limit, sets new target, and kicks off processing. */ void balloon_set_new_target(unsigned long target) { … } EXPORT_SYMBOL_GPL(…); static int add_ballooned_pages(unsigned int nr_pages) { … } /** * xen_alloc_ballooned_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 xen_alloc_ballooned_pages(unsigned int nr_pages, struct page **pages) { … } EXPORT_SYMBOL(…); /** * xen_free_ballooned_pages - return pages retrieved with get_ballooned_pages * @nr_pages: Number of pages * @pages: pages to return */ void xen_free_ballooned_pages(unsigned int nr_pages, struct page **pages) { … } EXPORT_SYMBOL(…); static void __init balloon_add_regions(void) { … } static int __init balloon_init(void) { … } subsys_initcall(balloon_init); static int __init balloon_wait_finish(void) { … } late_initcall_sync(balloon_wait_finish);