Manipulando solicitações de paginação PnP
Um driver de filtro de armazenamento deve lidar com solicitações de paginação PnP (IRP_MJ_PNP com IRP_MN_DEVICE_USAGE_NOTIFICATION e Parameters.UsageNotification.Type definido como DeviceUsageTypePaging) se o driver de função que ele está filtrando manipular esse IRP.
Os seguintes itens devem ser adicionados à DeviceExtension do Filter DO:
ULONG PagingCount;
KEVENT PagingCountEvent;
Ao receber solicitações de paginação PnP, um driver de filtro de armazenamento deve atualizar pagingCount e a configuração do DO_POWER_PAGABLE bit no Filter DO. O tempo da atualização do DO_POWER_PAGABLE bit depende se o bit está sendo definido ou limpo. Se o IRP indicar que o bit deve ser definido, o driver de filtro deverá defini-lo antes de encaminhar o IRP para baixo na pilha do driver. Mas se o IRP indicar que o bit deve ser limpo, o driver de filtro não deve limpar o bit imediatamente. Ele deve primeiro encaminhar o IRP, depois esperar que os drivers inferiores retornem seus status e limpar o bit somente se os drivers inferiores retornarem STATUS_SUCCESS.
O seguinte rastreia o fluxo de ações executadas pelo driver de filtro de armazenamento. Consulte o exemplo de pseudocódigo imediatamente abaixo da estrutura de tópicos para ver uma representação dessa estrutura de tópicos no código C:
a. Verifique se o dispositivo foi iniciado. Caso contrário, falhe com STATUS_DEVICE_NOT_READY.
B. Sincronize no PagingCountEvent (KeWaitForSingleObject( PagingCountEvent, ...)).
C. Se estiver removendo o último dispositivo de paginação ( (! Parameters.UsageNotification.InPath && (PagingCount == 1) ) e, em seguida,
Definir um booliano local como TRUE e
Se o bit DO_POWER_INRUSH não estiver definido no Filtro DO, defina o bit DO_POWER_PAGABLE .
O seguinte explica por que o bit DO_POWER_PAGABLE deve ser definido no caminho para baixo e não no caminho para cima:
Os requisitos de energia afirmam que, se qualquer objeto de dispositivo inferior definir o DO_POWER_PAGABLE bit, todos os drivers de nível superior deverão fazer o mesmo. Se o driver de filtro não definir o DO_POWER_PAGABLE bit antes de enviar o IRP da solicitação de paginação para baixo na pilha, ele poderá violar essa condição da seguinte maneira:
Suponha que o driver de filtro não defina o DO_POWER_PAGABLE bit em seu Filter DO antes de encaminhar o IRP da solicitação de paginação para os drivers abaixo dele na pilha do driver. Em seguida, suponha que um driver inferior defina o DO_POWER_PAGABLE bit em seu próprio DO. Por fim, suponha que antes da conclusão do IRP pelo driver de filtro ocorra um IRP de energia. Nesse ponto, o bit DO_POWER_PAGABLE seria limpo no Filter DO, mas seria definido no DO do driver de nível inferior, causando uma falha no sistema.
É seguro definir o DO_POWER_PAGABLE bit antes de encaminhar uma solicitação de paginação para baixo na pilha, pois não há mais um arquivo de paginação ativo no dispositivo do driver de filtro e, portanto, não ocorrerá mais E/S de paginação nele. Se a solicitação para remover esse arquivo de paginação for bem-sucedida, o driver de filtro será feito. Se a solicitação falhar, o driver de filtro poderá restaurar o estado original de seus sinalizadores simplesmente limpando o DO_POWER_PAGABLE bit antes de concluir o IRP. Como as solicitações de arquivo de paginação são serializadas, não há perigo de que algum outro thread tenha modificado esse bit desde que o driver de filtro o alterou pela última vez.
D. Encaminhe de forma síncrona o IRP para os drivers inferiores.
E. Se o IRP for concluído com êxito,
Chame IoAdjustPagingPathCount(&PagingCount, Parameters.UsageNotification.InPath) para incrementar ou diminuir o PagingCount. IoAdjustPagingPathCount faz um InterlockedIncrement ou InterlockedDecrement do PagingCount, dependendo do valor em Parameters.UsageNotification.InPath. Um valor true indica que um arquivo de paginação está sendo adicionado, portanto, incremente PagingCount; um valor false indica que um arquivo de paginação está sendo removido, portanto, decremente PagingCount.
Se Parameters.UsageNotification.InPath for TRUE, um arquivo de paginação será adicionado, portanto, limpe o DO_POWER_PAGABLE bit.
F. Caso contrário, se o IRP falhar,
Verifique o booliano local para ver se DO_POWER_PAGABLE foi definido no Filtro DO no caminho para baixo.
Se DO_POWER_PAGABLE foi definido no caminho para baixo, limpe-o.
G. Sincronização final (KeSetEvent(PagingCountEvent, ...)).
Exemplo de pseudocódigo
As seções marcadas por letras (//A, //B etc.) no exemplo de código a seguir são mapeadas para as letras da estrutura de tópicos acima.
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.