|
@@ -52,6 +52,9 @@
|
|
#include <linux/writeback.h>
|
|
#include <linux/writeback.h>
|
|
#include <linux/memcontrol.h>
|
|
#include <linux/memcontrol.h>
|
|
#include <linux/mmu_notifier.h>
|
|
#include <linux/mmu_notifier.h>
|
|
|
|
+#include <linux/kallsyms.h>
|
|
|
|
+#include <linux/swapops.h>
|
|
|
|
+#include <linux/elf.h>
|
|
|
|
|
|
#include <asm/pgalloc.h>
|
|
#include <asm/pgalloc.h>
|
|
#include <asm/uaccess.h>
|
|
#include <asm/uaccess.h>
|
|
@@ -59,9 +62,6 @@
|
|
#include <asm/tlbflush.h>
|
|
#include <asm/tlbflush.h>
|
|
#include <asm/pgtable.h>
|
|
#include <asm/pgtable.h>
|
|
|
|
|
|
-#include <linux/swapops.h>
|
|
|
|
-#include <linux/elf.h>
|
|
|
|
-
|
|
|
|
#include "internal.h"
|
|
#include "internal.h"
|
|
|
|
|
|
#ifndef CONFIG_NEED_MULTIPLE_NODES
|
|
#ifndef CONFIG_NEED_MULTIPLE_NODES
|
|
@@ -375,15 +375,41 @@ static inline void add_mm_rss(struct mm_struct *mm, int file_rss, int anon_rss)
|
|
*
|
|
*
|
|
* The calling function must still handle the error.
|
|
* The calling function must still handle the error.
|
|
*/
|
|
*/
|
|
-static void print_bad_pte(struct vm_area_struct *vma, pte_t pte,
|
|
|
|
- unsigned long vaddr)
|
|
|
|
-{
|
|
|
|
- printk(KERN_ERR "Bad pte = %08llx, process = %s, "
|
|
|
|
- "vm_flags = %lx, vaddr = %lx\n",
|
|
|
|
- (long long)pte_val(pte),
|
|
|
|
- (vma->vm_mm == current->mm ? current->comm : "???"),
|
|
|
|
- vma->vm_flags, vaddr);
|
|
|
|
|
|
+static void print_bad_pte(struct vm_area_struct *vma, unsigned long addr,
|
|
|
|
+ pte_t pte, struct page *page)
|
|
|
|
+{
|
|
|
|
+ pgd_t *pgd = pgd_offset(vma->vm_mm, addr);
|
|
|
|
+ pud_t *pud = pud_offset(pgd, addr);
|
|
|
|
+ pmd_t *pmd = pmd_offset(pud, addr);
|
|
|
|
+ struct address_space *mapping;
|
|
|
|
+ pgoff_t index;
|
|
|
|
+
|
|
|
|
+ mapping = vma->vm_file ? vma->vm_file->f_mapping : NULL;
|
|
|
|
+ index = linear_page_index(vma, addr);
|
|
|
|
+
|
|
|
|
+ printk(KERN_EMERG "Bad page map in process %s pte:%08llx pmd:%08llx\n",
|
|
|
|
+ current->comm,
|
|
|
|
+ (long long)pte_val(pte), (long long)pmd_val(*pmd));
|
|
|
|
+ if (page) {
|
|
|
|
+ printk(KERN_EMERG
|
|
|
|
+ "page:%p flags:%p count:%d mapcount:%d mapping:%p index:%lx\n",
|
|
|
|
+ page, (void *)page->flags, page_count(page),
|
|
|
|
+ page_mapcount(page), page->mapping, page->index);
|
|
|
|
+ }
|
|
|
|
+ printk(KERN_EMERG
|
|
|
|
+ "addr:%p vm_flags:%08lx anon_vma:%p mapping:%p index:%lx\n",
|
|
|
|
+ (void *)addr, vma->vm_flags, vma->anon_vma, mapping, index);
|
|
|
|
+ /*
|
|
|
|
+ * Choose text because data symbols depend on CONFIG_KALLSYMS_ALL=y
|
|
|
|
+ */
|
|
|
|
+ if (vma->vm_ops)
|
|
|
|
+ print_symbol(KERN_EMERG "vma->vm_ops->fault: %s\n",
|
|
|
|
+ (unsigned long)vma->vm_ops->fault);
|
|
|
|
+ if (vma->vm_file && vma->vm_file->f_op)
|
|
|
|
+ print_symbol(KERN_EMERG "vma->vm_file->f_op->mmap: %s\n",
|
|
|
|
+ (unsigned long)vma->vm_file->f_op->mmap);
|
|
dump_stack();
|
|
dump_stack();
|
|
|
|
+ add_taint(TAINT_BAD_PAGE);
|
|
}
|
|
}
|
|
|
|
|
|
static inline int is_cow_mapping(unsigned int flags)
|
|
static inline int is_cow_mapping(unsigned int flags)
|
|
@@ -773,6 +799,8 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb,
|
|
file_rss--;
|
|
file_rss--;
|
|
}
|
|
}
|
|
page_remove_rmap(page, vma);
|
|
page_remove_rmap(page, vma);
|
|
|
|
+ if (unlikely(page_mapcount(page) < 0))
|
|
|
|
+ print_bad_pte(vma, addr, ptent, page);
|
|
tlb_remove_page(tlb, page);
|
|
tlb_remove_page(tlb, page);
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
@@ -2684,7 +2712,7 @@ static int do_nonlinear_fault(struct mm_struct *mm, struct vm_area_struct *vma,
|
|
/*
|
|
/*
|
|
* Page table corrupted: show pte and kill process.
|
|
* Page table corrupted: show pte and kill process.
|
|
*/
|
|
*/
|
|
- print_bad_pte(vma, orig_pte, address);
|
|
|
|
|
|
+ print_bad_pte(vma, address, orig_pte, NULL);
|
|
return VM_FAULT_OOM;
|
|
return VM_FAULT_OOM;
|
|
}
|
|
}
|
|
|
|
|