Hi, I have a mini-filter driver that uses per-stream context. I have a couple of questions regarding some race condition that I encounter:
- We use FsRtlInitPerStreamContext to init our context with a FreeCallback routine. We also use a reference count to maintain the life-cycle of the per-stream context. Basically the life-cycle management is like this:
PreCreate callback:
{
if (per-stream context for this file does not exist) {
Create new context.
Set ref count to 1.
}
Increment ref count.
… process the per-stream context here …
Decrement ref count. Destroy per-stream context if ref count is 0.
}
PreRead/PreWrite callbacks:
{
if (! (non-cached I/O || paging I/O)) {
return;
}
// Here it expects the per-stream context to have been create by
// PreCreate callback earlier.
Increment ref count.
… process the per-stream context here …
Decrement ref count. Destroy per-stream context if ref count is 0.
}
FreeCallback:
{
Increment ref count.
… process the per-stream context here …
Decrement ref count.
Decrement ref count. Destroy per-stream context if ref count is 0.
}
This works most of the time. However, the race condition that I encounter is that when FreeCallback is called in one thread, PreCreate callback is also called in another thread at the same time. Then the following happens:
- FreeCallback increments ref count to 2.
- PreCreate callback increments ref count to 3.
- FreeCallback decrements ref count to 2.
- FreeCallback decrements ref count to 1.
- PreCreate callback decrements ref count to 0, and Destroys the per-
stream context. - PreRead/PreWrite callbacks cannot find the per-stream context. Hence
error occurs.
Question: Is the race condition I’m seeing a normal behavior? Or did I do something wrong?
- Given the race condition above, I thought one solution is not to use any reference count at all. So I changed my code to the following:
PreCreate callback:
{
if (per-stream context for this file does not exist) {
Create new context.
}
… process the per-stream context here …
}
PreRead/PreWrite callbacks:
{
if (! (non-cached I/O || paging I/O)) {
return;
}
// Here it expects the per-stream context to have been create by
// PreCreate callback earlier.
… process the per-stream context here …
}
PreCleanup callback:
{
Destroy per-stream context.
}
FreeCallback:
{
// Do nothing.
}
However, the code doesn’t seem to work. It looks like the driver is receiving PreWrite calls for paging I/O on a file after it receives PreCleanup calls for the same file. Therefore error occurs.
Is it normal that PreWrite for paging I/O occurs after PreCleanup? Or am I missing something?
Thanks for any help!
— Allen Yuen
STATEMENT OF CONFIDENTIALITY
The information contained in this electronic message and any attachments to this message are intended for the exclusive use of the addressee(s) and may contain confidential or privileged information. No representation is made on its accuracy or completeness of the information contained in this electronic message. Certain assumptions may have been made in the preparation of this material as at this date, and are subject to change without notice. If you are not the intended recipient, you are hereby notified that any dissemination, distribution or copying of this e-mail and any attachment(s) is strictly prohibited. Please reply to the sender at NextLabs Inc and destroy all copies of this message and any attachments from your system. ======================================================================