diff options
-rw-r--r-- | drivers/xen/balloon.c | 73 |
1 files changed, 53 insertions, 20 deletions
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index c79329fcfa78..095bb6789731 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c | |||
@@ -54,6 +54,7 @@ | |||
54 | #include <linux/memory.h> | 54 | #include <linux/memory.h> |
55 | #include <linux/memory_hotplug.h> | 55 | #include <linux/memory_hotplug.h> |
56 | #include <linux/percpu-defs.h> | 56 | #include <linux/percpu-defs.h> |
57 | #include <linux/slab.h> | ||
57 | 58 | ||
58 | #include <asm/page.h> | 59 | #include <asm/page.h> |
59 | #include <asm/pgalloc.h> | 60 | #include <asm/pgalloc.h> |
@@ -208,26 +209,56 @@ static bool balloon_is_inflated(void) | |||
208 | return false; | 209 | return false; |
209 | } | 210 | } |
210 | 211 | ||
211 | /* | 212 | static struct resource *additional_memory_resource(phys_addr_t size) |
212 | * reserve_additional_memory() adds memory region of size >= credit above | 213 | { |
213 | * max_pfn. New region is section aligned and size is modified to be multiple | 214 | struct resource *res; |
214 | * of section size. Those features allow optimal use of address space and | 215 | int ret; |
215 | * establish proper alignment when this function is called first time after | 216 | |
216 | * boot (last section not fully populated at boot time contains unused memory | 217 | res = kzalloc(sizeof(*res), GFP_KERNEL); |
217 | * pages with PG_reserved bit not set; online_pages_range() does not allow page | 218 | if (!res) |
218 | * onlining in whole range if first onlined page does not have PG_reserved | 219 | return NULL; |
219 | * bit set). Real size of added memory is established at page onlining stage. | 220 | |
220 | */ | 221 | res->name = "System RAM"; |
222 | res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; | ||
223 | |||
224 | ret = allocate_resource(&iomem_resource, res, | ||
225 | size, 0, -1, | ||
226 | PAGES_PER_SECTION * PAGE_SIZE, NULL, NULL); | ||
227 | if (ret < 0) { | ||
228 | pr_err("Cannot allocate new System RAM resource\n"); | ||
229 | kfree(res); | ||
230 | return NULL; | ||
231 | } | ||
232 | |||
233 | return res; | ||
234 | } | ||
235 | |||
236 | static void release_memory_resource(struct resource *resource) | ||
237 | { | ||
238 | if (!resource) | ||
239 | return; | ||
240 | |||
241 | /* | ||
242 | * No need to reset region to identity mapped since we now | ||
243 | * know that no I/O can be in this region | ||
244 | */ | ||
245 | release_resource(resource); | ||
246 | kfree(resource); | ||
247 | } | ||
221 | 248 | ||
222 | static enum bp_state reserve_additional_memory(long credit) | 249 | static enum bp_state reserve_additional_memory(long credit) |
223 | { | 250 | { |
251 | struct resource *resource; | ||
224 | int nid, rc; | 252 | int nid, rc; |
225 | u64 hotplug_start_paddr; | 253 | unsigned long balloon_hotplug; |
226 | unsigned long balloon_hotplug = credit; | 254 | |
255 | balloon_hotplug = round_up(credit, PAGES_PER_SECTION); | ||
256 | |||
257 | resource = additional_memory_resource(balloon_hotplug * PAGE_SIZE); | ||
258 | if (!resource) | ||
259 | goto err; | ||
227 | 260 | ||
228 | hotplug_start_paddr = PFN_PHYS(SECTION_ALIGN_UP(max_pfn)); | 261 | nid = memory_add_physaddr_to_nid(resource->start); |
229 | balloon_hotplug = round_up(balloon_hotplug, PAGES_PER_SECTION); | ||
230 | nid = memory_add_physaddr_to_nid(hotplug_start_paddr); | ||
231 | 262 | ||
232 | #ifdef CONFIG_XEN_HAVE_PVMMU | 263 | #ifdef CONFIG_XEN_HAVE_PVMMU |
233 | /* | 264 | /* |
@@ -242,21 +273,20 @@ static enum bp_state reserve_additional_memory(long credit) | |||
242 | if (!xen_feature(XENFEAT_auto_translated_physmap)) { | 273 | if (!xen_feature(XENFEAT_auto_translated_physmap)) { |
243 | unsigned long pfn, i; | 274 | unsigned long pfn, i; |
244 | 275 | ||
245 | pfn = PFN_DOWN(hotplug_start_paddr); | 276 | pfn = PFN_DOWN(resource->start); |
246 | for (i = 0; i < balloon_hotplug; i++) { | 277 | for (i = 0; i < balloon_hotplug; i++) { |
247 | if (!set_phys_to_machine(pfn + i, INVALID_P2M_ENTRY)) { | 278 | if (!set_phys_to_machine(pfn + i, INVALID_P2M_ENTRY)) { |
248 | pr_warn("set_phys_to_machine() failed, no memory added\n"); | 279 | pr_warn("set_phys_to_machine() failed, no memory added\n"); |
249 | return BP_ECANCELED; | 280 | goto err; |
250 | } | 281 | } |
251 | } | 282 | } |
252 | } | 283 | } |
253 | #endif | 284 | #endif |
254 | 285 | ||
255 | rc = add_memory(nid, hotplug_start_paddr, balloon_hotplug << PAGE_SHIFT); | 286 | rc = add_memory_resource(nid, resource); |
256 | |||
257 | if (rc) { | 287 | if (rc) { |
258 | pr_warn("Cannot add additional memory (%i)\n", rc); | 288 | pr_warn("Cannot add additional memory (%i)\n", rc); |
259 | return BP_ECANCELED; | 289 | goto err; |
260 | } | 290 | } |
261 | 291 | ||
262 | balloon_hotplug -= credit; | 292 | balloon_hotplug -= credit; |
@@ -265,6 +295,9 @@ static enum bp_state reserve_additional_memory(long credit) | |||
265 | balloon_stats.balloon_hotplug = balloon_hotplug; | 295 | balloon_stats.balloon_hotplug = balloon_hotplug; |
266 | 296 | ||
267 | return BP_DONE; | 297 | return BP_DONE; |
298 | err: | ||
299 | release_memory_resource(resource); | ||
300 | return BP_ECANCELED; | ||
268 | } | 301 | } |
269 | 302 | ||
270 | static void xen_online_page(struct page *page) | 303 | static void xen_online_page(struct page *page) |