diff options
| -rw-r--r-- | include/linux/rmap.h | 13 | ||||
| -rw-r--r-- | mm/memory.c | 2 | ||||
| -rw-r--r-- | mm/rmap.c | 58 |
3 files changed, 62 insertions, 11 deletions
diff --git a/include/linux/rmap.h b/include/linux/rmap.h index bdd277223af0..97347f22fc20 100644 --- a/include/linux/rmap.h +++ b/include/linux/rmap.h | |||
| @@ -74,17 +74,14 @@ void page_add_new_anon_rmap(struct page *, struct vm_area_struct *, unsigned lon | |||
| 74 | void page_add_file_rmap(struct page *); | 74 | void page_add_file_rmap(struct page *); |
| 75 | void page_remove_rmap(struct page *, struct vm_area_struct *); | 75 | void page_remove_rmap(struct page *, struct vm_area_struct *); |
| 76 | 76 | ||
| 77 | /** | 77 | #ifdef CONFIG_DEBUG_VM |
| 78 | * page_dup_rmap - duplicate pte mapping to a page | 78 | void page_dup_rmap(struct page *page, struct vm_area_struct *vma, unsigned long address); |
| 79 | * @page: the page to add the mapping to | 79 | #else |
| 80 | * | 80 | static inline void page_dup_rmap(struct page *page, struct vm_area_struct *vma, unsigned long address) |
| 81 | * For copy_page_range only: minimal extract from page_add_rmap, | ||
| 82 | * avoiding unnecessary tests (already checked) so it's quicker. | ||
| 83 | */ | ||
| 84 | static inline void page_dup_rmap(struct page *page) | ||
| 85 | { | 81 | { |
| 86 | atomic_inc(&page->_mapcount); | 82 | atomic_inc(&page->_mapcount); |
| 87 | } | 83 | } |
| 84 | #endif | ||
| 88 | 85 | ||
| 89 | /* | 86 | /* |
| 90 | * Called from mm/vmscan.c to handle paging out | 87 | * Called from mm/vmscan.c to handle paging out |
diff --git a/mm/memory.c b/mm/memory.c index 1d647ab0ee72..cb94488ab96d 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
| @@ -481,7 +481,7 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm, | |||
| 481 | page = vm_normal_page(vma, addr, pte); | 481 | page = vm_normal_page(vma, addr, pte); |
| 482 | if (page) { | 482 | if (page) { |
| 483 | get_page(page); | 483 | get_page(page); |
| 484 | page_dup_rmap(page); | 484 | page_dup_rmap(page, vma, addr); |
| 485 | rss[!!PageAnon(page)]++; | 485 | rss[!!PageAnon(page)]++; |
| 486 | } | 486 | } |
| 487 | 487 | ||
| @@ -530,19 +530,51 @@ static void __page_set_anon_rmap(struct page *page, | |||
| 530 | } | 530 | } |
| 531 | 531 | ||
| 532 | /** | 532 | /** |
| 533 | * page_set_anon_rmap - sanity check anonymous rmap addition | ||
| 534 | * @page: the page to add the mapping to | ||
| 535 | * @vma: the vm area in which the mapping is added | ||
| 536 | * @address: the user virtual address mapped | ||
| 537 | */ | ||
| 538 | static void __page_check_anon_rmap(struct page *page, | ||
| 539 | struct vm_area_struct *vma, unsigned long address) | ||
| 540 | { | ||
| 541 | #ifdef CONFIG_DEBUG_VM | ||
| 542 | /* | ||
| 543 | * The page's anon-rmap details (mapping and index) are guaranteed to | ||
| 544 | * be set up correctly at this point. | ||
| 545 | * | ||
| 546 | * We have exclusion against page_add_anon_rmap because the caller | ||
| 547 | * always holds the page locked, except if called from page_dup_rmap, | ||
| 548 | * in which case the page is already known to be setup. | ||
| 549 | * | ||
| 550 | * We have exclusion against page_add_new_anon_rmap because those pages | ||
| 551 | * are initially only visible via the pagetables, and the pte is locked | ||
| 552 | * over the call to page_add_new_anon_rmap. | ||
| 553 | */ | ||
| 554 | struct anon_vma *anon_vma = vma->anon_vma; | ||
| 555 | anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON; | ||
| 556 | BUG_ON(page->mapping != (struct address_space *)anon_vma); | ||
| 557 | BUG_ON(page->index != linear_page_index(vma, address)); | ||
| 558 | #endif | ||
| 559 | } | ||
| 560 | |||
| 561 | /** | ||
| 533 | * page_add_anon_rmap - add pte mapping to an anonymous page | 562 | * page_add_anon_rmap - add pte mapping to an anonymous page |
| 534 | * @page: the page to add the mapping to | 563 | * @page: the page to add the mapping to |
| 535 | * @vma: the vm area in which the mapping is added | 564 | * @vma: the vm area in which the mapping is added |
| 536 | * @address: the user virtual address mapped | 565 | * @address: the user virtual address mapped |
| 537 | * | 566 | * |
| 538 | * The caller needs to hold the pte lock. | 567 | * The caller needs to hold the pte lock and the page must be locked. |
| 539 | */ | 568 | */ |
| 540 | void page_add_anon_rmap(struct page *page, | 569 | void page_add_anon_rmap(struct page *page, |
| 541 | struct vm_area_struct *vma, unsigned long address) | 570 | struct vm_area_struct *vma, unsigned long address) |
| 542 | { | 571 | { |
| 572 | VM_BUG_ON(!PageLocked(page)); | ||
| 573 | VM_BUG_ON(address < vma->vm_start || address >= vma->vm_end); | ||
| 543 | if (atomic_inc_and_test(&page->_mapcount)) | 574 | if (atomic_inc_and_test(&page->_mapcount)) |
| 544 | __page_set_anon_rmap(page, vma, address); | 575 | __page_set_anon_rmap(page, vma, address); |
| 545 | /* else checking page index and mapping is racy */ | 576 | else |
| 577 | __page_check_anon_rmap(page, vma, address); | ||
| 546 | } | 578 | } |
| 547 | 579 | ||
| 548 | /* | 580 | /* |
| @@ -553,10 +585,12 @@ void page_add_anon_rmap(struct page *page, | |||
| 553 | * | 585 | * |
| 554 | * Same as page_add_anon_rmap but must only be called on *new* pages. | 586 | * Same as page_add_anon_rmap but must only be called on *new* pages. |
| 555 | * This means the inc-and-test can be bypassed. | 587 | * This means the inc-and-test can be bypassed. |
| 588 | * Page does not have to be locked. | ||
| 556 | */ | 589 | */ |
| 557 | void page_add_new_anon_rmap(struct page *page, | 590 | void page_add_new_anon_rmap(struct page *page, |
| 558 | struct vm_area_struct *vma, unsigned long address) | 591 | struct vm_area_struct *vma, unsigned long address) |
| 559 | { | 592 | { |
| 593 | BUG_ON(address < vma->vm_start || address >= vma->vm_end); | ||
| 560 | atomic_set(&page->_mapcount, 0); /* elevate count by 1 (starts at -1) */ | 594 | atomic_set(&page->_mapcount, 0); /* elevate count by 1 (starts at -1) */ |
| 561 | __page_set_anon_rmap(page, vma, address); | 595 | __page_set_anon_rmap(page, vma, address); |
| 562 | } | 596 | } |
| @@ -573,6 +607,26 @@ void page_add_file_rmap(struct page *page) | |||
| 573 | __inc_zone_page_state(page, NR_FILE_MAPPED); | 607 | __inc_zone_page_state(page, NR_FILE_MAPPED); |
| 574 | } | 608 | } |
| 575 | 609 | ||
| 610 | #ifdef CONFIG_DEBUG_VM | ||
| 611 | /** | ||
| 612 | * page_dup_rmap - duplicate pte mapping to a page | ||
| 613 | * @page: the page to add the mapping to | ||
| 614 | * | ||
| 615 | * For copy_page_range only: minimal extract from page_add_file_rmap / | ||
| 616 | * page_add_anon_rmap, avoiding unnecessary tests (already checked) so it's | ||
| 617 | * quicker. | ||
| 618 | * | ||
| 619 | * The caller needs to hold the pte lock. | ||
| 620 | */ | ||
| 621 | void page_dup_rmap(struct page *page, struct vm_area_struct *vma, unsigned long address) | ||
| 622 | { | ||
| 623 | BUG_ON(page_mapcount(page) == 0); | ||
| 624 | if (PageAnon(page)) | ||
| 625 | __page_check_anon_rmap(page, vma, address); | ||
| 626 | atomic_inc(&page->_mapcount); | ||
| 627 | } | ||
| 628 | #endif | ||
| 629 | |||
| 576 | /** | 630 | /** |
| 577 | * page_remove_rmap - take down pte mapping from a page | 631 | * page_remove_rmap - take down pte mapping from a page |
| 578 | * @page: page to remove mapping from | 632 | * @page: page to remove mapping from |
