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

[win-pv-devel] [PATCH 07/14 v2] Enumerate non-default consoles



From: Owen Smith <owen.smith@xxxxxxxxxx>

* Add enumeration thread and watch
* Non-default consoles will fail any read/write/iocontrol IRPs

Signed-off-by: Owen Smith <owen.smith@xxxxxxxxxx>
---
 src/xencons/fdo.c | 316 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/xencons/pdo.c |  64 +++++++++--
 src/xencons/pdo.h |   5 +
 3 files changed, 376 insertions(+), 9 deletions(-)

diff --git a/src/xencons/fdo.c b/src/xencons/fdo.c
index 45a1fdd..4046acf 100644
--- a/src/xencons/fdo.c
+++ b/src/xencons/fdo.c
@@ -85,6 +85,9 @@ struct _XENCONS_FDO {
 
     CHAR                        VendorName[MAXNAMELEN];
 
+    PXENCONS_THREAD             ScanThread;
+    KEVENT                      ScanEvent;
+    PXENBUS_STORE_WATCH         ScanWatch;
     MUTEX                       Mutex;
     ULONG                       References;
 
@@ -653,6 +656,9 @@ done:
     RemoveEntryList(&Dx->ListEntry);
     ASSERT3U(Fdo->References, != , 0);
     --Fdo->References;
+
+    if (Fdo->ScanThread)
+        ThreadWake(Fdo->ScanThread);
 }
 
 static FORCEINLINE VOID
@@ -690,6 +696,112 @@ FdoReleaseMutex(
         FdoDestroy(Fdo);
 }
 
