@@ -2256,18 +2256,23 @@ static void check_for_pcpu_work(void)
* Process pending work for the vCPU. Any call should be fast or
* implement preemption.
*/
-static void check_for_vcpu_work(void)
+static bool check_for_vcpu_work(void)
{
struct vcpu *v = current;
#ifdef CONFIG_IOREQ_SERVER
+ bool handled;
+
local_irq_enable();
- handle_io_completion(v);
+ handled = handle_io_completion(v);
local_irq_disable();
+
+ if ( !handled )
+ return true;
#endif
if ( likely(!v->arch.need_flush_to_ram) )
- return;
+ return false;
/*
* Give a chance for the pCPU to process work before handling the vCPU
@@ -2278,6 +2283,8 @@ static void check_for_vcpu_work(void)
local_irq_enable();
p2m_flush_vm(v);
local_irq_disable();
+
+ return false;
}
/*
@@ -2290,8 +2297,22 @@ void leave_hypervisor_to_guest(void)
{
local_irq_disable();
- check_for_vcpu_work();
- check_for_pcpu_work();
+ /*
+ * The reason to use an unbounded loop here is the fact that vCPU
+ * shouldn't continue until an I/O has completed. In Xen case, if an I/O
+ * never completes then it most likely means that something went horribly
+ * wrong with the Device Emulator. And it is most likely not safe to
+ * continue. So letting the vCPU to spin forever if I/O never completes
+ * is a safer action than letting it continue and leaving the guest in
+ * unclear state and is the best what we can do for now.
+ *
+ * This wouldn't be an issue for Xen as do_softirq() would be called at
+ * every loop. In case of failure, the guest will crash and the vCPU
+ * will be unscheduled.
+ */
+ do {
+ check_for_pcpu_work();
+ } while ( check_for_vcpu_work() );
vgic_sync_to_lrs();