Granting Oplocks

Oplocks are requested through FSCTLs. The following list shows the FSCTLs for the different oplock types (which user-mode applications and kernel-mode drivers can issue):

  • FSCTL_REQUEST_OPLOCK_LEVEL_1

  • FSCTL_REQUEST_OPLOCK_LEVEL_2

  • FSCTL_REQUEST_BATCH_OPLOCK

  • FSCTL_REQUEST_FILTER_OPLOCK

  • FSCTL_REQUEST_OPLOCK

The first four FSCTLs in the list are used to request legacy oplocks. The last FSCTL is used to request Windows 7 oplocks with the REQUEST_OPLOCK_INPUT_FLAG_REQUEST flag specified in the Flags member of the REQUEST_OPLOCK_INPUT_BUFFER structure, passed as the lpInBuffer parameter of DeviceIoControl. In a similar manner, ZwFsControlFile can be used to request Windows 7 oplocks from kernel mode. A file system minifilter must use FltAllocateCallbackData and FltPerformAsynchronousIo to request a Windows 7 oplock. To specify which of the four Windows 7 oplocks is required, one or more of the flags OPLOCK_LEVEL_CACHE_READ, OPLOCK_LEVEL_CACHE_HANDLE, or OPLOCK_LEVEL_CACHE_WRITE is set in the RequestedOplockLevel member of the REQUEST_OPLOCK_INPUT_BUFFER structure. For more information, see FSCTL_REQUEST_OPLOCK.

When a request is made for an oplock and the oplock can be granted, the file system returns STATUS_PENDING (because of this, oplocks are never granted for synchronous I/O). The FSCTL IRP does not complete until the oplock is broken. If the oplock cannot be granted, an appropriate error code is returned. The most commonly returned error codes are STATUS_OPLOCK_NOT_GRANTED and STATUS_INVALID_PARAMETER (and their equivalent user-mode analogs).

As mentioned previously, the Filter oplock allows an application to "back out" when other applications/clients try to access the same stream. This mechanism allows an application to access a stream without causing other accessors of the stream to receive sharing violations when attempting to open the stream. To avoid sharing violations, a special three-step procedure should be used to request a Filter oplock (FSCTL_REQUEST_FILTER_OPLOCK):

  1. Open the file with a required access of FILE_READ_ATTRIBUTES and a share mode of FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE.

  2. Request a Filter oplock on the handle from step 1.

  3. Open the file again for read access.

The handle opened in step 1 will not cause other applications to receive sharing violations, since it is open only for attribute access (FILE_READ_ATTRIBUTES), and not data access (FILE_READ_DATA). This handle is suitable for requesting the Filter oplock, but not for performing actual I/O on the data stream. The handle opened in step 3 allows the holder of the oplock to perform I/O on the stream, while the oplock granted in step 2 allows the holder of the oplock to "get out of the way" without causing a sharing violation to another application that attempts to access the stream.

The NTFS file system provides an optimization for this procedure through the FILE_RESERVE_OPFILTER create option flag. If this flag is specified in step 1 of the previous procedure, it allows the file system to fail the create request with STATUS_OPLOCK_NOT_GRANTED if the file system can determine that step 2 will fail. Be aware that if step 1 succeeds, there is no guarantee that step 2 will succeed, even if FILE_RESERVE_OPFILTER was specified for the create request.

The following table identifies the required conditions necessary to grant an oplock.

Request type Conditions

Level 1

Filter

Batch

Granted only if all of the following conditions are true:

  • The request is for a given stream of a file.
    • If a directory, STATUS_INVALID_PARAMETER is returned.
  • The stream is opened for ASYNCHRONOUS access.
    • If opened for SYNCHRONOUS access, STATUS_OPLOCK_NOT_GRANTED is returned (oplocks are not granted for synchronous I/O requests).
  • There are no TxF transactions on any stream of the file.
    • Else STATUS_OPLOCK_NOT_GRANTED is returned.
  • There are no other opens on the stream (even by the same thread).
    • Else STATUS_OPLOCK_NOT_GRANTED is returned.

Be aware that if the current oplock state is:

  • No Oplock: The request is granted.

  • Level 2: The original Level 2 request is broken with FILE_OPLOCK_BROKEN_TO_NONE. The requested exclusive oplock is then granted.

  • Level 1, Batch, Filter, Read, Read-Handle, Read-Write, or Read-Write-Handle: STATUS_OPLOCK_NOT_GRANTED is returned.

Level 2

Granted only if all of the following conditions are true:

  • The request is for a given stream of a file.
    • If a directory, STATUS_INVALID_PARAMETER is returned.
  • The stream is opened for ASYNCHRONOUS access.
    • If opened for SYNCHRONOUS access, STATUS_OPLOCK_NOT_GRANTED is returned.
  • There are no TxF transactions on the file.
    • Else STATUS_OPLOCK_NOT_GRANTED is returned.
  • There are no current Byte Range Locks on the stream.
    • Else STATUS_OPLOCK_NOT_GRANTED is returned.
    • Be aware that prior to Windows 7, the operating system verifies if a byte range lock ever existed on the stream since the last time it was opened, and fails the request if so.

