Garantizar el progreso hacia delante de las operaciones de E/S

Algunos controladores, como los controladores de almacenamiento para el dispositivo de paginación del sistema, deben realizar al menos algunas de sus operaciones de E/S admitidas sin errores, para evitar perder datos críticos del sistema. Una posible causa de un error de controlador es una situación de poca memoria. Si el marco o el controlador no pueden asignar memoria suficiente para controlar una solicitud de E/S, una u otra podría tener que producir un error en la solicitud de E/S completando con un valor de estado de error.

En versiones de KMDF anteriores a la versión 1.9, el marco siempre produce un error en una solicitud de E/S si no puede asignar un objeto de solicitud de marco para un paquete de solicitud de E/S (IRP) que el administrador de E/S ha enviado al controlador. Para proporcionar a los controladores la capacidad de procesar solicitudes de E/S durante situaciones de poca memoria, las versiones 1.9 y posteriores del marco proporcionan una funcionalidad de progreso hacia delante garantizada para las colas de E/S.

Esta funcionalidad permite que el marco y el controlador asignen previamente memoria para conjuntos de objetos de solicitud y búferes de contexto del controlador relacionados con la solicitud, respectivamente. El marco y el controlador usan esta memoria asignada previamente solo cuando la cantidad de memoria del sistema es baja.

Características del progreso hacia delante garantizado

Mediante el progreso hacia delante garantizado del marco para las colas de E/S, un controlador puede:

  • Pida al marco que asigne previamente un conjunto de objetos de solicitud para usarlos con una cola de E/S específica durante situaciones de poca memoria.

  • Proporcione una función de devolución de llamada que asigne previamente recursos específicos de la solicitud que el controlador puede usar cuando recibe objetos de solicitud asignados previamente desde el marco durante situaciones de poca memoria.

  • Proporcione otra función de devolución de llamada que asigne recursos específicos del controlador para una solicitud de E/S cuando no se detecte una situación de memoria baja. Si se produce un error en la asignación de esta función de devolución de llamada debido a una situación de memoria baja, puede indicar si el marco debe usar uno de sus objetos de solicitud asignados previamente.

  • Especifique qué solicitudes de E/S requieren el uso de objetos de solicitud asignados previamente. Entre las opciones se incluyen el uso de objetos asignados previamente para todos los IRP, usarlos solo si una operación de E/S de paginación está en curso o si hay una función de devolución de llamada de controlador adicional que examina cada IRP para determinar si se debe usar un objeto asignado previamente.

Si el controlador implementa el progreso hacia delante garantizado para una o varias de sus colas de E/S, el controlador podrá procesar correctamente las solicitudes de E/S durante situaciones de poca memoria. Puede implementar el progreso hacia delante garantizado para la cola de E/S predeterminada de un dispositivo y para cualquier cola de E/S que configure el controlador llamando a WdfDeviceConfigureRequestDispatching.

La funcionalidad de progreso hacia delante garantizada del marco solo funciona para el controlador si tanto el controlador como los destinos de E /S del controlador implementan el progreso hacia delante garantizado. En otras palabras, si un controlador implementa el progreso hacia delante garantizado para un dispositivo, todos los controladores de nivel inferior de la pila de controladores del dispositivo también deben implementar el progreso hacia delante garantizado.

Habilitación del progreso hacia delante garantizado para una cola de E/S

Para habilitar el progreso hacia delante garantizado para una cola de E/S, el controlador inicializa una estructura de WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY y, a continuación, llama al método WdfIoQueueAssignForwardProgressPolicy . Si el controlador llama a WdfDeviceConfigureRequestDispatching para configurar una cola de E/S, debe hacerlo antes de llamar a WdfIoQueueAssignForwardProgressPolicy.

Cuando el controlador llama a WdfIoQueueAssignForwardProgressPolicy, puede especificar las tres funciones de devolución de llamada de eventos siguientes, todas ellas opcionales:

EvtIoAllocateResourcesForReservedRequest
La función de devolución de llamada EvtIoAllocateResourcesForReservedRequest de un controlador asigna y almacena recursos específicos de la solicitud para los objetos de solicitud que el marco está reservando para situaciones de poca memoria.

El marco llama a esta función de devolución de llamada cada vez que crea un objeto de solicitud reservado. El controlador debe asignar recursos específicos de la solicitud para una solicitud de E/S, normalmente mediante el espacio de contexto del objeto de solicitud reservada.

EvtIoAllocateRequestResources
La función de devolución de llamada EvtIoAllocateRequestResources de un controlador asigna recursos específicos de la solicitud para su uso inmediato. Se llama inmediatamente después de que el marco haya recibido un IRP y haya creado un objeto de solicitud para el IRP.

