diff options
Diffstat (limited to 'drivers/xen/balloon.c')
| -rw-r--r-- | drivers/xen/balloon.c | 175 |
1 files changed, 15 insertions, 160 deletions
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 2e15da5459cf..8c83abc73400 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c | |||
| @@ -53,7 +53,6 @@ | |||
| 53 | #include <asm/tlb.h> | 53 | #include <asm/tlb.h> |
| 54 | 54 | ||
| 55 | #include <xen/interface/memory.h> | 55 | #include <xen/interface/memory.h> |
| 56 | #include <xen/balloon.h> | ||
| 57 | #include <xen/xenbus.h> | 56 | #include <xen/xenbus.h> |
| 58 | #include <xen/features.h> | 57 | #include <xen/features.h> |
| 59 | #include <xen/page.h> | 58 | #include <xen/page.h> |
| @@ -226,9 +225,8 @@ static int increase_reservation(unsigned long nr_pages) | |||
| 226 | } | 225 | } |
| 227 | 226 | ||
| 228 | set_xen_guest_handle(reservation.extent_start, frame_list); | 227 | set_xen_guest_handle(reservation.extent_start, frame_list); |
| 229 | reservation.nr_extents = nr_pages; | 228 | reservation.nr_extents = nr_pages; |
| 230 | rc = HYPERVISOR_memory_op( | 229 | rc = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation); |
| 231 | XENMEM_populate_physmap, &reservation); | ||
| 232 | if (rc < nr_pages) { | 230 | if (rc < nr_pages) { |
| 233 | if (rc > 0) { | 231 | if (rc > 0) { |
| 234 | int ret; | 232 | int ret; |
| @@ -236,7 +234,7 @@ static int increase_reservation(unsigned long nr_pages) | |||
| 236 | /* We hit the Xen hard limit: reprobe. */ | 234 | /* We hit the Xen hard limit: reprobe. */ |
| 237 | reservation.nr_extents = rc; | 235 | reservation.nr_extents = rc; |
| 238 | ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, | 236 | ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, |
| 239 | &reservation); | 237 | &reservation); |
| 240 | BUG_ON(ret != rc); | 238 | BUG_ON(ret != rc); |
| 241 | } | 239 | } |
| 242 | if (rc >= 0) | 240 | if (rc >= 0) |
| @@ -420,7 +418,7 @@ static int __init balloon_init(void) | |||
| 420 | unsigned long pfn; | 418 | unsigned long pfn; |
| 421 | struct page *page; | 419 | struct page *page; |
| 422 | 420 | ||
| 423 | if (!is_running_on_xen()) | 421 | if (!xen_pv_domain()) |
| 424 | return -ENODEV; | 422 | return -ENODEV; |
| 425 | 423 | ||
| 426 | pr_info("xen_balloon: Initialising balloon driver.\n"); | 424 | pr_info("xen_balloon: Initialising balloon driver.\n"); |
| @@ -464,136 +462,13 @@ static void balloon_exit(void) | |||
| 464 | 462 | ||
| 465 | module_exit(balloon_exit); | 463 | module_exit(balloon_exit); |
| 466 | 464 | ||
| 467 | static void balloon_update_driver_allowance(long delta) | 465 | #define BALLOON_SHOW(name, format, args...) \ |
| 468 | { | 466 | static ssize_t show_##name(struct sys_device *dev, \ |
| 469 | unsigned long flags; | 467 | struct sysdev_attribute *attr, \ |
| 470 | 468 | char *buf) \ | |
| 471 | spin_lock_irqsave(&balloon_lock, flags); | 469 | { \ |
| 472 | balloon_stats.driver_pages += delta; | 470 | return sprintf(buf, format, ##args); \ |
| 473 | spin_unlock_irqrestore(&balloon_lock, flags); | 471 | } \ |
| 474 | } | ||
| 475 | |||
| 476 | static int dealloc_pte_fn( | ||
| 477 | pte_t *pte, struct page *pmd_page, unsigned long addr, void *data) | ||
| 478 | { | ||
| 479 | unsigned long mfn = pte_mfn(*pte); | ||
| 480 | int ret; | ||
| 481 | struct xen_memory_reservation reservation = { | ||
| 482 | .nr_extents = 1, | ||
| 483 | .extent_order = 0, | ||
| 484 | .domid = DOMID_SELF | ||
| 485 | }; | ||
| 486 | set_xen_guest_handle(reservation.extent_start, &mfn); | ||
| 487 | set_pte_at(&init_mm, addr, pte, __pte_ma(0ull)); | ||
| 488 | set_phys_to_machine(__pa(addr) >> PAGE_SHIFT, INVALID_P2M_ENTRY); | ||
| 489 | ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation); | ||
| 490 | BUG_ON(ret != 1); | ||
| 491 | return 0; | ||
| 492 | } | ||
| 493 | |||
| 494 | static struct page **alloc_empty_pages_and_pagevec(int nr_pages) | ||
| 495 | { | ||
| 496 | unsigned long vaddr, flags; | ||
| 497 | struct page *page, **pagevec; | ||
| 498 | int i, ret; | ||
| 499 | |||
| 500 | pagevec = kmalloc(sizeof(page) * nr_pages, GFP_KERNEL); | ||
| 501 | if (pagevec == NULL) | ||
| 502 | return NULL; | ||
| 503 | |||
| 504 | for (i = 0; i < nr_pages; i++) { | ||
| 505 | page = pagevec[i] = alloc_page(GFP_KERNEL); | ||
| 506 | if (page == NULL) | ||
| 507 | goto err; | ||
| 508 | |||
| 509 | vaddr = (unsigned long)page_address(page); | ||
| 510 | |||
| 511 | scrub_page(page); | ||
| 512 | |||
| 513 | spin_lock_irqsave(&balloon_lock, flags); | ||
| 514 | |||
| 515 | if (xen_feature(XENFEAT_auto_translated_physmap)) { | ||
| 516 | unsigned long gmfn = page_to_pfn(page); | ||
| 517 | struct xen_memory_reservation reservation = { | ||
| 518 | .nr_extents = 1, | ||
| 519 | .extent_order = 0, | ||
| 520 | .domid = DOMID_SELF | ||
| 521 | }; | ||
| 522 | set_xen_guest_handle(reservation.extent_start, &gmfn); | ||
| 523 | ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, | ||
| 524 | &reservation); | ||
| 525 | if (ret == 1) | ||
| 526 | ret = 0; /* success */ | ||
| 527 | } else { | ||
| 528 | ret = apply_to_page_range(&init_mm, vaddr, PAGE_SIZE, | ||
| 529 | dealloc_pte_fn, NULL); | ||
| 530 | } | ||
| 531 | |||
| 532 | if (ret != 0) { | ||
| 533 | spin_unlock_irqrestore(&balloon_lock, flags); | ||
| 534 | __free_page(page); | ||
| 535 | goto err; | ||
| 536 | } | ||
| 537 | |||
| 538 | totalram_pages = --balloon_stats.current_pages; | ||
| 539 | |||
| 540 | spin_unlock_irqrestore(&balloon_lock, flags); | ||
| 541 | } | ||
| 542 | |||
| 543 | out: | ||
| 544 | schedule_work(&balloon_worker); | ||
| 545 | flush_tlb_all(); | ||
| 546 | return pagevec; | ||
| 547 | |||
| 548 | err: | ||
| 549 | spin_lock_irqsave(&balloon_lock, flags); | ||
| 550 | while (--i >= 0) | ||
| 551 | balloon_append(pagevec[i]); | ||
| 552 | spin_unlock_irqrestore(&balloon_lock, flags); | ||
| 553 | kfree(pagevec); | ||
| 554 | pagevec = NULL; | ||
| 555 | goto out; | ||
| 556 | } | ||
| 557 | |||
| 558 | static void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages) | ||
| 559 | { | ||
| 560 | unsigned long flags; | ||
| 561 | int i; | ||
| 562 | |||
| 563 | if (pagevec == NULL) | ||
| 564 | return; | ||
| 565 | |||
| 566 | spin_lock_irqsave(&balloon_lock, flags); | ||
| 567 | for (i = 0; i < nr_pages; i++) { | ||
| 568 | BUG_ON(page_count(pagevec[i]) != 1); | ||
| 569 | balloon_append(pagevec[i]); | ||
| 570 | } | ||
| 571 | spin_unlock_irqrestore(&balloon_lock, flags); | ||
| 572 | |||
| 573 | kfree(pagevec); | ||
| 574 | |||
| 575 | schedule_work(&balloon_worker); | ||
| 576 | } | ||
| 577 | |||
| 578 | static void balloon_release_driver_page(struct page *page) | ||
| 579 | { | ||
| 580 | unsigned long flags; | ||
| 581 | |||
| 582 | spin_lock_irqsave(&balloon_lock, flags); | ||
| 583 | balloon_append(page); | ||
| 584 | balloon_stats.driver_pages--; | ||
| 585 | spin_unlock_irqrestore(&balloon_lock, flags); | ||
| 586 | |||
| 587 | schedule_work(&balloon_worker); | ||
| 588 | } | ||
| 589 | |||
| 590 | |||
| 591 | #define BALLOON_SHOW(name, format, args...) \ | ||
| 592 | static ssize_t show_##name(struct sys_device *dev, \ | ||
| 593 | char *buf) \ | ||
| 594 | { \ | ||
| 595 | return sprintf(buf, format, ##args); \ | ||
| 596 | } \ | ||
| 597 | static SYSDEV_ATTR(name, S_IRUGO, show_##name, NULL) | 472 | static SYSDEV_ATTR(name, S_IRUGO, show_##name, NULL) |
| 598 | 473 | ||
| 599 | BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages)); | 474 | BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages)); |
| @@ -604,7 +479,8 @@ BALLOON_SHOW(hard_limit_kb, | |||
| 604 | (balloon_stats.hard_limit!=~0UL) ? PAGES2KB(balloon_stats.hard_limit) : 0); | 479 | (balloon_stats.hard_limit!=~0UL) ? PAGES2KB(balloon_stats.hard_limit) : 0); |
| 605 | BALLOON_SHOW(driver_kb, "%lu\n", PAGES2KB(balloon_stats.driver_pages)); | 480 | BALLOON_SHOW(driver_kb, "%lu\n", PAGES2KB(balloon_stats.driver_pages)); |
| 606 | 481 | ||
| 607 | static ssize_t show_target_kb(struct sys_device *dev, char *buf) | 482 | static ssize_t show_target_kb(struct sys_device *dev, struct sysdev_attribute *attr, |
| 483 | char *buf) | ||
| 608 | { | 484 | { |
| 609 | return sprintf(buf, "%lu\n", PAGES2KB(balloon_stats.target_pages)); | 485 | return sprintf(buf, "%lu\n", PAGES2KB(balloon_stats.target_pages)); |
| 610 | } | 486 | } |
| @@ -614,19 +490,14 @@ static ssize_t store_target_kb(struct sys_device *dev, | |||
| 614 | const char *buf, | 490 | const char *buf, |
| 615 | size_t count) | 491 | size_t count) |
| 616 | { | 492 | { |
| 617 | char memstring[64], *endchar; | 493 | char *endchar; |
| 618 | unsigned long long target_bytes; | 494 | unsigned long long target_bytes; |
| 619 | 495 | ||
| 620 | if (!capable(CAP_SYS_ADMIN)) | 496 | if (!capable(CAP_SYS_ADMIN)) |
| 621 | return -EPERM; | 497 | return -EPERM; |
| 622 | 498 | ||
| 623 | if (count <= 1) | 499 | target_bytes = memparse(buf, &endchar); |
| 624 | return -EBADMSG; /* runt */ | ||
| 625 | if (count > sizeof(memstring)) | ||
| 626 | return -EFBIG; /* too long */ | ||
| 627 | strcpy(memstring, buf); | ||
| 628 | 500 | ||
| 629 | target_bytes = memparse(memstring, &endchar); | ||
| 630 | balloon_set_new_target(target_bytes >> PAGE_SHIFT); | 501 | balloon_set_new_target(target_bytes >> PAGE_SHIFT); |
| 631 | 502 | ||
| 632 | return count; | 503 | return count; |
| @@ -694,20 +565,4 @@ static int register_balloon(struct sys_device *sysdev) | |||
| 694 | return error; | 565 | return error; |
| 695 | } | 566 | } |
| 696 | 567 | ||
| 697 | static void unregister_balloon(struct sys_device *sysdev) | ||
| 698 | { | ||
| 699 | int i; | ||
| 700 | |||
| 701 | sysfs_remove_group(&sysdev->kobj, &balloon_info_group); | ||
| 702 | for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++) | ||
| 703 | sysdev_remove_file(sysdev, balloon_attrs[i]); | ||
| 704 | sysdev_unregister(sysdev); | ||
| 705 | sysdev_class_unregister(&balloon_sysdev_class); | ||
| 706 | } | ||
| 707 | |||
| 708 | static void balloon_sysfs_exit(void) | ||
| 709 | { | ||
| 710 | unregister_balloon(&balloon_sysdev); | ||
| 711 | } | ||
| 712 | |||
| 713 | MODULE_LICENSE("GPL"); | 568 | MODULE_LICENSE("GPL"); |
