Who is responsible for synchronizing access to the OPLOCK structure?

Hi,

We implement oplock support in our FSD similar to how FastFat does it. We have an OPLOCK-type member variable in our FCB struct.

What is not clear to me is who is responsible for synchronizing access to the OPLOCK struct. It is an opaque struct for the FSD, but still, is the FSD responsible for synchronizing access to it by e.g. ensuring that the FCB main resource is acquired exclusively or shared before any calls to e.g. FsRtlOplockFsctrl or FsRtlCheckOplock?

I’ve examined the FastFat sample but I can’t get a definitive conclusion from there.

Obviously, the FSD needs to ensure that the OPLOCK struct stays around while such calls are made, i.e., we need to ensure that the whole FCB struct that contains the OPLOCK struct doesn’t get deallocated while e.g. a FsRtlCheckOplock call is executing.

But, assuming that the FCB is guaranteed to have been initialized properly and to stay alive, is it OK to let FsRtlCheckOplock, FsRtlOplockFsctrl and similar calls from multiple threads access the same OPLOCK struct concurrently? Or is the FSD responsible for synchronizing those calls by using the FCB’s main resource or paging IO resource or by some additional synchronization structure?

In particular, I’m looking at this aspect because I’m investigating the following bugcheck where an FsRtlOplockFsctrl call made by our driver results in a bugcheck in FsRtlpRequestShareableOplock:

KERNEL_SECURITY_CHECK_FAILURE (139)
A kernel component has corrupted a critical data structure. The corruption
could potentially allow a malicious user to gain control of this machine.
Arguments:
Arg1: 0000000000000003, A LIST_ENTRY has been corrupted (i.e. double remove).
Arg2: fffff8801b2a8c50, Address of the trap frame for the exception that caused the bugcheck
Arg3: fffff8801b2a8ba8, Address of the exception record for the exception that caused the bugcheck
Arg4: 0000000000000000, Reserved

STACK_TEXT:
nt!KeBugCheckEx
nt!KiBugCheckDispatch+0x69
nt!KiFastFailDispatch+0xd0
nt!KiRaiseSecurityCheckFailure+0xf4
nt!FsRtlpRequestShareableOplock+0xb13
nt!FsRtlOplockFsctrlEx+0x32c
mffsd!MFFSDProcessCheckAndUpdateShareAccess+0x442

-Antti

The oplock package synchronizes access to the oplock struct itself using a mutex. The file system is supposed to ensure that oplock requests can happen concurrently with oplock break acknowledgements. More importantly, it must ensure that an oplock request can’t occur between a check for oplock break (FsRtlCheckOplock) and the I/O that is being checked.

Examples:

When processing an oplock request, the file system would acquire some resource exclusive, call FsRtlOplockFsctrlEx, and release the resource.

When processing an oplock break acknowledgement, the file system would acquire that same resource shared, call FsRtlOplockFsctrlEx, and release the resource.

When performing I/O, the file system would acquire that same resource shared, call FsRtlCheckOplockEx, perform the I/O, and release the resource.


Christian [MSFT]
This posting is provided “AS IS” with no warranties, and confers no rights.

Hi Christian,

Many thanks for your response. One clarification request: Is the following correct (quote from your post), or should it read “cannot” instead of “can”?

“The file system is supposed to ensure that oplock requests can happen
concurrently with oplock break acknowledgements.”

I’m trying to understand the example you provided and it seems to be in contradiction with that sentence. Or, I might just be reading this somehow differently. Anyway, please clarify.

-Antti