Solicitar e conceder oplocks
Quando o redirecionador de rede acessa os arquivos em servidores remotos, ele solicita o oplock do servidor remoto. Os aplicativos cliente solicitam diretamente os oplocks somente quando o bloqueio é destinado a um arquivo no servidor local.
Oplocks são solicitados por meio de FSCTLs. Os FSCTLs a seguir são usados para os diferentes tipos de oplock, que tanto aplicativos em modo de usuário quanto drivers em modo kernel podem emitir.
- Para solicitar oplocks do Windows 7:
- Para solicitar oplocks herdados:
Solicitando um oplock no modo de usuário
Para solicitar um oplock do Windows 7 no modo de usuário, chame DeviceIoControl:
- Defina dwIoControlCode como FSCTL_REQUEST_OPLOCK.
- Passe um ponteiro para uma estrutura REQUEST_OPLOCK_INPUT_BUFFER no parâmetro lpInBuffer.
- Consulte a documentação dessa estrutura para obter informações sobre como formatar a solicitação do oplock.
- Passe um ponteiro para uma estrutura REQUEST_OPLOCK_OUTPUT_BUFFER no parâmetro lpOutBuffer.
Para obter mais informações, consulte FSCTL_REQUEST_OPLOCK.
Se o oplock solicitado puder ser concedido, DeviceIoControl retornará FALSE e GetLastError retornará ERROR_IO_PENDING. Por esse motivo, os oplocks nunca são concedidos para E/S síncrona. A operação sobreposta não é concluída até que o oplock seja interrompido. Após a conclusão da operação, REQUEST_OPLOCK_OUTPUT_BUFFER conterá informações sobre a interrupção do oplock.
Se o oplock não puder ser concedido, o sistema de arquivos retornará um código de erro apropriado. Os códigos de erro mais retornados são ERROR_OPLOCK_NOT_GRANTED e ERROR_INVALID_PARAMETER.
Solicitando um oplock no modo kernel
Para solicitar oplocks do Windows 7 no modo kernel:
Minifiltros do sistema de arquivos
Um minifiltro do sistema de arquivos deve usar FltAllocateCallbackData e preencher o FLT_CALLBACK_DATA alocado da seguinte maneira:
- Defina o campo Iopb->MajorFunction como IRP_MJ_FILE_SYSETM_CONTROL.
- Defina o campo Iopb->MinorFunction como IRP_MN_USER_FS_REQUEST.
- Defina o membro Iopb->Parameters.FileSystemControl.Buffered.FsControlCode como FSCTL_REQUEST_OPLOCK.
- Alocar um buffer cujo tamanho seja igual ao maior REQUEST_OPLOCK_INPUT_BUFFER ou REQUEST_OPLOCK_OUTPUT_BUFFER.
- Defina o membro alocado FLT_CALLBACK_DATA's Iopb->Parameters.FileSystemControl.Buffered.SystemBuffer para apontar para esse buffer.
- Defina os campos alocados FLT_CALLBACK_DATA's Iopb->Parameters.FileSystemControl.Buffered.InputBufferLength e Iopb->Parameters.FileSystemControl.Buffered.OutputBufferLength para o tamanho desse buffer.
Consulte a documentação da estrutura REQUEST_OPLOCK_INPUT_BUFFER para obter informações sobre como formatar a solicitação do oplock.
Em seguida, o minifiltro do sistema de arquivos deve chamar FltPerformAsynchronousIo, passando o FLT_CALLBACK_DATA alocado como o parâmetro CallbackData.
Se o oplock solicitado puder ser concedido, a chamada FltPerformAsynchronousIo retornará STATUS_PENDING. Por esse motivo, os oplocks nunca são concedidos para E/S síncrona. A operação não será concluída até a interrupção do oplock. Após a conclusão da operação, REQUEST_OPLOCK_OUTPUT_BUFFER conterá informações sobre a interrupção do oplock.
Se o oplock não puder ser concedido, o sistema de arquivos retornará um código de erro apropriado. Os códigos de erro mais retornados são STATUS_OPLOCK_NOT_GRANTED e STATUS_INVALID_PARAMETER.
Outros tipos de drivers
Outros tipos de drivers podem chamar ZwFsControlFile:
- Defina FsControlCode como FSCTL_REQUEST_OPLOCK.
- Passe um ponteiro para uma estrutura REQUEST_OPLOCK_INPUT_BUFFER no parâmetro InputBuffer e defina o parâmetro InputBufferLength com o tamanho desse buffer.
- Passe um ponteiro para uma estrutura REQUEST_OPLOCK_OUTPUT_BUFFER no parâmetro OutputBuffer e defina o parâmetro OutputBufferLength para o tamanho desse buffer.
Consulte a documentação da estrutura REQUEST_OPLOCK_INPUT_BUFFER para obter informações sobre como formatar a solicitação do oplock.
Se o oplock solicitado puder ser concedido, a chamada ZwFsControlFile retornará STATUS_PENDING. Por esse motivo, os oplocks nunca são concedidos para E/S síncrona. A operação não será concluída até a interrupção do oplock. Após a conclusão da operação, REQUEST_OPLOCK_OUTPUT_BUFFER conterá informações sobre a interrupção do oplock.
Se o oplock não puder ser concedido, o sistema de arquivos retornará um código de erro apropriado. Os códigos de erro mais retornados são STATUS_OPLOCK_NOT_GRANTED e STATUS_INVALID_PARAMETER.
Evitando violações de compartilhamento ao solicitar oplocks
Usando o método atomic create-with-oplock
Atomic create-with-oplock não é um tipo de oplock. Em vez disso, é um procedimento que permite que as operações abertas evitem causar violações de modo de compartilhamento no intervalo de tempo entre abrir um arquivo e receber um oplock. Com os oplocks herdados, é necessário filtrar os oplocks e abrir dois identificadores. Com os oplocks do Windows 7, um aplicativo ou driver pode solicitar qualquer tipo de oplock usando esse procedimento e precisa abrir apenas um identificador.
Para executar o procedimento atomic create-with-oplock, você deve:
- Use FltCreateFileEx2 ou ZwCreateFile, conforme apropriado, para abrir o arquivo. No parâmetro CreateOptions, passe o sinalizador FILE_OPEN_REQUIRING_OPLOCK. Você pode definir conforme desejado os parâmetros DesiredAccess e ShareAccess. Por exemplo, no parâmetro DesiredAccess, defina GENERIC_READ para que você possa ler o arquivo, e no parâmetro ShareAccess, defina os sinalizadores FILE_SHARE_READ | FILE_SHARE_DELETE para permitir que outras pessoas leiam, renomeiem e/ou marquem o arquivo para exclusão enquanto você o tiver aberto.
- Use o código de controle FSCTL_REQUEST_OPLOCK para solicitar um oplock no objeto ou identificador de arquivo resultante, conforme descrito em Solicitando um Oplock no Modo Kernel.
Não execute nenhuma operação do sistema de arquivos no arquivo entre as etapas 1 e 2. Fazer isso pode causar deadlocks.
O oplock mais comum que pode ser solicitado usando-se esse procedimento é o tipo Leitura-Identificador. Isso permite conceder a outros chamadores o máximo de acesso simultâneo possível e ainda permite que você seja notificado se precisar fechar o identificador para evitar uma violação de compartilhamento em uma abertura conflitante.
Usando o oplock Filtro herdado
O oplock Filtro herdado também permite que um aplicativo "volte atrás" quando outros aplicativos/clientes tentam acessar o mesmo fluxo, mas é menos flexível do que o método atomic create-with-oplock. Esse mecanismo permite que um aplicativo acesse um fluxo sem que os outros acessadores do fluxo recebam violações de compartilhamento quando tentarem abrir o fluxo. Para evitar violações de compartilhamento, execute o seguinte procedimento de três etapas para solicitar um oplock Filtro:
Abra o arquivo com o acesso necessário de FILE_READ_ATTRIBUTES e um modo de compartilhamento de FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE. O identificador aberto nessa etapa não causará violações de compartilhamento em outros aplicativos porque está aberto apenas para acesso de atributo (FILE_READ_ATTRIBUTES) e não para acesso de dados (FILE_READ_DATA). Esse identificador é apropriado para solicitar o oplock Filtro, mas não para executar a E/S propriamente dita no fluxo de dados.
Solicite um oplock Filtro (FSCTL_REQUEST_FILTER_OPLOCK) no identificador obtido na etapa 1. O oplock concedido nessa etapa permite que o titular do oplock "saia do caminho" sem causar uma violação de compartilhamento para outro aplicativo que tenta acessar o fluxo.
Abra o arquivo novamente com o acesso de leitura. O identificador aberto nessa etapa permite que o titular do oplock execute E/S no fluxo.
O sistema de arquivos NTFS fornece uma otimização para esse procedimento por meio do sinalizador FILE_RESERVE_OPFILTER da opção de criação. Se esse sinalizador for especificado na etapa 1 do procedimento anterior, permitirá que o sistema de arquivos falhe na solicitação de criação com STATUS_OPLOCK_NOT_GRANTED se puder determinar que a etapa 2 falhará. Se a etapa 1 for bem-sucedida, isso não significa que a etapa 2 terá êxito, mesmo que haja a especificação de FILE_RESERVE_OPFILTER para a solicitação de criação.
Condições para conceder oplocks
A tabela a seguir identifica as condições necessárias para conceder um oplock.
Tipo de solicitação | Condições |
---|---|
Nível 1 Filtro Lote |
Concessão feita somente se todas as seguintes condições forem verdadeiras:
Se o estado do oplock atual é:
|
Nível 2 |
Concessão feita somente se todas as seguintes condições forem verdadeiras:
Se o estado do oplock atual é:
|
Ler |
Concessão feita somente se todas as seguintes condições forem verdadeiras:
Se o estado do oplock atual é:
|
Leitura-Identificador |
Concessão feita somente se todas as seguintes condições forem verdadeiras:
Se o estado do oplock atual é:
|
Leitura/Gravação |
Concessão feita somente se todas as seguintes condições forem verdadeiras:
Se o estado do oplock atual é:
|
Leitura-Gravação-Identificador |
Concessão feita somente se todas as seguintes condições forem verdadeiras:
Se o estado do oplock atual é:
|
Observação
Os oplocks Leitura e Nível 2 podem coexistir no mesmo fluxo, e os oplocks Leitura e Leitura-Identificador podem coexistir, mas os oplocks Nível 2 e Leitura-Identificador não podem coexistir.