When switching to balloon compaction, we want to drop the cmm_lock and completely rely on the balloon compaction list lock internally. loaned_pages is currently protected under the cmm_lock. Note: Right now cmm_alloc_pages() and cmm_free_pages() can be called at the same time, e.g., via the thread and a concurrent OOM notifier.
Unified · Split
| @@ -73,7 +73,7 @@ MODULE_PARM_DESC(debug, "Enable module debugging logging. Set to 1 to enable. " · 72 unmodified lines | |||
| 73 | 73 | ||
| 74 | #define cmm_dbg(...) if (cmm_debug) { printk(KERN_INFO "cmm: "__VA_ARGS__); } | 74 | #define cmm_dbg(...) if (cmm_debug) { printk(KERN_INFO "cmm: "__VA_ARGS__); } |
| 75 | 75 | ||
| 76 | static unsigned long loaned_pages; | 76 | static atomic_long_t loaned_pages; |
| 77 | static unsigned long loaned_pages_target; | 77 | static unsigned long loaned_pages_target; |
| 78 | static unsigned long oom_freed_pages; | 78 | static unsigned long oom_freed_pages; |
| 79 | 79 | ||
| @@ -159,7 +159,7 @@ static long cmm_alloc_pages(long nr) · 79 unmodified lines | |||
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | list_add(&page->lru, &cmm_page_list); | 161 | list_add(&page->lru, &cmm_page_list); |
| 162 | loaned_pages++; | 162 | atomic_long_inc(&loaned_pages); |
| 163 | adjust_managed_page_count(page, -1); | 163 | adjust_managed_page_count(page, -1); |
| 164 | spin_unlock(&cmm_lock); | 164 | spin_unlock(&cmm_lock); |
| 165 | nr--; | 165 | nr--; |
| @@ -189,7 +189,7 @@ static long cmm_free_pages(long nr) · 23 unmodified lines | |||
| 189 | list_del(&page->lru); | 189 | list_del(&page->lru); |
| 190 | adjust_managed_page_count(page, 1); | 190 | adjust_managed_page_count(page, 1); |
| 191 | __free_page(page); | 191 | __free_page(page); |
| 192 | loaned_pages--; | 192 | atomic_long_dec(&loaned_pages); |
| 193 | nr--; | 193 | nr--; |
| 194 | } | 194 | } |
| 195 | spin_unlock(&cmm_lock); | 195 | spin_unlock(&cmm_lock); |
| @@ -214,7 +214,7 @@ static int cmm_oom_notify(struct notifier_block *self, · 18 unmodified lines | |||
| 214 | 214 | ||
| 215 | cmm_dbg("OOM processing started\n"); | 215 | cmm_dbg("OOM processing started\n"); |
| 216 | nr = cmm_free_pages(nr); | 216 | nr = cmm_free_pages(nr); |
| 217 | loaned_pages_target = loaned_pages; | 217 | loaned_pages_target = atomic_long_read(&loaned_pages); |
| 218 | *freed += KB2PAGES(oom_kb) - nr; | 218 | *freed += KB2PAGES(oom_kb) - nr; |
| 219 | oom_freed_pages += KB2PAGES(oom_kb) - nr; | 219 | oom_freed_pages += KB2PAGES(oom_kb) - nr; |
| 220 | cmm_dbg("OOM processing complete\n"); | 220 | cmm_dbg("OOM processing complete\n"); |
| @@ -231,10 +231,11 @@ static int cmm_oom_notify(struct notifier_block *self, · 10 unmodified lines | |||
| 231 | **/ | 231 | **/ |
| 232 | static void cmm_get_mpp(void) | 232 | static void cmm_get_mpp(void) |
| 233 | { | 233 | { |
| 234 | const long __loaned_pages = atomic_long_read(&loaned_pages); | ||
| 235 | const long total_pages = totalram_pages() + __loaned_pages; | ||
| 234 | int rc; | 236 | int rc; |
| 235 | struct hvcall_mpp_data mpp_data; | 237 | struct hvcall_mpp_data mpp_data; |
| 236 | signed long active_pages_target, page_loan_request, target; | 238 | signed long active_pages_target, page_loan_request, target; |
| 237 | signed long total_pages = totalram_pages() + loaned_pages; | ||
| 238 | signed long min_mem_pages = (min_mem_mb * 1024 * 1024) / PAGE_SIZE; | 239 | signed long min_mem_pages = (min_mem_mb * 1024 * 1024) / PAGE_SIZE; |
| 239 | 240 | ||
| 240 | rc = h_get_mpp(&mpp_data); | 241 | rc = h_get_mpp(&mpp_data); |
| @@ -243,7 +244,7 @@ static void cmm_get_mpp(void) · 2 unmodified lines | |||
| 243 | return; | 244 | return; |
| 244 | 245 | ||
| 245 | page_loan_request = div_s64((s64)mpp_data.loan_request, PAGE_SIZE); | 246 | page_loan_request = div_s64((s64)mpp_data.loan_request, PAGE_SIZE); |
| 246 | target = page_loan_request + (signed long)loaned_pages; | 247 | target = page_loan_request + __loaned_pages; |
| 247 | 248 | ||
| 248 | if (target < 0 || total_pages < min_mem_pages) | 249 | if (target < 0 || total_pages < min_mem_pages) |
| 249 | target = 0; | 250 | target = 0; |
| @@ -264,7 +265,7 @@ static void cmm_get_mpp(void) · 14 unmodified lines | |||
| 264 | loaned_pages_target = target; | 265 | loaned_pages_target = target; |
| 265 | 266 | ||
| 266 | cmm_dbg("delta = %ld, loaned = %lu, target = %lu, oom = %lu, totalram = %lu\n", | 267 | cmm_dbg("delta = %ld, loaned = %lu, target = %lu, oom = %lu, totalram = %lu\n", |
| 267 | page_loan_request, loaned_pages, loaned_pages_target, | 268 | page_loan_request, __loaned_pages, loaned_pages_target, |
| 268 | oom_freed_pages, totalram_pages()); | 269 | oom_freed_pages, totalram_pages()); |
| 269 | } | 270 | } |
| 270 | 271 | ||
| @@ -282,6 +283,7 @@ static struct notifier_block cmm_oom_nb = { · 11 unmodified lines | |||
| 282 | static int cmm_thread(void *dummy) | 283 | static int cmm_thread(void *dummy) |
| 283 | { | 284 | { |
| 284 | unsigned long timeleft; | 285 | unsigned long timeleft; |
| 286 | long __loaned_pages; | ||
| 285 | 287 | ||
| 286 | while (1) { | 288 | while (1) { |
| 287 | timeleft = msleep_interruptible(delay * 1000); | 289 | timeleft = msleep_interruptible(delay * 1000); |
| @@ -312,11 +314,12 @@ static int cmm_thread(void *dummy) · 24 unmodified lines | |||
| 312 | 314 | ||
| 313 | cmm_get_mpp(); | 315 | cmm_get_mpp(); |
| 314 | 316 | ||
| 315 | if (loaned_pages_target > loaned_pages) { | 317 | __loaned_pages = atomic_long_read(&loaned_pages); |
| 316 | if (cmm_alloc_pages(loaned_pages_target - loaned_pages)) | 318 | if (loaned_pages_target > __loaned_pages) { |
| 317 | loaned_pages_target = loaned_pages; | 319 | if (cmm_alloc_pages(loaned_pages_target - __loaned_pages)) |
| 318 | } else if (loaned_pages_target < loaned_pages) | 320 | loaned_pages_target = __loaned_pages; |
| 319 | cmm_free_pages(loaned_pages - loaned_pages_target); | 321 | } else if (loaned_pages_target < __loaned_pages) |
| 322 | cmm_free_pages(__loaned_pages - loaned_pages_target); | ||
| 320 | } | 323 | } |
| 321 | return 0; | 324 | return 0; |
| 322 | } | 325 | } |
| @@ -330,7 +333,7 @@ static int cmm_thread(void *dummy) · 7 unmodified lines | |||
| 330 | } \ | 333 | } \ |
| 331 | static DEVICE_ATTR(name, 0444, show_##name, NULL) | 334 | static DEVICE_ATTR(name, 0444, show_##name, NULL) |
| 332 | 335 | ||
| 333 | CMM_SHOW(loaned_kb, "%lu\n", PAGES2KB(loaned_pages)); | 336 | CMM_SHOW(loaned_kb, "%lu\n", PAGES2KB(atomic_long_read(&loaned_pages))); |
| 334 | CMM_SHOW(loaned_target_kb, "%lu\n", PAGES2KB(loaned_pages_target)); | 337 | CMM_SHOW(loaned_target_kb, "%lu\n", PAGES2KB(loaned_pages_target)); |
| 335 | 338 | ||
| 336 | static ssize_t show_oom_pages(struct device *dev, | 339 | static ssize_t show_oom_pages(struct device *dev, |
| @@ -433,7 +436,7 @@ static int cmm_reboot_notifier(struct notifier_block *nb, · 96 unmodified lines | |||
| 433 | if (cmm_thread_ptr) | 436 | if (cmm_thread_ptr) |
| 434 | kthread_stop(cmm_thread_ptr); | 437 | kthread_stop(cmm_thread_ptr); |
| 435 | cmm_thread_ptr = NULL; | 438 | cmm_thread_ptr = NULL; |
| 436 | cmm_free_pages(loaned_pages); | 439 | cmm_free_pages(atomic_long_read(&loaned_pages)); |
| 437 | } | 440 | } |
| 438 | return NOTIFY_DONE; | 441 | return NOTIFY_DONE; |
| 439 | } | 442 | } |
| @@ -540,7 +543,7 @@ static void cmm_exit(void) · 100 unmodified lines | |||
| 540 | unregister_oom_notifier(&cmm_oom_nb); | 543 | unregister_oom_notifier(&cmm_oom_nb); |
| 541 | unregister_reboot_notifier(&cmm_reboot_nb); | 544 | unregister_reboot_notifier(&cmm_reboot_nb); |
| 542 | unregister_memory_notifier(&cmm_mem_nb); | 545 | unregister_memory_notifier(&cmm_mem_nb); |
| 543 | cmm_free_pages(loaned_pages); | 546 | cmm_free_pages(atomic_long_read(&loaned_pages)); |
| 544 | cmm_unregister_sysfs(&cmm_dev); | 547 | cmm_unregister_sysfs(&cmm_dev); |
| 545 | } | 548 | } |
| 546 | 549 | ||
| @@ -561,7 +564,7 @@ static int cmm_set_disable(const char *val, const struct kernel_param *kp) · 14 unmodified lines | |||
| 561 | if (cmm_thread_ptr) | 564 | if (cmm_thread_ptr) |
| 562 | kthread_stop(cmm_thread_ptr); | 565 | kthread_stop(cmm_thread_ptr); |
| 563 | cmm_thread_ptr = NULL; | 566 | cmm_thread_ptr = NULL; |
| 564 | cmm_free_pages(loaned_pages); | 567 | cmm_free_pages(atomic_long_read(&loaned_pages)); |
| 565 | } else if (!disable && cmm_disabled) { | 568 | } else if (!disable && cmm_disabled) { |
| 566 | cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread"); | 569 | cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread"); |
| 567 | if (IS_ERR(cmm_thread_ptr)) | 570 | if (IS_ERR(cmm_thread_ptr)) |