Si se produce un error en el intento de la función de devolución de llamada para asignar recursos, la función de devolución de llamada devuelve un valor de estado de error. A continuación, el marco elimina el objeto de solicitud recién creado y usa uno de sus objetos de solicitud reservados. A su vez, el controlador de solicitudes del controlador usa recursos específicos de la solicitud que su función de devolución de llamada EvtIoAllocateRequestResources asignó anteriormente.

EvtIoWdmIrpForForForwardProgress
La función de devolución de llamada EvtIoWdmIrpForforwardProgress de un controlador examina un IRP e indica al marco si se debe usar un objeto de solicitud reservado para irP o si se produce un error en la solicitud de E/S completando con un valor de estado de error.

El marco llama a esta función de devolución de llamada solo si el marco no puede crear un nuevo objeto de solicitud y ha indicado (estableciendo una marca en la estructura de WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY del controlador) que desea que el controlador examine los IRP durante situaciones de poca memoria. En otras palabras, el controlador puede evaluar cada IRP y decidir si es uno que debe procesarse incluso durante situaciones de poca memoria.

Cuando el controlador llama a WdfIoQueueAssignForwardProgressPolicy, también especifica el número de objetos de solicitud reservados que desea que el marco asigne previamente para situaciones de poca memoria. Puede elegir el número de objetos de solicitud adecuados para el dispositivo y el controlador. Para evitar un rendimiento reducido, el controlador normalmente debe especificar un número que aproxima el número de solicitudes de E/S que el controlador y el dispositivo pueden controlar en paralelo.

Sin embargo, si la llamada del controlador a WdfIoQueueAssignForwardProgressPolicy y su EvtIoAllocateResourcesForReservedRequest asignan previamente demasiados objetos de solicitud reservados o demasiada memoria de recursos específica de la solicitud, el controlador puede contribuir realmente a las situaciones de poca memoria que está intentando controlar. Debe probar el rendimiento del controlador y el dispositivo e incluir simulaciones de memoria baja para determinar los mejores números que elegir.

Antes de que se devuelva WdfIoQueueAssignForwardProgressPolicy , el marco crea y reserva el número de objetos de solicitud que el controlador ha especificado. Cada vez que reserva un objeto de solicitud, el marco llama inmediatamente a la función de devolución de llamada EvtIoAllocateResourcesForReservedRequest del controlador para que el controlador pueda asignar y guardar recursos específicos de la solicitud, en caso de que el marco use realmente los objetos de solicitud reservados.

Cuando uno de los controladores de solicitudes del controlador recibe una solicitud de E/S de la cola de E/S, puede llamar al método WdfRequestIsReserved para determinar si el objeto de solicitud es uno que el marco preasignó para situaciones de poca memoria. Si este método devuelve TRUE, el controlador debe usar recursos reservados para su función de devolución de llamada EvtIoAllocateResourcesForReservedRequest .

Si el marco usa uno de sus objetos de solicitud reservados, devuelve el objeto a su conjunto de objetos reservados después de que el controlador complete la solicitud. El marco guarda el objeto de solicitud y cualquier espacio de contexto que el controlador haya creado llamando a WdfDeviceInitSetRequestAttributes o WdfObjectAllocateContext, para reutilizarlo si se produce otra situación de memoria baja.

Cómo se garantiza el progreso hacia delante del marco y del controlador

A continuación se indican los pasos que realiza el controlador y el marco para admitir el progreso hacia delante garantizado para una cola de E/S:

  1. El controlador llama a WdfIoQueueAssignForwardProgressPolicy.

    En respuesta, el marco asigna y almacena el número de objetos de solicitud que especifica el controlador. Si el controlador anteriormente llamado WdfDeviceInitSetRequestAttributes, cada asignación incluye espacio de contexto que WdfDeviceInitSetRequestAttributes especificó.

    Además, si el controlador ha proporcionado una función de devolución de llamada EvtIoAllocateResourcesForReservedRequest , el marco llama a la función de devolución de llamada cada vez que asigna y almacena un objeto de solicitud.

  2. El marco recibe un paquete de solicitud de E/S (IRP) que el administrador de E/S envía al controlador.

    El marco intenta asignar un objeto de solicitud para irP. Si la cola de E/S que creó el controlador para el tipo de solicitud admite el progreso hacia delante garantizado, el siguiente paso depende de si la asignación se realiza correctamente o no:

    • La asignación de objetos de solicitud se realiza correctamente.

      Si el controlador proporcionó una función de devolución de llamada EvtIoAllocateRequestResources , el marco lo llama. Si la función de devolución de llamada devuelve STATUS_SUCCESS, el marco agrega la solicitud a la cola de E/S. Si la función de devolución de llamada devuelve un valor de estado de error, el marco elimina el objeto de solicitud que acaba de crear y usa uno de sus objetos de solicitud asignados previamente. Cuando el controlador de solicitudes del controlador recibe el objeto de solicitud, determina si el objeto de solicitud se asignó previamente y, por lo tanto, si debe usar los recursos asignados previamente del controlador.

      Si el controlador no proporcionó una función de devolución de llamada EvtIoAllocateRequestResources , el marco agrega la solicitud a la cola de E/S, igual que si el controlador no hubiera habilitado el progreso hacia delante garantizado.

    • Se produce un error en la asignación de objetos de solicitud.

      Lo que hace el marco de trabajo a continuación depende del valor que el controlador proporcionó para el miembro ForwardProgressReservedPolicy de la estructura de WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY . Este miembro informa al marco de trabajo cuándo usar una solicitud reservada: siempre, solo si la solicitud de E/S es una operación de E/S de paginación o solo si la función de devolución de llamada EvtIoWdmIrpForwardProgress indica que se debe usar una solicitud reservada.

    En todos los casos, los controladores de solicitud del controlador pueden llamar a WdfRequestIsReserved para determinar si el marco ha usado un objeto de solicitud reservado. Si es así, el controlador debe usar los recursos de solicitud asignados a su función de devolución de llamada EvtIoAllocateResourcesForReservedRequest .

