Compartilhar via


Interrompendo oplocks

Depois que um oplock é solicitado e concedido, o proprietário dele tem acesso ao fluxo com base no tipo de oplock solicitado. Se a operação recebida não for compatível com o oplock atual, o sistema o interromperá.

Quando um oplock é concedido, o sistema aguarda o IRP solicitante. Quando um oplock é interrompido, o IRP da solicitação do oplock pendente é concluído com STATUS_SUCCESS. Para oplocks de Nível 1, Lote e Filtro, o membro IoStatus.Information do IRP é configurado para indicar o nível de interrupção do oplock. Esses níveis são:

  • FILE_OPLOCK_BROKEN_TO_NONE: o oplock foi interrompido e não há nenhum oplock atual no fluxo. O oplock é considerado "interrompido para Nenhum".

  • FILE_OPLOCK_BROKEN_TO_LEVEL_2: o oplock atual (Nível 1 ou Lote) foi convertido em um oplock de Nível 2. Oplocks Filtro nunca são interrompidos para Nível 2; eles sempre são interrompidos para Nenhum.

Para oplocks Leitura-Identificador, Leitura-Gravação e Leitura-Gravação-Identificador, o nível para o qual o oplock está sendo interrompido é descrito como uma combinação de zero ou mais sinalizadores OPLOCK_LEVEL_CACHE_READ, OPLOCK_LEVEL_CACHE_HANDLE ou OPLOCK_LEVEL_CACHE_WRITE no membro NewOplockLevel da estrutura REQUEST_OPLOCK_OUTPUT_BUFFER passada como o parâmetro lpOutBuffer de DeviceIoControl. De maneira semelhante, FltFsControlFile e ZwFsControlFile podem ser usados para solicitar oplocks do Windows 7 no modo kernel. Para obter mais informações, consulte FSCTL_REQUEST_OPLOCK.

Quando o pacote de oplock do sistema interrompe um oplock Nível 1, Lote, Filtro, Leitura-Gravação, Leitura-Gravação-Identificador ou, em determinadas circunstâncias, um oplock Leitura-Identificador:

  • O pacote de oplock conclui o IRP da solicitação de oplock pendente.
  • A operação que causou a interrupção do oplock está pendente.

O gerenciador de E/S faz com que a operação seja bloqueada, em vez de retornar STATUS_PENDING, se a operação:

  • É emitido em um identificador síncrono.
  • É um IRP_MJ_CREATE, que é sempre síncrono.

O gerenciador de E/S aguarda uma confirmação do proprietário do oplock para informar ao pacote de oplock que o processamento foi concluído e que é seguro dar andamento à operação pendente. Esse atraso permite que o proprietário do oplock recoloque o fluxo em um estado consistente antes de prosseguir com a operação atual. O sistema esperaria para sempre para receber a confirmação, pois não há tempo limite. Portanto, cabe ao proprietário do oplock confirmar a interrupção em tempo hábil. O IRP da operação pendente é definido para um estado cancelável. Se a aplicação ou o driver que executa a espera for encerrado, o pacote de oplock concluirá imediatamente o IRP com STATUS_CANCELLED.

Um IRP_MJ_CREATE IRP pode especificar a opção de criação FILE_COMPLETE_IF_OPLOCKED para evitar ser bloqueado como parte da confirmação de interrupção do oplock. Essa opção instrui o pacote de oplock a não bloquear a criação do IRP até o recebimento da confirmação de interrupção do oplock. Em vez disso, a criação tem permissão para continuar. Se uma criação bem-sucedida resultar em uma interrupção do oplock, o código de retorno será STATUS_OPLOCK_BREAK_IN_PROGRESS em vez de STATUS_SUCCESS. O flag FILE_COMPLETE_IF_OPLOCKED normalmente é usado para evitar deadlocks. Por exemplo, se um cliente tiver um oplock em um fluxo e, mais tarde, o mesmo cliente abrir o mesmo fluxo, ele bloqueará a espera para confirmar a interrupção do oplock. Nesse cenário, o uso do sinalizador FILE_COMPLETE_IF_OPLOCKED evita o deadlock.

O sistema de arquivos NTFS inicia interrupções de oplock para oplocks Lote e Filtro antes de verificar se há violações de compartilhamento. Portanto, é possível que uma criação que especificou FILE_COMPLETE_IF_OPLOCKED falhe com STATUS_SHARING_VIOLATION, mas ainda assim interrompa um oplock Lote ou Filtro. Nesse caso, o membro com informações da estrutura IO_STATUS_BLOCK é definido como FILE_OPBATCH_BREAK_UNDERWAY para permitir que o chamador detecte esse caso.

Para oplocks Leitura-Identificador e Leitura-Gravação-Identificador, a interrupção do oplock é iniciada depois que o NTFS verifica e detecta uma violação de compartilhamento. Essa sequência dá aos titulares do oplock a oportunidade de fechar os identificadores e sair do caminho, desse modo permitindo a possibilidade de não retornar a violação de compartilhamento para o usuário. Isso também evita a interrupção incondicional do oplock nos casos em que o identificador que o oplock armazena em cache não entra em conflito com a nova criação.

Quando oplocks Nível 2, Leitura e, em determinadas circunstâncias, Leitura-Identificador são interrompidos, o sistema não aguarda uma confirmação. O motivo é que não deve haver nenhum estado armazenado em cache no fluxo que precise ser restaurado para o arquivo antes de permitir que outros clientes acessem ele.

Há certas operações do sistema de arquivos que verificam o estado do oplock atual para determinar a necessidade de interrupção. Os artigos específicos de operações listados a seguir descrevem o que dispara uma interrupção de oplock, o que determina o nível de interrupção e se uma confirmação da interrupção é necessária.

Uma interrupção de oplock do Windows 7 exige confirmação se o sinalizador REQUEST_OPLOCK_OUTPUT_FLAG_ACK_REQUIRED está configurado no membro Flags da estrutura REQUEST_OPLOCK_OUTPUT_BUFFER passada como parâmetro de saída de DeviceIoControl(lpOutBuffer), FltFsControlFile(OutBuffer) ou ZwFsControlFile(OutBuffer). Para obter mais informações, consulte FSCTL_REQUEST_OPLOCK.

Os artigos listados por operação descrevem os detalhes de quando a interrupção de um oplock Leitura-Identificador resulta na pendência da operação que interrompeu o oplock. Por exemplo, o artigo IRP_MJ_CREATE contém os detalhes associados de Leitura-Identificador.