diff options
author | Hugh Dickins <hugh@veritas.com> | 2009-01-06 17:40:10 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-06 18:59:07 -0500 |
commit | 2509ef26db4699a5d9fa876e90ddfc107afcab84 (patch) | |
tree | 09e65185142c60b5d766d8b75f3cbc8a65de6a39 | |
parent | 22b31eec63e5f2e219a3ee15f456897272bc73e8 (diff) |
badpage: zap print_bad_pte on swap and file
Complete zap_pte_range()'s coverage of bad pagetable entries by calling
print_bad_pte() on a pte_file in a linear vma and on a bad swap entry.
That needs free_swap_and_cache() to tell it, which will also have shown
one of those "swap_free" errors (but with much less information).
Similar checks in fork's copy_one_pte()? No, that would be more noisy
than helpful: we'll see them when parent and child exec or exit.
Where do_nonlinear_fault() calls print_bad_pte(): omit !VM_CAN_NONLINEAR
case, that could only be a bug in sys_remap_file_pages(), not a bad pte.
VM_FAULT_OOM rather than VM_FAULT_SIGBUS? Well, okay, that is consistent
with what happens if do_swap_page() operates a bad swap entry; but don't
we have patches to be more careful about killing when VM_FAULT_OOM?
Signed-off-by: Hugh Dickins <hugh@veritas.com>
Cc: Nick Piggin <nickpiggin@yahoo.com.au>
Cc: Christoph Lameter <cl@linux-foundation.org>
Cc: Mel Gorman <mel@csn.ul.ie>
Cc: Rik van Riel <riel@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | include/linux/swap.h | 12 | ||||
-rw-r--r-- | mm/memory.c | 11 | ||||
-rw-r--r-- | mm/swapfile.c | 7 |
3 files changed, 14 insertions, 16 deletions
diff --git a/include/linux/swap.h b/include/linux/swap.h index cbf7fbed3dfd..91dee50fe260 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h | |||
@@ -302,7 +302,7 @@ extern swp_entry_t get_swap_page_of_type(int); | |||
302 | extern int swap_duplicate(swp_entry_t); | 302 | extern int swap_duplicate(swp_entry_t); |
303 | extern int valid_swaphandles(swp_entry_t, unsigned long *); | 303 | extern int valid_swaphandles(swp_entry_t, unsigned long *); |
304 | extern void swap_free(swp_entry_t); | 304 | extern void swap_free(swp_entry_t); |
305 | extern void free_swap_and_cache(swp_entry_t); | 305 | extern int free_swap_and_cache(swp_entry_t); |
306 | extern int swap_type_of(dev_t, sector_t, struct block_device **); | 306 | extern int swap_type_of(dev_t, sector_t, struct block_device **); |
307 | extern unsigned int count_swap_pages(int, int); | 307 | extern unsigned int count_swap_pages(int, int); |
308 | extern sector_t map_swap_page(struct swap_info_struct *, pgoff_t); | 308 | extern sector_t map_swap_page(struct swap_info_struct *, pgoff_t); |
@@ -352,14 +352,8 @@ static inline void show_swap_cache_info(void) | |||
352 | { | 352 | { |
353 | } | 353 | } |
354 | 354 | ||
355 | static inline void free_swap_and_cache(swp_entry_t swp) | 355 | #define free_swap_and_cache(swp) is_migration_entry(swp) |
356 | { | 356 | #define swap_duplicate(swp) is_migration_entry(swp) |
357 | } | ||
358 | |||
359 | static inline int swap_duplicate(swp_entry_t swp) | ||
360 | { | ||
361 | return 0; | ||
362 | } | ||
363 | 357 | ||
364 | static inline void swap_free(swp_entry_t swp) | 358 | static inline void swap_free(swp_entry_t swp) |
365 | { | 359 | { |
diff --git a/mm/memory.c b/mm/memory.c index 890095f5f36d..b273cc12b15d 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -810,8 +810,12 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb, | |||
810 | */ | 810 | */ |
811 | if (unlikely(details)) | 811 | if (unlikely(details)) |
812 | continue; | 812 | continue; |
813 | if (!pte_file(ptent)) | 813 | if (pte_file(ptent)) { |
814 | free_swap_and_cache(pte_to_swp_entry(ptent)); | 814 | if (unlikely(!(vma->vm_flags & VM_NONLINEAR))) |
815 | print_bad_pte(vma, addr, ptent, NULL); | ||
816 | } else if | ||
817 | (unlikely(!free_swap_and_cache(pte_to_swp_entry(ptent)))) | ||
818 | print_bad_pte(vma, addr, ptent, NULL); | ||
815 | pte_clear_not_present_full(mm, addr, pte, tlb->fullmm); | 819 | pte_clear_not_present_full(mm, addr, pte, tlb->fullmm); |
816 | } while (pte++, addr += PAGE_SIZE, (addr != end && *zap_work > 0)); | 820 | } while (pte++, addr += PAGE_SIZE, (addr != end && *zap_work > 0)); |
817 | 821 | ||
@@ -2707,8 +2711,7 @@ static int do_nonlinear_fault(struct mm_struct *mm, struct vm_area_struct *vma, | |||
2707 | if (!pte_unmap_same(mm, pmd, page_table, orig_pte)) | 2711 | if (!pte_unmap_same(mm, pmd, page_table, orig_pte)) |
2708 | return 0; | 2712 | return 0; |
2709 | 2713 | ||
2710 | if (unlikely(!(vma->vm_flags & VM_NONLINEAR) || | 2714 | if (unlikely(!(vma->vm_flags & VM_NONLINEAR))) { |
2711 | !(vma->vm_flags & VM_CAN_NONLINEAR))) { | ||
2712 | /* | 2715 | /* |
2713 | * Page table corrupted: show pte and kill process. | 2716 | * Page table corrupted: show pte and kill process. |
2714 | */ | 2717 | */ |
diff --git a/mm/swapfile.c b/mm/swapfile.c index d00523601913..f28745855772 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c | |||
@@ -571,13 +571,13 @@ int try_to_free_swap(struct page *page) | |||
571 | * Free the swap entry like above, but also try to | 571 | * Free the swap entry like above, but also try to |
572 | * free the page cache entry if it is the last user. | 572 | * free the page cache entry if it is the last user. |
573 | */ | 573 | */ |
574 | void free_swap_and_cache(swp_entry_t entry) | 574 | int free_swap_and_cache(swp_entry_t entry) |
575 | { | 575 | { |
576 | struct swap_info_struct * p; | 576 | struct swap_info_struct *p; |
577 | struct page *page = NULL; | 577 | struct page *page = NULL; |
578 | 578 | ||
579 | if (is_migration_entry(entry)) | 579 | if (is_migration_entry(entry)) |
580 | return; | 580 | return 1; |
581 | 581 | ||
582 | p = swap_info_get(entry); | 582 | p = swap_info_get(entry); |
583 | if (p) { | 583 | if (p) { |
@@ -603,6 +603,7 @@ void free_swap_and_cache(swp_entry_t entry) | |||
603 | unlock_page(page); | 603 | unlock_page(page); |
604 | page_cache_release(page); | 604 | page_cache_release(page); |
605 | } | 605 | } |
606 | return p != NULL; | ||
606 | } | 607 | } |
607 | 608 | ||
608 | #ifdef CONFIG_HIBERNATION | 609 | #ifdef CONFIG_HIBERNATION |