Escenario de progreso hacia delante garantizado

Está escribiendo un controlador para un dispositivo de almacenamiento que puede contener el archivo de paginación del sistema. Es importante que las operaciones de lectura de y escritura en el archivo de paginación se realicen correctamente.

Decide crear colas de E/S independientes para operaciones de lectura y escritura, y para habilitar el progreso hacia delante garantizado para ambas colas de E/S. Decide crear una tercera cola de E/S para todos los demás tipos de solicitudes sin habilitar el progreso hacia delante garantizado.

La pila de controladores y el dispositivo son capaces de procesar cuatro operaciones de escritura en paralelo, por lo que se establece el miembro TotalForwardProgressRequests de la estructura de WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY en 4 antes de llamar a WdfIoQueueAssignForwardProgressPolicy.

Decide que garantizar el progreso hacia delante solo es importante si el dispositivo del controlador es el dispositivo de paginación, por lo que el controlador establece el miembro ForwardProgressReservedPolicy de la estructura de WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY en WdfIoForwardProgressReservedPolicyPagingIO.

Dado que el controlador requiere un objeto de memoria de marco para cada solicitud de lectura y cada solicitud de escritura, decide que el controlador debe asignar previamente algunos objetos de memoria que se usarán para sus llamadas a WdfIoTargetFormatRequestForRead y WdfIoTargetFormatRequestForWrite en situaciones de poca memoria.

Por lo tanto, el controlador proporciona una función de devolución de llamada EvtIoAllocateResourcesForReservedRequest para la cola de lectura y otra para la cola de escritura. Cada vez que el marco llama a una de estas funciones de devolución de llamada, la función de devolución de llamada llama a WdfMemoryCreate y guarda el identificador de objeto devuelto para situaciones de poca memoria. Dado que la función de devolución de llamada recibe un identificador para un objeto de solicitud asignado previamente, puede primario el objeto de memoria al objeto de solicitud. (Un controlador para un dispositivo DMA también puede asignar previamente objetos DMA de marco).

Los controladores de solicitudes de las colas de lectura y escritura deben determinar si cada objeto de solicitud recibido es uno que el marco reservado para situaciones de poca memoria. Un controlador de solicitudes puede llamar a WdfRequestIsReserved o puede comparar el identificador del objeto de solicitud con los que la función de devolución de llamada EvtIoAllocateResourcesForReservedRequest recibió anteriormente.

El controlador también proporciona una función de devolución de llamada EvtIoAllocateRequestResources para la cola de lectura y otra para la cola de escritura. El marco llama a una de estas funciones de devolución de llamada cuando recibe una solicitud de lectura o escritura del administrador de E/S y crea correctamente un objeto de solicitud. Cada una de estas funciones de devolución de llamada llama a WdfMemoryCreate para asignar un objeto de memoria para una solicitud. Si se produce un error en la asignación, la función de devolución de llamada devuelve un valor de estado de error para notificar al marco que acaba de producirse una situación de memoria baja. El marco de trabajo, al detectar el valor devuelto de error, elimina el objeto de solicitud que acaba de crear y usa uno de sus objetos asignados previamente.

Este controlador no proporciona una función de devolución de llamada EvtIoWdmIrpForwardProgress , ya que no es necesario examinar irP individuales de lectura o escritura antes de que el marco los agregue a una cola de E/S.

Recuerde que cuando un controlador implementa el progreso hacia delante garantizado para un dispositivo, todos los controladores de nivel inferior de la pila de controladores del dispositivo también deben implementar el progreso hacia delante garantizado.