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

[Xen-changelog] [xen-unstable] hvm: Xen must take care to hold a reference to ioreq pages, to ensure



# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1176463746 -3600
# Node ID ba8d4bc2435a742f74909c3fc9efab1655aae41f
# Parent  0b14423e75f8e5207c87b0d5de1a40dcf7713002
hvm: Xen must take care to hold a reference to ioreq pages, to ensure
that domain runs only when it has valid mapped ioreq pages, and to
safely drop ioreq page references when a domain dies.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
 xen/arch/x86/domain.c             |    4 +
 xen/arch/x86/hvm/hvm.c            |  106 ++++++++++++++++++++++++++------------
 xen/arch/x86/x86_32/domain_page.c |   21 +++++++
 xen/common/domain.c               |    2 
 xen/include/asm-x86/hvm/hvm.h     |    1 
 xen/include/xen/domain_page.h     |   13 +++-
 6 files changed, 111 insertions(+), 36 deletions(-)

diff -r 0b14423e75f8 -r ba8d4bc2435a xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c     Fri Apr 13 12:01:37 2007 +0100
+++ b/xen/arch/x86/domain.c     Fri Apr 13 12:29:06 2007 +0100
@@ -1540,8 +1540,10 @@ void domain_relinquish_resources(struct 
     relinquish_memory(d, &d->xenpage_list, PGT_l2_page_table);
     relinquish_memory(d, &d->page_list, PGT_l2_page_table);
 
-    /* Free page used by xen oprofile buffer */
+    /* Free page used by xen oprofile buffer. */
     free_xenoprof_pages(d);
+
+    hvm_domain_relinquish_resources(d);
 }
 
 void arch_dump_domain_info(struct domain *d)
diff -r 0b14423e75f8 -r ba8d4bc2435a xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Fri Apr 13 12:01:37 2007 +0100
+++ b/xen/arch/x86/hvm/hvm.c    Fri Apr 13 12:29:06 2007 +0100
@@ -146,6 +146,59 @@ void hvm_do_resume(struct vcpu *v)
     }
 }
 
