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

[Xen-devel] 2.6.32 PV Xen donU guest panic on nested call to arch_enter_lazy_mmu_mode()



I'm posting this because I am writing a patch to fix a 2.6.32 based PV Xen domU panic due to a nested call to arch/x86/include/asm/paravirt.h arch_enter_lazy_mmu_mode() (see details below). The following BUG_ON() was triggered:

   arch/x86/kernel/paravirt.c

   static inline void enter_lazy(enum paravirt_lazy_mode mode)
   {
           BUG_ON(percpu_read(paravirt_lazy_mode) != PARAVIRT_LAZY_NONE);

           percpu_write(paravirt_lazy_mode, mode);
   }

because enter_lazy() was called twice, once through mm/memory.c copy_pte_range() and a second time through an interrupt path.

The easy fix is to disable interrupts in copy_pte_range() before calling arch_enter_lazy_mmu_mode() and re-enable them after the call to arch_leave_lazy_mmu_mode() but I'm asking if there is a better way to handle this. If disabling interrupts is best, there are other calls to arch_enter_lazy_mmu_mode() that appear to have the same interruption issue. It may be best then to disable interrupts in arch_enter_lazy_mmu_mode() or paravirt_enter_lazy_mmu().

Here is how the nested call to arch_enter_lazy_mmu_mode() was made. The first call path is:

   do_fork()
     copy_process()
       dup_mm()
         dup_mmap()
           copy_page_range()
             copy_pud_range()
               copy_pmd_range()
                 copy_pte_range()
                   arch_enter_lazy_mmu_mode()
                     paravirt_enter_lazy_mmu()
                       enter_lazy()

We bubble back up to mm/memory.c copy_pte_range(). The guest is interrupted in that function. Here is the edited interrupt call stack that gets us to arch_enter_lazy_mmu_mode() for the second time without an intervening arch_leave_lazy_mmu_mode(), triggering the BUG_ON() in enter_lazy():

   xen_evtchn_do_upcall()
    handle_irq()
      blkif_interrupt()
        do_blkif_request()
          blkif_queue_request()
            gnttab_alloc_grant_references()
              get_free_entries()
                gnttab_expand()
                  gnttab_map()
                    arch_gnttab_map_shared()
                      apply_to_page_range(... map_pte_fn ...)

We get to enter_lazy() downstream from apply_to_page_range():

   apply_to_page_range(... map_pte_fn ...)
     apply_to_pud_range(... map_pte_fn ...)
       apply_to_pmd_range(... map_pte_fn ...)
          apply_to_pte_range(... map_pte_fn ...)
            arch_enter_lazy_mmu_mode()
              paravirt_enter_lazy_mmu()
                enter_lazy()

The spin locks acquired indirectly through mm/memory.c copy_pte_range() are obtained with spin_lock() and spin_acquire() which I believe do not disable interrupts.

Thanks,
Chuck

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.