Richiesta e concessione di oplock
Quando il redirector di rete accede ai file nei server remoti, richiede l'oplock dal server remoto. Le applicazioni client richiedono direttamente oplock solo quando il blocco è destinato a un file nel server locale.
i oplock vengono richiesti tramite . I seguenti FSCTL sono utilizzati per i diversi tipi di oplock e, che possono essere emessi sia dalle applicazioni in modalità utente sia dai driver in modalità kernel.
- Per richiedere gli oplock di Windows 7:
- Per richiedere gli oplock legacy:
Richiesta di un oplock in modalità utente
Per richiedere un oplock di Windows 7 in modalità utente, chiamare DeviceIoControl:
- Impostare dwIoControlCode su FSCTL_REQUEST_OPLOCK.
- Passare un puntatore a una struttura REQUEST_OPLOCK_INPUT_BUFFER nel parametro lpInBuffer.
- Per informazioni su come formattare la richiesta di oplock, vedere la documentazione di tale struttura.
- Passa un puntatore a una struttura REQUEST_OPLOCK_OUTPUT_BUFFER nel parametro lpOutBuffer .
Per altre informazioni, vedere FSCTL_REQUEST_OPLOCK.
Se è possibile concedere l'oplock richiesto, DeviceIoControl restituisce FALSE e GetLastError restituisce ERROR_IO_PENDING. Per questo motivo, gli oplock non vengono mai concessi per le operazioni di I/O sincrone. L'operazione sovrapposta non viene completata fino a quando l'oplock non si interrompe. Al termine dell'operazione, il REQUEST_OPLOCK_OUTPUT_BUFFER conterrà informazioni sull'interruzione oplock.
Se non è possibile concedere l'oplock, il file system restituisce un codice di errore appropriato. I codici di errore restituiti più comunemente sono ERROR_OPLOCK_NOT_GRANTED e ERROR_INVALID_PARAMETER.
Richiesta di un oplock in modalità kernel
Per richiedere oplock di Windows 7 in modalità kernel:
Minifiltri del file system
Un minifiltro del file system deve usare FltAllocateCallbackData e compilare il FLT_CALLBACK_DATA allocato in questo modo:
- Imposta il campo MajorFunction di>-su IRP_MJ_FILE_SYSTEM_CONTROL.
- Imposta il campo Iopb->MinorFunction su IRP_MN_USER_FS_REQUEST.
- Impostare il membro dei parametri Iopb->.FileSystemControl.Buffered.FsControlCode su FSCTL_REQUEST_OPLOCK.
- Allocare un buffer le cui dimensioni sono uguali a quelle di REQUEST_OPLOCK_INPUT_BUFFER o di REQUEST_OPLOCK_OUTPUT_BUFFER.
- Impostare il membro > in modo che punti al buffer allocato FLT_CALLBACK_DATA.
- Impostare i campi del FLT_CALLBACK_DATAIopb->Parameters.FileSystemControl.Buffered.InputBufferLength e Iopb->Parameters.FileSystemControl.Buffered.OutputBufferLength alle dimensioni del buffer.
Per informazioni su come formattare la richiesta di oplock, vedere la documentazione della struttura REQUEST_OPLOCK_INPUT_BUFFER.
Il minifiltro del file system deve quindi chiamare FltPerformAsynchronousIo, passando il FLT_CALLBACK_DATA allocato come parametro CallbackData.
Se è possibile concedere l'oplock richiesto, la chiamata FltPerformAsynchronousIo restituisce STATUS_PENDING. Per questo motivo, gli oplock non vengono mai concessi per le operazioni di I/O sincrone. L'operazione non viene completata finché l'oplock non viene revocato. Al termine dell'operazione, il REQUEST_OPLOCK_OUTPUT_BUFFER conterrà informazioni sull'interruzione oplock.
Se non è possibile concedere l'oplock, il file system restituisce un codice di errore appropriato. I codici di errore restituiti più comunemente sono STATUS_OPLOCK_NOT_GRANTED e STATUS_INVALID_PARAMETER.
Altri tipi di driver
Altri tipi di driver possono chiamare ZwFsControlFile:
- Impostare FsControlCode su FSCTL_REQUEST_OPLOCK.
- Passare un puntatore a una struttura REQUEST_OPLOCK_INPUT_BUFFER nel parametro InputBuffer e impostare il parametro InputBufferLength sulla dimensione di quel buffer.
- Passare un puntatore a una struttura REQUEST_OPLOCK_OUTPUT_BUFFER nel parametro OutputBuffer e impostare il parametro OutputBufferLength sulle dimensioni del buffer.
Per informazioni su come formattare la richiesta di oplock, vedere la documentazione della struttura REQUEST_OPLOCK_INPUT_BUFFER.
Se l'oplock richiesto può essere concesso, la chiamata ZwFsControlFile restituisce STATUS_PENDING. Per questo motivo, gli oplock non vengono mai concessi per le operazioni di I/O sincrone. L'operazione non viene completata finché l'oplock non viene revocato. Al termine dell'operazione, il REQUEST_OPLOCK_OUTPUT_BUFFER conterrà informazioni sull'interruzione oplock.
Se non è possibile concedere l'oplock, il file system restituisce un codice di errore appropriato. I codici di errore restituiti più comunemente sono STATUS_OPLOCK_NOT_GRANTED e STATUS_INVALID_PARAMETER.
Evitare violazioni di condivisione durante la richiesta di Oplock
Uso del metodo Atomic Create-With-Oplock
La creazione atomica con oplock non è un tipo di oplock. Si tratta invece di una procedura che consente alle operazioni aperte di evitare di causare violazioni della modalità di condivisione nell'intervallo di tempo tra l'apertura di un file e la ricezione di un oplock. Con gli oplock legacy, è necessario filtrare gli oplock e aprire due handle. Con gli oplock di Windows 7, un'applicazione o un driver può richiedere qualsiasi tipo di oplock usando questa procedura ed è necessario aprire un solo handle.
Per eseguire la procedura atomica di creazione con oplock, è necessario:
- Usare FltCreateFileEx2 o ZwCreateFile, in base alle esigenze, per aprire il file. Nel parametro CreateOptions, passare il flag FILE_OPEN_REQUIRING_OPLOCK. È possibile impostare i parametri DesiredAccess e ShareAccess in base alle esigenze. Ad esempio, nel set di parametri DesiredAccessGENERIC_READ in modo da poter leggere il file e nel parametro ShareAccess impostare il FILE_SHARE_READ | FILE_SHARE_DELETE flag per consentire ad altri utenti di leggere, rinominare e/o contrassegnare il file per l'eliminazione mentre è aperto.
- Usare il codice di controllo FSCTL_REQUEST_OPLOCK per richiedere un oplock sull'oggetto file o sull'handle risultante, come descritto in Richiesta di oplock in modalità kernel.
Non eseguire alcuna operazione di file system sul file tra i passaggi 1 e 2. In questo modo possono verificarsi deadlock.
L'oplock più comune da richiedere tramite questa procedura è il tipo di Read-Handle. In questo modo è possibile consentire ad altri chiamanti il massimo accesso simultaneo possibile, ricevendo comunque una notifica se è necessario chiudere l'handle per evitare di causare una violazione di condivisione con un'apertura in conflitto.
Utilizzo dell'oplock del filtro legacy
L'oplock filtro legacy consente anche a un'applicazione di fare un passo indietro quando altre applicazioni/clienti tentano di accedere allo stesso flusso, ma è meno flessibile rispetto al metodo "atomic create-with-oplock". Questo meccanismo consente a un'applicazione di accedere a un flusso senza causare la ricezione di violazioni di condivisione da parte di altre funzioni di accesso del flusso durante il tentativo di aprire il flusso. Per evitare violazioni di condivisione, è necessario utilizzare la seguente procedura in tre passaggi per richiedere un Filter oplock:
Aprire il file con l'accesso necessario di FILE_READ_ATTRIBUTES e una modalità di condivisione di FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE. L'handle aperto in questo passaggio non causerà la ricezione di violazioni di condivisione da parte di altre applicazioni perché è aperta solo per l'accesso agli attributi (FILE_READ_ATTRIBUTES) e non per l'accesso ai dati (FILE_READ_DATA). Questo handle è adatto per richiedere il filtro oplock, ma non per eseguire operazioni di I/O effettive sul flusso di dati.
Richiedere un oplock di filtro (FSCTL_REQUEST_FILTER_OPLOCK) nell'handle del passaggio 1. L'oplock concesso in questo passaggio consente al titolare di oplock di "farsi da parte" senza causare una violazione di condivisione a un'altra applicazione che tenta di accedere al flusso di dati.
Aprire di nuovo il file per l'accesso in lettura. L'handle aperto in questo passaggio consente al titolare dell'oplock di effettuare operazioni di I/O nel flusso.
Il file system NTFS fornisce un'ottimizzazione per questa procedura tramite il flag di creazione dell'opzione FILE_RESERVE_OPFILTER. Se questo flag viene specificato nel passaggio 1 della procedura precedente, consente al file system di far fallire la richiesta di creazione con STATUS_OPLOCK_NOT_GRANTED se il file system può determinare che il passaggio 2 non andrà a buon fine. Se il passaggio 1 ha esito positivo, non è garantito che il passaggio 2 abbia esito positivo, anche se FILE_RESERVE_OPFILTER è stato specificato per la richiesta di creazione.
Condizioni per la concessione di oplocks
Nella tabella seguente vengono identificate le condizioni necessarie per concedere un oplock.
Tipo di richiesta | Condizioni |
---|---|
Livello 1 Filtro Lotto |
Concesso solo se tutte le condizioni seguenti sono vere:
Se lo stato di oplock corrente è:
|
Livello 2 |
Concesso solo se tutte le condizioni seguenti sono vere:
Se lo stato di oplock corrente è:
|
Leggere |
Concesso solo se tutte le condizioni seguenti sono vere:
Se lo stato di oplock corrente è:
|
Read-Handle |
Concesso solo se tutte le condizioni seguenti sono vere:
Se lo stato di oplock corrente è:
|
Read-Write |
Concesso solo se tutte le condizioni seguenti sono vere:
Se lo stato di oplock corrente è:
|
Lettura -Write-Handle |
Concesso solo se sono soddisfatte tutte le condizioni seguenti:
Se lo stato di oplock corrente è:
|
Nota
Gli oplock di lettura e di livello 2 possono coesistere nello stesso flusso e gli oplock di lettura e Read-Handle possono coesistere, ma gli oplock di livello 2 e Read-Handle non possono coesistere.