Be aware that if the current oplock state is:

  • No Oplock: The request is granted.

  • Level 2 and/or Read: The request is granted. You can have multiple Level 2/Read oplocks granted on the same stream at the same time. Multiple Level 2 (but not Read) oplocks can even exist on the same handle.
    • If a Read oplock is requested on a handle that already has a Read oplock granted to it, the first Read oplock's IRP is completed with STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE before the second Read oplock is granted.
  • Level 1, Batch, Filter, Read-Handle, Read-Write, Read-Write-Handle: STATUS_OPLOCK_NOT_GRANTED is returned.

Read

Granted only if all of the following conditions are true:

  • The request is for a given stream of a file.
    • If a directory, STATUS_INVALID_PARAMETER is returned.
  • The stream is opened for ASYNCHRONOUS access.
    • If opened for SYNCHRONOUS access, STATUS_OPLOCK_NOT_GRANTED is returned.
  • There are no TxF transactions on the file.
    • Else STATUS_OPLOCK_NOT_GRANTED is returned.
  • There are no current Byte Range Locks on the stream.
    • Else STATUS_OPLOCK_NOT_GRANTED is returned.

Be aware that if the current oplock state is:

  • No Oplock: The request is granted.

  • Level 2 and/or Read: The request is granted. You can have multiple Level 2/Read oplocks granted on the same stream at the same time.
    • Additionally, if an existing oplock has the same oplock key as the new request, its IRP is completed with STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE.
  • Read-Handle and the existing oplock have a different oplock key from the new request: The request is granted. Multiple Read and Read-Handle oplocks can coexist on the same stream (see the note following this table).
    • Else (oplock keys are the same) STATUS_OPLOCK_NOT_GRANTED is returned.
  • Level 1, Batch, Filter, Read-Write, Read-Write-Handle: STATUS_OPLOCK_NOT_GRANTED is returned.

Read-Handle

Granted only if all of the following conditions are true:

  • The request is for a given stream of a file.
    • If a directory, STATUS_INVALID_PARAMETER is returned.
  • The stream is opened for ASYNCHRONOUS access.
    • If opened for SYNCHRONOUS access, STATUS_OPLOCK_NOT_GRANTED is returned.
  • There are no TxF transactions on the file.
    • Else STATUS_OPLOCK_NOT_GRANTED is returned.
  • There are no current Byte Range Locks on the stream.
    • Else STATUS_OPLOCK_NOT_GRANTED is returned.

Be aware that if the current oplock state is:

  • No Oplock: the request is granted.

  • Read: the request is granted.
    • If an existing Read oplock has the same oplock key as the new request, its IRP is completed with STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE. This means that the oplock is upgraded from Read to Read-Handle.
    • Any existing Read oplock that does not have the same oplock key as the new request remains unchanged.
  • Level 2, Level 1, Batch, Filter, Read-Write, Read-Write-Handle: STATUS_OPLOCK_NOT_GRANTED is returned.

Read-Write

Granted only if all of the following conditions are true:

  • The request is for a given stream of a file.
    • If a directory, STATUS_INVALID_PARAMETER is returned.
  • The stream is opened for ASYNCHRONOUS access.
    • If opened for SYNCHRONOUS access, STATUS_OPLOCK_NOT_GRANTED is returned.
  • There are no TxF transactions on the file.
    • Else STATUS_OPLOCK_NOT_GRANTED is returned.
  • If there are other opens on the stream (even by the same thread) they must have the same oplock key.
    • Else STATUS_OPLOCK_NOT_GRANTED is returned.

Be aware that if the current oplock state is:

  • No Oplock: the request is granted.

  • Read or Read-Write and the existing oplock has the same oplock key as the request: the existing oplock's IRP is completed with STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE, the request is granted.
    • Else STATUS_OPLOCK_NOT_GRANTED is returned.
  • Level 2, Level 1, Batch, Filter, Read-Handle, Read-Write-Handle: STATUS_OPLOCK_NOT_GRANTED is returned.

Read-Write-Handle

Granted only if all of the following are true:

  • The request is for a given stream of a file.
    • If a directory, STATUS_INVALID_PARAMETER is returned.
  • The stream is opened for ASYNCHRONOUS access.
    • If opened for SYNCHRONOUS access, STATUS_OPLOCK_NOT_GRANTED is returned.
  • There are no TxF transactions on the file.
    • Else STATUS_OPLOCK_NOT_GRANTED is returned.
  • If there are other open requests on the stream (even by the same thread) they must have the same oplock key.
    • Else STATUS_OPLOCK_NOT_GRANTED is returned.

Be aware that if the current oplock state is:

  • No Oplock: the request is granted.

  • Read, Read-Handle, Read-Write, or Read-Write-Handle and the existing oplock has the same oplock key as the request: the existing oplock's IRP is completed with STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE, the request is granted.
    • Else STATUS_OPLOCK_NOT_GRANTED is returned.
  • Level 2, Level 1, Batch, Filter: STATUS_OPLOCK_NOT_GRANTED is returned.

Note Read and Level 2 oplocks may coexist on the same stream, and Read and Read-Handle oplocks may coexist, but Level 2 and Read-Handle oplocks may not coexist.