diff options
author | Namhoon Kim <namhoonk@cs.unc.edu> | 2016-09-09 16:18:12 -0400 |
---|---|---|
committer | Namhoon Kim <namhoonk@cs.unc.edu> | 2016-09-09 16:18:12 -0400 |
commit | 805c547ee3cdc2ef6a5f7556fdf449ced2e48680 (patch) | |
tree | abeae409739a576291942281f9acf56725d73a1a | |
parent | 418e60bb6948a4cf6eb7c737bea21c2314619c73 (diff) |
TODO: Fix condition checks in replicate_page_move_mapping()wip-shared-lib
-rw-r--r-- | include/linux/migrate.h | 8 | ||||
-rw-r--r-- | include/litmus/replicate_lib.h | 6 | ||||
-rw-r--r-- | kernel/sched/litmus.c | 5 | ||||
-rw-r--r-- | litmus/litmus.c | 60 | ||||
-rw-r--r-- | litmus/replicate_lib.c | 2 | ||||
-rw-r--r-- | mm/migrate.c | 552 |
6 files changed, 618 insertions, 15 deletions
diff --git a/include/linux/migrate.h b/include/linux/migrate.h index cac1c0904d5f..b16047b82472 100644 --- a/include/linux/migrate.h +++ b/include/linux/migrate.h | |||
@@ -33,6 +33,8 @@ extern int migrate_page(struct address_space *, | |||
33 | struct page *, struct page *, enum migrate_mode); | 33 | struct page *, struct page *, enum migrate_mode); |
34 | extern int migrate_pages(struct list_head *l, new_page_t new, free_page_t free, | 34 | extern int migrate_pages(struct list_head *l, new_page_t new, free_page_t free, |
35 | unsigned long private, enum migrate_mode mode, int reason); | 35 | unsigned long private, enum migrate_mode mode, int reason); |
36 | extern int replicate_pages(struct list_head *l, new_page_t new, free_page_t free, | ||
37 | unsigned long private, enum migrate_mode mode, int reason); | ||
36 | 38 | ||
37 | extern int migrate_prep(void); | 39 | extern int migrate_prep(void); |
38 | extern int migrate_prep_local(void); | 40 | extern int migrate_prep_local(void); |
@@ -50,7 +52,11 @@ static inline int migrate_pages(struct list_head *l, new_page_t new, | |||
50 | free_page_t free, unsigned long private, enum migrate_mode mode, | 52 | free_page_t free, unsigned long private, enum migrate_mode mode, |
51 | int reason) | 53 | int reason) |
52 | { return -ENOSYS; } | 54 | { return -ENOSYS; } |
53 | 55 | static inline int replicate_pages(struct list_head *l, new_page_t new, | |
56 | free_page_t free, unsigned long private, enum migrate_mode mode, | ||
57 | int reason) | ||
58 | { return -ENOSYS; } | ||
59 | |||
54 | static inline int migrate_prep(void) { return -ENOSYS; } | 60 | static inline int migrate_prep(void) { return -ENOSYS; } |
55 | static inline int migrate_prep_local(void) { return -ENOSYS; } | 61 | static inline int migrate_prep_local(void) { return -ENOSYS; } |
56 | 62 | ||
diff --git a/include/litmus/replicate_lib.h b/include/litmus/replicate_lib.h index af2af36b6b79..480ce4631529 100644 --- a/include/litmus/replicate_lib.h +++ b/include/litmus/replicate_lib.h | |||
@@ -7,8 +7,12 @@ | |||
7 | 7 | ||
8 | struct shared_lib_page { | 8 | struct shared_lib_page { |
9 | struct page *p_page; | 9 | struct page *p_page; |
10 | unsigned long pfn; | 10 | struct page *r_page; |
11 | unsigned long p_pfn; | ||
12 | unsigned long r_pfn; | ||
11 | struct list_head list; | 13 | struct list_head list; |
12 | }; | 14 | }; |
13 | 15 | ||
16 | extern struct list_head shared_lib_pages; | ||
17 | |||
14 | #endif | 18 | #endif |
diff --git a/kernel/sched/litmus.c b/kernel/sched/litmus.c index 9d58690cf51a..cd36358cee75 100644 --- a/kernel/sched/litmus.c +++ b/kernel/sched/litmus.c | |||
@@ -20,8 +20,9 @@ static void update_time_litmus(struct rq *rq, struct task_struct *p) | |||
20 | /* task counter */ | 20 | /* task counter */ |
21 | p->se.sum_exec_runtime += delta; | 21 | p->se.sum_exec_runtime += delta; |
22 | if (delta) { | 22 | if (delta) { |
23 | TRACE_TASK(p, "charged %llu exec time (total:%llu, rem:%llu)\n", | 23 | //TRACE_TASK(p, "charged %llu exec time (total:%llu, rem:%llu)\n", |
24 | delta, p->rt_param.job_params.exec_time, budget_remaining(p)); | 24 | //delta, p->rt_param.job_params.exec_time, budget_remaining(p)); |
25 | ; | ||
25 | } | 26 | } |
26 | /* sched_clock() */ | 27 | /* sched_clock() */ |
27 | p->se.exec_start = rq->clock; | 28 | p->se.exec_start = rq->clock; |
diff --git a/litmus/litmus.c b/litmus/litmus.c index 402c495f62c6..8e7f5e2e68df 100644 --- a/litmus/litmus.c +++ b/litmus/litmus.c | |||
@@ -353,6 +353,10 @@ extern void putback_movable_page(struct page *page); | |||
353 | extern struct page *new_alloc_page(struct page *page, unsigned long node, int **x); | 353 | extern struct page *new_alloc_page(struct page *page, unsigned long node, int **x); |
354 | 354 | ||
355 | DECLARE_PER_CPU(struct list_head, shared_lib_page_list); | 355 | DECLARE_PER_CPU(struct list_head, shared_lib_page_list); |
356 | #define INVALID_PFN (0xffffffff) | ||
357 | LIST_HEAD(shared_lib_pages); | ||
358 | //struct list_head shared_lib_pages = LIST_HEAD_INIT(shared_lib_pages); | ||
359 | EXPORT_SYMBOL(shared_lib_pages); | ||
356 | 360 | ||
357 | asmlinkage long sys_set_page_color(int cpu) | 361 | asmlinkage long sys_set_page_color(int cpu) |
358 | { | 362 | { |
@@ -366,8 +370,8 @@ asmlinkage long sys_set_page_color(int cpu) | |||
366 | //struct list_head *shared_pagelist = this_cpu_ptr(&shared_lib_page_list); | 370 | //struct list_head *shared_pagelist = this_cpu_ptr(&shared_lib_page_list); |
367 | 371 | ||
368 | LIST_HEAD(pagelist); | 372 | LIST_HEAD(pagelist); |
369 | LIST_HEAD(shared_pagelist); | 373 | LIST_HEAD(task_shared_pagelist); |
370 | 374 | ||
371 | migrate_prep(); | 375 | migrate_prep(); |
372 | 376 | ||
373 | rcu_read_lock(); | 377 | rcu_read_lock(); |
@@ -408,10 +412,36 @@ asmlinkage long sys_set_page_color(int cpu) | |||
408 | 412 | ||
409 | if (page_count(old_page) > 2 && vma_itr->vm_file != NULL && !(vma_itr->vm_flags&VM_WRITE)) { | 413 | if (page_count(old_page) > 2 && vma_itr->vm_file != NULL && !(vma_itr->vm_flags&VM_WRITE)) { |
410 | struct shared_lib_page *lib_page; | 414 | struct shared_lib_page *lib_page; |
411 | lib_page = kmalloc(sizeof(struct shared_lib_page), GFP_KERNEL); | 415 | int is_exist = 0; |
412 | lib_page->p_page = old_page; | 416 | |
413 | lib_page->pfn = page_to_pfn(old_page); | 417 | /* update PSL list */ |
414 | list_add_tail(&lib_page->list, &shared_pagelist); | 418 | /* check if this page is in the PSL list */ |
419 | rcu_read_lock(); | ||
420 | list_for_each_entry(lib_page, &shared_lib_pages, list) | ||
421 | { | ||
422 | if (page_to_pfn(old_page) == lib_page->p_pfn) { | ||
423 | is_exist = 1; | ||
424 | break; | ||
425 | } | ||
426 | } | ||
427 | rcu_read_unlock(); | ||
428 | |||
429 | if (is_exist == 0) { | ||
430 | lib_page = kmalloc(sizeof(struct shared_lib_page), GFP_KERNEL); | ||
431 | lib_page->p_page = old_page; | ||
432 | lib_page->r_page = NULL; | ||
433 | lib_page->p_pfn = page_to_pfn(old_page); | ||
434 | lib_page->r_pfn = INVALID_PFN; | ||
435 | list_add_tail(&lib_page->list, &shared_lib_pages); | ||
436 | TRACE_TASK(current, "NEW PAGE %ld ADDED.\n", lib_page->p_pfn); | ||
437 | } | ||
438 | else { | ||
439 | TRACE_TASK(current, "FOUND PAGE %ld in the list.\n", lib_page->p_pfn); | ||
440 | } | ||
441 | |||
442 | /* add to task_shared_pagelist */ | ||
443 | list_add_tail(&old_page->lru, &task_shared_pagelist); | ||
444 | |||
415 | nr_shared_pages++; | 445 | nr_shared_pages++; |
416 | TRACE_TASK(current, "SHARED\n"); | 446 | TRACE_TASK(current, "SHARED\n"); |
417 | } | 447 | } |
@@ -428,7 +458,7 @@ asmlinkage long sys_set_page_color(int cpu) | |||
428 | } | 458 | } |
429 | //printk(KERN_INFO "PRIVATE _mapcount = %d, _count = %d\n", page_mapcount(old_page), page_count(old_page)); | 459 | //printk(KERN_INFO "PRIVATE _mapcount = %d, _count = %d\n", page_mapcount(old_page), page_count(old_page)); |
430 | put_page(old_page); | 460 | put_page(old_page); |
431 | TRACE_TASK(current, "PRIVATE\n"); | 461 | //TRACE_TASK(current, "PRIVATE\n"); |
432 | } | 462 | } |
433 | } | 463 | } |
434 | TRACE_TASK(current, "PAGES_IN_VMA = %d size = %d KB\n", pages_in_vma, pages_in_vma*4); | 464 | TRACE_TASK(current, "PAGES_IN_VMA = %d size = %d KB\n", pages_in_vma, pages_in_vma*4); |
@@ -454,13 +484,21 @@ asmlinkage long sys_set_page_color(int cpu) | |||
454 | if (!list_empty(&pagelist)) { | 484 | if (!list_empty(&pagelist)) { |
455 | ret = migrate_pages(&pagelist, new_alloc_page, NULL, node, MIGRATE_SYNC, MR_SYSCALL); | 485 | ret = migrate_pages(&pagelist, new_alloc_page, NULL, node, MIGRATE_SYNC, MR_SYSCALL); |
456 | TRACE_TASK(current, "%ld pages not migrated.\n", ret); | 486 | TRACE_TASK(current, "%ld pages not migrated.\n", ret); |
457 | printk(KERN_INFO "%ld pages not migrated.\n", ret); | ||
458 | nr_not_migrated = ret; | 487 | nr_not_migrated = ret; |
459 | if (ret) { | 488 | if (ret) { |
460 | putback_movable_pages(&pagelist); | 489 | putback_movable_pages(&pagelist); |
461 | } | 490 | } |
462 | } | 491 | } |
463 | 492 | ||
493 | if (!list_empty(&task_shared_pagelist)) { | ||
494 | ret = replicate_pages(&task_shared_pagelist, new_alloc_page, NULL, node, MIGRATE_SYNC, MR_SYSCALL); | ||
495 | TRACE_TASK(current, "%ld shared pages not migrated.\n", ret); | ||
496 | nr_not_migrated += ret; | ||
497 | if (ret) { | ||
498 | putback_movable_pages(&task_shared_pagelist); | ||
499 | } | ||
500 | } | ||
501 | |||
464 | /* handle sigpage and litmus ctrl_page */ | 502 | /* handle sigpage and litmus ctrl_page */ |
465 | /* vma_itr = current->mm->mmap; | 503 | /* vma_itr = current->mm->mmap; |
466 | while (vma_itr != NULL) { | 504 | while (vma_itr != NULL) { |
@@ -480,14 +518,14 @@ asmlinkage long sys_set_page_color(int cpu) | |||
480 | 518 | ||
481 | flush_cache(1); | 519 | flush_cache(1); |
482 | /* for debug START */ | 520 | /* for debug START */ |
483 | TRACE_TASK(current, "SHARED PAGES\n"); | 521 | TRACE_TASK(current, "PSL PAGES\n"); |
484 | { | 522 | { |
485 | struct shared_lib_page *lpage; | 523 | struct shared_lib_page *lpage; |
486 | 524 | ||
487 | rcu_read_lock(); | 525 | rcu_read_lock(); |
488 | list_for_each_entry(lpage, &shared_pagelist, list) | 526 | list_for_each_entry(lpage, &shared_lib_pages, list) |
489 | { | 527 | { |
490 | TRACE_TASK(current, "PFN = %ld\n", lpage->pfn); | 528 | TRACE_TASK(current, "p_PFN = %ld r_PFN = %ld\n", lpage->p_pfn, lpage->r_pfn); |
491 | } | 529 | } |
492 | rcu_read_unlock(); | 530 | rcu_read_unlock(); |
493 | } | 531 | } |
diff --git a/litmus/replicate_lib.c b/litmus/replicate_lib.c index 7aa240058ef5..cfc525809412 100644 --- a/litmus/replicate_lib.c +++ b/litmus/replicate_lib.c | |||
@@ -25,6 +25,8 @@ DEFINE_PER_CPU(struct list_head, shared_lib_page_list); | |||
25 | #define shared_lib_pages_for(cpu_id) (&per_cpu(shared_lib_page_list, cpu_id)) | 25 | #define shared_lib_pages_for(cpu_id) (&per_cpu(shared_lib_page_list, cpu_id)) |
26 | #define local_shared_lib_pages() (this_cpu_ptr(&shared_lib_page_list)) | 26 | #define local_shared_lib_pages() (this_cpu_ptr(&shared_lib_page_list)) |
27 | 27 | ||
28 | #define INVALID_PFN (0xffffffff) | ||
29 | |||
28 | static int __init litmus_replicate_lib_init(void) | 30 | static int __init litmus_replicate_lib_init(void) |
29 | { | 31 | { |
30 | int cpu, ret = 0; | 32 | int cpu, ret = 0; |
diff --git a/mm/migrate.c b/mm/migrate.c index f53838fe3dfe..c88f881f2daa 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
@@ -38,6 +38,8 @@ | |||
38 | #include <linux/balloon_compaction.h> | 38 | #include <linux/balloon_compaction.h> |
39 | #include <linux/mmu_notifier.h> | 39 | #include <linux/mmu_notifier.h> |
40 | 40 | ||
41 | #include <litmus/litmus.h> // for TRACE_TASK | ||
42 | |||
41 | #include <asm/tlbflush.h> | 43 | #include <asm/tlbflush.h> |
42 | 44 | ||
43 | #define CREATE_TRACE_POINTS | 45 | #define CREATE_TRACE_POINTS |
@@ -391,6 +393,106 @@ int migrate_page_move_mapping(struct address_space *mapping, | |||
391 | } | 393 | } |
392 | 394 | ||
393 | /* | 395 | /* |
396 | * Replace the page in the mapping. | ||
397 | * | ||
398 | * The number of remaining references must be: | ||
399 | * 1 for anonymous pages without a mapping | ||
400 | * 2 for pages with a mapping | ||
401 | * 3 for pages with a mapping and PagePrivate/PagePrivate2 set. | ||
402 | */ | ||
403 | int replicate_page_move_mapping(struct address_space *mapping, | ||
404 | struct page *newpage, struct page *page, | ||
405 | struct buffer_head *head, enum migrate_mode mode, | ||
406 | int extra_count) | ||
407 | { | ||
408 | int expected_count = 1 + extra_count; | ||
409 | void **pslot; | ||
410 | |||
411 | // if (!mapping) { | ||
412 | /* Anonymous page without mapping */ | ||
413 | // if (page_count(page) != expected_count) | ||
414 | // return -EAGAIN; | ||
415 | // return MIGRATEPAGE_SUCCESS; | ||
416 | // } | ||
417 | |||
418 | TRACE_TASK(current, "page has mapping.\n"); | ||
419 | spin_lock_irq(&mapping->tree_lock); | ||
420 | |||
421 | pslot = radix_tree_lookup_slot(&mapping->page_tree, | ||
422 | page_index(page)); | ||
423 | |||
424 | expected_count += 1 + page_has_private(page); | ||
425 | |||
426 | TRACE_TASK(current, "page_count(page) = %d, expected_count = %d, page_has_private? %d\n", page_count(page), expected_count, page_has_private(page)); | ||
427 | |||
428 | if (page_count(page) != expected_count || | ||
429 | radix_tree_deref_slot_protected(pslot, &mapping->tree_lock) != page) { | ||
430 | spin_unlock_irq(&mapping->tree_lock); | ||
431 | TRACE_TASK(current, "1\n"); | ||
432 | return -EAGAIN; | ||
433 | } | ||
434 | |||
435 | if (!page_freeze_refs(page, expected_count)) { | ||
436 | spin_unlock_irq(&mapping->tree_lock); | ||
437 | TRACE_TASK(current, "2\n"); | ||
438 | return -EAGAIN; | ||
439 | } | ||
440 | |||
441 | /* | ||
442 | * In the async migration case of moving a page with buffers, lock the | ||
443 | * buffers using trylock before the mapping is moved. If the mapping | ||
444 | * was moved, we later failed to lock the buffers and could not move | ||
445 | * the mapping back due to an elevated page count, we would have to | ||
446 | * block waiting on other references to be dropped. | ||
447 | */ | ||
448 | /* if (mode == MIGRATE_ASYNC && head && | ||
449 | !buffer_migrate_lock_buffers(head, mode)) { | ||
450 | page_unfreeze_refs(page, expected_count); | ||
451 | spin_unlock_irq(&mapping->tree_lock); | ||
452 | TRACE_TASK(current, "3\n"); | ||
453 | return -EAGAIN; | ||
454 | } | ||
455 | */ | ||
456 | /* | ||
457 | * Now we know that no one else is looking at the page. | ||
458 | */ | ||
459 | get_page(newpage); /* add cache reference */ | ||
460 | if (PageSwapCache(page)) { | ||
461 | SetPageSwapCache(newpage); | ||
462 | set_page_private(newpage, page_private(page)); | ||
463 | } | ||
464 | |||
465 | radix_tree_replace_slot(pslot, newpage); | ||
466 | |||
467 | /* | ||
468 | * Drop cache reference from old page by unfreezing | ||
469 | * to one less reference. | ||
470 | * We know this isn't the last reference. | ||
471 | */ | ||
472 | page_unfreeze_refs(page, expected_count - 1); | ||
473 | |||
474 | /* | ||
475 | * If moved to a different zone then also account | ||
476 | * the page for that zone. Other VM counters will be | ||
477 | * taken care of when we establish references to the | ||
478 | * new page and drop references to the old page. | ||
479 | * | ||
480 | * Note that anonymous pages are accounted for | ||
481 | * via NR_FILE_PAGES and NR_ANON_PAGES if they | ||
482 | * are mapped to swap space. | ||
483 | */ | ||
484 | __dec_zone_page_state(page, NR_FILE_PAGES); | ||
485 | __inc_zone_page_state(newpage, NR_FILE_PAGES); | ||
486 | if (!PageSwapCache(page) && PageSwapBacked(page)) { | ||
487 | __dec_zone_page_state(page, NR_SHMEM); | ||
488 | __inc_zone_page_state(newpage, NR_SHMEM); | ||
489 | } | ||
490 | spin_unlock_irq(&mapping->tree_lock); | ||
491 | |||
492 | return MIGRATEPAGE_SUCCESS; | ||
493 | } | ||
494 | |||
495 | /* | ||
394 | * The expected number of remaining references is the same as that | 496 | * The expected number of remaining references is the same as that |
395 | * of migrate_page_move_mapping(). | 497 | * of migrate_page_move_mapping(). |
396 | */ | 498 | */ |
@@ -578,6 +680,23 @@ int migrate_page(struct address_space *mapping, | |||
578 | } | 680 | } |
579 | EXPORT_SYMBOL(migrate_page); | 681 | EXPORT_SYMBOL(migrate_page); |
580 | 682 | ||
683 | int replicate_page(struct address_space *mapping, | ||
684 | struct page *newpage, struct page *page, | ||
685 | enum migrate_mode mode) | ||
686 | { | ||
687 | int rc, extra_count = 0; | ||
688 | |||
689 | BUG_ON(PageWriteback(page)); /* Writeback must be complete */ | ||
690 | //extra_count = page_count(page) - 2; | ||
691 | rc = replicate_page_move_mapping(mapping, newpage, page, NULL, mode, extra_count); | ||
692 | TRACE_TASK(current, "replicate_page_move_mapping returned %d\n", rc); | ||
693 | if (rc != MIGRATEPAGE_SUCCESS) | ||
694 | return rc; | ||
695 | |||
696 | migrate_page_copy(newpage, page); | ||
697 | return MIGRATEPAGE_SUCCESS; | ||
698 | } | ||
699 | |||
581 | #ifdef CONFIG_BLOCK | 700 | #ifdef CONFIG_BLOCK |
582 | /* | 701 | /* |
583 | * Migration function for pages with buffers. This function can only be used | 702 | * Migration function for pages with buffers. This function can only be used |
@@ -638,6 +757,60 @@ int buffer_migrate_page(struct address_space *mapping, | |||
638 | EXPORT_SYMBOL(buffer_migrate_page); | 757 | EXPORT_SYMBOL(buffer_migrate_page); |
639 | #endif | 758 | #endif |
640 | 759 | ||
760 | int replicate_buffer_page(struct address_space *mapping, | ||
761 | struct page *newpage, struct page *page, enum migrate_mode mode) | ||
762 | { | ||
763 | struct buffer_head *bh, *head; | ||
764 | int rc; | ||
765 | |||
766 | if (!page_has_buffers(page)) { | ||
767 | TRACE_TASK(current, "page does not have buffers\n"); | ||
768 | return replicate_page(mapping, newpage, page, mode); | ||
769 | } | ||
770 | |||
771 | head = page_buffers(page); | ||
772 | |||
773 | rc = migrate_page_move_mapping(mapping, newpage, page, head, mode, 0); | ||
774 | |||
775 | if (rc != MIGRATEPAGE_SUCCESS) | ||
776 | return rc; | ||
777 | |||
778 | /* | ||
779 | * In the async case, migrate_page_move_mapping locked the buffers | ||
780 | * with an IRQ-safe spinlock held. In the sync case, the buffers | ||
781 | * need to be locked now | ||
782 | */ | ||
783 | if (mode != MIGRATE_ASYNC) | ||
784 | BUG_ON(!buffer_migrate_lock_buffers(head, mode)); | ||
785 | |||
786 | ClearPagePrivate(page); | ||
787 | set_page_private(newpage, page_private(page)); | ||
788 | set_page_private(page, 0); | ||
789 | put_page(page); | ||
790 | get_page(newpage); | ||
791 | |||
792 | bh = head; | ||
793 | do { | ||
794 | set_bh_page(bh, newpage, bh_offset(bh)); | ||
795 | bh = bh->b_this_page; | ||
796 | |||
797 | } while (bh != head); | ||
798 | |||
799 | SetPagePrivate(newpage); | ||
800 | |||
801 | migrate_page_copy(newpage, page); | ||
802 | |||
803 | bh = head; | ||
804 | do { | ||
805 | unlock_buffer(bh); | ||
806 | put_bh(bh); | ||
807 | bh = bh->b_this_page; | ||
808 | |||
809 | } while (bh != head); | ||
810 | |||
811 | return MIGRATEPAGE_SUCCESS; | ||
812 | } | ||
813 | |||
641 | /* | 814 | /* |
642 | * Writeback a page to clean the dirty state | 815 | * Writeback a page to clean the dirty state |
643 | */ | 816 | */ |
@@ -763,6 +936,74 @@ static int move_to_new_page(struct page *newpage, struct page *page, | |||
763 | return rc; | 936 | return rc; |
764 | } | 937 | } |
765 | 938 | ||
939 | /* | ||
940 | * Copy a page to a newly allocated page | ||
941 | * The page is locked and all ptes have been successfully removed. | ||
942 | * | ||
943 | * The new page will have replaced the old page if this function | ||
944 | * is successful. | ||
945 | * | ||
946 | * Return value: | ||
947 | * < 0 - error code | ||
948 | * MIGRATEPAGE_SUCCESS - success | ||
949 | */ | ||
950 | static int copy_to_new_page(struct page *newpage, struct page *page, | ||
951 | int page_was_mapped, enum migrate_mode mode, | ||
952 | int has_replica) | ||
953 | { | ||
954 | struct address_space *mapping; | ||
955 | int rc; | ||
956 | |||
957 | /* | ||
958 | * Block others from accessing the page when we get around to | ||
959 | * establishing additional references. We are the only one | ||
960 | * holding a reference to the new page at this point. | ||
961 | */ | ||
962 | if (!trylock_page(newpage)) | ||
963 | BUG(); | ||
964 | |||
965 | /* Prepare mapping for the new page.*/ | ||
966 | newpage->index = page->index; | ||
967 | newpage->mapping = page->mapping; | ||
968 | if (PageSwapBacked(page)) | ||
969 | SetPageSwapBacked(newpage); | ||
970 | |||
971 | mapping = page_mapping(page); | ||
972 | if (!mapping) { | ||
973 | rc = migrate_page(mapping, newpage, page, mode); | ||
974 | } | ||
975 | else if (mapping->a_ops->migratepage) { | ||
976 | TRACE_TASK(current, "ops migration callback\n"); | ||
977 | /* | ||
978 | * Most pages have a mapping and most filesystems provide a | ||
979 | * migratepage callback. Anonymous pages are part of swap | ||
980 | * space which also has its own migratepage callback. This | ||
981 | * is the most common path for page migration. | ||
982 | */ | ||
983 | //rc = mapping->a_ops->migratepage(mapping, | ||
984 | // newpage, page, mode); | ||
985 | rc = replicate_buffer_page(mapping, newpage, page, mode); | ||
986 | } | ||
987 | else { | ||
988 | TRACE_TASK(current, "fallback function\n"); | ||
989 | rc = fallback_migrate_page(mapping, newpage, page, mode); | ||
990 | } | ||
991 | |||
992 | if (rc != MIGRATEPAGE_SUCCESS) { | ||
993 | newpage->mapping = NULL; | ||
994 | } else { | ||
995 | mem_cgroup_migrate(page, newpage, false); | ||
996 | if (page_was_mapped) | ||
997 | remove_migration_ptes(page, newpage); | ||
998 | page->mapping = NULL; | ||
999 | } | ||
1000 | |||
1001 | unlock_page(newpage); | ||
1002 | |||
1003 | return rc; | ||
1004 | } | ||
1005 | |||
1006 | |||
766 | static int __unmap_and_move(struct page *page, struct page *newpage, | 1007 | static int __unmap_and_move(struct page *page, struct page *newpage, |
767 | int force, enum migrate_mode mode) | 1008 | int force, enum migrate_mode mode) |
768 | { | 1009 | { |
@@ -901,6 +1142,146 @@ out: | |||
901 | return rc; | 1142 | return rc; |
902 | } | 1143 | } |
903 | 1144 | ||
1145 | static int __unmap_and_copy(struct page *page, struct page *newpage, | ||
1146 | int force, enum migrate_mode mode, int has_replica) | ||
1147 | { | ||
1148 | int rc = -EAGAIN; | ||
1149 | int page_was_mapped = 0; | ||
1150 | struct anon_vma *anon_vma = NULL; | ||
1151 | |||
1152 | if (!trylock_page(page)) { | ||
1153 | if (!force || mode == MIGRATE_ASYNC) | ||
1154 | goto out; | ||
1155 | |||
1156 | /* | ||
1157 | * It's not safe for direct compaction to call lock_page. | ||
1158 | * For example, during page readahead pages are added locked | ||
1159 | * to the LRU. Later, when the IO completes the pages are | ||
1160 | * marked uptodate and unlocked. However, the queueing | ||
1161 | * could be merging multiple pages for one bio (e.g. | ||
1162 | * mpage_readpages). If an allocation happens for the | ||
1163 | * second or third page, the process can end up locking | ||
1164 | * the same page twice and deadlocking. Rather than | ||
1165 | * trying to be clever about what pages can be locked, | ||
1166 | * avoid the use of lock_page for direct compaction | ||
1167 | * altogether. | ||
1168 | */ | ||
1169 | if (current->flags & PF_MEMALLOC) | ||
1170 | goto out; | ||
1171 | |||
1172 | lock_page(page); | ||
1173 | } | ||
1174 | |||
1175 | if (PageWriteback(page)) { | ||
1176 | /* | ||
1177 | * Only in the case of a full synchronous migration is it | ||
1178 | * necessary to wait for PageWriteback. In the async case, | ||
1179 | * the retry loop is too short and in the sync-light case, | ||
1180 | * the overhead of stalling is too much | ||
1181 | */ | ||
1182 | if (mode != MIGRATE_SYNC) { | ||
1183 | rc = -EBUSY; | ||
1184 | goto out_unlock; | ||
1185 | } | ||
1186 | if (!force) | ||
1187 | goto out_unlock; | ||
1188 | wait_on_page_writeback(page); | ||
1189 | } | ||
1190 | /* | ||
1191 | * By try_to_unmap(), page->mapcount goes down to 0 here. In this case, | ||
1192 | * we cannot notice that anon_vma is freed while we migrates a page. | ||
1193 | * This get_anon_vma() delays freeing anon_vma pointer until the end | ||
1194 | * of migration. File cache pages are no problem because of page_lock() | ||
1195 | * File Caches may use write_page() or lock_page() in migration, then, | ||
1196 | * just care Anon page here. | ||
1197 | */ | ||
1198 | if (PageAnon(page) && !PageKsm(page)) { | ||
1199 | /* | ||
1200 | * Only page_lock_anon_vma_read() understands the subtleties of | ||
1201 | * getting a hold on an anon_vma from outside one of its mms. | ||
1202 | */ | ||
1203 | anon_vma = page_get_anon_vma(page); | ||
1204 | if (anon_vma) { | ||
1205 | /* | ||
1206 | * Anon page | ||
1207 | */ | ||
1208 | } else if (PageSwapCache(page)) { | ||
1209 | /* | ||
1210 | * We cannot be sure that the anon_vma of an unmapped | ||
1211 | * swapcache page is safe to use because we don't | ||
1212 | * know in advance if the VMA that this page belonged | ||
1213 | * to still exists. If the VMA and others sharing the | ||
1214 | * data have been freed, then the anon_vma could | ||
1215 | * already be invalid. | ||
1216 | * | ||
1217 | * To avoid this possibility, swapcache pages get | ||
1218 | * migrated but are not remapped when migration | ||
1219 | * completes | ||
1220 | */ | ||
1221 | } else { | ||
1222 | goto out_unlock; | ||
1223 | } | ||
1224 | } | ||
1225 | |||
1226 | if (unlikely(isolated_balloon_page(page))) { | ||
1227 | /* | ||
1228 | * A ballooned page does not need any special attention from | ||
1229 | * physical to virtual reverse mapping procedures. | ||
1230 | * Skip any attempt to unmap PTEs or to remap swap cache, | ||
1231 | * in order to avoid burning cycles at rmap level, and perform | ||
1232 | * the page migration right away (proteced by page lock). | ||
1233 | */ | ||
1234 | rc = balloon_page_migrate(newpage, page, mode); | ||
1235 | goto out_unlock; | ||
1236 | } | ||
1237 | |||
1238 | /* | ||
1239 | * Corner case handling: | ||
1240 | * 1. When a new swap-cache page is read into, it is added to the LRU | ||
1241 | * and treated as swapcache but it has no rmap yet. | ||
1242 | * Calling try_to_unmap() against a page->mapping==NULL page will | ||
1243 | * trigger a BUG. So handle it here. | ||
1244 | * 2. An orphaned page (see truncate_complete_page) might have | ||
1245 | * fs-private metadata. The page can be picked up due to memory | ||
1246 | * offlining. Everywhere else except page reclaim, the page is | ||
1247 | * invisible to the vm, so the page can not be migrated. So try to | ||
1248 | * free the metadata, so the page can be freed. | ||
1249 | */ | ||
1250 | if (!page->mapping) { | ||
1251 | VM_BUG_ON_PAGE(PageAnon(page), page); | ||
1252 | if (page_has_private(page)) { | ||
1253 | try_to_free_buffers(page); | ||
1254 | goto out_unlock; | ||
1255 | } | ||
1256 | goto skip_unmap; | ||
1257 | } | ||
1258 | |||
1259 | /* Establish migration ptes or remove ptes */ | ||
1260 | if (page_mapped(page)) { | ||
1261 | try_to_unmap(page, | ||
1262 | TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS); | ||
1263 | page_was_mapped = 1; | ||
1264 | } | ||
1265 | |||
1266 | skip_unmap: | ||
1267 | if (!page_mapped(page)) { | ||
1268 | TRACE_TASK(current, "Call copy_to_new_page\n"); | ||
1269 | rc = copy_to_new_page(newpage, page, page_was_mapped, mode, has_replica); | ||
1270 | } | ||
1271 | |||
1272 | if (rc && page_was_mapped) | ||
1273 | remove_migration_ptes(page, page); | ||
1274 | |||
1275 | /* Drop an anon_vma reference if we took one */ | ||
1276 | if (anon_vma) | ||
1277 | put_anon_vma(anon_vma); | ||
1278 | |||
1279 | out_unlock: | ||
1280 | unlock_page(page); | ||
1281 | out: | ||
1282 | return rc; | ||
1283 | } | ||
1284 | |||
904 | /* | 1285 | /* |
905 | * gcc 4.7 and 4.8 on arm get an ICEs when inlining unmap_and_move(). Work | 1286 | * gcc 4.7 and 4.8 on arm get an ICEs when inlining unmap_and_move(). Work |
906 | * around it. | 1287 | * around it. |
@@ -976,6 +1357,97 @@ out: | |||
976 | } | 1357 | } |
977 | 1358 | ||
978 | /* | 1359 | /* |
1360 | * Obtain the lock on page, remove all ptes. | ||
1361 | * 1) If r_pfn == INVALID_PFN, then copy the page to the newly allocated page in newpage. | ||
1362 | * 2) If r_pfn != INVALID_PFN, then unmap and modify ptes. | ||
1363 | */ | ||
1364 | #include <litmus/replicate_lib.h> | ||
1365 | |||
1366 | static ICE_noinline int unmap_and_copy(new_page_t get_new_page, | ||
1367 | free_page_t put_new_page, | ||
1368 | unsigned long private, struct page *page, | ||
1369 | int force, enum migrate_mode mode) | ||
1370 | { | ||
1371 | int rc = 0; | ||
1372 | int *result = NULL; | ||
1373 | struct page *newpage; | ||
1374 | struct shared_lib_page *lib_page; | ||
1375 | int is_exist_in_psl = 0, has_replica = 0; | ||
1376 | |||
1377 | /* check if this page is in the PSL list */ | ||
1378 | rcu_read_lock(); | ||
1379 | list_for_each_entry(lib_page, &shared_lib_pages, list) | ||
1380 | { | ||
1381 | if (page_to_pfn(page) == lib_page->p_pfn) { | ||
1382 | is_exist_in_psl = 1; | ||
1383 | break; | ||
1384 | } | ||
1385 | } | ||
1386 | rcu_read_unlock(); | ||
1387 | |||
1388 | if (is_exist_in_psl) | ||
1389 | TRACE_TASK(current, "Page %ld exists in PSL list\n", lib_page->p_pfn); | ||
1390 | |||
1391 | if (lib_page->r_page == NULL) { | ||
1392 | newpage = get_new_page(page, private, &result); | ||
1393 | if (!newpage) | ||
1394 | return -ENOMEM; | ||
1395 | } | ||
1396 | else { | ||
1397 | newpage = lib_page->r_page; | ||
1398 | has_replica = 1; | ||
1399 | } | ||
1400 | |||
1401 | if (page_count(page) == 1) { | ||
1402 | /* page was freed from under us. So we are done. */ | ||
1403 | TRACE_TASK(current, "page %ld _count == 1\n", page_to_pfn(page)); | ||
1404 | goto out; | ||
1405 | } | ||
1406 | |||
1407 | if (unlikely(PageTransHuge(page))) | ||
1408 | if (unlikely(split_huge_page(page))) | ||
1409 | goto out; | ||
1410 | |||
1411 | rc = __unmap_and_copy(page, newpage, force, mode, has_replica); | ||
1412 | |||
1413 | out: | ||
1414 | if (rc != -EAGAIN) { | ||
1415 | /* | ||
1416 | * A page that has been migrated has all references | ||
1417 | * removed and will be freed. A page that has not been | ||
1418 | * migrated will have kepts its references and be | ||
1419 | * restored. | ||
1420 | */ | ||
1421 | list_del(&page->lru); | ||
1422 | dec_zone_page_state(page, NR_ISOLATED_ANON + | ||
1423 | page_is_file_cache(page)); | ||
1424 | putback_lru_page(page); | ||
1425 | } | ||
1426 | |||
1427 | /* | ||
1428 | * If migration was not successful and there's a freeing callback, use | ||
1429 | * it. Otherwise, putback_lru_page() will drop the reference grabbed | ||
1430 | * during isolation. | ||
1431 | */ | ||
1432 | if (rc != MIGRATEPAGE_SUCCESS && put_new_page) { | ||
1433 | ClearPageSwapBacked(newpage); | ||
1434 | put_new_page(newpage, private); | ||
1435 | } else if (unlikely(__is_movable_balloon_page(newpage))) { | ||
1436 | /* drop our reference, page already in the balloon */ | ||
1437 | put_page(newpage); | ||
1438 | } else | ||
1439 | putback_lru_page(newpage); | ||
1440 | |||
1441 | if (result) { | ||
1442 | if (rc) | ||
1443 | *result = rc; | ||
1444 | else | ||
1445 | *result = page_to_nid(newpage); | ||
1446 | } | ||
1447 | return rc; | ||
1448 | } | ||
1449 | |||
1450 | /* | ||
979 | * Counterpart of unmap_and_move_page() for hugepage migration. | 1451 | * Counterpart of unmap_and_move_page() for hugepage migration. |
980 | * | 1452 | * |
981 | * This function doesn't wait the completion of hugepage I/O | 1453 | * This function doesn't wait the completion of hugepage I/O |
@@ -1159,6 +1631,86 @@ out: | |||
1159 | return rc; | 1631 | return rc; |
1160 | } | 1632 | } |
1161 | 1633 | ||
1634 | /* | ||
1635 | * replicate_pages - replicate the pages specified in a list | ||
1636 | * | ||
1637 | * @from: The list of pages to be migrated. | ||
1638 | * @get_new_page: The function used to allocate free pages to be used | ||
1639 | * if there is no replicated page. | ||
1640 | * @put_new_page: The function used to free target pages if migration | ||
1641 | * fails, or NULL if no special handling is necessary. | ||
1642 | * @private: Private data to be passed on to get_new_page() | ||
1643 | * @mode: The migration mode that specifies the constraints for | ||
1644 | * page migration, if any. | ||
1645 | * @reason: The reason for page migration. | ||
1646 | * | ||
1647 | * The function returns after 10 attempts or if no pages are movable any more | ||
1648 | * because the list has become empty or no retryable pages exist any more. | ||
1649 | * The caller should call putback_lru_pages() to return pages to the LRU | ||
1650 | * or free list only if ret != 0. | ||
1651 | * | ||
1652 | * Returns the number of pages that were not migrated, or an error code. | ||
1653 | */ | ||
1654 | int replicate_pages(struct list_head *from, new_page_t get_new_page, | ||
1655 | free_page_t put_new_page, unsigned long private, | ||
1656 | enum migrate_mode mode, int reason) | ||
1657 | { | ||
1658 | int retry = 1; | ||
1659 | int nr_failed = 0; | ||
1660 | int nr_succeeded = 0; | ||
1661 | int pass = 0; | ||
1662 | struct page *page; | ||
1663 | struct page *page2; | ||
1664 | int swapwrite = current->flags & PF_SWAPWRITE; | ||
1665 | int rc; | ||
1666 | |||
1667 | if (!swapwrite) | ||
1668 | current->flags |= PF_SWAPWRITE; | ||
1669 | |||
1670 | for(pass = 0; pass < 10 && retry; pass++) { | ||
1671 | retry = 0; | ||
1672 | |||
1673 | list_for_each_entry_safe(page, page2, from, lru) { | ||
1674 | cond_resched(); | ||
1675 | |||
1676 | rc = unmap_and_copy(get_new_page, put_new_page, private, page, pass > 2, mode); | ||
1677 | TRACE_TASK(current, "rc = %d\n", rc); | ||
1678 | |||
1679 | switch(rc) { | ||
1680 | case -ENOMEM: | ||
1681 | goto out; | ||
1682 | case -EAGAIN: | ||
1683 | retry++; | ||
1684 | break; | ||
1685 | case MIGRATEPAGE_SUCCESS: | ||
1686 | nr_succeeded++; | ||
1687 | break; | ||
1688 | default: | ||
1689 | /* | ||
1690 | * Permanent failure (-EBUSY, -ENOSYS, etc.): | ||
1691 | * unlike -EAGAIN case, the failed page is | ||
1692 | * removed from migration page list and not | ||
1693 | * retried in the next outer loop. | ||
1694 | */ | ||
1695 | nr_failed++; | ||
1696 | break; | ||
1697 | } | ||
1698 | } | ||
1699 | } | ||
1700 | rc = nr_failed + retry; | ||
1701 | out: | ||
1702 | if (nr_succeeded) | ||
1703 | count_vm_events(PGMIGRATE_SUCCESS, nr_succeeded); | ||
1704 | if (nr_failed) | ||
1705 | count_vm_events(PGMIGRATE_FAIL, nr_failed); | ||
1706 | trace_mm_migrate_pages(nr_succeeded, nr_failed, mode, reason); | ||
1707 | |||
1708 | if (!swapwrite) | ||
1709 | current->flags &= ~PF_SWAPWRITE; | ||
1710 | |||
1711 | return rc; | ||
1712 | } | ||
1713 | |||
1162 | #ifdef CONFIG_NUMA | 1714 | #ifdef CONFIG_NUMA |
1163 | /* | 1715 | /* |
1164 | * Move a list of individual pages | 1716 | * Move a list of individual pages |