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

[win-pv-devel] [PATCH] Make sure unplug and reboot is requested at the right time



Because the installation of XENNET now steals the stack binding of any
corresponding emulated NIC, should that NIC re-appear (which it may if
the unplug key is cleared from the registry for some reason) then
Windows will not attempt to start the PV NIC. This means that the code
to check for aliasing emulated device and request unplug and reboot is
never executed.

This patch re-works the code to perform the checks at PDO creation time,
which is unaffected by the new XENNET installation behaviour.

Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
---
 src/xenvif/pdo.c | 276 +++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 187 insertions(+), 89 deletions(-)

diff --git a/src/xenvif/pdo.c b/src/xenvif/pdo.c
index 33a75ae..d4c1962 100644
--- a/src/xenvif/pdo.c
+++ b/src/xenvif/pdo.c
@@ -97,6 +97,7 @@ struct _XENVIF_PDO {
     PXENVIF_VIF_CONTEXT         VifContext;
     XENVIF_VIF_INTERFACE        VifInterface;
 
+    BOOLEAN                     HasDriver;
     BOOLEAN                     HasAlias;
 };
 
@@ -1199,8 +1200,8 @@ PdoUnplugRequest(
 {
     NTSTATUS        status;
 
-    ASSERT3U(Pdo->UnplugRequested, !=, Make);
-    Pdo->UnplugRequested = Make;
+    if (Pdo->UnplugRequested == Make)
+        return;
 
     status = XENBUS_UNPLUG(Acquire, &Pdo->UnplugInterface);
     if (!NT_SUCCESS(status))
@@ -1212,6 +1213,8 @@ PdoUnplugRequest(
                   Make);
 
     XENBUS_UNPLUG(Release, &Pdo->UnplugInterface);
+
+    Pdo->UnplugRequested = Make;
 }
 
 static DECLSPEC_NOINLINE NTSTATUS
@@ -1220,17 +1223,16 @@ PdoStartDevice(
     IN  PIRP            Irp
     )
 {
-    NTSTATUS            (*__GetIfTable2)(PMIB_IF_TABLE2 *);
-    VOID                (*__FreeMibTable)(PVOID);
-    PMIB_IF_TABLE2      Table;
-    ULONG               Index;
-    PMIB_IF_ROW2        Row;
     PIO_STACK_LOCATION  StackLocation;
     NTSTATUS            status;
 
     status = STATUS_UNSUCCESSFUL;
-    if (Pdo->HasAlias)
+    if (Pdo->HasAlias) {
+        PdoUnplugRequest(Pdo, TRUE);
+        DriverRequestReboot();
+
         goto fail1;
+    }
 
     if (DriverSafeMode())
         goto fail2;
@@ -1249,95 +1251,20 @@ PdoStartDevice(
     if (!NT_SUCCESS(status))
         goto fail5;
 
-    status = LinkGetRoutineAddress("netio.sys",
-                                   "GetIfTable2",
-                                   (PVOID *)&__GetIfTable2);
-    if (!NT_SUCCESS(status))
-        goto fail6;
-
-    status = LinkGetRoutineAddress("netio.sys",
-                                   "FreeMibTable",
-                                   (PVOID *)&__FreeMibTable);
-    if (!NT_SUCCESS(status))
-        goto fail7;
-
-    status = __GetIfTable2(&Table);
-    if (!NT_SUCCESS(status))
-        goto fail8;
-
-    //
-    // Look for a network interface with the same permanent address
-    // that is already up. If there is one then it must be an
-    // aliasing emulated device, so save its settings.
-    //
-    for (Index = 0; Index < Table->NumEntries; Index++) {
-        Row = &Table->Table[Index];
-
-        Trace("%s: checking %ws (%ws)\n",
-              __PdoGetName(Pdo),
-              Row->Alias,
-              Row->Description);
-
-        if (!Row->InterfaceAndOperStatusFlags.ConnectorPresent)
-            continue;
-
-        if (Row->PhysicalAddressLength != sizeof (ETHERNET_ADDRESS))
-            continue;
-
-        if (memcmp(Row->PermanentPhysicalAddress,
-                   __PdoGetPermanentAddress(Pdo),
-                   sizeof (ETHERNET_ADDRESS)) != 0)
-            continue;
-
-        if (Row->OperStatus != IfOperStatusUp)
-            continue;
-
-        Pdo->HasAlias = TRUE;
-    }
-
-    if (Pdo->HasAlias) {
-        PdoUnplugRequest(Pdo, TRUE);
-
-        status = STATUS_UNSUCCESSFUL;
-        goto fail9;
-    }
-
     StackLocation = IoGetCurrentIrpStackLocation(Irp);
 
     status = PdoD3ToD0(Pdo);
     if (!NT_SUCCESS(status))
-        goto fail10;
-
-    PdoUnplugRequest(Pdo, TRUE);
+        goto fail6;
 
     __PdoSetDevicePnpState(Pdo, Started);
 
     Irp->IoStatus.Status = STATUS_SUCCESS;
     IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
-    __FreeMibTable(Table);
 
     return STATUS_SUCCESS;
 
-fail10:
-    Error("fail10\n");
-
-    __FreeMibTable(Table);
-
-    goto fail6;
-
-fail9:
-    Error("fail9\n");
-
-    DriverRequestReboot();
-    __FreeMibTable(Table);
-
-fail8:
-    Error("fail8\n");
-
-fail7:
-    Error("fail7\n");
-
 fail6:
     Error("fail6\n");
 
@@ -1415,8 +1342,6 @@ PdoStopDevice(
     if (__PdoGetDevicePowerState(Pdo) != PowerDeviceD0)
         goto done;
 
-    PdoUnplugRequest(Pdo, FALSE);
-
     PdoD0ToD3(Pdo);
 
 done:
@@ -1506,8 +1431,6 @@ PdoRemoveDevice(
     if (__PdoGetDevicePowerState(Pdo) != PowerDeviceD0)
         goto done;
 
-    PdoUnplugRequest(Pdo, FALSE);
-
     PdoD0ToD3(Pdo);
 
 done:
@@ -2625,6 +2548,156 @@ PdoSuspend(
     FrontendSuspend(__PdoGetFrontend(Pdo));
 }
 
+#define ENUM_KEY(_Driver) \
+        "\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum\\" ## _Driver
+
+static FORCEINLINE NTSTATUS
+__PdoCheckForDriver(
+    IN  PXENVIF_PDO         Pdo
+    )
+{
+    HANDLE                  EnumKey;
+    ULONG                   Index;
+    PXENVIF_PDO_REVISION    Revision;
+    CHAR                    HardwareKeyName[MAXNAMELEN];
+    HANDLE                  HardwareKey;
+    PANSI_STRING            Ansi;
+    NTSTATUS                status;
+
+    status = RegistryOpenSubKey(NULL,
+                                ENUM_KEY(__MODULE__),
+                                KEY_READ,
+                                &EnumKey);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    Index = ARRAYSIZE(PdoRevision) - 1;
+    Revision = &PdoRevision[Index];
+
+    status = RtlStringCbPrintfA(HardwareKeyName,
+                                MAXNAMELEN,
+                                "VEN_%s&DEV_NET&REV_%08X\\%s",
+                                __PdoGetVendorName(Pdo),
+                                Revision->Number,
+                                __PdoGetName(Pdo));
+    ASSERT(NT_SUCCESS(status));
+
+    status = RegistryOpenSubKey(EnumKey,
+                                HardwareKeyName,
+                                KEY_READ,
+                                &HardwareKey);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    status = RegistryQuerySzValue(HardwareKey,
+                                  "Driver",
+                                  NULL,
+                                  &Ansi);
+    if (NT_SUCCESS(status)) {
+        Info("Driver = %Z\n", &Ansi[0]);
+        RegistryFreeSzValue(Ansi);
+
+        Pdo->HasDriver = TRUE;
+    } else if (status != STATUS_OBJECT_NAME_NOT_FOUND) {
+        goto fail3;
+    }
+
+    RegistryCloseKey(HardwareKey);
+
+    RegistryCloseKey(EnumKey);
+
+    return 0;
+
+fail3:
+    Error("fail3\n");
+
+    RegistryCloseKey(HardwareKey);
+
+fail2:
+    Error("fail2\n");
+
+    RegistryCloseKey(EnumKey);
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+static FORCEINLINE NTSTATUS
+__PdoCheckForAlias(
+    IN  PXENVIF_PDO     Pdo
+    )
+{
+    NTSTATUS            (*__GetIfTable2)(PMIB_IF_TABLE2 *);
+    VOID                (*__FreeMibTable)(PVOID);
+    PMIB_IF_TABLE2      Table;
+    ULONG               Index;
+    NTSTATUS            status;
+
+    status = LinkGetRoutineAddress("netio.sys",
+                                   "GetIfTable2",
+                                   (PVOID *)&__GetIfTable2);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    status = LinkGetRoutineAddress("netio.sys",
+                                   "FreeMibTable",
+                                   (PVOID *)&__FreeMibTable);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    status = __GetIfTable2(&Table);
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
+    //
+    // Look for a network interface with the same permanent address
+    // that is already up. If there is one then it must be an
+    // aliasing emulated device, so save its settings.
+    //
+    for (Index = 0; Index < Table->NumEntries; Index++) {
+        PMIB_IF_ROW2    Row = &Table->Table[Index];
+
+        Trace("%s: checking %ws (%ws)\n",
+              __PdoGetName(Pdo),
+              Row->Alias,
+              Row->Description);
+
+        if (!Row->InterfaceAndOperStatusFlags.ConnectorPresent)
+            continue;
+
+        if (Row->PhysicalAddressLength != sizeof (ETHERNET_ADDRESS))
+            continue;
+
+        if (memcmp(Row->PermanentPhysicalAddress,
+                   __PdoGetPermanentAddress(Pdo),
+                   sizeof (ETHERNET_ADDRESS)) != 0)
+            continue;
+
+        if (Row->OperStatus != IfOperStatusUp)
+            continue;
+
+        Pdo->HasAlias = TRUE;
+        break;
+    }
+
+    __FreeMibTable(Table);
+
+    return 0;
+
+fail3:
+    Error("fail3\n");
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
 NTSTATUS
 PdoCreate(
     IN  PXENVIF_FDO     Fdo,
@@ -2709,6 +2782,21 @@ PdoCreate(
     if (__PdoIsEjectRequested(Pdo))
         goto fail11;
 
+    status = __PdoCheckForAlias(Pdo);
+    if (!NT_SUCCESS(status))
+        goto fail12;
+
+    status = __PdoCheckForDriver(Pdo);
+    if (!NT_SUCCESS(status))
+        goto fail13;
+
+    if (Pdo->HasDriver) {
+        PdoUnplugRequest(Pdo, TRUE);
+
+        if (Pdo->HasAlias)
+            DriverRequestReboot();
+    }
+
     Info("%p (%s)\n",
          PhysicalDeviceObject,
          __PdoGetName(Pdo));
@@ -2718,6 +2806,14 @@ PdoCreate(
     PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
     return STATUS_SUCCESS;
 
+fail13:
+    Error("fail13\n");
+
+    Pdo->HasAlias = FALSE;
+
+fail12:
+    Error("fail12\n");
+
 fail11:
     Error("fail11\n");
 
@@ -2806,7 +2902,9 @@ PdoDestroy(
 
     ASSERT3U(__PdoGetDevicePnpState(Pdo), ==, Deleted);
 
-    Pdo->UnplugRequested = FALSE;
+    PdoUnplugRequest(Pdo, FALSE);
+
+    Pdo->HasDriver = FALSE;
     Pdo->HasAlias = FALSE;
 
     ASSERT(__PdoIsMissing(Pdo));
-- 
2.1.1


_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
https://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®.