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

[win-pv-devel] [PATCH] Use EVTCHNOP_unmask to unmask in some cases



If the EVTCHN Unmask method is called in context of the event channel
upcall, or on a CPU to which the event is not bound then use the unmask
hypercall. In the former case not doing this may lead to priorty
inversion once setting event channel priorities is enabled. In the latter
case not doing it again stops a lower priority event handler trigger from
blocking a higher priority event injection.

Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
---
 include/xen.h            |  7 ++++++
 src/xen/event_channel.c  | 28 ++++++++++++++++++++++++
 src/xenbus/evtchn.c      | 56 +++++++++++++++++++++++++++++-------------------
 src/xenbus/evtchn_fifo.c |  5 +----
 src/xenbus/shared_info.c |  5 +----
 5 files changed, 71 insertions(+), 30 deletions(-)

diff --git a/include/xen.h b/include/xen.h
index 84197a5..fa95edd 100644
--- a/include/xen.h
+++ b/include/xen.h
@@ -212,6 +212,13 @@ EventChannelBindVirtualCpu(
     IN  unsigned int        vcpu_id
     );
 
+__checkReturn
+XEN_API
+NTSTATUS
+EventChannelUnmask(
+    IN  ULONG   LocalPort
+    );
+
 // GRANT TABLE
 
 __checkReturn
diff --git a/src/xen/event_channel.c b/src/xen/event_channel.c
index 94a6b82..aa9fb48 100644
--- a/src/xen/event_channel.c
+++ b/src/xen/event_channel.c
@@ -357,3 +357,31 @@ fail1:
 
     return status;
 }
+
+__checkReturn
+XEN_API
+NTSTATUS
+EventChannelUnmask(
+    IN  ULONG               LocalPort
+    )
+{
+    struct evtchn_unmask    op;
+    LONG_PTR                rc;
+    NTSTATUS                status;
+
+    op.port = LocalPort;
+
+    rc = EventChannelOp(EVTCHNOP_unmask, &op);
+
+    if (rc < 0) {
+        ERRNO_TO_STATUS(-rc, status);
+        goto fail1;
+    }
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
diff --git a/src/xenbus/evtchn.c b/src/xenbus/evtchn.c
index c6ac30d..f88c208 100644
--- a/src/xenbus/evtchn.c
+++ b/src/xenbus/evtchn.c
@@ -624,60 +624,72 @@ static BOOLEAN
 EvtchnUnmask(
     IN  PINTERFACE              Interface,
     IN  PXENBUS_EVTCHN_CHANNEL  Channel,
-    IN  BOOLEAN                 InCallback
+    IN  BOOLEAN                 InUpcall
     )
 {
     PXENBUS_EVTCHN_CONTEXT      Context = Interface->Context;
     KIRQL                       Irql = PASSIVE_LEVEL;
-    BOOLEAN                     Pending = FALSE;
+    BOOLEAN                     Pending;
+    ULONG                       LocalPort;
     ULONG                       Cpu;
-    PXENBUS_INTERRUPT           Interrupt;
 
     ASSERT3U(Channel->Magic, ==, XENBUS_EVTCHN_CHANNEL_MAGIC);
 
-    if (!InCallback)
+    if (!InUpcall)
         KeAcquireSpinLock(&Channel->Lock, &Irql);
 
     ASSERT3U(KeGetCurrentIrql(), >=, DISPATCH_LEVEL);
 
+    Pending = FALSE;
+
     if (!Channel->Active)
         goto done;
 
+    LocalPort = Channel->LocalPort;
+
     Pending = XENBUS_EVTCHN_ABI(PortUnmask,
                                 &Context->EvtchnAbi,
-                                Channel->LocalPort);
+                                LocalPort);
 
     if (!Pending)
         goto done;
 
-    if (InCallback)
-        goto mask;
-
-    ASSERT3U(KeGetCurrentIrql(), >=, DISPATCH_LEVEL);
-    Cpu = KeGetCurrentProcessorNumber();
-
-    Interrupt = Context->LatchedInterrupt[Cpu];
+    //
+    // If we are in context of the upcall then use a hypercall
+    // to schedule the pending event.
+    //
+    if (InUpcall) {
+        (VOID) EventChannelUnmask(LocalPort);
 
-    if (Channel->Interrupt == Interrupt)
-        goto mask;
+        Pending = FALSE;
+        goto done;
+    }
 
     //
-    // We are not on the CPU to which the event is bound so
-    // we must trigger.
+    // If we are not unmasking on the same CPU to which the
+    // event channel is bound, then we need to use a hypercall
+    // to schedule the upcall on the correct CPU.
     //
-    EvtchnTrigger(Interface, Channel);
+    Cpu = KeGetCurrentProcessorNumber();
 
-    Pending = FALSE;
-    goto done;
+    if (Channel->Cpu != Cpu) {
+        (VOID) EventChannelUnmask(LocalPort);
+
+        Pending = FALSE;
+        goto done;
+    }
 
-mask:
     if (Channel->Mask)
         XENBUS_EVTCHN_ABI(PortMask,
                           &Context->EvtchnAbi,
-                          Channel->LocalPort);
+                          LocalPort);
+
+    XENBUS_EVTCHN_ABI(PortAck,
+                      &Context->EvtchnAbi,
+                      LocalPort);
 
 done:
-    if (!InCallback)
+    if (!InUpcall)
         KeReleaseSpinLock(&Channel->Lock, Irql);
 
     return Pending;
diff --git a/src/xenbus/evtchn_fifo.c b/src/xenbus/evtchn_fifo.c
index f65cc1b..e045cd0 100644
--- a/src/xenbus/evtchn_fifo.c
+++ b/src/xenbus/evtchn_fifo.c
@@ -437,10 +437,7 @@ EvtchnFifoPortUnmask(
         return FALSE;
 
     // If we cleared the mask then check whether something is pending
-    if (!__EvtchnFifoTestAndClearFlag(EventWord, EVTCHN_FIFO_PENDING))
-        return FALSE;
-
-    return TRUE;
+    return __EvtchnFifoTestFlag(EventWord, EVTCHN_FIFO_PENDING);
 }
 
 static VOID
diff --git a/src/xenbus/shared_info.c b/src/xenbus/shared_info.c
index 67be20c..240d87b 100644
--- a/src/xenbus/shared_info.c
+++ b/src/xenbus/shared_info.c
@@ -316,10 +316,7 @@ SharedInfoEvtchnUnmask(
     KeMemoryBarrier();
 
     // If we cleared the mask then check whether something was pending
-    if (!SharedInfoClearBit(&Shared->evtchn_pending[SelectorBit], PortBit))
-        return FALSE;
-
-    return TRUE;
+    return SharedInfoTestBit(&Shared->evtchn_pending[SelectorBit], PortBit);
 }
 
 static LARGE_INTEGER
-- 
2.1.1


_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel


 


Rackspace

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