If you’re implementing a layered file system and having trouble passing some of the Enhanced Oplock Tests in the Windows HCK or HLK then the information presented in this blog entry might prove helpful. Starting in Windows 7, Microsoft introduced a new Extra Create Parameter (ECP) for OpLock processing. Then again in Windows 8, they added another ECP for OpLocks. If you are not familiar with them and you make a call to FltCreateFile() in your pre-create handler, then read on …
As a quick background, Opportunist Locks, or OpLocks, implement the distributed locking model used in Windows. They allow, for example, a client system to cache data locally for a given file and later be notified if another client is trying to open the same file resulting in having to flush dirty data, etc. Because OpLocks are tied to a given file handle, an issue arises when a given application takes an OpLock on a file but then requires to re-open the file, perhaps in a different thread. The application does not want to break the OpLock it currently has when the second thread attempts to open the file so it can leverage a new ECP to get around this scenario. Of course, this is a generalization of the problem but it could be applied to, for example, distinct clients in a network which are communicating the necessary information to prevent one client from breaking OpLocks on a file held by the other client.
To get around this issue, when a file is opened the caller can specify one of the new ECPs associated to OpLocks. In both of the ECPs, a GUID is specified which is used as a key for any OpLock taken on the file. In the newer OpLock ECP, the caller can specify a parent key as well. After the caller opens the file, specifying the OpLock ECP with the key, it then proceeds to take out an OpLock on that file. At this point, any subsequent open on the file could break that held OpLock unless the secondary opens specify the OpLock ECP and the GUID specified in the first open of the file. If this information is provided then the OpLock will not be broken and the open request will proceed as normal.
Now you may be asking yourself why would I be interested in this if I am implementing a layered file system that takes ownership of the file objects passed in? In the case where you are either building a new FLT_CALLBACK_DATA request to open the file or issuing a FltCreateFile(), or one of its variants, you must correctly propagate the described ECPs to the file system or the open request will block until the OpLock is broken. In the case of the HCK or HLK Enhanced Oplock Tests, there are several which perform this exact operation. Thread1 opens a file specifying the OpLock ECP with a key GUID and proceeds to take an OpLock out on the file. It then issues a second open under Thread2 which also specifies the OpLock ECP with the correct key GUID. If your design receives the open request and reissues the open through a FltCreateFile(), the OpLock will be broken by Thread2 if you do not correctly propagate the OpLock ECP to the FltCreateFileEx2() call. But if you recognize the OpLock ECP is being sent in the request and you correctly copy it over into a new ECP list used in your call, the test will pass and life will be problem free again …
Note that you can only send ECPs using the FltCreateFileEx2() API so you may need to change your routines accordingly. But following this piece of advice for propagating these ECPs through your calls will save you hours of headaches wondering why the test fails.
For more details on the specific layout of these two ECPs, see the following official documentation: