Condividi tramite


Uso di MDLs

Un buffer di I/O che si estende su un intervallo di indirizzi di memoria virtuale contigui può essere distribuito in più pagine fisiche e queste pagine possono essere discontigue. Il sistema operativo usa un elenco descrittore di memoria (MDL) per descrivere il layout di pagina fisico per un buffer di memoria virtuale.

Un MDL è costituito da una strutturaMDLseguita da una matrice di dati che descrive la memoria fisica in cui risiede il buffer di I/O. Le dimensioni di un file MDL variano in base alle caratteristiche del buffer di I/O descritto dal file MDL. Le routine di sistema sono disponibili per calcolare le dimensioni necessarie di un MDL e per allocare e liberare il file MDL.

Una struttura MDL è semi-opaca. Il driver deve accedere direttamente solo ai membri Next e MdlFlags di questa struttura. Per un esempio di codice che usa questi due membri, vedere la sezione Esempio seguente.

I membri rimanenti di un MDL sono opachi. Non accedere direttamente ai membri opachi di un file MDL. Utilizzare invece le macro seguenti, che il sistema operativo fornisce per eseguire operazioni di base sulla struttura:

MmGetMdlVirtualAddress restituisce l'indirizzo di memoria virtuale del buffer di I/O descritto da MDL.

MmGetMdlByteCount restituisce le dimensioni, in byte, del buffer di I/O.

MmGetMdlByteOffset restituisce l'offset all'interno di una pagina fisica dell'inizio del buffer di I/O.

È possibile allocare un MDL con la routineIoAllocateMdl. Per liberare il file MDL, usare la routine diIoFreeMdl. In alternativa, è possibile allocare un blocco di memoria non di paging e quindi formattare questo blocco di memoria come MDL chiamando la routine MmInitializeMdl.

IoAllocateMdl né MmInitializeMdl inizializza la matrice di dati che segue immediatamente la struttura MDL. Per un MDL che risiede in un blocco allocato dal driver di memoria non paginata, usare MmBuildMdlForNonPagedPool per inizializzare questo array per descrivere la memoria fisica in cui risiede il buffer di I/O.

Per la memoria paginabile, la corrispondenza tra memoria virtuale e fisica è temporanea, quindi l'array di dati che segue la struttura Descrittore di Lista di Memoria (MDL) è valido solo in determinate circostanze. Chiamare MmProbeAndLockPages per bloccare la memoria paginabile in posizione e inizializzare questo array di dati per il layout corrente. La memoria non verrà esaurita finché il chiamante non utilizza la routine MmUnlockPages, a quel punto il contenuto della matrice di dati non è più valido.

La routine MmGetSystemAddressForMdlSafe esegue il mapping delle pagine fisiche descritte dal file MDL specificato a un indirizzo virtuale nello spazio degli indirizzi di sistema, se non sono già mappate allo spazio indirizzi di sistema. Questo indirizzo virtuale è utile per i driver che potrebbero dover esaminare le pagine per eseguire operazioni di I/O, perché l'indirizzo virtuale originale potrebbe essere un indirizzo utente che può essere usato solo nel contesto originale e può essere eliminato in qualsiasi momento.

Si noti che quando si compila un MDL parziale usando la routineIoBuildPartialMdl che MmGetMdlVirtualAddress restituisce l'indirizzo iniziale originale per il file MDL parziale. Questo indirizzo è un indirizzo in modalità utente se il file MDL è stato originariamente creato in seguito a una richiesta in modalità utente. Di conseguenza, l'indirizzo non ha rilevanza al di fuori del contesto del processo in cui ha avuto origine la richiesta.

In genere, un driver crea invece un indirizzo di sistema in modalità chiamando la macro MmGetSystemAddressForMdlSafe per eseguire il mapping del file MDL parziale. In questo modo il driver può continuare ad accedere alle pagine in modo sicuro indipendentemente dal contesto del processo.

Quando un driver chiama IoAllocateMdl, può associare un IRP al file MDL appena allocato specificando un puntatore all'IRP come parametro Irp di IoAllocateMdl. Un IRP può avere uno o più MDL associati. Se l'IRP ha un singolo MDL associato, il membro MdlAddress dell'IRP punta a tale MDL. Se a questo IRP sono associati più MDL, MdlAddress punta al primo MDL in un elenco collegato di MDL associati all'IRP, noto come catena di MDL . Gli MDLs sono collegati dai loro membri successivi. Il membro Successivo dell'ultimo MDL nella catena è impostato su NULL.

Se, quando il driver chiama IoAllocateMdl, specifica FALSE per il parametro SecondaryBuffer, il membro MdlAddress dell'IRP viene impostato per puntare al nuovo MDL. Se SecondaryBuffer è TRUE, la routine inserisce il nuovo MDL alla fine della catena MDL.

Al termine dell'IRP, il sistema sblocca e libera tutti gli MDL associati all'IRP. Il sistema sblocca gli MDLs prima di accodare la routine di completamento I/O e li libera dopo l'esecuzione della stessa.

I driver possono attraversare la catena MDL usando il membro successivo di ogni MDL per accedere al MDL successivo nella catena. I driver possono inserire manualmente MDLs nella catena aggiornando i membri Next.

Le catene MDL vengono in genere usate per gestire una matrice di buffer associati a una singola richiesta di I/O. Ad esempio, un driver di rete potrebbe usare un buffer per ogni pacchetto IP in un'operazione di rete. Ogni buffer nella matrice ha un proprio file MDL nella catena. Quando il driver completa la richiesta, combina i buffer in un singolo buffer di grandi dimensioni. Il sistema esegue quindi automaticamente la pulizia di tutti gli mdls allocati per la richiesta.

Il manager di I/O è una fonte frequente di richieste di I/O. Quando il gestore di I/O completa una richiesta di I/O, il gestore di I/O libera l'IRP e libera qualsiasi MDL collegato all'IRP. Alcuni di questi MDLs potrebbero essere stati collegati all'IRP dai driver che si trovano al di sotto del gestore dell'I/O nella gerarchia dei dispositivi. Analogamente, se il driver è l'origine di una richiesta di I/O, al termine della richiesta di I/O, il driver deve pulire l'IRP e tutti gli MDL collegati all'IRP.

Esempio

L'esempio di codice seguente è una funzione implementata dal driver che libera una catena MDL da un IRP:

VOID MyFreeMdl(PMDL Mdl)
{
    PMDL currentMdl, nextMdl;

    for (currentMdl = Mdl; currentMdl != NULL; currentMdl = nextMdl) 
    {
        nextMdl = currentMdl->Next;
        if (currentMdl->MdlFlags & MDL_PAGES_LOCKED) 
        {
            MmUnlockPages(currentMdl);
        }
        IoFreeMdl(currentMdl);
    }
} 

Se le pagine fisiche descritte da un MDL nella catena sono bloccate, la funzione di esempio chiama la routineMmUnlockPages per sbloccare le pagine prima di chiamare IoFreeMdl per liberare il file MDL. Tuttavia, la funzione di esempio non deve smappare esplicitamente le pagine prima di chiamare IoFreeMdl. Al contrario, IoFreeMdl annulla automaticamente il mapping delle pagine quando libera il file MDL.