Condividi tramite


Creazione di pacchetti di richiesta I/O per driver Lower-Level

Per allocare un IRP per una richiesta asincrona, che verrà elaborata in un contesto di thread arbitrario da driver inferiori, una routine DispatchReadWrite può chiamare una delle routine di supporto seguenti:

  • IoAllocateIrp, che alloca un IRP e un certo numero di posizioni dello stack di I/O inizializzate a zero

    La routine di dispatch deve configurare la posizione dello stack di I/O del driver immediatamente inferiore per l'IRP appena allocato, in genere copiando le informazioni dalla propria posizione dello stack, eventualmente modificate, nell'IRP originale. Se un driver di livello superiore alloca una posizione dello stack di I/O propria per un IRP appena allocato, la routine dispatch può configurare le informazioni sul contesto per ogni richiesta per la routine IoCompletion da usare.

  • IoBuildAsynchronousFsdRequest, che configura la posizione dello stack I/O del driver inferiore successivo per il chiamante, in base ai parametri specificati dal chiamante

    I driver di livello superiore possono chiamare questa routine per allocare gli IRP per IRP_MJ_READ, IRP_MJ_WRITE, IRP_MJ_FLUSH_BUFFERS e IRP_MJ_SHUTDOWN.

    Quando viene chiamata una routine IoCompletion per questo tipo di IRP, può controllare il blocco di stato di I/O e, se necessario (o possibile) configurare la posizione dello stack I/O del driver inferiore successivo in IRP e ripetere la richiesta o riutilizzarla. Tuttavia, la routine IoCompletion non dispone di alcuna risorsa di archiviazione del contesto locale per se stessa nell'IRP, quindi il driver deve mantenere il contesto della richiesta originale altrove nella memoria residente.

  • IoMakeAssociatedIrp, che alloca un IRP e un certo numero di posizioni dello stack di I/O inizializzate a zero e associa l'IRP a un IRP master.

    I driver intermediari non possono chiamare IoMakeAssociatedIrp per creare IRPs per driver di livello inferiore.

    Qualsiasi driver di livello più alto che chiama IoMakeAssociatedIrp per creare IRP per i driver inferiori può restituire il controllo al gestore di I/O dopo aver inviato i relativi IRP associati e chiamato IoMarkIrpPending per l'IRP principale originale. Un driver di livello più alto può fare affidamento sul gestore di I/O per completare l'IRP master quando tutti gli IRP associati sono stati completati dai driver inferiori.

    I driver raramente impostano una routine di IoCompletion per un IRP associato. Se un driver di livello più alto chiama IoSetCompletionRoutine per un IRP associato che crea, l'I/O manager non completa l'IRP master se il driver restituisce STATUS_MORE_PROCESSING_REQUIRED dalla sua routine IoCompletion. In queste circostanze, la routine IoCompletion del driver deve completare in modo esplicito l'IRP master con IoCompleteRequest.

Se un driver alloca una posizione dello stack I/O propria in un nuovo IRP, la routine di dispatch deve chiamare IoSetNextIrpStackLocation prima di chiamare IoGetCurrentIrpStackLocation per impostare il contesto nella propria posizione dello stack I/O per la routine di IoCompletion. Per altre informazioni, vedere Elaborazione di runtime di integrazione in un driver Intermediate-Level.

La routine di dispatch deve chiamare IoMarkIrpPending con l'IRP originale, ma non con alcun IRP allocato dal driver, poiché la routine IoCompletion li libererà.

Se la routine di dispatch alloca IRP per i trasferimenti parziali e il driver di dispositivo sottostante potrebbe controllare un dispositivo di supporti rimovibili, la routine di dispatch deve configurare il contesto del thread nei nuovi IRP appena allocati dal valore in Tail.Overlay.Thread nell'IRP originale.

Un driver sottostante per un dispositivo multimediale rimovibile potrebbe chiamare IoSetHardErrorOrVerifyDevice, che fa riferimento al puntatore in Irp->Tail.Overlay.Thread, per un IRP allocato dal driver. Se il driver chiama questa routine di supporto, il driver del file system può inviare una finestra di dialogo al thread utente appropriato che richiede all'utente di annullare, riprovare o non riuscire a eseguire un'operazione che il driver non è riuscito a soddisfare. Per altre informazioni, vedere Supporto di supporti rimovibili .

Le routine di gestione devono restituire STATUS_PENDING dopo l'invio di tutti gli IRP allocati ai driver inferiori.

La routine IoCompletion di un driver deve rilasciare tutti gli IRP allocati dal driver con IoFreeIrp prima di chiamare IoCompleteRequest per l'IRP originale. Al termine dell'IRP originale, la routine IoCompletion deve liberare tutti gli IRP allocati dal driver prima di restituire il controllo.

Ogni driver di livello superiore imposta gli IRP (pacchetti di richiesta I/O) allocati (e riutilizzati) per i driver inferiori in modo tale che sia irrilevante per il driver di dispositivo sottostante se una determinata richiesta proviene da un driver intermedio o da qualsiasi altra origine, come ad esempio un file system o un'applicazione in modalità utente.

I driver di livello più alto possono chiamare IoMakeAssociatedIrp per allocare gli IRP e prepararli per una catena di driver inferiori. Il gestore di I/O completa automaticamente l'IRP originale quando tutti i runtime di integrazione associati sono stati completati, purché il driver non chiami IoSetCompletionRoutine con l'IRP originale o con uno dei runtime di integrazione associati allocati. I driver di livello più elevato non devono tuttavia allocare gli IRP associati per qualsiasi IRP che richiede un'operazione di I/O con buffer.

Un driver di livello intermedio non può allocare IRP per i driver di livello inferiore chiamando IoMakeAssociatedIrp. Qualsiasi IRP ricevuto da un driver intermedio potrebbe essere già un IRP associato e un driver non può associare un altro IRP a tale IRP.

Se invece un driver intermedio crea gli IRP per driver inferiori, deve chiamare IoAllocateIrp, IoBuildDeviceIoControlRequest, IoBuildSynchronousFsdRequest o IoBuildAsynchronousFsdRequest. Tuttavia, IoBuildSynchronousFsdRequest può essere chiamato solo nelle circostanze seguenti:

  • Da un thread creato dal driver per costruire IRP per le richieste di lettura o scrittura, poiché tale thread può attendere nel proprio contesto di thread non arbitrario su un oggetto dispatcher, come un Evento inizializzato dal driver passato a IoBuildSynchronousFsdRequest

  • Nel contesto del thread di sistema durante l'inizializzazione o durante lo scaricamento

  • Per costruire IRP per operazioni intrinsecamente sincrone, come creare, svuotare, arrestare, chiudere e richieste di controllo del dispositivo

Tuttavia, è più probabile che un driver chiami IoBuildDeviceIoControlRequest per allocare irP di controllo del dispositivo rispetto a IoBuildSynchronousFsdRequest.