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

[Xen-changelog] [xen-unstable] [IA64] fix races caused by p2m entry update



# HG changeset patch
# User awilliam@xxxxxxxxxxx
# Node ID d60da6514d65c8bf577d136adc720b1dc6c28388
# Parent  7e26d6ffdde76edad122ed07a973a7384d39b480
[IA64] fix races caused by p2m entry update

fixed some races in ia64_do_page_fault(), vcpu_itc_i(), vcpu_itc_d() and 
vcpu_fc().
introduce struct p2m_entry and check it later and try it again.

Signed-off-by: Isaku Yamahata <yamahata@xxxxxxxxxxxxx>
---
 xen/arch/ia64/vmx/vmx_process.c |    1 
 xen/arch/ia64/vmx/vtlb.c        |    2 -
 xen/arch/ia64/xen/faults.c      |    5 ++--
 xen/arch/ia64/xen/fw_emul.c     |   12 +++++------
 xen/arch/ia64/xen/mm.c          |   41 ++++++++++++++++------------------------
 xen/arch/ia64/xen/vcpu.c        |   23 ++++++++++++++++++----
 xen/include/asm-ia64/domain.h   |   26 ++++++++++++++++++++++++-
 xen/include/asm-ia64/mm.h       |   14 +++++--------
 8 files changed, 77 insertions(+), 47 deletions(-)

diff -r 7e26d6ffdde7 -r d60da6514d65 xen/arch/ia64/vmx/vmx_process.c
--- a/xen/arch/ia64/vmx/vmx_process.c   Mon Jun 19 12:54:34 2006 -0600
+++ b/xen/arch/ia64/vmx/vmx_process.c   Mon Jun 19 13:00:37 2006 -0600
@@ -58,7 +58,6 @@
 
 extern void die_if_kernel(char *str, struct pt_regs *regs, long err);
 extern void rnat_consumption (VCPU *vcpu);
-extern unsigned long translate_domain_mpaddr(unsigned long mpaddr);
 extern void alt_itlb (VCPU *vcpu, u64 vadr);
 extern void itlb_fault (VCPU *vcpu, u64 vadr);
 extern void ivhpt_fault (VCPU *vcpu, u64 vadr);