+static void hvm_clear_ioreq_pfn(
+    struct domain *d, unsigned long *pva)
+{
+    unsigned long va, mfn;
+
+    BUG_ON(!d->is_dying);
+
+    if ( (va = xchg(pva, 0UL)) == 0UL )
+        return;
+
+    mfn = mfn_from_mapped_domain_page((void *)va);
+    unmap_domain_page_global((void *)va);
+    put_page_and_type(mfn_to_page(mfn));
+}
+
+static int hvm_set_ioreq_pfn(
+    struct domain *d, unsigned long *pva, unsigned long gmfn)
+{
+    unsigned long mfn;
+    void *va;
+
+    mfn = gmfn_to_mfn(d, gmfn);
+    if ( !mfn_valid(mfn) ||
+         !get_page_and_type(mfn_to_page(mfn), d, PGT_writable_page) )
+        return -EINVAL;
+
+    va = map_domain_page_global(mfn);
+    if ( va == NULL )
+    {
+        put_page_and_type(mfn_to_page(mfn));
+        return -ENOMEM;
+    }
+
+    if ( cmpxchg(pva, 0UL, (unsigned long)va) != 0UL )
+    {
+        unmap_domain_page_global(va);
+        put_page_and_type(mfn_to_page(mfn));
+        return -EINVAL;
+    }
+
+    /*
+     * Check dying status /after/ setting *pva. cmpxchg() is a barrier.
+     * We race against hvm_domain_relinquish_resources(). 
+     */
+    if ( d->is_dying )
+        hvm_clear_ioreq_pfn(d, pva);
+
+    /* Balance the domain_pause() in hvm_domain_initialise(). */
+    domain_unpause(d);
+
+    return 0;
+}
+
 int hvm_domain_initialise(struct domain *d)
 {
     int rc;
@@ -161,7 +214,6 @@ int hvm_domain_initialise(struct domain 
     spin_lock_init(&d->arch.hvm_domain.buffered_io_lock);
     spin_lock_init(&d->arch.hvm_domain.irq_lock);
 
-    /* paging support will be determined inside paging.c */
     rc = paging_enable(d, PG_refcounts|PG_translate|PG_external);
     if ( rc != 0 )
         return rc;
@@ -169,7 +221,17 @@ int hvm_domain_initialise(struct domain 
     vpic_init(d);
     vioapic_init(d);
 
+    /* Do not allow domain to run until it has ioreq shared pages. */
+    domain_pause(d); /* HVM_PARAM_IOREQ_PFN */
+    domain_pause(d); /* HVM_PARAM_BUFIOREQ_PFN */
+
     return 0;
+}
+
+void hvm_domain_relinquish_resources(struct domain *d)
+{
+    hvm_clear_ioreq_pfn(d, &d->arch.hvm_domain.shared_page_va);
+    hvm_clear_ioreq_pfn(d, &d->arch.hvm_domain.buffered_io_va);
 }
 
 void hvm_domain_destroy(struct domain *d)
@@ -178,13 +240,6 @@ void hvm_domain_destroy(struct domain *d
     rtc_deinit(d);
     pmtimer_deinit(d);
     hpet_deinit(d);
-
-    if ( d->arch.hvm_domain.shared_page_va )
-        unmap_domain_page_global(
-            (void *)d->arch.hvm_domain.shared_page_va);
-
-    if ( d->arch.hvm_domain.buffered_io_va )
-        unmap_domain_page_global((void *)d->arch.hvm_domain.buffered_io_va);
 }
 
 static int hvm_save_cpu_ctxt(struct domain *d, hvm_domain_context_t *h)
@@ -928,8 +983,6 @@ long do_hvm_op(unsigned long op, XEN_GUE
         struct xen_hvm_param a;
         struct domain *d;
         struct vcpu *v;
-        unsigned long mfn;
-        void *p;
 
         if ( copy_from_guest(&a, arg, 1) )
             return -EFAULT;
@@ -956,30 +1009,19 @@ long do_hvm_op(unsigned long op, XEN_GUE
             switch ( a.index )
             {
             case HVM_PARAM_IOREQ_PFN:
-                if ( d->arch.hvm_domain.shared_page_va )
-                    goto param_fail;
-                mfn = gmfn_to_mfn(d, a.value);
-                if ( mfn == INVALID_MFN )
-                    goto param_fail;
-                p = map_domain_page_global(mfn);
-                if ( p == NULL )
-                    goto param_fail;
-                d->arch.hvm_domain.shared_page_va = (unsigned long)p;
-                /* Initialise evtchn port info if VCPUs already created. */
-                for_each_vcpu ( d, v )
-                    get_vio(d, v->vcpu_id)->vp_eport =
-                    v->arch.hvm_vcpu.xen_port;
+                rc = hvm_set_ioreq_pfn(
+                    d, &d->arch.hvm_domain.shared_page_va, a.value);
+                if ( rc == 0 )
+                {
+                    /* Initialise evtchn port info if VCPUs already created. */
+                    for_each_vcpu ( d, v )
+                        get_vio(d, v->vcpu_id)->vp_eport =
+                        v->arch.hvm_vcpu.xen_port;
+                }
                 break;
             case HVM_PARAM_BUFIOREQ_PFN:
-                if ( d->arch.hvm_domain.buffered_io_va )
-                    goto param_fail;
-                mfn = gmfn_to_mfn(d, a.value);
-                if ( mfn == INVALID_MFN )
-                    goto param_fail;
-                p = map_domain_page_global(mfn);
-                if ( p == NULL )
-                    goto param_fail;
-                d->arch.hvm_domain.buffered_io_va = (unsigned long)p;
+                rc = hvm_set_ioreq_pfn(
+                    d, &d->arch.hvm_domain.buffered_io_va, a.value);
                 break;
             case HVM_PARAM_CALLBACK_IRQ:
                 hvm_set_callback_via(d, a.value);
diff -r 0b14423e75f8 -r ba8d4bc2435a xen/arch/x86/x86_32/domain_page.c
--- a/xen/arch/x86/x86_32/domain_page.c Fri Apr 13 12:01:37 2007 +0100
+++ b/xen/arch/x86/x86_32/domain_page.c Fri Apr 13 12:29:06 2007 +0100
@@ -251,3 +251,24 @@ void unmap_domain_page_global(void *va)
     idx = (__va - IOREMAP_VIRT_START) >> PAGE_SHIFT;
     set_bit(idx, garbage);
 }
+
+unsigned long mfn_from_mapped_domain_page(void *va) 
+{
+    unsigned long __va = (unsigned long)va;
+    l2_pgentry_t *pl2e;
+    l1_pgentry_t *pl1e;
+    unsigned int idx;
+    struct mapcache *cache;
+
+    if ( (__va >= MAPCACHE_VIRT_START) && (__va < MAPCACHE_VIRT_END) )
+    {
+        cache = &mapcache_current_vcpu()->domain->arch.mapcache;
+        idx = ((unsigned long)va - MAPCACHE_VIRT_START) >> PAGE_SHIFT;
+        return l1e_get_pfn(cache->l1tab[idx]);
+    }
+
+    ASSERT(__va >= IOREMAP_VIRT_START);
+    pl2e = virt_to_xen_l2e(__va);
+    pl1e = l2e_to_l1e(*pl2e) + l1_table_offset(__va);
+    return l1e_get_pfn(*pl1e);
+}
diff -r 0b14423e75f8 -r ba8d4bc2435a xen/common/domain.c
--- a/xen/common/domain.c       Fri Apr 13 12:01:37 2007 +0100
+++ b/xen/common/domain.c       Fri Apr 13 12:29:06 2007 +0100
@@ -314,7 +314,7 @@ void domain_kill(struct domain *d)
     }
 
     /* Tear down state /after/ setting the dying flag. */
-    smp_wmb();
+    smp_mb();
 
     gnttab_release_mappings(d);
     domain_relinquish_resources(d);
diff -r 0b14423e75f8 -r ba8d4bc2435a xen/include/asm-x86/hvm/hvm.h
--- a/xen/include/asm-x86/hvm/hvm.h     Fri Apr 13 12:01:37 2007 +0100
+++ b/xen/include/asm-x86/hvm/hvm.h     Fri Apr 13 12:29:06 2007 +0100
@@ -145,6 +145,7 @@ extern struct hvm_function_table hvm_fun
 extern struct hvm_function_table hvm_funcs;
 
 int hvm_domain_initialise(struct domain *d);
+void hvm_domain_relinquish_resources(struct domain *d);
 void hvm_domain_destroy(struct domain *d);
 
 int hvm_vcpu_initialise(struct vcpu *v);
diff -r 0b14423e75f8 -r ba8d4bc2435a xen/include/xen/domain_page.h
--- a/xen/include/xen/domain_page.h     Fri Apr 13 12:01:37 2007 +0100
+++ b/xen/include/xen/domain_page.h     Fri Apr 13 12:29:06 2007 +0100
@@ -33,6 +33,13 @@ void unmap_domain_page(void *va);
  */
 void *map_domain_page_global(unsigned long mfn);
 void unmap_domain_page_global(void *va);
+
+/* 
+ * Convert a VA (within a page previously mapped in the context of the
+ * currently-executing VCPU via a call to map_domain_page(), or via a
+ * previous call to map_domain_page_global()) to the mapped page frame.
+ */
+unsigned long mfn_from_mapped_domain_page(void *va);
 
 #define DMCACHE_ENTRY_VALID 1U
 #define DMCACHE_ENTRY_HELD  2U
@@ -96,11 +103,13 @@ domain_mmap_cache_destroy(struct domain_
 
 #else /* !CONFIG_DOMAIN_PAGE */
 
-#define map_domain_page(mfn)                maddr_to_virt((mfn)<<PAGE_SHIFT)
+#define map_domain_page(mfn)                mfn_to_virt(mfn)
 #define unmap_domain_page(va)               ((void)(va))
 
-#define map_domain_page_global(mfn)         maddr_to_virt((mfn)<<PAGE_SHIFT)
+#define map_domain_page_global(mfn)         mfn_to_virt(mfn)
 #define unmap_domain_page_global(va)        ((void)(va))
+
+#define mfn_from_mapped_domain_page(va)     virt_to_mfn(va)
 
 struct domain_mmap_cache { 
 };

_______________________________________________
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®.