cmm.c (1ef2f06b71792c2efaa4fb4aef8f1fc2a115ee1f) | cmm.c (fe030c9b85e6783bc52fe86449c0a4b8aa16c753) |
---|---|
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Collaborative memory management interface. 4 * 5 * Copyright (C) 2008 IBM Corporation 6 * Author(s): Brian King (brking@linux.vnet.ibm.com), 7 */ 8 --- 5 unchanged lines hidden (view full) --- 14#include <linux/kthread.h> 15#include <linux/module.h> 16#include <linux/oom.h> 17#include <linux/reboot.h> 18#include <linux/sched.h> 19#include <linux/stringify.h> 20#include <linux/swap.h> 21#include <linux/device.h> | 1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Collaborative memory management interface. 4 * 5 * Copyright (C) 2008 IBM Corporation 6 * Author(s): Brian King (brking@linux.vnet.ibm.com), 7 */ 8 --- 5 unchanged lines hidden (view full) --- 14#include <linux/kthread.h> 15#include <linux/module.h> 16#include <linux/oom.h> 17#include <linux/reboot.h> 18#include <linux/sched.h> 19#include <linux/stringify.h> 20#include <linux/swap.h> 21#include <linux/device.h> |
22#include <linux/mount.h> 23#include <linux/pseudo_fs.h> 24#include <linux/magic.h> 25#include <linux/balloon_compaction.h> |
|
22#include <asm/firmware.h> 23#include <asm/hvcall.h> 24#include <asm/mmu.h> 25#include <asm/pgalloc.h> 26#include <linux/uaccess.h> 27#include <linux/memory.h> 28#include <asm/plpar_wrappers.h> 29 --- 42 unchanged lines hidden (view full) --- 72 "[Default=" __stringify(CMM_DEBUG) "]"); 73 74#define cmm_dbg(...) if (cmm_debug) { printk(KERN_INFO "cmm: "__VA_ARGS__); } 75 76static atomic_long_t loaned_pages; 77static unsigned long loaned_pages_target; 78static unsigned long oom_freed_pages; 79 | 26#include <asm/firmware.h> 27#include <asm/hvcall.h> 28#include <asm/mmu.h> 29#include <asm/pgalloc.h> 30#include <linux/uaccess.h> 31#include <linux/memory.h> 32#include <asm/plpar_wrappers.h> 33 --- 42 unchanged lines hidden (view full) --- 76 "[Default=" __stringify(CMM_DEBUG) "]"); 77 78#define cmm_dbg(...) if (cmm_debug) { printk(KERN_INFO "cmm: "__VA_ARGS__); } 79 80static atomic_long_t loaned_pages; 81static unsigned long loaned_pages_target; 82static unsigned long oom_freed_pages; 83 |
80static LIST_HEAD(cmm_page_list); 81static DEFINE_SPINLOCK(cmm_lock); 82 | |
83static DEFINE_MUTEX(hotplug_mutex); 84static int hotplug_occurred; /* protected by the hotplug mutex */ 85 86static struct task_struct *cmm_thread_ptr; | 84static DEFINE_MUTEX(hotplug_mutex); 85static int hotplug_occurred; /* protected by the hotplug mutex */ 86 87static struct task_struct *cmm_thread_ptr; |
88static struct balloon_dev_info b_dev_info; |
|
87 88static long plpar_page_set_loaned(struct page *page) 89{ 90 const unsigned long vpa = page_to_phys(page); 91 unsigned long cmo_page_sz = cmo_get_page_size(); 92 long rc = 0; 93 int i; 94 --- 49 unchanged lines hidden (view full) --- 144 } else { 145 break; 146 } 147 148 page = alloc_page(GFP_NOIO | __GFP_NOWARN | __GFP_NORETRY | 149 __GFP_NOMEMALLOC); 150 if (!page) 151 break; | 89 90static long plpar_page_set_loaned(struct page *page) 91{ 92 const unsigned long vpa = page_to_phys(page); 93 unsigned long cmo_page_sz = cmo_get_page_size(); 94 long rc = 0; 95 int i; 96 --- 49 unchanged lines hidden (view full) --- 146 } else { 147 break; 148 } 149 150 page = alloc_page(GFP_NOIO | __GFP_NOWARN | __GFP_NORETRY | 151 __GFP_NOMEMALLOC); 152 if (!page) 153 break; |
152 spin_lock(&cmm_lock); | |
153 rc = plpar_page_set_loaned(page); 154 if (rc) { 155 pr_err("%s: Can not set page to loaned. rc=%ld\n", __func__, rc); | 154 rc = plpar_page_set_loaned(page); 155 if (rc) { 156 pr_err("%s: Can not set page to loaned. rc=%ld\n", __func__, rc); |
156 spin_unlock(&cmm_lock); | |
157 __free_page(page); 158 break; 159 } 160 | 157 __free_page(page); 158 break; 159 } 160 |
161 list_add(&page->lru, &cmm_page_list); | 161 balloon_page_enqueue(&b_dev_info, page); |
162 atomic_long_inc(&loaned_pages); 163 adjust_managed_page_count(page, -1); | 162 atomic_long_inc(&loaned_pages); 163 adjust_managed_page_count(page, -1); |
164 spin_unlock(&cmm_lock); | |
165 nr--; 166 } 167 168 cmm_dbg("End request with %ld pages unfulfilled\n", nr); 169 return nr; 170} 171 172/** 173 * cmm_free_pages - Free pages and mark them as active 174 * @nr: number of pages to free 175 * 176 * Return value: 177 * number of pages requested to be freed which were not 178 **/ 179static long cmm_free_pages(long nr) 180{ | 164 nr--; 165 } 166 167 cmm_dbg("End request with %ld pages unfulfilled\n", nr); 168 return nr; 169} 170 171/** 172 * cmm_free_pages - Free pages and mark them as active 173 * @nr: number of pages to free 174 * 175 * Return value: 176 * number of pages requested to be freed which were not 177 **/ 178static long cmm_free_pages(long nr) 179{ |
181 struct page *page, *tmp; | 180 struct page *page; |
182 183 cmm_dbg("Begin free of %ld pages.\n", nr); | 181 182 cmm_dbg("Begin free of %ld pages.\n", nr); |
184 spin_lock(&cmm_lock); 185 list_for_each_entry_safe(page, tmp, &cmm_page_list, lru) { 186 if (!nr) | 183 while (nr) { 184 page = balloon_page_dequeue(&b_dev_info); 185 if (!page) |
187 break; 188 plpar_page_set_active(page); | 186 break; 187 plpar_page_set_active(page); |
189 list_del(&page->lru); | |
190 adjust_managed_page_count(page, 1); 191 __free_page(page); 192 atomic_long_dec(&loaned_pages); 193 nr--; 194 } | 188 adjust_managed_page_count(page, 1); 189 __free_page(page); 190 atomic_long_dec(&loaned_pages); 191 nr--; 192 } |
195 spin_unlock(&cmm_lock); | |
196 cmm_dbg("End request with %ld pages unfulfilled\n", nr); 197 return nr; 198} 199 200/** 201 * cmm_oom_notify - OOM notifier 202 * @self: notifier block struct 203 * @dummy: not used --- 275 unchanged lines hidden (view full) --- 479 return notifier_from_errno(ret); 480} 481 482static struct notifier_block cmm_mem_nb = { 483 .notifier_call = cmm_memory_cb, 484 .priority = CMM_MEM_HOTPLUG_PRI 485}; 486 | 193 cmm_dbg("End request with %ld pages unfulfilled\n", nr); 194 return nr; 195} 196 197/** 198 * cmm_oom_notify - OOM notifier 199 * @self: notifier block struct 200 * @dummy: not used --- 275 unchanged lines hidden (view full) --- 476 return notifier_from_errno(ret); 477} 478 479static struct notifier_block cmm_mem_nb = { 480 .notifier_call = cmm_memory_cb, 481 .priority = CMM_MEM_HOTPLUG_PRI 482}; 483 |
484#ifdef CONFIG_BALLOON_COMPACTION 485static struct vfsmount *balloon_mnt; 486 487static int cmm_init_fs_context(struct fs_context *fc) 488{ 489 return init_pseudo(fc, PPC_CMM_MAGIC) ? 0 : -ENOMEM; 490} 491 492static struct file_system_type balloon_fs = { 493 .name = "ppc-cmm", 494 .init_fs_context = cmm_init_fs_context, 495 .kill_sb = kill_anon_super, 496}; 497 498static int cmm_migratepage(struct balloon_dev_info *b_dev_info, 499 struct page *newpage, struct page *page, 500 enum migrate_mode mode) 501{ 502 unsigned long flags; 503 504 /* 505 * loan/"inflate" the newpage first. 506 * 507 * We might race against the cmm_thread who might discover after our 508 * loan request that another page is to be unloaned. However, once 509 * the cmm_thread runs again later, this error will automatically 510 * be corrected. 511 */ 512 if (plpar_page_set_loaned(newpage)) { 513 /* Unlikely, but possible. Tell the caller not to retry now. */ 514 pr_err_ratelimited("%s: Cannot set page to loaned.", __func__); 515 return -EBUSY; 516 } 517 518 /* balloon page list reference */ 519 get_page(newpage); 520 521 spin_lock_irqsave(&b_dev_info->pages_lock, flags); 522 balloon_page_insert(b_dev_info, newpage); 523 balloon_page_delete(page); 524 b_dev_info->isolated_pages--; 525 spin_unlock_irqrestore(&b_dev_info->pages_lock, flags); 526 527 /* 528 * activate/"deflate" the old page. We ignore any errors just like the 529 * other callers. 530 */ 531 plpar_page_set_active(page); 532 533 /* balloon page list reference */ 534 put_page(page); 535 536 return MIGRATEPAGE_SUCCESS; 537} 538 539static int cmm_balloon_compaction_init(void) 540{ 541 int rc; 542 543 balloon_devinfo_init(&b_dev_info); 544 b_dev_info.migratepage = cmm_migratepage; 545 546 balloon_mnt = kern_mount(&balloon_fs); 547 if (IS_ERR(balloon_mnt)) { 548 rc = PTR_ERR(balloon_mnt); 549 balloon_mnt = NULL; 550 return rc; 551 } 552 553 b_dev_info.inode = alloc_anon_inode(balloon_mnt->mnt_sb); 554 if (IS_ERR(b_dev_info.inode)) { 555 rc = PTR_ERR(b_dev_info.inode); 556 b_dev_info.inode = NULL; 557 kern_unmount(balloon_mnt); 558 balloon_mnt = NULL; 559 return rc; 560 } 561 562 b_dev_info.inode->i_mapping->a_ops = &balloon_aops; 563 return 0; 564} 565static void cmm_balloon_compaction_deinit(void) 566{ 567 if (b_dev_info.inode) 568 iput(b_dev_info.inode); 569 b_dev_info.inode = NULL; 570 kern_unmount(balloon_mnt); 571 balloon_mnt = NULL; 572} 573#else /* CONFIG_BALLOON_COMPACTION */ 574static int cmm_balloon_compaction_init(void) 575{ 576 return 0; 577} 578 579static void cmm_balloon_compaction_deinit(void) 580{ 581} 582#endif /* CONFIG_BALLOON_COMPACTION */ 583 |
|
487/** 488 * cmm_init - Module initialization 489 * 490 * Return value: 491 * 0 on success / other on failure 492 **/ 493static int cmm_init(void) 494{ 495 int rc; 496 497 if (!firmware_has_feature(FW_FEATURE_CMO)) 498 return -EOPNOTSUPP; 499 | 584/** 585 * cmm_init - Module initialization 586 * 587 * Return value: 588 * 0 on success / other on failure 589 **/ 590static int cmm_init(void) 591{ 592 int rc; 593 594 if (!firmware_has_feature(FW_FEATURE_CMO)) 595 return -EOPNOTSUPP; 596 |
500 if ((rc = register_oom_notifier(&cmm_oom_nb)) < 0) | 597 rc = cmm_balloon_compaction_init(); 598 if (rc) |
501 return rc; 502 | 599 return rc; 600 |
601 rc = register_oom_notifier(&cmm_oom_nb); 602 if (rc < 0) 603 goto out_balloon_compaction; 604 |
|
503 if ((rc = register_reboot_notifier(&cmm_reboot_nb))) 504 goto out_oom_notifier; 505 506 if ((rc = cmm_sysfs_register(&cmm_dev))) 507 goto out_reboot_notifier; 508 509 rc = register_memory_notifier(&cmm_mem_nb); 510 if (rc) --- 11 unchanged lines hidden (view full) --- 522 return 0; 523out_unregister_notifier: 524 unregister_memory_notifier(&cmm_mem_nb); 525 cmm_unregister_sysfs(&cmm_dev); 526out_reboot_notifier: 527 unregister_reboot_notifier(&cmm_reboot_nb); 528out_oom_notifier: 529 unregister_oom_notifier(&cmm_oom_nb); | 605 if ((rc = register_reboot_notifier(&cmm_reboot_nb))) 606 goto out_oom_notifier; 607 608 if ((rc = cmm_sysfs_register(&cmm_dev))) 609 goto out_reboot_notifier; 610 611 rc = register_memory_notifier(&cmm_mem_nb); 612 if (rc) --- 11 unchanged lines hidden (view full) --- 624 return 0; 625out_unregister_notifier: 626 unregister_memory_notifier(&cmm_mem_nb); 627 cmm_unregister_sysfs(&cmm_dev); 628out_reboot_notifier: 629 unregister_reboot_notifier(&cmm_reboot_nb); 630out_oom_notifier: 631 unregister_oom_notifier(&cmm_oom_nb); |
632out_balloon_compaction: 633 cmm_balloon_compaction_deinit(); |
|
530 return rc; 531} 532 533/** 534 * cmm_exit - Module exit 535 * 536 * Return value: 537 * nothing 538 **/ 539static void cmm_exit(void) 540{ 541 if (cmm_thread_ptr) 542 kthread_stop(cmm_thread_ptr); 543 unregister_oom_notifier(&cmm_oom_nb); 544 unregister_reboot_notifier(&cmm_reboot_nb); 545 unregister_memory_notifier(&cmm_mem_nb); 546 cmm_free_pages(atomic_long_read(&loaned_pages)); 547 cmm_unregister_sysfs(&cmm_dev); | 634 return rc; 635} 636 637/** 638 * cmm_exit - Module exit 639 * 640 * Return value: 641 * nothing 642 **/ 643static void cmm_exit(void) 644{ 645 if (cmm_thread_ptr) 646 kthread_stop(cmm_thread_ptr); 647 unregister_oom_notifier(&cmm_oom_nb); 648 unregister_reboot_notifier(&cmm_reboot_nb); 649 unregister_memory_notifier(&cmm_mem_nb); 650 cmm_free_pages(atomic_long_read(&loaned_pages)); 651 cmm_unregister_sysfs(&cmm_dev); |
652 cmm_balloon_compaction_deinit(); |
|
548} 549 550/** 551 * cmm_set_disable - Disable/Enable CMM 552 * 553 * Return value: 554 * 0 on success / other on failure 555 **/ --- 29 unchanged lines hidden --- | 653} 654 655/** 656 * cmm_set_disable - Disable/Enable CMM 657 * 658 * Return value: 659 * 0 on success / other on failure 660 **/ --- 29 unchanged lines hidden --- |