balloon.c (40095de1f9082f058970b985a96d2fbef43f94f4) | balloon.c (803eb047a28d239809fff1f87274cdaa94e0d8ea) |
---|---|
1/****************************************************************************** | 1/****************************************************************************** |
2 * balloon.c 3 * | |
4 * Xen balloon driver - enables returning/claiming memory to/from Xen. 5 * 6 * Copyright (c) 2003, B Dragovic 7 * Copyright (c) 2003-2004, M Williamson, K Fraser 8 * Copyright (c) 2005 Dan M. Smith, IBM Corporation 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License version 2 --- 16 unchanged lines hidden (view full) --- 28 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 31 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 32 * IN THE SOFTWARE. 33 */ 34 35#include <linux/kernel.h> | 2 * Xen balloon driver - enables returning/claiming memory to/from Xen. 3 * 4 * Copyright (c) 2003, B Dragovic 5 * Copyright (c) 2003-2004, M Williamson, K Fraser 6 * Copyright (c) 2005 Dan M. Smith, IBM Corporation 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License version 2 --- 16 unchanged lines hidden (view full) --- 26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 30 * IN THE SOFTWARE. 31 */ 32 33#include <linux/kernel.h> |
36#include <linux/module.h> | |
37#include <linux/sched.h> 38#include <linux/errno.h> 39#include <linux/mm.h> 40#include <linux/bootmem.h> 41#include <linux/pagemap.h> 42#include <linux/highmem.h> 43#include <linux/mutex.h> 44#include <linux/list.h> | 34#include <linux/sched.h> 35#include <linux/errno.h> 36#include <linux/mm.h> 37#include <linux/bootmem.h> 38#include <linux/pagemap.h> 39#include <linux/highmem.h> 40#include <linux/mutex.h> 41#include <linux/list.h> |
45#include <linux/sysdev.h> | |
46#include <linux/gfp.h> 47 48#include <asm/page.h> 49#include <asm/pgalloc.h> 50#include <asm/pgtable.h> | 42#include <linux/gfp.h> 43 44#include <asm/page.h> 45#include <asm/pgalloc.h> 46#include <asm/pgtable.h> |
51#include <asm/uaccess.h> | |
52#include <asm/tlb.h> 53#include <asm/e820.h> 54 55#include <asm/xen/hypervisor.h> 56#include <asm/xen/hypercall.h> 57 58#include <xen/xen.h> 59#include <xen/interface/xen.h> 60#include <xen/interface/memory.h> | 47#include <asm/tlb.h> 48#include <asm/e820.h> 49 50#include <asm/xen/hypervisor.h> 51#include <asm/xen/hypercall.h> 52 53#include <xen/xen.h> 54#include <xen/interface/xen.h> 55#include <xen/interface/memory.h> |
61#include <xen/xenbus.h> | 56#include <xen/balloon.h> |
62#include <xen/features.h> 63#include <xen/page.h> 64 | 57#include <xen/features.h> 58#include <xen/page.h> 59 |
65#define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10)) 66 67#define BALLOON_CLASS_NAME "xen_memory" 68 | |
69/* 70 * balloon_process() state: 71 * 72 * BP_DONE: done or nothing to do, 73 * BP_EAGAIN: error, go to sleep, 74 * BP_ECANCELED: error, balloon operation canceled. 75 */ 76 77enum bp_state { 78 BP_DONE, 79 BP_EAGAIN, 80 BP_ECANCELED 81}; 82 | 60/* 61 * balloon_process() state: 62 * 63 * BP_DONE: done or nothing to do, 64 * BP_EAGAIN: error, go to sleep, 65 * BP_ECANCELED: error, balloon operation canceled. 66 */ 67 68enum bp_state { 69 BP_DONE, 70 BP_EAGAIN, 71 BP_ECANCELED 72}; 73 |
83#define RETRY_UNLIMITED 0 | |
84 | 74 |
85struct balloon_stats { 86 /* We aim for 'current allocation' == 'target allocation'. */ 87 unsigned long current_pages; 88 unsigned long target_pages; 89 /* Number of pages in high- and low-memory balloons. */ 90 unsigned long balloon_low; 91 unsigned long balloon_high; 92 unsigned long schedule_delay; 93 unsigned long max_schedule_delay; 94 unsigned long retry_count; 95 unsigned long max_retry_count; 96}; 97 | |
98static DEFINE_MUTEX(balloon_mutex); 99 | 75static DEFINE_MUTEX(balloon_mutex); 76 |
100static struct sys_device balloon_sysdev; | 77struct balloon_stats balloon_stats; 78EXPORT_SYMBOL_GPL(balloon_stats); |
101 | 79 |
102static int register_balloon(struct sys_device *sysdev); 103 104static struct balloon_stats balloon_stats; 105 | |
106/* We increase/decrease in batches which fit in a page */ 107static unsigned long frame_list[PAGE_SIZE / sizeof(unsigned long)]; 108 109#ifdef CONFIG_HIGHMEM 110#define inc_totalhigh_pages() (totalhigh_pages++) 111#define dec_totalhigh_pages() (totalhigh_pages--) 112#else 113#define inc_totalhigh_pages() do {} while(0) --- 265 unchanged lines hidden (view full) --- 379 /* Schedule more work if there is some still to be done. */ 380 if (state == BP_EAGAIN) 381 schedule_delayed_work(&balloon_worker, balloon_stats.schedule_delay * HZ); 382 383 mutex_unlock(&balloon_mutex); 384} 385 386/* Resets the Xen limit, sets new target, and kicks off processing. */ | 80/* We increase/decrease in batches which fit in a page */ 81static unsigned long frame_list[PAGE_SIZE / sizeof(unsigned long)]; 82 83#ifdef CONFIG_HIGHMEM 84#define inc_totalhigh_pages() (totalhigh_pages++) 85#define dec_totalhigh_pages() (totalhigh_pages--) 86#else 87#define inc_totalhigh_pages() do {} while(0) --- 265 unchanged lines hidden (view full) --- 353 /* Schedule more work if there is some still to be done. */ 354 if (state == BP_EAGAIN) 355 schedule_delayed_work(&balloon_worker, balloon_stats.schedule_delay * HZ); 356 357 mutex_unlock(&balloon_mutex); 358} 359 360/* Resets the Xen limit, sets new target, and kicks off processing. */ |
387static void balloon_set_new_target(unsigned long target) | 361void balloon_set_new_target(unsigned long target) |
388{ 389 /* No need for lock. Not read-modify-write updates. */ 390 balloon_stats.target_pages = target; 391 schedule_delayed_work(&balloon_worker, 0); 392} | 362{ 363 /* No need for lock. Not read-modify-write updates. */ 364 balloon_stats.target_pages = target; 365 schedule_delayed_work(&balloon_worker, 0); 366} |
367EXPORT_SYMBOL_GPL(balloon_set_new_target); |
|
393 | 368 |
394static struct xenbus_watch target_watch = 395{ 396 .node = "memory/target" 397}; 398 399/* React to a change in the target key */ 400static void watch_target(struct xenbus_watch *watch, 401 const char **vec, unsigned int len) 402{ 403 unsigned long long new_target; 404 int err; 405 406 err = xenbus_scanf(XBT_NIL, "memory", "target", "%llu", &new_target); 407 if (err != 1) { 408 /* This is ok (for domain0 at least) - so just return */ 409 return; 410 } 411 412 /* The given memory/target value is in KiB, so it needs converting to 413 * pages. PAGE_SHIFT converts bytes to pages, hence PAGE_SHIFT - 10. 414 */ 415 balloon_set_new_target(new_target >> (PAGE_SHIFT - 10)); 416} 417 418static int balloon_init_watcher(struct notifier_block *notifier, 419 unsigned long event, 420 void *data) 421{ 422 int err; 423 424 err = register_xenbus_watch(&target_watch); 425 if (err) 426 printk(KERN_ERR "Failed to set balloon watcher\n"); 427 428 return NOTIFY_DONE; 429} 430 431static struct notifier_block xenstore_notifier; 432 | |
433static int __init balloon_init(void) 434{ 435 unsigned long pfn, extra_pfn_end; 436 struct page *page; 437 438 if (!xen_pv_domain()) 439 return -ENODEV; 440 | 369static int __init balloon_init(void) 370{ 371 unsigned long pfn, extra_pfn_end; 372 struct page *page; 373 374 if (!xen_pv_domain()) 375 return -ENODEV; 376 |
441 pr_info("xen_balloon: Initialising balloon driver.\n"); | 377 pr_info("xen/balloon: Initialising balloon driver.\n"); |
442 443 balloon_stats.current_pages = min(xen_start_info->nr_pages, max_pfn); 444 balloon_stats.target_pages = balloon_stats.current_pages; 445 balloon_stats.balloon_low = 0; 446 balloon_stats.balloon_high = 0; 447 448 balloon_stats.schedule_delay = 1; 449 balloon_stats.max_schedule_delay = 32; 450 balloon_stats.retry_count = 1; 451 balloon_stats.max_retry_count = RETRY_UNLIMITED; 452 | 378 379 balloon_stats.current_pages = min(xen_start_info->nr_pages, max_pfn); 380 balloon_stats.target_pages = balloon_stats.current_pages; 381 balloon_stats.balloon_low = 0; 382 balloon_stats.balloon_high = 0; 383 384 balloon_stats.schedule_delay = 1; 385 balloon_stats.max_schedule_delay = 32; 386 balloon_stats.retry_count = 1; 387 balloon_stats.max_retry_count = RETRY_UNLIMITED; 388 |
453 register_balloon(&balloon_sysdev); 454 | |
455 /* 456 * Initialise the balloon with excess memory space. We need 457 * to make sure we don't add memory which doesn't exist or 458 * logically exist. The E820 map can be trimmed to be smaller 459 * than the amount of physical memory due to the mem= command 460 * line parameter. And if this is a 32-bit non-HIGHMEM kernel 461 * on a system with memory which requires highmem to access, 462 * don't try to use it. --- 4 unchanged lines hidden (view full) --- 467 pfn < extra_pfn_end; 468 pfn++) { 469 page = pfn_to_page(pfn); 470 /* totalram_pages doesn't include the boot-time 471 balloon extension, so don't subtract from it. */ 472 __balloon_append(page); 473 } 474 | 389 /* 390 * Initialise the balloon with excess memory space. We need 391 * to make sure we don't add memory which doesn't exist or 392 * logically exist. The E820 map can be trimmed to be smaller 393 * than the amount of physical memory due to the mem= command 394 * line parameter. And if this is a 32-bit non-HIGHMEM kernel 395 * on a system with memory which requires highmem to access, 396 * don't try to use it. --- 4 unchanged lines hidden (view full) --- 401 pfn < extra_pfn_end; 402 pfn++) { 403 page = pfn_to_page(pfn); 404 /* totalram_pages doesn't include the boot-time 405 balloon extension, so don't subtract from it. */ 406 __balloon_append(page); 407 } 408 |
475 target_watch.callback = watch_target; 476 xenstore_notifier.notifier_call = balloon_init_watcher; 477 478 register_xenstore_notifier(&xenstore_notifier); 479 | |
480 return 0; 481} 482 483subsys_initcall(balloon_init); 484 | 409 return 0; 410} 411 412subsys_initcall(balloon_init); 413 |
485static void balloon_exit(void) 486{ 487 /* XXX - release balloon here */ 488 return; 489} 490 491module_exit(balloon_exit); 492 493#define BALLOON_SHOW(name, format, args...) \ 494 static ssize_t show_##name(struct sys_device *dev, \ 495 struct sysdev_attribute *attr, \ 496 char *buf) \ 497 { \ 498 return sprintf(buf, format, ##args); \ 499 } \ 500 static SYSDEV_ATTR(name, S_IRUGO, show_##name, NULL) 501 502BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages)); 503BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_low)); 504BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_high)); 505 506static SYSDEV_ULONG_ATTR(schedule_delay, 0444, balloon_stats.schedule_delay); 507static SYSDEV_ULONG_ATTR(max_schedule_delay, 0644, balloon_stats.max_schedule_delay); 508static SYSDEV_ULONG_ATTR(retry_count, 0444, balloon_stats.retry_count); 509static SYSDEV_ULONG_ATTR(max_retry_count, 0644, balloon_stats.max_retry_count); 510 511static ssize_t show_target_kb(struct sys_device *dev, struct sysdev_attribute *attr, 512 char *buf) 513{ 514 return sprintf(buf, "%lu\n", PAGES2KB(balloon_stats.target_pages)); 515} 516 517static ssize_t store_target_kb(struct sys_device *dev, 518 struct sysdev_attribute *attr, 519 const char *buf, 520 size_t count) 521{ 522 char *endchar; 523 unsigned long long target_bytes; 524 525 if (!capable(CAP_SYS_ADMIN)) 526 return -EPERM; 527 528 target_bytes = simple_strtoull(buf, &endchar, 0) * 1024; 529 530 balloon_set_new_target(target_bytes >> PAGE_SHIFT); 531 532 return count; 533} 534 535static SYSDEV_ATTR(target_kb, S_IRUGO | S_IWUSR, 536 show_target_kb, store_target_kb); 537 538 539static ssize_t show_target(struct sys_device *dev, struct sysdev_attribute *attr, 540 char *buf) 541{ 542 return sprintf(buf, "%llu\n", 543 (unsigned long long)balloon_stats.target_pages 544 << PAGE_SHIFT); 545} 546 547static ssize_t store_target(struct sys_device *dev, 548 struct sysdev_attribute *attr, 549 const char *buf, 550 size_t count) 551{ 552 char *endchar; 553 unsigned long long target_bytes; 554 555 if (!capable(CAP_SYS_ADMIN)) 556 return -EPERM; 557 558 target_bytes = memparse(buf, &endchar); 559 560 balloon_set_new_target(target_bytes >> PAGE_SHIFT); 561 562 return count; 563} 564 565static SYSDEV_ATTR(target, S_IRUGO | S_IWUSR, 566 show_target, store_target); 567 568 569static struct sysdev_attribute *balloon_attrs[] = { 570 &attr_target_kb, 571 &attr_target, 572 &attr_schedule_delay.attr, 573 &attr_max_schedule_delay.attr, 574 &attr_retry_count.attr, 575 &attr_max_retry_count.attr 576}; 577 578static struct attribute *balloon_info_attrs[] = { 579 &attr_current_kb.attr, 580 &attr_low_kb.attr, 581 &attr_high_kb.attr, 582 NULL 583}; 584 585static struct attribute_group balloon_info_group = { 586 .name = "info", 587 .attrs = balloon_info_attrs, 588}; 589 590static struct sysdev_class balloon_sysdev_class = { 591 .name = BALLOON_CLASS_NAME, 592}; 593 594static int register_balloon(struct sys_device *sysdev) 595{ 596 int i, error; 597 598 error = sysdev_class_register(&balloon_sysdev_class); 599 if (error) 600 return error; 601 602 sysdev->id = 0; 603 sysdev->cls = &balloon_sysdev_class; 604 605 error = sysdev_register(sysdev); 606 if (error) { 607 sysdev_class_unregister(&balloon_sysdev_class); 608 return error; 609 } 610 611 for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++) { 612 error = sysdev_create_file(sysdev, balloon_attrs[i]); 613 if (error) 614 goto fail; 615 } 616 617 error = sysfs_create_group(&sysdev->kobj, &balloon_info_group); 618 if (error) 619 goto fail; 620 621 return 0; 622 623 fail: 624 while (--i >= 0) 625 sysdev_remove_file(sysdev, balloon_attrs[i]); 626 sysdev_unregister(sysdev); 627 sysdev_class_unregister(&balloon_sysdev_class); 628 return error; 629} 630 | |
631MODULE_LICENSE("GPL"); | 414MODULE_LICENSE("GPL"); |