On Thu, 2009-06-04 at 16:26 -0400, Pasi Kärkkäinen wrote:
> What do you suggest me to try next?
I'm at a bit of a loss to be honest...
It's interesting that it's always kswapd0 even in the case with no swap
configured. Were you running with CONFIG_SWAP=n or just with the swap
device turned off?
Judging from the backtrace the sequence of events seems to be roughly:
kswapd<0> runs and calls balance_pgdat which calls shrink_zone who in
turn calls shrink_active_list if inactive_anon_is_low() (so I think we
are dealing with anon pages). shrink_active_list() then iterates over a
list of pages calling page_referenced() on each one. page_referenced()
eventually calls down to page_referenced_one() (presumably via
page_referenced_anon()) and eventually to page_check_address() which
walks the page table and attempts to map the PTE page. This goes via
pte_offset_map() to kmap_atomic_pte() then xen_kmap_atomic_pte(). Here
we check if the page is pinned and then attempt to map it, since we
_think_ the page is not pinned the mapping is writable. However at this
point Xen reports that the page really is pinned (28000001 => Page Type
1 == L1 PT) and we are trying to make a writable mapping (e0000000 =>
Page Type 7 == Writable) which is disallowed.
Do you know which line of xen_set_pte() the fault is occurring at? I
assume either "ptep->pte_high =" or "ptep->pte_low =".
So the question is -- how come we have a page which is pinned but this
fact is not recorded in the struct page information? It might be
interesting to know if the corresponding L3 PT is pinned. If the mm is
active then this should always be the case and I _think_ it would be a
bug for the L3 to be pinned but not all the which L1s which it contains.
Can you try this patch which tries to notice this situation and prints
some potentially interesting information, similarly on the fault it
dumps a little more info. Since I can't repro I've only tested that it
doesn't break normal use, I've not actually seen the debug trigger...
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index abe8e4b..483bad7 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -285,7 +285,7 @@ check_v8086_mode(struct pt_regs *regs, unsigned long
address,
tsk->thread.screen_bitmap |= 1 << bit;
}
-static void dump_pagetable(unsigned long address)
+void dump_pagetable(unsigned long address)
{
__typeof__(pte_val(__pte(0))) page;
@@ -603,6 +603,10 @@ show_fault_oops(struct pt_regs *regs, unsigned long
error_code,
printk_address(regs->ip, 1);
dump_pagetable(address);
+ printk(KERN_CRIT "Fixmap KM_PTE0 @ %#lx\n", fix_to_virt(KM_PTE0));
+ dump_pagetable(fix_to_virt(KM_PTE0));
+ printk(KERN_CRIT "Fixmap KM_PTE0 @ %#lx\n", fix_to_virt(KM_PTE1));
+ dump_pagetable(fix_to_virt(KM_PTE1));
}
static noinline void
diff --git a/include/xen/swiotlb.h b/include/xen/swiotlb.h
index f35183b..5db8659 100644
--- a/include/xen/swiotlb.h
+++ b/include/xen/swiotlb.h
@@ -5,6 +5,10 @@ extern void xen_swiotlb_fixup(void *buf, size_t size, unsigned
long nslabs);
extern phys_addr_t xen_bus_to_phys(dma_addr_t daddr);
extern dma_addr_t xen_phys_to_bus(phys_addr_t paddr);
extern int xen_range_needs_mapping(phys_addr_t phys, size_t size);
+#ifdef CONFIG_XEN_PCI
extern int xen_wants_swiotlb(void);
+#else
+static inline int xen_wants_swiotlb(void) { return 0; }
+#endif
#endif /* _XEN_SWIOTLB_H */
diff --git a/mm/rmap.c b/mm/rmap.c
index 1652166..ae5d5a0 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -267,6 +267,7 @@ unsigned long page_address_in_vma(struct page *page, struct
vm_area_struct *vma)
pte_t *page_check_address(struct page *page, struct mm_struct *mm,
unsigned long address, spinlock_t **ptlp, int sync)
{
+ struct page *pgd_page, *pte_page;
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
@@ -285,6 +286,22 @@ pte_t *page_check_address(struct page *page, struct
mm_struct *mm,
if (!pmd_present(*pmd))
return NULL;
+ pgd_page = virt_to_page(mm->pgd);
+ pte_page = pmd_page(*pmd);
+
+ if (PagePinned(pgd_page) != PagePinned(pte_page)) {
+ extern void dump_pagetable(unsigned long address);
+ printk(KERN_CRIT "L4 at %p is %s contains L2 at %p which points
at an L1 which is %s %s\n",
+ pgd, PagePinned(pgd_page) ? "pinned" : "unpinned",
+ pmd, PagePinned(pte_page) ? "pinned" : "unpinned",
+ PageHighMem(pte_page) ? "highmem" : "lowmem");
+ printk(KERN_CRIT "address %#lx\n", address);
+ dump_pagetable(address);
+ printk(KERN_CRIT "Fixmap KM_PTE0 @ %#lx\n",
fix_to_virt(KM_PTE0));
+ dump_pagetable(fix_to_virt(KM_PTE0));
+ printk(KERN_CRIT "Fixmap KM_PTE0 @ %#lx\n",
fix_to_virt(KM_PTE1));
+ dump_pagetable(fix_to_virt(KM_PTE1));
+ }
pte = pte_offset_map(pmd, address);
/* Make a quick check before getting the lock */
if (!sync && !pte_present(*pte)) {
I'd guess that this would at least work around the issue, I doubt it's a
proper fix and it's going to shaft perf I suspect (not that highpte
won't be doing a pretty good job of that ;-)).
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index fefdeee..4c694e4 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -1521,7 +1521,7 @@ static void *xen_kmap_atomic_pte(struct page *page, enum
km_type type)
{
pgprot_t prot = PAGE_KERNEL;
- if (PagePinned(page))
+ if (1 || PagePinned(page))
prot = PAGE_KERNEL_RO;
if (0 && PageHighMem(page))
Ian.
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|