Verarbeiten von PnP-Paginganforderungen
Ein Speicherfiltertreiber muss PnP-Paginganforderungen verarbeiten (IRP_MJ_PNP mit IRP_MN_DEVICE_USAGE_NOTIFICATION und Parameters.UsageNotification.Type auf DeviceUsageTypePaging festgelegt ist), wenn der zu filternde Funktionstreiber diese IRP verarbeitet.
Die folgenden Elemente müssen der DeviceExtension der Filter-DO hinzugefügt werden:
ULONG PagingCount;
KEVENT PagingCountEvent;
Beim Empfang von PnP-Paginganforderungen muss ein Speicherfiltertreiber sowohl den PagingCount als auch die Einstellung des DO_POWER_PAGABLE Bits in der Filter-DO aktualisieren. Der Zeitpunkt der Aktualisierung des DO_POWER_PAGABLE Bits hängt davon ab, ob das Bit festgelegt oder gelöscht wird. Wenn das IRP angibt, dass das Bit festgelegt werden soll, muss es vom Filtertreiber festgelegt werden, bevor der IRP nach unten im Treiberstapel weitergeleitet wird. Wenn der IRP jedoch angibt, dass das Bit gelöscht werden soll, sollte der Filtertreiber das Bit nicht sofort löschen. Es muss zuerst die IRP weiterleiten, dann warten, bis niedrigere Treiber ihre status zurückgeben, und das Bit nur löschen, wenn die niedrigeren Treiber STATUS_SUCCESS zurückgeben.
Im Folgenden werden die Vom Speicherfiltertreiber ausgeführten Aktionen verfolgt. Eine Darstellung dieser Gliederung in C-Code finden Sie im Pseudocodebeispiel direkt unter der Gliederung:
A. Vergewissern Sie sich, dass das Gerät gestartet wurde. Wenn nicht, schlagen Sie mit STATUS_DEVICE_NOT_READY fehl.
B. Synchronisieren Sie auf dem PagingCountEvent (KeWaitForSingleObject( PagingCountEvent, ...)).
C. Beim Entfernen des letzten Auslagerungsgeräts ( (! Parameters.UsageNotification.InPath && (PagingCount == 1) )
Legen Sie einen lokalen booleschen Wert auf TRUE fest, und
Wenn das DO_POWER_INRUSH Bit in der Filter-DO nicht festgelegt ist, legen Sie das DO_POWER_PAGABLE Bit fest.
Im Folgenden wird erläutert, warum das DO_POWER_PAGABLE Bit auf dem Weg nach unten und nicht auf dem Weg nach oben festgelegt werden muss:
Die Energieanforderungen geben an, dass, wenn ein niedrigeres Geräteobjekt das DO_POWER_PAGABLE Bit festlegt, alle treiber der höheren Ebene dasselbe tun müssen. Wenn der Filtertreiber das DO_POWER_PAGABLE Bit nicht festlegen kann, bevor die AuslagerungsanforderungS-IRP im Stapel gesendet wird, kann dies wie folgt gegen diese Bedingung verstoßen:
Angenommen, der Filtertreiber legt das DO_POWER_PAGABLE Bit in seinem Filter-DO nicht fest, bevor die AuslagerungsanforderungS-IRP an die Treiber darunter im Treiberstapel weitergeleitet wird. Angenommen, ein niedrigerer Treiber legt das DO_POWER_PAGABLE Bit in seinem eigenen DO fest. Nehmen wir schließlich an, dass vor Abschluss des IRP durch den Filtertreiber ein Leistungs-IRP auftritt. Zu diesem Zeitpunkt wird das DO_POWER_PAGABLE Bit in der Filter-DO gelöscht, aber im DO des Treibers auf niedrigerer Ebene festgelegt, was zu einem Systemabsturz führt.
Es ist sicher, das DO_POWER_PAGABLE Bit festzulegen, bevor sie eine Auslagerungsanforderung im Stapel weiterleitet, da auf dem Gerät des Filtertreibers keine aktive Auslagerungsdatei mehr vorhanden ist und daher keine paging-E/A mehr darauf ausgeführt wird. Wenn die Anforderung zum Entfernen dieser Auslagerungsdatei erfolgreich ist, wird der Filtertreiber ausgeführt. Wenn die Anforderung fehlschlägt, kann der Filtertreiber den ursprünglichen Zustand seiner Flags wiederherstellen, indem er einfach das DO_POWER_PAGABLE Bit vor Abschluss der IRP löscht. Da die Anforderungen der Auslagerungsdatei serialisiert werden, besteht keine Gefahr, dass ein anderer Thread dieses Bit geändert hat, da der Filtertreiber es zuletzt geändert hat.
D: Leiten Sie den IRP synchron an die niedrigeren Treiber weiter.
E. Wenn die IRP erfolgreich abgeschlossen wurde, dann
Rufen Sie IoAdjustPagingPathCount(&PagingCount, Parameters.UsageNotification.InPath) auf, um pagingCount zu erhöhen oder zu verringern. IoAdjustPagingPathCount führt in Abhängigkeit vom Wert in Parameters.UsageNotification.InPath ein InterlockedIncrement oder InterlockedDecrement des PagingCount durch. Der Wert TRUE gibt an, dass eine Auslagerungsdatei hinzugefügt wird. Erhöhen Sie also den PagingCount; Der Wert FALSE gibt an, dass eine Auslagerungsdatei entfernt wird. Verringern Sie also den PagingCount.
Wenn Parameters.UsageNotification.InPathTRUE ist, wird eine Auslagerungsdatei hinzugefügt. Löschen Sie also das DO_POWER_PAGABLE Bit.
F. Andernfalls, wenn die IRP fehlschlägt, dann
Überprüfen Sie den lokalen Booleschen Wert, um festzustellen, ob DO_POWER_PAGABLE auf dem Weg nach unten in der Filter-DO festgelegt wurde.
Wenn DO_POWER_PAGABLE auf dem Weg nach unten festgelegt wurde, löschen Sie es.
G. Beenden der Synchronisierung (KeSetEvent(PagingCountEvent, ...)).
Pseudocodebeispiel
Die durch Buchstaben (//A, //B usw.) gekennzeichneten Abschnitte im folgenden Codebeispiel entsprechen den Buchstaben der obigen Gliederung.
case DeviceUsageTypePaging: {
BOOLEAN setPageable = FALSE;
BOOLEAN addPageFile = irpStack ->
Parameters.UsageNotification.InPath;
// A
if((addPageFile) &&
(extension -> CurrentPnpState !=
IRP_MN_START_DEVICE)) {
status = STATUS_DEVICE_NOT_READY;
break;
}
// B
KeWaitForSingleObject(&commonExtension -> PagingCountEvent,
Executive, KernelMode,
FALSE, NULL);
// C
if (!addPageFile && commonExtension -> PagingCount == 1 ) {
// The last paging file is no longer active.
// Set the DO_POWER_PAGABLE bit before
// forwarding the paging request down the
// stack.
if (!(DeviceObject->Flags & DO_POWER_INRUSH)) {
DeviceObject->Flags |= DO_POWER_PAGABLE;
setPageable = TRUE;
)
)
// D
status = ForwardIrpSynchronous(commonExtension, Irp);
// E
if (NT_SUCCESS(status)) {
IoAdjustPagingPathCount(&commonExtension -> PagingCount,
addPageFile);
if (addPageFile && commonExtension -> PagingCount == 1) {
// Once the lower device objects have
// succeeded the addition of the paging
// file, it is illegal to fail the
// request. It is also the time to
// clear the Filter DO's
//DO_POWER_PAGABLE flag.
DeviceObject->Flags &= ~DO_POWER_PAGABLE;
}
} else {
// F
if (setPageable == TRUE) {
DeviceObject->Flags &= ~DO_POWER_PAGABLE;
setPageable = FALSE;
}
}
// G
KeSetEvent(&commonExtension->PagingCountEvent,
IO_NO_INCREMENT, FALSE);
break;
} *Do not use or delete the last paragraph mark. It maintains the template setup and formats.