+static FORCEINLINE BOOLEAN
+__FdoEnumerate(
+    IN  PXENCONS_FDO    Fdo,
+    IN  PANSI_STRING    Devices
+    )
+{
+    BOOLEAN             NeedInvalidate;
+    HANDLE              ParametersKey;
+    ULONG               Enumerate;
+    PLIST_ENTRY         ListEntry;
+    ULONG               Index;
+    NTSTATUS            status;
+
+    Trace("====>\n");
+
+    NeedInvalidate = FALSE;
+
+    ParametersKey = DriverGetParametersKey();
+
+    status = RegistryQueryDwordValue(ParametersKey,
+                                     "Enumerate",
+                                     &Enumerate);
+    if (!NT_SUCCESS(status))
+        Enumerate = 1;
+
+    if (Enumerate == 0)
+        goto done;
+
+    __FdoAcquireMutex(Fdo);
+
+    ListEntry = Fdo->Dx->ListEntry.Flink;
+    while (ListEntry != &Fdo->Dx->ListEntry) {
+        PLIST_ENTRY     Next = ListEntry->Flink;
+        PXENCONS_DX     Dx = CONTAINING_RECORD(ListEntry, XENCONS_DX, 
ListEntry);
+        PXENCONS_PDO    Pdo = Dx->Pdo;
+
+        // If the PDO is the default console, it wont exist in the
+        // the device list, as its statically created
+        if (PdoIsDefault(Pdo))
+            continue;
+
+        if (PdoGetDevicePnpState(Pdo) != Deleted) {
+            PCHAR           Name;
+            BOOLEAN         Missing;
+
+            Name = PdoGetName(Pdo);
+            Missing = TRUE;
+
+            // If the PDO already exists and its name is in the device list
+            // then we don't want to remove it.
+            for (Index = 0; Devices[Index].Buffer != NULL; Index++) {
+                PANSI_STRING Device = &Devices[Index];
+
+                if (Device->Length == 0)
+                    continue;
+
+                if (strcmp(Name, Device->Buffer) == 0) {
+                    Missing = FALSE;
+                    Device->Length = 0;  // avoid duplication
+                    break;
+                }
+            }
+
+            if (!PdoIsMissing(Pdo)) {
+                if (PdoIsEjectRequested(Pdo)) {
+                    IoRequestDeviceEject(PdoGetDeviceObject(Pdo));
+                } else if (Missing) {
+                    PdoSetMissing(Pdo, "device disappeared");
+
+                    // If the PDO has not yet been enumerated then we can
+                    // go ahead and mark it as deleted, otherwise we need
+                    // to notify PnP manager and wait for the REMOVE_DEVICE
+                    // IRP.
+                    if (PdoGetDevicePnpState(Pdo) == Present) {
+                        PdoSetDevicePnpState(Pdo, Deleted);
+                        PdoDestroy(Pdo);
+                    } else {
+                        NeedInvalidate = TRUE;
+                    }
+                }
+            }
+        }
+
+        ListEntry = Next;
+    }
+
+    // Walk the class list and create PDOs for any new device
+    for (Index = 0; Devices[Index].Buffer != NULL; Index++) {
+        PANSI_STRING Device = &Devices[Index];
+
+        if (Device->Length == 0)
+            continue;
+
+        status = PdoCreate(Fdo, Device);
+        if (NT_SUCCESS(status))
+            NeedInvalidate = TRUE;
+    }
+
+    __FdoReleaseMutex(Fdo);
+
+done:
+    Trace("<====\n");
+
+    return NeedInvalidate;
+}
+
 static FORCEINLINE PANSI_STRING
 __FdoMultiSzToUpcaseAnsi(
     IN  PCHAR       Buffer
@@ -768,6 +880,125 @@ __FdoFreeAnsi(
     __FdoFree(Ansi);
 }
 
+static NTSTATUS
+FdoScan(
+    PXENCONS_THREAD     Self,
+    PVOID               Context
+    )
+{
+    PXENCONS_FDO        Fdo = Context;
+    PKEVENT             Event;
+    HANDLE              ParametersKey;
+    NTSTATUS            status;
+
+    Trace("====>\n");
+
+    Event = ThreadGetEvent(Self);
+
+    ParametersKey = DriverGetParametersKey();
+
+    for (;;) {
+        PCHAR           Buffer;
+        PANSI_STRING    Devices;
+        PANSI_STRING    UnsupportedDevices;
+        ULONG           Index;
+        BOOLEAN         NeedInvalidate;
+
+        Trace("waiting...\n");
+
+        (VOID)KeWaitForSingleObject(Event,
+                                    Executive,
+                                    KernelMode,
+                                    FALSE,
+                                    NULL);
+        KeClearEvent(Event);
+
+        if (ThreadIsAlerted(Self))
+            break;
+
+        // It is not safe to use interfaces before this point
+        if (__FdoGetDevicePnpState(Fdo) != Started) {
+            KeSetEvent(&Fdo->ScanEvent, IO_NO_INCREMENT, FALSE);
+            continue;
+        }
+
+        status = XENBUS_STORE(Directory,
+                              &Fdo->StoreInterface,
+                              NULL,
+                              "device",
+                              "console",
+                              &Buffer);
+        if (NT_SUCCESS(status)) {
+            Devices = __FdoMultiSzToUpcaseAnsi(Buffer);
+
+            XENBUS_STORE(Free,
+                         &Fdo->StoreInterface,
+                         Buffer);
+        } else {
+            Devices = NULL;
+        }
+
+        if (Devices == NULL)
+            goto loop;
+
+        if (ParametersKey != NULL) {
+            status = RegistryQuerySzValue(ParametersKey,
+                                          "UnsupportedDevices",
+                                          NULL,
+                                          &UnsupportedDevices);
+            if (!NT_SUCCESS(status))
+                UnsupportedDevices = NULL;
+        } else {
+            UnsupportedDevices = NULL;
+        }
+
+        // NULL out anything in the Devices list that is in the
+        // UnsupportedDevices list
+        for (Index = 0; Devices[Index].Buffer != NULL; Index++) {
+            PANSI_STRING    Device = &Devices[Index];
+            ULONG           Entry;
+            BOOLEAN         Supported;
+
+            Supported = TRUE;
+
+            for (Entry = 0;
+                 UnsupportedDevices != NULL && 
UnsupportedDevices[Entry].Buffer != NULL;
+                 Entry++) {
+                if (strncmp(Device->Buffer,
+                            UnsupportedDevices[Entry].Buffer,
+                            Device->Length) == 0) {
+                    Supported = FALSE;
+                    break;
+                }
+            }
+
+            if (!Supported)
+                Device->Length = 0;
+        }
+
+        if (UnsupportedDevices != NULL)
+            RegistryFreeSzValue(UnsupportedDevices);
+
+        NeedInvalidate = __FdoEnumerate(Fdo, Devices);
+
+        __FdoFreeAnsi(Devices);
+
+        if (NeedInvalidate) {
+            NeedInvalidate = FALSE;
+            IoInvalidateDeviceRelations(__FdoGetPhysicalDeviceObject(Fdo),
+                                        BusRelations);
+        }
+
+    loop:
+        KeSetEvent(&Fdo->ScanEvent, IO_NO_INCREMENT, FALSE);
+    }
+
+    KeSetEvent(&Fdo->ScanEvent, IO_NO_INCREMENT, FALSE);
+
+    Trace("<====\n");
+    return STATUS_SUCCESS;
+}
+
 static FORCEINLINE BOOLEAN
 __FdoMatchDistribution(
     IN  PXENCONS_FDO    Fdo,
@@ -989,15 +1220,39 @@ __FdoD3ToD0(
     IN  PXENCONS_FDO    Fdo
     )
 {
+    NTSTATUS        status;
+
     Trace("====>\n");
 
     ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
 
     (VOID) FdoSetDistribution(Fdo);
 
+    status = XENBUS_STORE(WatchAdd,
+                          &Fdo->StoreInterface,
+                          "device",
+                          "console",
+                          ThreadGetEvent(Fdo->ScanThread),
+                          &Fdo->ScanWatch);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    (VOID)XENBUS_STORE(Printf,
+                       &Fdo->StoreInterface,
+                       NULL,
+                       "feature/hotplug",
+                       "console",
+                       "%u",
+                       TRUE);
+
     Trace("<====\n");
 
     return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
 }
 
 static FORCEINLINE VOID
@@ -1009,6 +1264,17 @@ __FdoD0ToD3(
 
     ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
 
+    (VOID)XENBUS_STORE(Remove,
+                       &Fdo->StoreInterface,
+                       NULL,
+                       "feature/hotplug",
+                       "console");
+
+    (VOID)XENBUS_STORE(WatchRemove,
+                       &Fdo->StoreInterface,
+                       Fdo->ScanWatch);
+    Fdo->ScanWatch = NULL;
+
     FdoClearDistribution(Fdo);
 
     Trace("<====\n");
@@ -1221,17 +1487,31 @@ FdoStartDevice(
                       StackLocation->Parameters.StartDevice.AllocatedResources,
                       
StackLocation->Parameters.StartDevice.AllocatedResourcesTranslated);
 
-    status = FdoD3ToD0(Fdo);
+    KeInitializeEvent(&Fdo->ScanEvent, NotificationEvent, FALSE);
+
+    status = ThreadCreate(FdoScan, Fdo, &Fdo->ScanThread);
     if (!NT_SUCCESS(status))
         goto fail2;
 
+    status = FdoD3ToD0(Fdo);
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
     __FdoSetDevicePnpState(Fdo, Started);
+    ThreadWake(Fdo->ScanThread);
 
     status = Irp->IoStatus.Status;
     IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
     return status;
 
+fail3:
+    Error("fail3\n");
+
+    ThreadAlert(Fdo->ScanThread);
+    ThreadJoin(Fdo->ScanThread);
+    Fdo->ScanThread = NULL;
+
 fail2:
     Error("fail2\n");
 
@@ -1292,6 +1572,12 @@ FdoStopDevice(
     if (__FdoGetDevicePowerState(Fdo) == PowerDeviceD0)
         FdoD0ToD3(Fdo);
 
+    ThreadAlert(Fdo->ScanThread);
+    ThreadJoin(Fdo->ScanThread);
+    Fdo->ScanThread = NULL;
+
+    RtlZeroMemory(&Fdo->ScanEvent, sizeof(KEVENT));
+
     RtlZeroMemory(&Fdo->Resource, sizeof (FDO_RESOURCE) * RESOURCE_COUNT);
 
     __FdoSetDevicePnpState(Fdo, Stopped);
@@ -1387,6 +1673,17 @@ FdoRemoveDevice(
     if (__FdoGetPreviousDevicePnpState(Fdo) != Started)
         goto done;
 
+    KeClearEvent(&Fdo->ScanEvent);
+    ThreadWake(Fdo->ScanThread);
+
+    Trace("waiting for scan thread\n");
+
+    (VOID)KeWaitForSingleObject(&Fdo->ScanEvent,
+                                Executive,
+                                KernelMode,
+                                FALSE,
+                                NULL);
+
     __FdoAcquireMutex(Fdo);
 
     ListEntry = Fdo->Dx->ListEntry.Flink;
@@ -1414,6 +1711,12 @@ FdoRemoveDevice(
     if (__FdoGetDevicePowerState(Fdo) == PowerDeviceD0)
         FdoD0ToD3(Fdo);
 
+    ThreadAlert(Fdo->ScanThread);
+    ThreadJoin(Fdo->ScanThread);
+    Fdo->ScanThread = NULL;
+
+    RtlZeroMemory(&Fdo->ScanEvent, sizeof(KEVENT));
+
     RtlZeroMemory(&Fdo->Resource, sizeof (FDO_RESOURCE) * RESOURCE_COUNT);
 
 done:
@@ -1463,6 +1766,17 @@ FdoQueryDeviceRelations(
         goto done;
     }
 
+    KeClearEvent(&Fdo->ScanEvent);
+    ThreadWake(Fdo->ScanThread);
+
+    Trace("waiting for scan thread\n");
+
+    (VOID)KeWaitForSingleObject(&Fdo->ScanEvent,
+                                Executive,
+                                KernelMode,
+                                FALSE,
+                                NULL);
+
     __FdoAcquireMutex(Fdo);
 
     Count = 0;
diff --git a/src/xencons/pdo.c b/src/xencons/pdo.c
index 62f366c..2acd86a 100755
--- a/src/xencons/pdo.c
+++ b/src/xencons/pdo.c
@@ -71,6 +71,7 @@ struct _XENCONS_PDO {
     XENBUS_SUSPEND_INTERFACE    SuspendInterface;
     PXENBUS_SUSPEND_CALLBACK    SuspendCallbackLate;
 
+    BOOLEAN                     IsDefault;
     PXENCONS_CONSOLE            Console;
 };
 
@@ -286,6 +287,14 @@ __PdoGetName(
     return Dx->Name;
 }
 
+PCHAR
+PdoGetName(
+    IN  PXENCONS_PDO    Pdo
+    )
+{
+    return __PdoGetName(Pdo);
+}
+
 static FORCEINLINE PCHAR
 __PdoGetVendorName(
     IN  PXENCONS_PDO    Pdo
@@ -295,6 +304,22 @@ __PdoGetVendorName(
 }
 
 static FORCEINLINE BOOLEAN
+__PdoIsDefault(
+    IN  PXENCONS_PDO    Pdo
+    )
+{
+    return Pdo->IsDefault;
+}
+
+BOOLEAN
+PdoIsDefault(
+    IN  PXENCONS_PDO    Pdo
+    )
+{
+    return __PdoIsDefault(Pdo);
+}
+
+static FORCEINLINE BOOLEAN
 __PdoSetEjectRequested(
     IN  PXENCONS_PDO    Pdo
     )
@@ -441,7 +466,10 @@ PdoD3ToD0(
 
     KeLowerIrql(Irql);
 
-    status = ConsoleD3ToD0(Pdo->Console);
+    if (__PdoIsDefault(Pdo))
+        status = ConsoleD3ToD0(Pdo->Console);
+    else
+        status = STATUS_SUCCESS;
     if (!NT_SUCCESS(status))
         goto fail4;
 
@@ -495,7 +523,8 @@ PdoD0ToD3(
 #pragma prefast(suppress:28123)
     (VOID) IoSetDeviceInterfaceState(&Pdo->Dx->Link, FALSE);
 
-    ConsoleD0ToD3(Pdo->Console);
+    if (__PdoIsDefault(Pdo))
+        ConsoleD0ToD3(Pdo->Console);
 
     KeRaiseIrql(DISPATCH_LEVEL, &Irql);
 
@@ -1689,7 +1718,10 @@ PdoDispatchCreate(
 
     StackLocation = IoGetCurrentIrpStackLocation(Irp);
 
-    status = ConsoleOpen(Pdo->Console, StackLocation->FileObject);
+    if (__PdoIsDefault(Pdo))
+        status = ConsoleOpen(Pdo->Console, StackLocation->FileObject);
+    else
+        status = STATUS_SUCCESS;
 
     Irp->IoStatus.Status = status;
     IoCompleteRequest(Irp, IO_NO_INCREMENT);
@@ -1708,7 +1740,10 @@ PdoDispatchCleanup(
 
     StackLocation = IoGetCurrentIrpStackLocation(Irp);
 
-    status = ConsoleClose(Pdo->Console, StackLocation->FileObject);
+    if (__PdoIsDefault(Pdo))
+        status = ConsoleClose(Pdo->Console, StackLocation->FileObject);
+    else
+        status = STATUS_SUCCESS;
 
     Irp->IoStatus.Status = status;
     IoCompleteRequest(Irp, IO_NO_INCREMENT);
@@ -1742,7 +1777,10 @@ PdoDispatchReadWriteControl(
 {
     NTSTATUS            status;
 
-    status = ConsolePutQueue(Pdo->Console, Irp);
+    if (__PdoIsDefault(Pdo))
+        status = ConsolePutQueue(Pdo->Console, Irp);
+    else
+        status = STATUS_DEVICE_NOT_READY;
     if (status == STATUS_SUCCESS)
         goto done;
     if (status != STATUS_PENDING)
@@ -1895,7 +1933,11 @@ PdoCreate(
 
     Dx->Pdo = Pdo;
 
-    status = ConsoleCreate(Fdo, &Pdo->Console);
+    Pdo->IsDefault = (Device == NULL);
+    if (Pdo->IsDefault)
+        status = ConsoleCreate(Fdo, &Pdo->Console);
+    else
+        status = STATUS_SUCCESS;
     if (!NT_SUCCESS(status))
         goto fail5;
 
@@ -1925,9 +1967,12 @@ fail6:
 
     (VOID)__PdoClearEjectRequested(Pdo);
 
-    ConsoleDestroy(Pdo->Console);
+    if (__PdoIsDefault(Pdo))
+        ConsoleDestroy(Pdo->Console);
     Pdo->Console = NULL;
 
+    Pdo->IsDefault = FALSE;
+
 fail5:
     Error("fail5\n");
 
@@ -1994,9 +2039,12 @@ PdoDestroy(
 
     Dx->Pdo = NULL;
 
-    ConsoleDestroy(Pdo->Console);
+    if (__PdoIsDefault(Pdo))
+        ConsoleDestroy(Pdo->Console);
     Pdo->Console = NULL;
 
+    Pdo->IsDefault = FALSE;
+
     RtlFreeUnicodeString(&Pdo->Dx->Link);
 
     RtlZeroMemory(&Pdo->SuspendInterface,
diff --git a/src/xencons/pdo.h b/src/xencons/pdo.h
index 0605483..85f73a3 100755
--- a/src/xencons/pdo.h
+++ b/src/xencons/pdo.h
@@ -83,6 +83,11 @@ PdoGetDeviceObject(
     IN  PXENCONS_PDO    Pdo
     );
 
+extern BOOLEAN
+PdoIsDefault(
+    IN  PXENCONS_PDO    Pdo
+    );
+
 extern NTSTATUS
 PdoCreate(
     IN  PXENCONS_FDO    Fdo,
-- 
2.8.3


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

 


Rackspace

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