Implementación de una rutina de IoCompletion
En la entrada, una rutina de IoCompletion recibe un puntero Context . Cuando una rutina de distribución llama a IoSetCompletionRoutine, puede proporcionar un puntero de contexto . Este puntero puede hacer referencia a cualquier información de contexto determinada por el controlador que requiera la rutina ioCompletion para procesar un IRP. Tenga en cuenta que el área de contexto no puede ser paginable porque se puede llamar a la rutina IoCompletion en IRQL = DISPATCH_LEVEL.
Tenga en cuenta las siguientes directrices de implementación para rutinas de IoCompletion:
Una rutina de IoCompletion puede comprobar el bloque de estado de E /S de IRP para determinar el resultado de la operación de E/S.
Si la rutina de distribución asignó el IRP de entrada mediante IoAllocateIrp o IoBuildAsynchronousFsdRequest, la rutina ioCompletion debe llamar a IoFreeIrp para liberar ese IRP, preferiblemente antes de completar el IRP original.
La rutina ioCompletion debe liberar todos los recursos por IRP que la rutina de envío asignada para el IRP asignado por el controlador, preferiblemente antes de liberar el IRP correspondiente.
Por ejemplo, si la rutina de distribución asigna una MDL con IoAllocateMdl y llama a IoBuildPartialMdl para un IRP de transferencia parcial, la rutina de IoCompletion debe liberar la MDL con IoFreeMdl. Si asigna recursos para mantener el estado sobre el IRP original, debe liberar esos recursos, preferiblemente antes de llamar a IoCompleteRequest con el IRP original y definitivamente antes de devolver el control.
En general, antes de liberar o completar un IRP, la rutina ioCompletion debe liberar los recursos por IRP asignados por la rutina Dispatch. De lo contrario, el controlador debe mantener el estado sobre los recursos que se liberarán antes de que su rutina de IoCompletion devuelva el control para completar la solicitud original.
Si la rutina ioCompletion no puede completar el IRP original con STATUS_SUCCESS, debe establecer el bloque de estado de E/S en el IRP original en el valor devuelto en el IRP asignado por el controlador que provocó que la rutina ioCompletion produzca un error en la solicitud original.
Si la rutina ioCompletion completará la solicitud original con STATUS_PENDING, debe llamar a IoMarkIrpPending con el IRP original antes de llamar a IoCompleteRequest.
Si la rutina ioCompletion debe producir un error en el IRP original con un error STATUS_XXX, puede registrar un error. Sin embargo, es responsabilidad del controlador de dispositivo subyacente registrar los errores de E/S del dispositivo que se produzcan, por lo que las rutinas de IoCompletion normalmente no registran errores.
Cuando la rutina ioCompletion ha procesado y liberado el IRP asignado por el controlador, la rutina debe devolver el control con STATUS_MORE_PROCESSING_REQUIRED.
Devolver STATUS_MORE_PROCESSING_REQUIRED de la rutina ioCompletion evita el procesamiento de finalización del administrador de E/S para un IRP asignado y liberado por el controlador. Una segunda llamada a IoCompleteRequest hace que el administrador de E/S reanude la llamada a las rutinas de finalización del IRP, empezando por la rutina de finalización inmediatamente por encima de la rutina que devolvió STATUS_MORE_PROCESSING_REQUIRED.
Si la rutina ioCompletion reutiliza un IRP entrante para enviar una o varias solicitudes a controladores inferiores, o si las operaciones de reintento de rutina no se pudieron realizar, debe actualizar el contexto que la rutina de IoCompletion mantiene sobre cada reutilización o reintento del IRP. A continuación, puede volver a configurar la ubicación de pila de E/S del controlador inferior siguiente, llamar a IoSetCompletionRoutine con su propio punto de entrada y llamar a IoCallDriver para irP.
La rutina IoCompletion no debe llamar a IoMarkIrpPending en cada reutilización o reintento del IRP.
La rutina de envío ya marcó el IRP original como pendiente. Hasta que todos los controladores de la cadena completen el IRP original con IoCompleteRequest, permanece pendiente.
Antes de reintentar una solicitud, la rutina IoCompletion debe restablecer el bloque de estado de E/S con STATUS_SUCCESS para Estado y cero para Information, posiblemente después de guardar la información de error devuelta.
Para cada reintento, la rutina IoCompletion normalmente disminuye un recuento de reintentos configurado por la rutina Dispatch. Normalmente, la rutina IoCompletion debe llamar a IoCompleteRequest para que produzca un error en el IRP cuando se haya producido un error en algún número limitado de reintentos.
La rutina IoCompletion debe devolver STATUS_MORE_PROCESSING_REQUIRED después de llamar a IoSetCompletionRoutine e IoCallDriver con un IRP que se está reutilizando o reintentando.
Devolver STATUS_MORE_PROCESSING_REQUIRED de la rutina ioCompletion impide que el administrador de E/S complete el procesamiento de un IRP reutilizado o reintentado.
Si la rutina ioCompletion no puede completar el IRP original con STATUS_SUCCESS, debe dejar el bloque de estado de E/S tal como lo devuelven los controladores inferiores para la operación de reutilización o reintento que hace que la rutina de IoCompletion produzca un error en el IRP.
Si la rutina ioCompletion completará la solicitud original con STATUS_PENDING, debe llamar a IoMarkIrpPending con el IRP original antes de llamar a IoCompleteRequest.
Si la rutina ioCompletion debe producir un error en el IRP original con un error STATUS_XXX, puede registrar un error. Sin embargo, es responsabilidad del controlador de dispositivo subyacente registrar los errores de E/S del dispositivo que se produzcan, por lo que las rutinas de IoCompletion normalmente no registran errores.
Cualquier controlador que establezca una rutina de IoCompletion en un IRP y, a continuación, pase el IRP hacia abajo a un controlador inferior debe comprobar la marca IRP-PendingReturned> en la rutina de IoCompletion. Si se establece la marca, la rutina IoCompletion debe llamar a IoMarkIrpPending con IRP. Sin embargo, tenga en cuenta que un controlador que pasa el IRP y, a continuación, espera en un evento no debe marcar el IRP pendiente. En su lugar, su rutina ioCompletion debe indicar el evento y devolver STATUS_MORE_PROCESSING_REQUIRED.
La rutina ioCompletion debe liberar los recursos asignados a la rutina de distribución para procesar el IRP original, preferiblemente antes de que la rutina ioCompletion llame a IoCompleteRequest con el IRP original y definitivamente antes de que la rutina de IoCompletion devuelva el control de completar el IRP original.
Si algún controlador de nivel superior ha establecido su rutina de IoCompletion en el IRP original, no se llama a la rutina ioCompletion del controlador hasta que se haya llamado a las rutinas de IoCompletion de todos los controladores de nivel inferior.
Proporcionar un aumento de prioridad en las llamadas a IoCompleteRequest
Si un controlador de dispositivo de nivel más bajo puede completar un IRP en su rutina de envío, llama a IoCompleteRequest con priorityBoost de IO_NO_INCREMENT. No se necesita ningún aumento de prioridad en tiempo de ejecución porque el controlador puede suponer que el solicitante original no ha esperado a que se complete su operación de E/S.
De lo contrario, el controlador de nivel más bajo proporciona un valor específico del tipo de dispositivo y definido por el sistema que aumenta la prioridad en tiempo de ejecución del solicitante para compensar el tiempo que el solicitante ha esperado en su solicitud de E/S del dispositivo. Consulte Wdm.h o Ntddk.h para obtener los valores de potenciación.
Los controladores de nivel superior aplican el mismo PriorityBoost que sus respectivos controladores de dispositivo subyacentes cuando llaman a IoCompleteRequest.
Efecto de llamar a IoCompleteRequest
Cuando un controlador llama a IoCompleteRequest, el administrador de E/S rellena la ubicación de pila de E/S del controlador con ceros antes de llamar al siguiente controlador de nivel superior, si existe, que ha configurado una rutina de IoCompletion para llamar a irP.
Una rutina de IoCompletion del controlador de nivel superior solo puede comprobar el bloque de estado de E/S de IRP para determinar cómo todos los controladores inferiores controlaron la solicitud.
El autor de la llamada de IoCompleteRequest no debe intentar acceder al IRP recién completado. Este intento es un error de programación que provoca un bloqueo del sistema.