NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: port-xen/45975 (panic: HYPERVISOR_mmu_update failed, ret: -22 during heavy activity)



On Fri, Feb 17, 2012 at 01:12:46PM +0100, Manuel Bouyer wrote:
> I think I found where the problem comes from:
> in uvm, uvm_km_pgremove_intrsafe() will return a page to the free list.
> But as it uses pmap_extract(), the mapping of the pages in pmap_kernel()
> is removed *after* calling uvm_km_pgremove_intrsafe().
> So there is a window where pages are returned to the free list, but
> are still mapped in pmap_kernel(); another CPU can allocate and map this
> page in this time (remember a CPU can be preempted by the hypervisor,
> so the window can be quite long).
> I confirmed this by adding an (expensive) check in uvm_pagefree() looking
> for existing mappings of a page.
> Multiple mappings of the same physical page with different
> attributes are not a problem on real hardware, so this is a problem only for
> Xen.
> One trivial fix is to call pmap_kremove() from uvm_km_pgremove_intrsafe()
> just after pmap_extract() has been done (and remove it from callers).
> I'm testing this now

See attached patch. I couldn't make my test domUs (a i386PAE with 4
virtual CPU on a dual-core box, and a amd64 with 8 virtual CPUs on
a 8-core box), several build.sh -j<as_appropriate> release have
completed.

-- 
Manuel Bouyer <bouyer%antioche.eu.org@localhost>
     NetBSD: 26 ans d'experience feront toujours la difference
--
Index: uvm/uvm_km.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_km.c,v
retrieving revision 1.119
diff -u -p -u -r1.119 uvm_km.c
--- uvm/uvm_km.c        4 Feb 2012 17:56:17 -0000       1.119
+++ uvm/uvm_km.c        17 Feb 2012 15:26:30 -0000
@@ -472,12 +472,18 @@ uvm_km_pgremove_intrsafe(struct vm_map *
                if (!pmap_extract(pmap_kernel(), start, &pa)) {
                        continue;
                }
+#ifdef __PMAP_NEED_UNMAP_BEFORE_FREE
+               pmap_kremove(start, PAGE_SIZE);
+#endif
                pg = PHYS_TO_VM_PAGE(pa);
                KASSERT(pg);
                KASSERT(pg->uobject == NULL && pg->uanon == NULL);
                KASSERT((pg->flags & PG_BUSY) == 0);
                uvm_pagefree(pg);
        }
+#ifndef __PMAP_NEED_UNMAP_BEFORE_FREE
+       pmap_kremove(start, end - start);
+#endif
 }
 
 #if defined(DEBUG)
@@ -670,7 +676,6 @@ uvm_km_free(struct vm_map *map, vaddr_t 
                 * remove it after.  See comment below about KVA visibility.
                 */
                uvm_km_pgremove_intrsafe(map, addr, addr + size);
-               pmap_kremove(addr, size);
        }
 
        /*
@@ -747,7 +752,6 @@ again:
                        } else {
                                uvm_km_pgremove_intrsafe(kernel_map, va,
                                    va + size);
-                               pmap_kremove(va, size);
                                vmem_free(kmem_va_arena, va, size);
                                return ENOMEM;
                        }
@@ -783,7 +787,6 @@ uvm_km_kmem_free(vmem_t *vm, vmem_addr_t
        }
 #endif /* PMAP_UNMAP_POOLPAGE */
        uvm_km_pgremove_intrsafe(kernel_map, addr, addr + size);
-       pmap_kremove(addr, size);
        pmap_update(pmap_kernel());
 
        vmem_free(vm, addr, size);
Index: uvm/uvm_kmguard.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_kmguard.c,v
retrieving revision 1.9
diff -u -p -u -r1.9 uvm_kmguard.c
--- uvm/uvm_kmguard.c   5 Feb 2012 11:08:06 -0000       1.9
+++ uvm/uvm_kmguard.c   17 Feb 2012 15:26:30 -0000
@@ -180,7 +180,6 @@ uvm_kmguard_free(struct uvm_kmguard *kg,
         */
 
        uvm_km_pgremove_intrsafe(kernel_map, va, va + PAGE_SIZE * 2);
-       pmap_kremove(va, PAGE_SIZE * 2);
        pmap_update(pmap_kernel());
 
        /*
Index: uvm/uvm_map.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_map.c,v
retrieving revision 1.312
diff -u -p -u -r1.312 uvm_map.c
--- uvm/uvm_map.c       28 Jan 2012 00:00:06 -0000      1.312
+++ uvm/uvm_map.c       17 Feb 2012 15:26:30 -0000
@@ -2246,7 +2246,6 @@ uvm_unmap_remove(struct vm_map *map, vad
                        if ((entry->flags & UVM_MAP_KMAPENT) == 0) {
                                uvm_km_pgremove_intrsafe(map, entry->start,
                                    entry->end);
-                               pmap_kremove(entry->start, len);
                        }
                } else if (UVM_ET_ISOBJ(entry) &&
                           UVM_OBJ_IS_KERN_OBJECT(entry->object.uvm_obj)) {
Index: arch/x86/include/pmap.h
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/include/pmap.h,v
retrieving revision 1.49
diff -u -p -u -r1.49 pmap.h
--- arch/x86/include/pmap.h     4 Dec 2011 16:24:13 -0000       1.49
+++ arch/x86/include/pmap.h     17 Feb 2012 15:26:30 -0000
@@ -296,6 +298,14 @@ void               pmap_tlb_intr(void);
 #define PMAP_GROWKERNEL                /* turn on pmap_growkernel interface */
 #define PMAP_FORK              /* turn on pmap_fork interface */
 
+#ifdef XEN
+/*
+ * If a free vm_page is allocated for a PDP, is will be rejected
+ * by Xen if it has still some R/W mapping.
+ */
+#define __PMAP_NEED_UNMAP_BEFORE_FREE
+#endif
+
 /*
  * Do idle page zero'ing uncached to avoid polluting the cache.
  */


Home | Main Index | Thread Index | Old Index