Поделиться через


Обработка запросов подкачки 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) затем )

  1. Присвойте локальному логическому значению значение TRUE и

  2. Если бит 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 успешно завершается, то

  1. Вызовите IoAdjustPagingPathCount(&PagingCount, Parameters.UsageNotification.InPath) для увеличения или уменьшения PagingCount. IoAdjustPagingPathCount выполняет interlockedIncrement или InterlockedDecrement PagingCount в зависимости от значения в Parameters.UsageNotification.InPath. Значение TRUE указывает, что добавляется файл подкачки, поэтому приумножение PagingCount; значение FALSE указывает, что файл подкачки удаляется, поэтому уменьшается PagingCount.

  2. Если параметр Parameters.UsageNotification.InPath имеет значение TRUE, добавляется файл подкачки, поэтому очистите бит DO_POWER_PAGABLE .

Е. В противном случае, если IRP завершается сбоем, то

  1. Проверьте локальный логический код, чтобы узнать, задано ли DO_POWER_PAGABLE в фильтре DO на пути вниз.

  2. Если 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.