diff -r 7e26d6ffdde7 -r d60da6514d65 xen/arch/ia64/vmx/vtlb.c
--- a/xen/arch/ia64/vmx/vtlb.c  Mon Jun 19 12:54:34 2006 -0600
+++ b/xen/arch/ia64/vmx/vtlb.c  Mon Jun 19 13:00:37 2006 -0600
@@ -425,7 +425,7 @@ u64 translate_phy_pte(VCPU *v, u64 *pte,
     phy_pte.val = *pte;
     addr = *pte;
     addr = ((addr & _PAGE_PPN_MASK)>>ps<<ps)|(va&((1UL<<ps)-1));
-    addr = lookup_domain_mpa(v->domain, addr);
+    addr = lookup_domain_mpa(v->domain, addr, NULL);
     if(addr & GPFN_IO_MASK){
         *pte |= VTLB_PTE_IO;
         return -1;
diff -r 7e26d6ffdde7 -r d60da6514d65 xen/arch/ia64/xen/faults.c
--- a/xen/arch/ia64/xen/faults.c        Mon Jun 19 12:54:34 2006 -0600
+++ b/xen/arch/ia64/xen/faults.c        Mon Jun 19 13:00:37 2006 -0600
@@ -236,9 +236,10 @@ void ia64_do_page_fault (unsigned long a
        fault = vcpu_translate(current,address,is_data,&pteval,&itir,&iha);
        if (fault == IA64_NO_FAULT || fault == IA64_USE_TLB) {
                u64 logps;
-               pteval = translate_domain_pte(pteval, address, itir, &logps);
+               struct p2m_entry entry;
+               pteval = translate_domain_pte(pteval, address, itir, &logps, 
&entry);
                vcpu_itc_no_srlz(current,is_data?2:1,address,pteval,-1UL,logps);
-               if (read_seqretry(vtlb_lock, seq)) {
+               if (read_seqretry(vtlb_lock, seq) || p2m_entry_retry(&entry)) {
                        vcpu_flush_tlb_vhpt_range(address & ((1 << logps) - 1),
                                                  logps);
                        goto again;
diff -r 7e26d6ffdde7 -r d60da6514d65 xen/arch/ia64/xen/fw_emul.c
--- a/xen/arch/ia64/xen/fw_emul.c       Mon Jun 19 12:54:34 2006 -0600
+++ b/xen/arch/ia64/xen/fw_emul.c       Mon Jun 19 13:00:37 2006 -0600
@@ -370,7 +370,7 @@ efi_translate_domain_addr(unsigned long 
                if (*fault != IA64_NO_FAULT) return 0;
        }
 
-       return ((unsigned long) __va(translate_domain_mpaddr(mpaddr)));
+       return ((unsigned long) __va(translate_domain_mpaddr(mpaddr, NULL)));
 }
 
 static efi_status_t
@@ -549,7 +549,7 @@ do_ssc(unsigned long ssc, struct pt_regs
            case SSC_WAIT_COMPLETION:
                if (arg0) {     // metaphysical address
 
-                       arg0 = translate_domain_mpaddr(arg0);
+                       arg0 = translate_domain_mpaddr(arg0, NULL);
 /**/                   stat = (struct ssc_disk_stat *)__va(arg0);
 ///**/                 if (stat->fd == last_fd) stat->count = last_count;
 /**/                   stat->count = last_count;
@@ -564,7 +564,7 @@ do_ssc(unsigned long ssc, struct pt_regs
                arg1 = vcpu_get_gr(current,33); // access rights
 if (!running_on_sim) { printf("SSC_OPEN, not implemented on hardware.  
(ignoring...)\n"); arg0 = 0; }
                if (arg0) {     // metaphysical address
-                       arg0 = translate_domain_mpaddr(arg0);
+                       arg0 = translate_domain_mpaddr(arg0, NULL);
                        retval = ia64_ssc(arg0,arg1,0,0,ssc);
                }
                else retval = -1L;
@@ -581,7 +581,7 @@ if (!running_on_sim) { printf("SSC_OPEN,
                        unsigned long mpaddr;
                        long len;
 
-                       arg2 = translate_domain_mpaddr(arg2);
+                       arg2 = translate_domain_mpaddr(arg2, NULL);
                        req = (struct ssc_disk_req *) __va(arg2);
                        req->len &= 0xffffffffL;        // avoid strange bug
                        len = req->len;
@@ -592,7 +592,7 @@ if (!running_on_sim) { printf("SSC_OPEN,
                        retval = 0;
                        if ((mpaddr & PAGE_MASK) != ((mpaddr+len-1) & 
PAGE_MASK)) {
                                // do partial page first
-                               req->addr = translate_domain_mpaddr(mpaddr);
+                               req->addr = translate_domain_mpaddr(mpaddr, 
NULL);
                                req->len = PAGE_SIZE - (req->addr & ~PAGE_MASK);
                                len -= req->len; mpaddr += req->len;
                                retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc);
@@ -602,7 +602,7 @@ if (!running_on_sim) { printf("SSC_OPEN,
 //if (last_count >= PAGE_SIZE) printf("ssc(%p,%lx)[part]=%x 
",req->addr,req->len,retval);
                        }
                        if (retval >= 0) while (len > 0) {
-                               req->addr = translate_domain_mpaddr(mpaddr);
+                               req->addr = translate_domain_mpaddr(mpaddr, 
NULL);
                                req->len = (len > PAGE_SIZE) ? PAGE_SIZE : len;
                                len -= PAGE_SIZE; mpaddr += PAGE_SIZE;
                                retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc);
diff -r 7e26d6ffdde7 -r d60da6514d65 xen/arch/ia64/xen/mm.c
--- a/xen/arch/ia64/xen/mm.c    Mon Jun 19 12:54:34 2006 -0600
+++ b/xen/arch/ia64/xen/mm.c    Mon Jun 19 13:00:37 2006 -0600
@@ -245,7 +245,7 @@ gmfn_to_mfn_foreign(struct domain *d, un
        if (d == dom0)
                return(gpfn);
 #endif
-       pte = lookup_domain_mpa(d,gpfn << PAGE_SHIFT);
+       pte = lookup_domain_mpa(d,gpfn << PAGE_SHIFT, NULL);
        if (!pte) {
                panic("gmfn_to_mfn_foreign: bad gpfn. spinning...\n");
        }
@@ -256,7 +256,8 @@ gmfn_to_mfn_foreign(struct domain *d, un
 // address, convert the pte for a physical address for (possibly different)
 // Xen PAGE_SIZE and return modified pte.  (NOTE: TLB insert should use
 // PAGE_SIZE!)
-u64 translate_domain_pte(u64 pteval, u64 address, u64 itir__, u64* logps)
+u64 translate_domain_pte(u64 pteval, u64 address, u64 itir__, u64* logps,
+                         struct p2m_entry* entry)
 {
        struct domain *d = current->domain;
        ia64_itir_t itir = {.itir = itir__};
@@ -298,7 +299,7 @@ u64 translate_domain_pte(u64 pteval, u64
                               address, pteval, itir.itir);
        }
 #endif
-       pteval2 = lookup_domain_mpa(d,mpaddr);
+       pteval2 = lookup_domain_mpa(d, mpaddr, entry);
        arflags  = pteval  & _PAGE_AR_MASK;
        arflags2 = pteval2 & _PAGE_AR_MASK;
        if (arflags != _PAGE_AR_R && arflags2 == _PAGE_AR_R) {
@@ -311,7 +312,7 @@ u64 translate_domain_pte(u64 pteval, u64
                        pteval2, arflags2, mpaddr);
 #endif
                pteval = (pteval & ~_PAGE_AR_MASK) | _PAGE_AR_R;
-}
+    }
 
        pteval2 &= _PAGE_PPN_MASK; // ignore non-addr bits
        pteval2 |= (pteval & _PAGE_ED);
@@ -321,7 +322,8 @@ u64 translate_domain_pte(u64 pteval, u64
 }
 
 // given a current domain metaphysical address, return the physical address
-unsigned long translate_domain_mpaddr(unsigned long mpaddr)
+unsigned long translate_domain_mpaddr(unsigned long mpaddr,
+                                      struct p2m_entry* entry)
 {
        unsigned long pteval;
 
@@ -333,7 +335,7 @@ unsigned long translate_domain_mpaddr(un
                }
        }
 #endif
-       pteval = lookup_domain_mpa(current->domain,mpaddr);
+       pteval = lookup_domain_mpa(current->domain, mpaddr, entry);
        return ((pteval & _PAGE_PPN_MASK) | (mpaddr & ~PAGE_MASK));
 }
 
@@ -484,23 +486,10 @@ ____lookup_domain_mpa(struct domain *d, 
         return GPFN_INV_MASK;
     return INVALID_MFN;
 }
-
-unsigned long
-__lookup_domain_mpa(struct domain *d, unsigned long mpaddr)
-{
-    unsigned long machine = ____lookup_domain_mpa(d, mpaddr);
-    if (machine != INVALID_MFN)
-        return machine;
-
-    printk("%s: d 0x%p id %d current 0x%p id %d\n",
-           __func__, d, d->domain_id, current, current->vcpu_id);
-    printk("%s: bad mpa 0x%lx (max_pages 0x%lx)\n",
-           __func__, mpaddr, (unsigned long)d->max_pages << PAGE_SHIFT);
-    return INVALID_MFN;
-}
-#endif
-
-unsigned long lookup_domain_mpa(struct domain *d, unsigned long mpaddr)
+#endif
+
+unsigned long lookup_domain_mpa(struct domain *d, unsigned long mpaddr,
+                                struct p2m_entry* entry)
 {
     volatile pte_t *pte;
 
@@ -521,6 +510,8 @@ unsigned long lookup_domain_mpa(struct d
         pte_t tmp_pte = *pte;// pte is volatile. copy the value.
         if (pte_present(tmp_pte)) {
 //printk("lookup_domain_page: found mapping for %lx, 
pte=%lx\n",mpaddr,pte_val(*pte));
+            if (entry != NULL)
+                p2m_entry_set(entry, pte, tmp_pte);
             return pte_val(tmp_pte);
         } else if (VMX_DOMAIN(d->vcpu[0]))
             return GPFN_INV_MASK;
@@ -535,6 +526,8 @@ unsigned long lookup_domain_mpa(struct d
         printk("%s: bad mpa 0x%lx (=> 0x%lx)\n", __func__,
                mpaddr, (unsigned long)d->max_pages << PAGE_SHIFT);
 
+    if (entry != NULL)
+        p2m_entry_set(entry, NULL, __pte(0));
     //XXX This is a work around until the emulation memory access to a region
     //    where memory or device are attached is implemented.
     return pte_val(pfn_pte(0, __pgprot(__DIRTY_BITS | _PAGE_PL_2 | 
_PAGE_AR_RWX)));
@@ -544,7 +537,7 @@ unsigned long lookup_domain_mpa(struct d
 #if 1
 void *domain_mpa_to_imva(struct domain *d, unsigned long mpaddr)
 {
-    unsigned long pte = lookup_domain_mpa(d,mpaddr);
+    unsigned long pte = lookup_domain_mpa(d, mpaddr, NULL);
     unsigned long imva;
 
     pte &= _PAGE_PPN_MASK;
diff -r 7e26d6ffdde7 -r d60da6514d65 xen/arch/ia64/xen/vcpu.c
--- a/xen/arch/ia64/xen/vcpu.c  Mon Jun 19 12:54:34 2006 -0600
+++ b/xen/arch/ia64/xen/vcpu.c  Mon Jun 19 13:00:37 2006 -0600
@@ -29,7 +29,6 @@ extern void setfpreg (unsigned long regn
 extern void setfpreg (unsigned long regnum, struct ia64_fpreg *fpval, struct 
pt_regs *regs);
 
 extern void panic_domain(struct pt_regs *, const char *, ...);
-extern unsigned long translate_domain_mpaddr(unsigned long);
 extern IA64_BUNDLE __get_domain_bundle(UINT64);
 
 typedef        union {
@@ -1978,18 +1977,24 @@ IA64FAULT vcpu_itc_d(VCPU *vcpu, UINT64 
 {
        unsigned long pteval, logps = itir_ps(itir);
        BOOLEAN swap_rr0 = (!(ifa>>61) && PSCB(vcpu,metaphysical_mode));
+       struct p2m_entry entry;
 
        if (logps < PAGE_SHIFT) {
                printf("vcpu_itc_d: domain trying to use smaller page size!\n");
                //FIXME: kill domain here
                while(1);
        }
+again:
        //itir = (itir & ~0xfc) | (PAGE_SHIFT<<2); // ignore domain's pagesize
-       pteval = translate_domain_pte(pte, ifa, itir, &logps);
+       pteval = translate_domain_pte(pte, ifa, itir, &logps, &entry);
        if (!pteval) return IA64_ILLOP_FAULT;
        if (swap_rr0) set_one_rr(0x0,PSCB(vcpu,rrs[0]));
        vcpu_itc_no_srlz(vcpu,2,ifa,pteval,pte,logps);
        if (swap_rr0) set_metaphysical_rr0();
+       if (p2m_entry_retry(&entry)) {
+               vcpu_flush_tlb_vhpt_range(ifa & ((1 << logps) - 1), logps);
+               goto again;
+       }
        return IA64_NO_FAULT;
 }
 
@@ -1997,6 +2002,7 @@ IA64FAULT vcpu_itc_i(VCPU *vcpu, UINT64 
 {
        unsigned long pteval, logps = itir_ps(itir);
        BOOLEAN swap_rr0 = (!(ifa>>61) && PSCB(vcpu,metaphysical_mode));
+       struct p2m_entry entry;
 
        // FIXME: validate ifa here (not in Xen space), COULD MACHINE CHECK!
        if (logps < PAGE_SHIFT) {
@@ -2004,13 +2010,18 @@ IA64FAULT vcpu_itc_i(VCPU *vcpu, UINT64 
                //FIXME: kill domain here
                while(1);
        }
+again:
        //itir = (itir & ~0xfc) | (PAGE_SHIFT<<2); // ignore domain's pagesize
-       pteval = translate_domain_pte(pte, ifa, itir, &logps);
+       pteval = translate_domain_pte(pte, ifa, itir, &logps, &entry);
        // FIXME: what to do if bad physical address? (machine check?)
        if (!pteval) return IA64_ILLOP_FAULT;
        if (swap_rr0) set_one_rr(0x0,PSCB(vcpu,rrs[0]));
        vcpu_itc_no_srlz(vcpu, 1,ifa,pteval,pte,logps);
        if (swap_rr0) set_metaphysical_rr0();
+       if (p2m_entry_retry(&entry)) {
+               vcpu_flush_tlb_vhpt_range(ifa & ((1 << logps) - 1), logps);
+               goto again;
+       }
        return IA64_NO_FAULT;
 }
 
@@ -2040,10 +2051,14 @@ IA64FAULT vcpu_fc(VCPU *vcpu, UINT64 vad
        UINT64 mpaddr, paddr;
        IA64FAULT fault;
 
+again:
        fault = vcpu_tpa(vcpu, vadr, &mpaddr);
        if (fault == IA64_NO_FAULT) {
-               paddr = translate_domain_mpaddr(mpaddr);
+               struct p2m_entry entry;
+               paddr = translate_domain_mpaddr(mpaddr, &entry);
                ia64_fc(__va(paddr));
+               if (p2m_entry_retry(&entry))
+                       goto again;
        }
        return fault;
 }
diff -r 7e26d6ffdde7 -r d60da6514d65 xen/include/asm-ia64/domain.h
--- a/xen/include/asm-ia64/domain.h     Mon Jun 19 12:54:34 2006 -0600
+++ b/xen/include/asm-ia64/domain.h     Mon Jun 19 13:00:37 2006 -0600
@@ -12,10 +12,34 @@
 #include <xen/cpumask.h>
 #include <asm/fpswa.h>
 
+struct p2m_entry {
+    volatile pte_t*     pte;
+    pte_t               used;
+};
+
+static inline void
+p2m_entry_set(struct p2m_entry* entry, volatile pte_t* pte, pte_t used)
+{
+    entry->pte  = pte;
+    entry->used = used;
+}
+
+static inline int
+p2m_entry_retry(struct p2m_entry* entry)
+{
+    //XXX see lookup_domian_pte().
+    //    NULL is set for invalid gpaddr for the time being.
+    if (entry->pte == NULL)
+        return 0;
+
+    return (pte_val(*entry->pte) != pte_val(entry->used));
+}
+
 extern void domain_relinquish_resources(struct domain *);
 
 /* given a current domain metaphysical address, return the physical address */
-extern unsigned long translate_domain_mpaddr(unsigned long mpaddr);
+extern unsigned long translate_domain_mpaddr(unsigned long mpaddr,
+                                             struct p2m_entry* entry);
 
 /* Flush cache of domain d.
    If sync_only is true, only synchronize I&D caches,
diff -r 7e26d6ffdde7 -r d60da6514d65 xen/include/asm-ia64/mm.h
--- a/xen/include/asm-ia64/mm.h Mon Jun 19 12:54:34 2006 -0600
+++ b/xen/include/asm-ia64/mm.h Mon Jun 19 13:00:37 2006 -0600
@@ -149,8 +149,6 @@ extern unsigned long max_page;
 
 extern void __init init_frametable(void);
 void add_to_domain_alloc_list(unsigned long ps, unsigned long pe);
-
-extern unsigned long gmfn_to_mfn_foreign(struct domain *d, unsigned long gpfn);
 
 static inline void put_page(struct page_info *page)
 {
@@ -428,7 +426,8 @@ extern void __assign_domain_page(struct 
 extern void __assign_domain_page(struct domain *d, unsigned long mpaddr, 
unsigned long physaddr, unsigned long flags);
 extern void assign_domain_page(struct domain *d, unsigned long mpaddr, 
unsigned long physaddr);
 extern void assign_domain_io_page(struct domain *d, unsigned long mpaddr, 
unsigned long flags);
-extern unsigned long lookup_domain_mpa(struct domain *d, unsigned long mpaddr);
+struct p2m_entry;
+extern unsigned long lookup_domain_mpa(struct domain *d, unsigned long mpaddr, 
struct p2m_entry* entry);
 extern void *domain_mpa_to_imva(struct domain *d, unsigned long mpaddr);
 
 #ifdef CONFIG_XEN_IA64_DOM0_VP
@@ -436,7 +435,6 @@ extern unsigned long assign_domain_mach_
 extern unsigned long assign_domain_mach_page(struct domain *d, unsigned long 
mpaddr, unsigned long size, unsigned long flags);
 int domain_page_mapped(struct domain *d, unsigned long mpaddr);
 int efi_mmio(unsigned long physaddr, unsigned long size);
-extern unsigned long __lookup_domain_mpa(struct domain *d, unsigned long 
mpaddr);
 extern unsigned long ____lookup_domain_mpa(struct domain *d, unsigned long 
mpaddr);
 extern unsigned long do_dom0vp_op(unsigned long cmd, unsigned long arg0, 
unsigned long arg1, unsigned long arg2, unsigned long arg3);
 extern unsigned long dom0vp_zap_physmap(struct domain *d, unsigned long gpfn, 
unsigned int extent_order);
@@ -445,7 +443,7 @@ extern unsigned long dom0vp_add_physmap(
 
 extern volatile unsigned long *mpt_table;
 extern unsigned long gmfn_to_mfn_foreign(struct domain *d, unsigned long gpfn);
-extern u64 translate_domain_pte(u64 pteval, u64 address, u64 itir__, u64* 
logps);
+extern u64 translate_domain_pte(u64 pteval, u64 address, u64 itir__, u64* 
logps, struct p2m_entry* entry);
 #define machine_to_phys_mapping        mpt_table
 
 #define INVALID_M2P_ENTRY        (~0UL)
@@ -466,7 +464,7 @@ extern u64 translate_domain_pte(u64 ptev
     gmfn_to_mfn_foreign((_d), (gpfn))
 
 #define __gpfn_invalid(_d, gpfn)                       \
-       (lookup_domain_mpa((_d), ((gpfn)<<PAGE_SHIFT)) & GPFN_INV_MASK)
+       (lookup_domain_mpa((_d), ((gpfn)<<PAGE_SHIFT), NULL) & GPFN_INV_MASK)
 
 #define __gmfn_valid(_d, gpfn) !__gpfn_invalid(_d, gpfn)
 
@@ -474,7 +472,7 @@ extern u64 translate_domain_pte(u64 ptev
 #define __gpfn_is_io(_d, gpfn)                         \
 ({                                          \
     u64 pte, ret=0;                                \
-    pte=lookup_domain_mpa((_d), ((gpfn)<<PAGE_SHIFT));      \
+    pte = lookup_domain_mpa((_d), ((gpfn)<<PAGE_SHIFT), NULL); \
     if(!(pte&GPFN_INV_MASK))        \
         ret = pte & GPFN_IO_MASK;        \
     ret;                \
@@ -483,7 +481,7 @@ extern u64 translate_domain_pte(u64 ptev
 #define __gpfn_is_mem(_d, gpfn)                                \
 ({                                          \
     u64 pte, ret=0;                                \
-    pte=lookup_domain_mpa((_d), ((gpfn)<<PAGE_SHIFT));      \
+    pte = lookup_domain_mpa((_d), ((gpfn)<<PAGE_SHIFT), NULL);            \
     if((!(pte&GPFN_INV_MASK))&&((pte & GPFN_IO_MASK)==GPFN_MEM))   \
         ret = 1;             \
     ret;                \

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


 


Rackspace

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