Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xen/balloon: set a mapping for ballooned out pages

Currently ballooned out pages are mapped to 0 and have INVALID_P2M_ENTRY
in the p2m. These ballooned out pages are used to map foreign grants
by gntdev and blkback (see alloc_xenballooned_pages).

Allocate a page per cpu and map all the ballooned out pages to the
corresponding mfn. Set the p2m accordingly. This way reading from a
ballooned out page won't cause a kernel crash (see
http://lists.xen.org/archives/html/xen-devel/2012-12/msg01154.html).

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Reviewed-by: David Vrabel <david.vrabel@citrix.com>
CC: alex@alex.org.uk
CC: dcrisan@flexiant.com
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>

authored by

Stefano Stabellini and committed by
Konrad Rzeszutek Wilk
cd9151e2 73cc4bb0

+69 -3
+66 -3
drivers/xen/balloon.c
··· 38 38 39 39 #define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt 40 40 41 + #include <linux/cpu.h> 41 42 #include <linux/kernel.h> 42 43 #include <linux/sched.h> 43 44 #include <linux/errno.h> ··· 53 52 #include <linux/notifier.h> 54 53 #include <linux/memory.h> 55 54 #include <linux/memory_hotplug.h> 55 + #include <linux/percpu-defs.h> 56 56 57 57 #include <asm/page.h> 58 58 #include <asm/pgalloc.h> ··· 92 90 93 91 /* We increase/decrease in batches which fit in a page */ 94 92 static xen_pfn_t frame_list[PAGE_SIZE / sizeof(unsigned long)]; 93 + static DEFINE_PER_CPU(struct page *, balloon_scratch_page); 94 + 95 95 96 96 /* List of ballooned pages, threaded through the mem_map array. */ 97 97 static LIST_HEAD(ballooned_pages); ··· 416 412 if (xen_pv_domain() && !PageHighMem(page)) { 417 413 ret = HYPERVISOR_update_va_mapping( 418 414 (unsigned long)__va(pfn << PAGE_SHIFT), 419 - __pte_ma(0), 0); 415 + pfn_pte(page_to_pfn(__get_cpu_var(balloon_scratch_page)), 416 + PAGE_KERNEL_RO), 0); 420 417 BUG_ON(ret); 421 418 } 422 419 #endif ··· 430 425 /* No more mappings: invalidate P2M and add to balloon. */ 431 426 for (i = 0; i < nr_pages; i++) { 432 427 pfn = mfn_to_pfn(frame_list[i]); 433 - __set_phys_to_machine(pfn, INVALID_P2M_ENTRY); 428 + __set_phys_to_machine(pfn, 429 + pfn_to_mfn(page_to_pfn(__get_cpu_var(balloon_scratch_page)))); 434 430 balloon_append(pfn_to_page(pfn)); 435 431 } 436 432 ··· 484 478 schedule_delayed_work(&balloon_worker, balloon_stats.schedule_delay * HZ); 485 479 486 480 mutex_unlock(&balloon_mutex); 481 + } 482 + 483 + struct page *get_balloon_scratch_page(void) 484 + { 485 + struct page *ret = get_cpu_var(balloon_scratch_page); 486 + BUG_ON(ret == NULL); 487 + return ret; 488 + } 489 + 490 + void put_balloon_scratch_page(void) 491 + { 492 + put_cpu_var(balloon_scratch_page); 487 493 } 488 494 489 495 /* Resets the Xen limit, sets new target, and kicks off processing. */ ··· 591 573 } 592 574 } 593 575 576 + static int __cpuinit balloon_cpu_notify(struct notifier_block *self, 577 + unsigned long action, void *hcpu) 578 + { 579 + int cpu = (long)hcpu; 580 + switch (action) { 581 + case CPU_UP_PREPARE: 582 + if (per_cpu(balloon_scratch_page, cpu) != NULL) 583 + break; 584 + per_cpu(balloon_scratch_page, cpu) = alloc_page(GFP_KERNEL); 585 + if (per_cpu(balloon_scratch_page, cpu) == NULL) { 586 + pr_warn("Failed to allocate balloon_scratch_page for cpu %d\n", cpu); 587 + return NOTIFY_BAD; 588 + } 589 + break; 590 + default: 591 + break; 592 + } 593 + return NOTIFY_OK; 594 + } 595 + 596 + static struct notifier_block balloon_cpu_notifier __cpuinitdata = { 597 + .notifier_call = balloon_cpu_notify, 598 + }; 599 + 594 600 static int __init balloon_init(void) 595 601 { 596 - int i; 602 + int i, cpu; 597 603 598 604 if (!xen_domain()) 599 605 return -ENODEV; 606 + 607 + for_each_online_cpu(cpu) 608 + { 609 + per_cpu(balloon_scratch_page, cpu) = alloc_page(GFP_KERNEL); 610 + if (per_cpu(balloon_scratch_page, cpu) == NULL) { 611 + pr_warn("Failed to allocate balloon_scratch_page for cpu %d\n", cpu); 612 + return -ENOMEM; 613 + } 614 + } 615 + register_cpu_notifier(&balloon_cpu_notifier); 600 616 601 617 pr_info("Initialising balloon driver\n"); 602 618 ··· 667 615 } 668 616 669 617 subsys_initcall(balloon_init); 618 + 619 + static int __init balloon_clear(void) 620 + { 621 + int cpu; 622 + 623 + for_each_possible_cpu(cpu) 624 + per_cpu(balloon_scratch_page, cpu) = NULL; 625 + 626 + return 0; 627 + } 628 + early_initcall(balloon_clear); 670 629 671 630 MODULE_LICENSE("GPL");
+3
include/xen/balloon.h
··· 29 29 bool highmem); 30 30 void free_xenballooned_pages(int nr_pages, struct page **pages); 31 31 32 + struct page *get_balloon_scratch_page(void); 33 + void put_balloon_scratch_page(void); 34 + 32 35 struct device; 33 36 #ifdef CONFIG_XEN_SELFBALLOONING 34 37 extern int register_xen_selfballooning(struct device *dev);