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

[PATCH xenbus 4/4] Don't restrict event channels to vCPU 0...



From: Paul Durrant <pdurrant@xxxxxxxxxx>

... when using the 2-level event channel ABI.

With a small modification to track port numbers per-vcpu, the 2-level polling
code will happily deal with event channels bound to any vCPU up to
XEN_LEGACY_MAX_VCPUS. We just need to be careful to only process events on the
correct vCPU, to avoid list corruption. Hence, the newly introduced 'Pending'
flag needs to be set atomically in case we re-bind an event channel whilst a
poll is in progress.

The XEN_LEGACY_MAX_VCPUS limit is because the 2-level poll currently relies
on using the vcpu_info array embedded in the shared_info. This limit will be
removed in a subsequent patch.

Signed-off-by: Paul Durrant <pdurrant@xxxxxxxxxx>
---
 src/xenbus/evtchn.c      | 51 ++++++++++++++++++++++++++--------------
 src/xenbus/evtchn_2l.c   | 16 ++++---------
 src/xenbus/shared_info.c |  8 +++----
 3 files changed, 42 insertions(+), 33 deletions(-)

diff --git a/src/xenbus/evtchn.c b/src/xenbus/evtchn.c
index e32cb629a101..662ca038fc31 100644
--- a/src/xenbus/evtchn.c
+++ b/src/xenbus/evtchn.c
@@ -77,6 +77,7 @@ struct _XENBUS_EVTCHN_CHANNEL {
     KSPIN_LOCK                  Lock;
     LIST_ENTRY                  ListEntry;
     LIST_ENTRY                  PendingListEntry;
+    LONG                        Pending;
     PVOID                       Caller;
     PKSERVICE_ROUTINE           Callback;
     PVOID                       Argument;
@@ -378,8 +379,6 @@ EvtchnOpen(
 
     Trace("%u\n", LocalPort);
 
-    InitializeListHead(&Channel->PendingListEntry);
-
     status = XENBUS_EVTCHN_ABI(PortEnable,
                                &Context->EvtchnAbi,
                                LocalPort);
@@ -414,9 +413,6 @@ fail4:
 fail3:
     Error("fail3\n");
 
-    ASSERT(IsListEmpty(&Channel->PendingListEntry));
-    RtlZeroMemory(&Channel->PendingListEntry, sizeof (LIST_ENTRY));
-
     Channel->LocalPort = 0;
     Channel->Mask = FALSE;
     RtlZeroMemory(&Channel->Parameters, sizeof (XENBUS_EVTCHN_PARAMETERS));
@@ -471,9 +467,6 @@ EvtchnReap(
 
     Channel->Cpu = 0;
 
-    ASSERT(IsListEmpty(&Channel->PendingListEntry));
-    RtlZeroMemory(&Channel->PendingListEntry, sizeof (LIST_ENTRY));
-
     Channel->LocalPort = 0;
     Channel->Mask = FALSE;
     RtlZeroMemory(&Channel->Parameters, sizeof (XENBUS_EVTCHN_PARAMETERS));
@@ -501,8 +494,8 @@ EvtchnPollCallback(
 {
     PXENBUS_EVTCHN_PROCESSOR    Processor = Argument;
     PXENBUS_EVTCHN_CONTEXT      Context = Processor->Context;
+    ULONG                       Cpu = Processor->Cpu;
     PXENBUS_EVTCHN_CHANNEL      Channel;
-    BOOLEAN                     Pending;
     NTSTATUS                    status;
 
     status = HashTableLookup(Context->Table,
@@ -513,11 +506,15 @@ EvtchnPollCallback(
 
     ASSERT3U(Channel->LocalPort, ==, LocalPort);
 
-    Pending = !IsListEmpty(&Channel->PendingListEntry);
+    if (Channel->Cpu != Cpu)
+        goto done;
+
+    if (InterlockedBitTestAndSet(&Channel->Pending, 0) == 0) {
+        ASSERT(IsZeroMemory(&Channel->PendingListEntry, sizeof (LIST_ENTRY)));
 
-    if (!Pending)
         InsertTailList(&Processor->PendingList,
                        &Channel->PendingListEntry);
+    }
 
 done:
     return FALSE;
@@ -558,8 +555,18 @@ EvtchnPoll(
 
         KeMemoryBarrier();
         if (!Channel->Closed) {
+            ASSERT(Channel->Pending != 0);
+
             RemoveEntryList(&Channel->PendingListEntry);
-            InitializeListHead(&Channel->PendingListEntry);
+            RtlZeroMemory(&Channel->PendingListEntry, sizeof (LIST_ENTRY));
+
+            //
+            // Make sure the list removal is complete before we allow the
+            // channel to be queued again.
+            //
+            KeMemoryBarrier();
+
+            Channel->Pending = 0;
 
             if (Channel->Mask)
                 XENBUS_EVTCHN_ABI(PortMask,
@@ -583,6 +590,8 @@ EvtchnPoll(
 #pragma warning(suppress:6387)  // NULL argument
             DoneSomething |= Channel->Callback(NULL, Channel->Argument);
         } else if (List != NULL) {
+            ASSERT(Channel->Pending != 0);
+
             RemoveEntryList(&Channel->PendingListEntry);
             InsertTailList(List, &Channel->PendingListEntry);
         }
@@ -630,7 +639,12 @@ EvtchnFlush(
 
         ASSERT3U(Channel->Magic, ==, XENBUS_EVTCHN_CHANNEL_MAGIC);
 
-        InitializeListHead(&Channel->PendingListEntry);
+        ASSERT(Channel->Pending != 0);
+
+        RtlZeroMemory(&Channel->PendingListEntry, sizeof (LIST_ENTRY));
+
+        // No need to barrier as the event will not be queued again
+        Channel->Pending = 0;
 
         EvtchnReap(Context, Channel, TRUE);
     }
@@ -680,7 +694,7 @@ EvtchnTrigger(
     ULONG                       Cpu;
     PXENBUS_EVTCHN_PROCESSOR    Processor;
     PXENBUS_INTERRUPT           Interrupt;
-    BOOLEAN                     Pending;
+    BOOLEAN                     Queued;
 
     ASSERT3U(Channel->Magic, ==, XENBUS_EVTCHN_CHANNEL_MAGIC);
 
@@ -697,15 +711,16 @@ EvtchnTrigger(
 
     Irql = FdoAcquireInterruptLock(Context->Fdo, Interrupt);
 
-    Pending = !IsListEmpty(&Channel->PendingListEntry);
-
-    if (!Pending)
+    Queued = FALSE;
+    if (InterlockedBitTestAndSet(&Channel->Pending, 0) == 0) {
         InsertTailList(&Processor->PendingList,
                        &Channel->PendingListEntry);
+        Queued = TRUE;
+    }
 
     FdoReleaseInterruptLock(Context->Fdo, Interrupt, Irql);
 
-    if (Pending)
+    if (!Queued)
         return;
 
     KeInsertQueueDpc(&Processor->Dpc, NULL, NULL);
diff --git a/src/xenbus/evtchn_2l.c b/src/xenbus/evtchn_2l.c
index 0982b00c97c6..a869e150df29 100644
--- a/src/xenbus/evtchn_2l.c
+++ b/src/xenbus/evtchn_2l.c
@@ -71,19 +71,13 @@ EvtchnTwoLevelIsProcessorEnabled(
     IN  ULONG                       Index
     )
 {
-    unsigned int                    vcpu_id;
-    NTSTATUS                        status;
-
     UNREFERENCED_PARAMETER(_Context);
 
-    status = SystemVirtualCpuIndex(Index, &vcpu_id);
-    if (!NT_SUCCESS(status))
-        return FALSE;
-
-    if (vcpu_id != 0)
-        return FALSE;
-
-    return TRUE;
+    //
+    // We currently rely on using the vcpu_info array that is embedded
+    // in the shared_info.
+    //
+    return (Index < XEN_LEGACY_MAX_VCPUS) ? TRUE : FALSE;
 }
 
 static BOOLEAN
diff --git a/src/xenbus/shared_info.c b/src/xenbus/shared_info.c
index aa97255cce95..473088c18c93 100644
--- a/src/xenbus/shared_info.c
+++ b/src/xenbus/shared_info.c
@@ -48,7 +48,7 @@ struct _XENBUS_SHARED_INFO_CONTEXT {
     LONG                        References;
     PHYSICAL_ADDRESS            Address;
     shared_info_t               *Shared;
-    ULONG                       Port;
+    ULONG                       Port[HVM_MAX_VCPUS];
     XENBUS_SUSPEND_INTERFACE    SuspendInterface;
     PXENBUS_SUSPEND_CALLBACK    SuspendCallbackEarly;
     XENBUS_DEBUG_INTERFACE      DebugInterface;
@@ -204,7 +204,7 @@ SharedInfoEvtchnPoll(
 
     KeMemoryBarrier();
 
-    Port = Context->Port;
+    Port = Context->Port[vcpu_id];
 
     while (SelectorMask != 0) {
         ULONG   SelectorBit;
@@ -241,7 +241,7 @@ SharedInfoEvtchnPoll(
             Port = 0;
     }
 
-    Context->Port = Port;
+    Context->Port[vcpu_id] = Port;
 
 done:
     return DoneSomething;
@@ -652,7 +652,7 @@ SharedInfoRelease (
 
     Trace("====>\n");
 
-    Context->Port = 0;
+    RtlZeroMemory(Context->Port, sizeof (ULONG) * HVM_MAX_VCPUS);
 
     XENBUS_DEBUG(Deregister,
                  &Context->DebugInterface,
-- 
2.17.1




 


Rackspace

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