diff options
Diffstat (limited to 'mm/memory.c')
-rw-r--r-- | mm/memory.c | 51 |
1 files changed, 34 insertions, 17 deletions
diff --git a/mm/memory.c b/mm/memory.c index 8a7b4ccbe136..84c6d9eab182 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -3449,6 +3449,18 @@ static int do_nonlinear_fault(struct mm_struct *mm, struct vm_area_struct *vma, | |||
3449 | return __do_fault(mm, vma, address, pmd, pgoff, flags, orig_pte); | 3449 | return __do_fault(mm, vma, address, pmd, pgoff, flags, orig_pte); |
3450 | } | 3450 | } |
3451 | 3451 | ||
3452 | int numa_migrate_prep(struct page *page, struct vm_area_struct *vma, | ||
3453 | unsigned long addr, int current_nid) | ||
3454 | { | ||
3455 | get_page(page); | ||
3456 | |||
3457 | count_vm_numa_event(NUMA_HINT_FAULTS); | ||
3458 | if (current_nid == numa_node_id()) | ||
3459 | count_vm_numa_event(NUMA_HINT_FAULTS_LOCAL); | ||
3460 | |||
3461 | return mpol_misplaced(page, vma, addr); | ||
3462 | } | ||
3463 | |||
3452 | int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, | 3464 | int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, |
3453 | unsigned long addr, pte_t pte, pte_t *ptep, pmd_t *pmd) | 3465 | unsigned long addr, pte_t pte, pte_t *ptep, pmd_t *pmd) |
3454 | { | 3466 | { |
@@ -3477,18 +3489,14 @@ int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
3477 | set_pte_at(mm, addr, ptep, pte); | 3489 | set_pte_at(mm, addr, ptep, pte); |
3478 | update_mmu_cache(vma, addr, ptep); | 3490 | update_mmu_cache(vma, addr, ptep); |
3479 | 3491 | ||
3480 | count_vm_numa_event(NUMA_HINT_FAULTS); | ||
3481 | page = vm_normal_page(vma, addr, pte); | 3492 | page = vm_normal_page(vma, addr, pte); |
3482 | if (!page) { | 3493 | if (!page) { |
3483 | pte_unmap_unlock(ptep, ptl); | 3494 | pte_unmap_unlock(ptep, ptl); |
3484 | return 0; | 3495 | return 0; |
3485 | } | 3496 | } |
3486 | 3497 | ||
3487 | get_page(page); | ||
3488 | current_nid = page_to_nid(page); | 3498 | current_nid = page_to_nid(page); |
3489 | if (current_nid == numa_node_id()) | 3499 | target_nid = numa_migrate_prep(page, vma, addr, current_nid); |
3490 | count_vm_numa_event(NUMA_HINT_FAULTS_LOCAL); | ||
3491 | target_nid = mpol_misplaced(page, vma, addr); | ||
3492 | pte_unmap_unlock(ptep, ptl); | 3500 | pte_unmap_unlock(ptep, ptl); |
3493 | if (target_nid == -1) { | 3501 | if (target_nid == -1) { |
3494 | /* | 3502 | /* |
@@ -3505,7 +3513,8 @@ int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
3505 | current_nid = target_nid; | 3513 | current_nid = target_nid; |
3506 | 3514 | ||
3507 | out: | 3515 | out: |
3508 | task_numa_fault(current_nid, 1); | 3516 | if (current_nid != -1) |
3517 | task_numa_fault(current_nid, 1); | ||
3509 | return 0; | 3518 | return 0; |
3510 | } | 3519 | } |
3511 | 3520 | ||
@@ -3521,8 +3530,6 @@ static int do_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
3521 | spinlock_t *ptl; | 3530 | spinlock_t *ptl; |
3522 | bool numa = false; | 3531 | bool numa = false; |
3523 | int local_nid = numa_node_id(); | 3532 | int local_nid = numa_node_id(); |
3524 | unsigned long nr_faults = 0; | ||
3525 | unsigned long nr_faults_local = 0; | ||
3526 | 3533 | ||
3527 | spin_lock(&mm->page_table_lock); | 3534 | spin_lock(&mm->page_table_lock); |
3528 | pmd = *pmdp; | 3535 | pmd = *pmdp; |
@@ -3545,7 +3552,8 @@ static int do_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
3545 | for (addr = _addr + offset; addr < _addr + PMD_SIZE; pte++, addr += PAGE_SIZE) { | 3552 | for (addr = _addr + offset; addr < _addr + PMD_SIZE; pte++, addr += PAGE_SIZE) { |
3546 | pte_t pteval = *pte; | 3553 | pte_t pteval = *pte; |
3547 | struct page *page; | 3554 | struct page *page; |
3548 | int curr_nid; | 3555 | int curr_nid = local_nid; |
3556 | int target_nid; | ||
3549 | if (!pte_present(pteval)) | 3557 | if (!pte_present(pteval)) |
3550 | continue; | 3558 | continue; |
3551 | if (!pte_numa(pteval)) | 3559 | if (!pte_numa(pteval)) |
@@ -3566,21 +3574,30 @@ static int do_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
3566 | /* only check non-shared pages */ | 3574 | /* only check non-shared pages */ |
3567 | if (unlikely(page_mapcount(page) != 1)) | 3575 | if (unlikely(page_mapcount(page) != 1)) |
3568 | continue; | 3576 | continue; |
3569 | pte_unmap_unlock(pte, ptl); | ||
3570 | 3577 | ||
3571 | curr_nid = page_to_nid(page); | 3578 | /* |
3572 | task_numa_fault(curr_nid, 1); | 3579 | * Note that the NUMA fault is later accounted to either |
3580 | * the node that is currently running or where the page is | ||
3581 | * migrated to. | ||
3582 | */ | ||
3583 | curr_nid = local_nid; | ||
3584 | target_nid = numa_migrate_prep(page, vma, addr, | ||
3585 | page_to_nid(page)); | ||
3586 | if (target_nid == -1) { | ||
3587 | put_page(page); | ||
3588 | continue; | ||
3589 | } | ||
3573 | 3590 | ||
3574 | nr_faults++; | 3591 | /* Migrate to the requested node */ |
3575 | if (curr_nid == local_nid) | 3592 | pte_unmap_unlock(pte, ptl); |
3576 | nr_faults_local++; | 3593 | if (migrate_misplaced_page(page, target_nid)) |
3594 | curr_nid = target_nid; | ||
3595 | task_numa_fault(curr_nid, 1); | ||
3577 | 3596 | ||
3578 | pte = pte_offset_map_lock(mm, pmdp, addr, &ptl); | 3597 | pte = pte_offset_map_lock(mm, pmdp, addr, &ptl); |
3579 | } | 3598 | } |
3580 | pte_unmap_unlock(orig_pte, ptl); | 3599 | pte_unmap_unlock(orig_pte, ptl); |
3581 | 3600 | ||
3582 | count_vm_numa_events(NUMA_HINT_FAULTS, nr_faults); | ||
3583 | count_vm_numa_events(NUMA_HINT_FAULTS_LOCAL, nr_faults_local); | ||
3584 | return 0; | 3601 | return 0; |
3585 | } | 3602 | } |
3586 | #else | 3603 | #else |