Compartir vía


Procesamiento de IRP en un controlador de Intermediate-Level

Los controladores de nivel superior tienen un conjunto diferente de rutinas estándar que los controladores de dispositivos de nivel inferior, con un subconjunto superpuesto de rutinas estándar comunes a ambos tipos de controladores.

El conjunto de rutinas para los controladores intermedios y de nivel más alto también varía según los criterios siguientes:

  • La naturaleza del dispositivo físico subyacente

  • Si un controlador de dispositivo subyacente configura objetos de dispositivo para E/S directa o almacenada en búfer

  • El diseño del controlador de nivel superior individual

En la ilustración siguiente se muestra la ruta de acceso que un IRP puede llevar a cabo a través de las rutinas estándar de un controlador de reflejo intermedio en algún lugar sobre el controlador de dispositivo de nivel inferior descrito en la sección anterior.

El controlador que se muestra en la ilustración siguiente tiene las siguientes características:

  • El controlador se superpone a más de un dispositivo físico y, posiblemente, a más de un controlador de dispositivo.

  • A veces, el controlador asigna IRP adicionales para los controladores de nivel inferior, en función de la operación solicitada en el IRP de entrada.

  • El controlador tiene al menos un controlador del sistema de archivos superado por encima de él y ese controlador del sistema de archivos podría estar superpuesta a otros controladores intermedios en un nivel superior al de este.

diagrama que ilustra una ruta de acceso irp a través de rutinas de controlador intermedias.

Como se muestra en la ilustración, el administrador de E/S crea un IRP y lo envía a la rutina de distribución del controlador para el código de función principal especificado. Suponiendo que el código de la función es IRP_MJ_WRITE, la rutina de distribución es DDDispatchWrite. La ubicación de pila de E/S del controlador intermedio se muestra en el medio, con un número indefinido de ubicaciones de pila de E/S para controladores de nivel superior e inferior que se muestran sombreados.

Asignación de IRP

El propósito del controlador reflejado es enviar solicitudes de escritura a varios dispositivos físicos y enviar solicitudes de lectura alternativamente a los controladores de estos dispositivos. En el caso de las solicitudes de escritura, el controlador crea IRP duplicados para cada dispositivo en el que se van a escribir los datos, suponiendo que los parámetros del IRP de entrada son válidos.

En la ilustración anterior se muestra una llamada a IoAllocateIrp , pero los controladores de nivel superior pueden llamar a otras rutinas de soporte técnico para asignar IRP para controladores de nivel inferior. Consulte Creación de IRP para controladores de Lower-Level.

Cuando la rutina de distribución llama a IoAllocateIrp, especifica el número de ubicaciones de pila de E/S necesarias para irP. El controlador debe especificar una ubicación de pila para cada controlador inferior de la cadena, obteniendo el valor adecuado de los objetos de dispositivo de cada controlador justo debajo del controlador reflejado. Opcionalmente, el controlador puede agregar uno a este valor cuando llama a IoAllocateIrp para obtener una ubicación de pila propia para cada IRP que asigna, como lo hace el controlador de la ilustración anterior.

La rutina de distribución de este controlador intermedio llama a IoGetCurrentIrpStackLocation (no se muestra) con el IRP original para comprobar los parámetros.

Llama a IoSetNextIrpStackLocation porque asignó su propia ubicación de pila en cada IRP y IoGetCurrentIrpStackLocation recién creado para crear un contexto para sí mismo que usa más adelante en la rutina IoCompletion .

A continuación, llama a IoGetNextIrpStackLocation con cada IRP recién creado para que pueda configurar las siguientes ubicaciones de pila de E/S de los controladores de nivel inferior en los IRP que asignó. La rutina de distribución del controlador reflejado copia los códigos y parámetros de la función IRP (puntero al búfer de transferencia, longitud en bytes que se van a transferir para IRP_MJ_WRITE) en las ubicaciones de pila de E/S para los controladores inferiores siguientes. Estos controladores, a su vez, configurarán las ubicaciones de pila de E/S para los controladores justo debajo de ellos, si los hay.

Llamada a IoSetCompletionRoutine e IoCallDriver

La rutina de distribución de la ilustración anterior llama a IoSetCompletionRoutine para cada IRP que asignó. Dado que el controlador de la ilustración anterior debe eliminar los IRP que asignó, este controlador establece su rutina de IoCompletion que se llamará cuando los controladores inferiores completen sus IRP, si la operación de E/S se completó correctamente, produjo un error o se canceló.

Dado que el controlador de la ilustración anterior refleja en paralelo, pasa ambos IRP asignados a los controladores de nivel inferior siguiente llamando a IoCallDriver dos veces, una para cada objeto de dispositivo de destino que representa una partición reflejada.

Procesamiento de IRP en la rutina IoCompletion del controlador

Cuando cualquiera de los conjuntos de controladores de nivel inferior completa la operación solicitada, el administrador de E/S llama a la rutina IoCompletion del controlador reflejado intermedio. El controlador reflejado mantiene un recuento en su propia ubicación de pila de E/S para el IRP original, para realizar un seguimiento de cuándo los controladores inferiores han completado todos los IRP duplicados.

Suponiendo que el bloque de estado de E/S indica que un conjunto de controladores inferiores ha completado el IRP duplicado que se muestra en la ilustración anterior, la rutina ioCompletion del controlador reflejado disminuye su recuento, pero no puede completar el IRP original hasta que disminuye el recuento en cero. Si el recuento reducido aún no es cero, la rutina IoCompletion llama a IoFreeIrp con el IRP (DupIRP1 devuelto por primera vez en la figura anterior) que el controlador asignó y devuelve STATUS_MORE_PROCESSING_REQUIRED.

Cuando se vuelve a llamar a la rutina ioCompletion del controlador reflejado con el DupIRP2 que se muestra en la ilustración anterior, la rutina IoCompletion disminuye el recuento en el IRP original y determina que ambos conjuntos de controladores de nivel inferior han llevado a cabo las operaciones solicitadas.

Suponiendo que el bloque de estado de E/S de DupIRP2 también se establece con STATUS_SUCCESS, la rutina IoCompletion copia el bloque de estado de E/S de DupIRP2 en el IRP original y libera DupIRP2. Llama a IoCompleteRequest con el IRP original y devuelve STATUS_MORE_PROCESSING_REQUIRED. Devolver este estado impide que el administrador de E/S intente realizar cualquier procesamiento de finalización adicional en DupIRP2; dado que el IRP no está asociado a un subproceso, su procesamiento de finalización debe terminar con el controlador que lo creó.

Si alguno de los conjuntos de controladores de nivel inferior no completa correctamente los IRP del controlador reflejado, la rutina ioCompletion del controlador reflejado debe registrar un error e intentar la recuperación de datos reflejada adecuada. Para obtener más información, vea Errores de registro.