]> xenbits.xensource.com Git - xen.git/commitdiff
hvm: Fix the flush-all-tlbs hypercall.
authorKeir Fraser <keir@xensource.com>
Thu, 4 Oct 2007 08:57:17 +0000 (09:57 +0100)
committerKeir Fraser <keir@xensource.com>
Thu, 4 Oct 2007 08:57:17 +0000 (09:57 +0100)
From: Peter Johnston <pjohnston@xensource.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
xen/arch/x86/hvm/hvm.c
xen/common/domain.c
xen/include/xen/sched.h

index 6f4a92445eea5f0032de1a8cc206358956ee3418..a43ca392b25918117dc7541e744aebc846607c0f 100644 (file)
@@ -1661,14 +1661,38 @@ static int hvmop_set_pci_link_route(
 
 static int hvmop_flush_tlb_all(void)
 {
+    struct domain *d = current->domain;
     struct vcpu *v;
 
+    /* Avoid deadlock if more than one vcpu tries this at the same time. */
+    if ( !spin_trylock(&d->hypercall_deadlock_mutex) )
+        return -EAGAIN;
+
+    /* Pause all other vcpus. */
+    for_each_vcpu ( d, v )
+        if ( v != current )
+            vcpu_pause_nosync(v);
+
+    /* Now that all VCPUs are signalled to deschedule, we wait... */
+    for_each_vcpu ( d, v )
+        if ( v != current )
+            while ( !vcpu_runnable(v) && v->is_running )
+                cpu_relax();
+
+    /* All other vcpus are paused, safe to unlock now. */
+    spin_unlock(&d->hypercall_deadlock_mutex);
+
     /* Flush paging-mode soft state (e.g., va->gfn cache; PAE PDPE cache). */
-    for_each_vcpu ( current->domain, v )
+    for_each_vcpu ( d, v )
         paging_update_cr3(v);
 
     /* Flush all dirty TLBs. */
-    flush_tlb_mask(current->domain->domain_dirty_cpumask);
+    flush_tlb_mask(d->domain_dirty_cpumask);
+
+    /* Done. */
+    for_each_vcpu ( d, v )
+        if ( v != current )
+            vcpu_unpause(v);
 
     return 0;
 }
@@ -1780,6 +1804,10 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
     }
     }
 
+    if ( rc == -EAGAIN )
+        rc = hypercall_create_continuation(
+            __HYPERVISOR_hvm_op, "lh", op, arg);
+
     return rc;
 }
 
index e3b583d0215f3dce2ed05fe79415932101b3bec9..55152a3953fe88712110a1b139566f8cdc3f5abb 100644 (file)
@@ -68,6 +68,7 @@ struct domain *alloc_domain(domid_t domid)
     spin_lock_init(&d->big_lock);
     spin_lock_init(&d->page_alloc_lock);
     spin_lock_init(&d->shutdown_lock);
+    spin_lock_init(&d->hypercall_deadlock_mutex);
     INIT_LIST_HEAD(&d->page_list);
     INIT_LIST_HEAD(&d->xenpage_list);
 
index cf5342ccf112e9550e5a3af763364c59cee7b373..67a203b96977c91a8f234b81094f315d243c95e4 100644 (file)
@@ -227,6 +227,12 @@ struct domain
     int32_t time_offset_seconds;
 
     struct rcu_head rcu;
+
+    /*
+     * Hypercall deadlock avoidance lock. Used if a hypercall might
+     * cause a deadlock. Acquirers don't spin waiting; they preempt.
+     */
+    spinlock_t hypercall_deadlock_mutex;
 };
 
 struct domain_setup_info