Обработка запросов подкачки PnP
Драйвер фильтра хранилища должен обрабатывать запросы PnP на страницы (IRP_MJ_PNP с IRP_MN_DEVICE_USAGE_NOTIFICATION и Parameters.UsageNotification.Type , для параметра DeviceUsageTypePaging), если драйвер функции, который он фильтрует, обрабатывает этот IRP.
В раздел DeviceExtension фильтра DO необходимо добавить следующие элементы:
ULONG PagingCount;
KEVENT PagingCountEvent;
При получении запросов на разбиение по страницам PnP драйвер фильтра хранилища должен обновить значение PagingCount и параметр бита DO_POWER_PAGABLE в фильтре DO. Время обновления DO_POWER_PAGABLE бита зависит от того, задан или очищается бит. Если IRP указывает, что бит должен быть задан, драйвер фильтра должен установить его перед перенаправлением IRP в стек драйверов. Но если IRP указывает, что бит должен быть очищен, драйвер фильтра не должен очищать бит сразу. Он должен сначала переслать IRP, а затем дождаться, пока более низкие драйверы вернут свое состояние, и очистить бит только в том случае, если более низкие драйверы возвращают STATUS_SUCCESS.
Ниже показана трассировка потока действий, выполняемых драйвером фильтра хранилища. Обратитесь к примеру псевдокода непосредственно под структурой, чтобы увидеть представление этой структуры в коде C:
A. Убедитесь, что устройство запущено. В противном случае выполните сбой с STATUS_DEVICE_NOT_READY.
Б. Синхронизация в PagingCountEvent (KeWaitForSingleObject( PagingCountEvent, ...)).
В. При удалении последнего устройства подкачки ( (! Parameters.UsageNotification.InPath && (PagingCount == 1) затем )
Присвойте локальному логическому значению значение TRUE и
Если бит DO_POWER_INRUSH не задан в фильтре DO, задайте бит DO_POWER_PAGABLE .
Ниже объясняется, почему DO_POWER_PAGABLE бит должен быть задан на пути вниз, а не на пути вверх:
Требования к энергопотреблению утверждают, что если какой-либо более низкий объект устройства задает DO_POWER_PAGABLE бит, все драйверы более высокого уровня должны делать то же самое. Если драйверу фильтра не удается задать бит DO_POWER_PAGABLE перед отправкой IRP запроса на разбиение по страницам в стеке, это может нарушить это условие следующим образом:
Предположим, что драйвер фильтра не задает бит DO_POWER_PAGABLE в фильтре DO перед перенаправлением IRP запроса на разбиение по страницам в драйверы под ним в стеке драйверов. Далее предположим, что более низкий драйвер задает бит DO_POWER_PAGABLE в своем собственном DO. Наконец, предположим, что перед завершением IRP драйвером фильтра происходит IRP питания. На этом этапе бит DO_POWER_PAGABLE будет очищен в фильтре DO, но будет задан в DO драйвера нижнего уровня, что приведет к сбою системы.
Перед перенаправлением запроса на разбиение по страницам в стеке можно с уверенностью задать бит DO_POWER_PAGABLE , так как на устройстве драйвера фильтра больше нет активного файла подкачки, и, следовательно, на нем больше не будут выполняться операции ввода-вывода подкачки. Если запрос на удаление этого файла подкачки завершается успешно, будет выполнен драйвер фильтра. В случае сбоя запроса драйвер фильтра может восстановить исходное состояние своих флагов, просто очисв бит DO_POWER_PAGABLE перед завершением IRP. Так как запросы файла подкачки сериализуются, нет никакой опасности, что некоторые другие потоки изменят этот бит с момента последнего изменения драйвера фильтра.
Г. Синхронно перенаправите IRP в нижние драйверы.
Д. Если IRP успешно завершается, то
Вызовите IoAdjustPagingPathCount(&PagingCount, Parameters.UsageNotification.InPath) для увеличения или уменьшения PagingCount. IoAdjustPagingPathCount выполняет interlockedIncrement или InterlockedDecrement PagingCount в зависимости от значения в Parameters.UsageNotification.InPath. Значение TRUE указывает, что добавляется файл подкачки, поэтому приумножение PagingCount; значение FALSE указывает, что файл подкачки удаляется, поэтому уменьшается PagingCount.
Если параметр Parameters.UsageNotification.InPath имеет значение TRUE, добавляется файл подкачки, поэтому очистите бит DO_POWER_PAGABLE .
Е. В противном случае, если IRP завершается сбоем, то
Проверьте локальный логический код, чтобы узнать, задано ли DO_POWER_PAGABLE в фильтре DO на пути вниз.
Если DO_POWER_PAGABLE был задан на пути вниз, снимите его.
Ж. Завершение синхронизации (KeSetEvent(PagingCountEvent, ...)).
Пример псевдокода
Разделы, помеченные буквами (//A, //B и т. д.), в следующем примере кода сопоставляется с буквами структуры выше.
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.