mm: more rmap checking

Re-introduce rmap verification patches that Hugh removed when he removed
PG_map_lock. PG_map_lock actually isn't needed to synchronise access to
anonymous pages, because PG_locked and PTL together already do.

These checks were important in discovering and fixing a rare rmap corruption
in SLES9.

Signed-off-by: Nick Piggin <npiggin@suse.de>
Cc: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by Nick Piggin and committed by Linus Torvalds c97a9e10 ea125892

+62 -11
+5 -8
include/linux/rmap.h
··· 74 74 void page_add_file_rmap(struct page *); 75 75 void page_remove_rmap(struct page *, struct vm_area_struct *); 76 76 77 - /** 78 - * page_dup_rmap - duplicate pte mapping to a page 79 - * @page: the page to add the mapping to 80 - * 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) 77 + #ifdef CONFIG_DEBUG_VM 78 + void page_dup_rmap(struct page *page, struct vm_area_struct *vma, unsigned long address); 79 + #else 80 + static inline void page_dup_rmap(struct page *page, struct vm_area_struct *vma, unsigned long address) 85 81 { 86 82 atomic_inc(&page->_mapcount); 87 83 } 84 + #endif 88 85 89 86 /* 90 87 * Called from mm/vmscan.c to handle paging out
+1 -1
mm/memory.c
··· 481 481 page = vm_normal_page(vma, addr, pte); 482 482 if (page) { 483 483 get_page(page); 484 - page_dup_rmap(page); 484 + page_dup_rmap(page, vma, addr); 485 485 rss[!!PageAnon(page)]++; 486 486 } 487 487
+56 -2
mm/rmap.c
··· 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 562 * page_add_anon_rmap - add pte mapping to an anonymous page 534 563 * @page: the page to add the mapping to 535 564 * @vma: the vm area in which the mapping is added 536 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 569 void page_add_anon_rmap(struct page *page, 541 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 574 if (atomic_inc_and_test(&page->_mapcount)) 544 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 /* ··· 585 553 * 586 554 * Same as page_add_anon_rmap but must only be called on *new* pages. 587 555 * This means the inc-and-test can be bypassed. 556 + * Page does not have to be locked. 588 557 */ 589 558 void page_add_new_anon_rmap(struct page *page, 590 559 struct vm_area_struct *vma, unsigned long address) 591 560 { 561 + BUG_ON(address < vma->vm_start || address >= vma->vm_end); 592 562 atomic_set(&page->_mapcount, 0); /* elevate count by 1 (starts at -1) */ 593 563 __page_set_anon_rmap(page, vma, address); 594 564 } ··· 606 572 if (atomic_inc_and_test(&page->_mapcount)) 607 573 __inc_zone_page_state(page, NR_FILE_MAPPED); 608 574 } 575 + 576 + #ifdef CONFIG_DEBUG_VM 577 + /** 578 + * page_dup_rmap - duplicate pte mapping to a page 579 + * @page: the page to add the mapping to 580 + * 581 + * For copy_page_range only: minimal extract from page_add_file_rmap / 582 + * page_add_anon_rmap, avoiding unnecessary tests (already checked) so it's 583 + * quicker. 584 + * 585 + * The caller needs to hold the pte lock. 586 + */ 587 + void page_dup_rmap(struct page *page, struct vm_area_struct *vma, unsigned long address) 588 + { 589 + BUG_ON(page_mapcount(page) == 0); 590 + if (PageAnon(page)) 591 + __page_check_anon_rmap(page, vma, address); 592 + atomic_inc(&page->_mapcount); 593 + } 594 + #endif 609 595 610 596 /** 611 597 * page_remove_rmap - take down pte mapping from a page