Merge branch 'linus' into x86/xen
Ingo Molnar [Mon, 16 Jun 2008 09:21:27 +0000 (11:21 +0200)]
1  2 
arch/x86/xen/mmu.c
arch/x86/xen/time.c
include/linux/page-flags.h

diff --combined arch/x86/xen/mmu.c
  #include "multicalls.h"
  #include "mmu.h"
  
 +#define P2M_ENTRIES_PER_PAGE  (PAGE_SIZE / sizeof(unsigned long))
 +#define TOP_ENTRIES           (MAX_DOMAIN_PAGES / P2M_ENTRIES_PER_PAGE)
 +
 +/* Placeholder for holes in the address space */
 +static unsigned long p2m_missing[P2M_ENTRIES_PER_PAGE]
 +      __attribute__((section(".data.page_aligned"))) =
 +              { [ 0 ... P2M_ENTRIES_PER_PAGE-1 ] = ~0UL };
 +
 + /* Array of pointers to pages containing p2m entries */
 +static unsigned long *p2m_top[TOP_ENTRIES]
 +      __attribute__((section(".data.page_aligned"))) =
 +              { [ 0 ... TOP_ENTRIES - 1] = &p2m_missing[0] };
 +
 +/* Arrays of p2m arrays expressed in mfns used for save/restore */
 +static unsigned long p2m_top_mfn[TOP_ENTRIES]
 +      __attribute__((section(".bss.page_aligned")));
 +
 +static unsigned long p2m_top_mfn_list[
 +                      PAGE_ALIGN(TOP_ENTRIES / P2M_ENTRIES_PER_PAGE)]
 +      __attribute__((section(".bss.page_aligned")));
 +
 +static inline unsigned p2m_top_index(unsigned long pfn)
 +{
 +      BUG_ON(pfn >= MAX_DOMAIN_PAGES);
 +      return pfn / P2M_ENTRIES_PER_PAGE;
 +}
 +
 +static inline unsigned p2m_index(unsigned long pfn)
 +{
 +      return pfn % P2M_ENTRIES_PER_PAGE;
 +}
 +
 +/* Build the parallel p2m_top_mfn structures */
 +void xen_setup_mfn_list_list(void)
 +{
 +      unsigned pfn, idx;
 +
 +      for(pfn = 0; pfn < MAX_DOMAIN_PAGES; pfn += P2M_ENTRIES_PER_PAGE) {
 +              unsigned topidx = p2m_top_index(pfn);
 +
 +              p2m_top_mfn[topidx] = virt_to_mfn(p2m_top[topidx]);
 +      }
 +
 +      for(idx = 0; idx < ARRAY_SIZE(p2m_top_mfn_list); idx++) {
 +              unsigned topidx = idx * P2M_ENTRIES_PER_PAGE;
 +              p2m_top_mfn_list[idx] = virt_to_mfn(&p2m_top_mfn[topidx]);
 +      }
 +
 +      BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info);
 +
 +      HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
 +              virt_to_mfn(p2m_top_mfn_list);
 +      HYPERVISOR_shared_info->arch.max_pfn = xen_start_info->nr_pages;
 +}
 +
 +/* Set up p2m_top to point to the domain-builder provided p2m pages */
 +void __init xen_build_dynamic_phys_to_machine(void)
 +{
 +      unsigned long *mfn_list = (unsigned long *)xen_start_info->mfn_list;
 +      unsigned long max_pfn = min(MAX_DOMAIN_PAGES, xen_start_info->nr_pages);
 +      unsigned pfn;
 +
 +      for(pfn = 0; pfn < max_pfn; pfn += P2M_ENTRIES_PER_PAGE) {
 +              unsigned topidx = p2m_top_index(pfn);
 +
 +              p2m_top[topidx] = &mfn_list[pfn];
 +      }
 +}
 +
 +unsigned long get_phys_to_machine(unsigned long pfn)
 +{
 +      unsigned topidx, idx;
 +
 +      if (unlikely(pfn >= MAX_DOMAIN_PAGES))
 +              return INVALID_P2M_ENTRY;
 +
 +      topidx = p2m_top_index(pfn);
 +      idx = p2m_index(pfn);
 +      return p2m_top[topidx][idx];
 +}
 +EXPORT_SYMBOL_GPL(get_phys_to_machine);
 +
 +static void alloc_p2m(unsigned long **pp, unsigned long *mfnp)
 +{
 +      unsigned long *p;
 +      unsigned i;
 +
 +      p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL);
 +      BUG_ON(p == NULL);
 +
 +      for(i = 0; i < P2M_ENTRIES_PER_PAGE; i++)
 +              p[i] = INVALID_P2M_ENTRY;
 +
 +      if (cmpxchg(pp, p2m_missing, p) != p2m_missing)
 +              free_page((unsigned long)p);
 +      else
 +              *mfnp = virt_to_mfn(p);
 +}
 +
 +void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
 +{
 +      unsigned topidx, idx;
 +
 +      if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
 +              BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
 +              return;
 +      }
 +
 +      if (unlikely(pfn >= MAX_DOMAIN_PAGES)) {
 +              BUG_ON(mfn != INVALID_P2M_ENTRY);
 +              return;
 +      }
 +
 +      topidx = p2m_top_index(pfn);
 +      if (p2m_top[topidx] == p2m_missing) {
 +              /* no need to allocate a page to store an invalid entry */
 +              if (mfn == INVALID_P2M_ENTRY)
 +                      return;
 +              alloc_p2m(&p2m_top[topidx], &p2m_top_mfn[topidx]);
 +      }
 +
 +      idx = p2m_index(pfn);
 +      p2m_top[topidx][idx] = mfn;
 +}
 +
  xmaddr_t arbitrary_virt_to_machine(unsigned long address)
  {
        unsigned int level;
        pte_t *pte = lookup_address(address, &level);
-       unsigned offset = address & PAGE_MASK;
+       unsigned offset = address & ~PAGE_MASK;
  
        BUG_ON(pte == NULL);
  
@@@ -223,14 -98,7 +223,14 @@@ void make_lowmem_page_readwrite(void *v
  }
  
  
 -void xen_set_pmd(pmd_t *ptr, pmd_t val)
 +static bool page_pinned(void *ptr)
 +{
 +      struct page *page = virt_to_page(ptr);
 +
 +      return PagePinned(page);
 +}
 +
 +void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val)
  {
        struct multicall_space mcs;
        struct mmu_update *u;
        preempt_enable();
  }
  
 +void xen_set_pmd(pmd_t *ptr, pmd_t val)
 +{
 +      /* If page is not pinned, we can just update the entry
 +         directly */
 +      if (!page_pinned(ptr)) {
 +              *ptr = val;
 +              return;
 +      }
 +
 +      xen_set_pmd_hyper(ptr, val);
 +}
 +
  /*
   * Associate a virtual page frame with a given physical page frame
   * and protection flags for that frame.
@@@ -366,8 -222,8 +366,8 @@@ pmdval_t xen_pmd_val(pmd_t pmd
                ret = machine_to_phys(XMADDR(ret)).paddr | _PAGE_PRESENT;
        return ret;
  }
 -#ifdef CONFIG_X86_PAE
 -void xen_set_pud(pud_t *ptr, pud_t val)
 +
 +void xen_set_pud_hyper(pud_t *ptr, pud_t val)
  {
        struct multicall_space mcs;
        struct mmu_update *u;
        preempt_enable();
  }
  
 +void xen_set_pud(pud_t *ptr, pud_t val)
 +{
 +      /* If page is not pinned, we can just update the entry
 +         directly */
 +      if (!page_pinned(ptr)) {
 +              *ptr = val;
 +              return;
 +      }
 +
 +      xen_set_pud_hyper(ptr, val);
 +}
 +
  void xen_set_pte(pte_t *ptep, pte_t pte)
  {
        ptep->pte_high = pte.pte_high;
@@@ -418,7 -262,7 +418,7 @@@ void xen_pte_clear(struct mm_struct *mm
  
  void xen_pmd_clear(pmd_t *pmdp)
  {
 -      xen_set_pmd(pmdp, __pmd(0));
 +      set_pmd(pmdp, __pmd(0));
  }
  
  pmd_t xen_make_pmd(pmdval_t pmd)
  
        return native_make_pmd(pmd);
  }
 -#else  /* !PAE */
 -void xen_set_pte(pte_t *ptep, pte_t pte)
 -{
 -      *ptep = pte;
 -}
 -#endif        /* CONFIG_X86_PAE */
  
  /*
    (Yet another) pagetable walker.  This one is intended for pinning a
@@@ -580,6 -430,8 +580,6 @@@ static int pin_page(struct page *page, 
     read-only, and can be pinned. */
  void xen_pgd_pin(pgd_t *pgd)
  {
 -      unsigned level;
 -
        xen_mc_batch();
  
        if (pgd_walk(pgd, pin_page, TASK_SIZE)) {
                xen_mc_batch();
        }
  
 -#ifdef CONFIG_X86_PAE
 -      level = MMUEXT_PIN_L3_TABLE;
 -#else
 -      level = MMUEXT_PIN_L2_TABLE;
 -#endif
 +      xen_do_pin(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(pgd)));
 +      xen_mc_issue(0);
 +}
  
 -      xen_do_pin(level, PFN_DOWN(__pa(pgd)));
 +/*
 + * On save, we need to pin all pagetables to make sure they get their
 + * mfns turned into pfns.  Search the list for any unpinned pgds and pin
 + * them (unpinned pgds are not currently in use, probably because the
 + * process is under construction or destruction).
 + */
 +void xen_mm_pin_all(void)
 +{
 +      unsigned long flags;
 +      struct page *page;
  
 -      xen_mc_issue(0);
 +      spin_lock_irqsave(&pgd_lock, flags);
 +
 +      list_for_each_entry(page, &pgd_list, lru) {
 +              if (!PagePinned(page)) {
 +                      xen_pgd_pin((pgd_t *)page_address(page));
 +                      SetPageSavePinned(page);
 +              }
 +      }
 +
 +      spin_unlock_irqrestore(&pgd_lock, flags);
  }
  
  /* The init_mm pagetable is really pinned as soon as its created, but
@@@ -673,29 -509,6 +673,29 @@@ static void xen_pgd_unpin(pgd_t *pgd
        xen_mc_issue(0);
  }
  
 +/*
 + * On resume, undo any pinning done at save, so that the rest of the
 + * kernel doesn't see any unexpected pinned pagetables.
 + */
 +void xen_mm_unpin_all(void)
 +{
 +      unsigned long flags;
 +      struct page *page;
 +
 +      spin_lock_irqsave(&pgd_lock, flags);
 +
 +      list_for_each_entry(page, &pgd_list, lru) {
 +              if (PageSavePinned(page)) {
 +                      BUG_ON(!PagePinned(page));
 +                      printk("unpinning pinned %p\n", page_address(page));
 +                      xen_pgd_unpin((pgd_t *)page_address(page));
 +                      ClearPageSavePinned(page);
 +              }
 +      }
 +
 +      spin_unlock_irqrestore(&pgd_lock, flags);
 +}
 +
  void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next)
  {
        spin_lock(&next->page_table_lock);
@@@ -789,7 -602,7 +789,7 @@@ void xen_exit_mmap(struct mm_struct *mm
        spin_lock(&mm->page_table_lock);
  
        /* pgd may not be pinned in the error exit path of execve */
 -      if (PagePinned(virt_to_page(mm->pgd)))
 +      if (page_pinned(mm->pgd))
                xen_pgd_unpin(mm->pgd);
  
        spin_unlock(&mm->page_table_lock);
diff --combined arch/x86/xen/time.c
@@@ -12,6 -12,7 +12,7 @@@
  #include <linux/clocksource.h>
  #include <linux/clockchips.h>
  #include <linux/kernel_stat.h>
+ #include <linux/math64.h>
  
  #include <asm/xen/hypervisor.h>
  #include <asm/xen/hypercall.h>
@@@ -150,11 -151,7 +151,7 @@@ static void do_stolen_accounting(void
        if (stolen < 0)
                stolen = 0;
  
-       ticks = 0;
-       while (stolen >= NS_PER_TICK) {
-               ticks++;
-               stolen -= NS_PER_TICK;
-       }
+       ticks = iter_div_u64_rem(stolen, NS_PER_TICK, &stolen);
        __get_cpu_var(residual_stolen) = stolen;
        account_steal_time(NULL, ticks);
  
        if (blocked < 0)
                blocked = 0;
  
-       ticks = 0;
-       while (blocked >= NS_PER_TICK) {
-               ticks++;
-               blocked -= NS_PER_TICK;
-       }
+       ticks = iter_div_u64_rem(blocked, NS_PER_TICK, &blocked);
        __get_cpu_var(residual_blocked) = blocked;
        account_steal_time(idle_task(smp_processor_id()), ticks);
  }
@@@ -572,19 -565,6 +565,19 @@@ void xen_setup_cpu_clockevents(void
        clockevents_register_device(&__get_cpu_var(xen_clock_events));
  }
  
 +void xen_timer_resume(void)
 +{
 +      int cpu;
 +
 +      if (xen_clockevent != &xen_vcpuop_clockevent)
 +              return;
 +
 +      for_each_online_cpu(cpu) {
 +              if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
 +                      BUG();
 +      }
 +}
 +
  __init void xen_time_init(void)
  {
        int cpu = smp_processor_id();
@@@ -157,7 -157,6 +157,7 @@@ PAGEFLAG(Active, active) __CLEARPAGEFLA
  __PAGEFLAG(Slab, slab)
  PAGEFLAG(Checked, owner_priv_1)               /* Used by some filesystems */
  PAGEFLAG(Pinned, owner_priv_1) TESTSCFLAG(Pinned, owner_priv_1) /* Xen */
 +PAGEFLAG(SavePinned, dirty);                                  /* Xen */
  PAGEFLAG(Reserved, reserved) __CLEARPAGEFLAG(Reserved, reserved)
  PAGEFLAG(Private, private) __CLEARPAGEFLAG(Private, private)
        __SETPAGEFLAG(Private, private)
@@@ -307,5 -306,29 +307,29 @@@ static inline void __ClearPageTail(stru
  }
  
  #endif /* !PAGEFLAGS_EXTENDED */
+ #define PAGE_FLAGS    (1 << PG_lru   | 1 << PG_private   | 1 << PG_locked | \
+                        1 << PG_buddy | 1 << PG_writeback | \
+                        1 << PG_slab  | 1 << PG_swapcache | 1 << PG_active)
+ /*
+  * Flags checked in bad_page().  Pages on the free list should not have
+  * these flags set.  It they are, there is a problem.
+  */
+ #define PAGE_FLAGS_CLEAR_WHEN_BAD (PAGE_FLAGS | 1 << PG_reclaim | 1 << PG_dirty)
+ /*
+  * Flags checked when a page is freed.  Pages being freed should not have
+  * these flags set.  It they are, there is a problem.
+  */
+ #define PAGE_FLAGS_CHECK_AT_FREE (PAGE_FLAGS | 1 << PG_reserved)
+ /*
+  * Flags checked when a page is prepped for return by the page allocator.
+  * Pages being prepped should not have these flags set.  It they are, there
+  * is a problem.
+  */
+ #define PAGE_FLAGS_CHECK_AT_PREP (PAGE_FLAGS | 1 << PG_reserved | 1 << PG_dirty)
  #endif /* !__GENERATING_BOUNDS_H */
  #endif        /* PAGE_FLAGS_H */