I have read http://www.osronline.com/article.cfm?article=102 and I can see some of the complications regarding FileObjects. I have not yet seen any “Flags & FO_STREAM_FILE” (I ASSERT on it in my IRP dispatcher) so I have not yet done code to “remember” FileObjects (that did not come via MJ_CREATE).
I reference count in CREATE, and CLEANUP.
Then try to work out when I can free my FCB in CLOSE.
` if (IrpSp->FileObject->FsContext) {
vnode_t *vp = IrpSp->FileObject->FsContext;
if (vp->v_iocount == 1 && vp->v_usecount == 0) {
section = vnode_sectionpointer(vp);
if (section->ImageSectionObject)
(VOID)MmFlushImageSection(section, MmFlushForWrite);
if (FlagOn(IrpSp->FileObject->Flags, FO_CACHE_SUPPORTED) &&
section && section->DataSectionObject) {
CcFlushCache(section, NULL, 0, &iosb);
CcPurgeCacheSection(section, NULL, 0, FALSE);
}
if (IrpSp->FileObject->SectionObjectPointer) {
KeInitializeEvent(&UninitializeCompleteEvent.Event,
SynchronizationEvent,
FALSE);
CcUninitializeCacheMap(IrpSp->FileObject, NULL, &UninitializeCompleteEvent);
WaitStatus = KeWaitForSingleObject(&UninitializeCompleteEvent.Event,
Executive,
KernelMode,
FALSE,
NULL);
ASSERT(IrpSp->FileObject->SectionObjectPointer->ImageSectionObject == NULL);
ASSERT(IrpSp->FileObject->SectionObjectPointer->DataSectionObject == NULL);
IrpSp->FileObject->SectionObjectPointer = NULL;
}
FsRtlTeardownPerStreamContexts(&vp->FileHeader);
FsRtlUninitializeFileLock(&vp->lock);
}
if (vp->v_iocount == 1 && vp->v_usecount == 0 &&
(IrpSp->FileObject->SectionObjectPointer == NULL ||
(IrpSp->FileObject->SectionObjectPointer->ImageSectionObject == NULL &&
IrpSp->FileObject->SectionObjectPointer->DataSectionObject == NULL))) {
vnode_recycle(vp); // Release the memory at FsContext
}
} else {
dprintf("IRP_CLOSE but can't close yet.\n");
}
IrpSp->FileObject->FsContext = NULL;
`
So, it sucks to read other’s code - so I’ll try to summarise. Before I release the memory, I made sure that:
- ImageSectionObject is NULL
- DataSectionObject is NULL
- CcUninitializeCacheMap() is called and we wait on it (and we can handle that it may call CLOSE on us!)
- Free memory
- FsContext set to NULL
Most of the time it works, but every now and then we die:
nt!KiGeneralProtectionFault+0x2dc C/C++/ASM FLTMGR!FltpGetStreamListCtrl+0x66 C/C++/ASM FLTMGR!FltpPerformPreCallbacks+0x68f C/C++/ASM FLTMGR!FltpPassThroughInternal+0x8c C/C++/ASM FLTMGR!FltpPassThrough+0x144 C/C++/ASM FLTMGR!FltpDispatch+0x9e C/C++/ASM nt!IofCallDriver+0x59 C/C++/ASM nt!IopDeleteFile+0x124 C/C++/ASM nt!ObpRemoveObjectRoutine+0x80 C/C++/ASM nt!ObfDereferenceObject+0xa1 C/C++/ASM nt!MiSegmentDelete+0x192 C/C++/ASM nt!MiProcessDereferenceList+0xa3 C/C++/ASM nt!MiDereferenceSegmentThread+0x125 C/C++/ASM nt!PspSystemThreadStartup+0x47 C/C++/ASM nt!KiStartSystemThread+0x16 C/C++/ASM
I believe that IofCallDriver (or there abouts) calls my MJ_CLOSE, and I detect that I can finally release the memory - the memory allocator scribbles 0xdeadbeef to the memory - then the kernel keeps going, and ends up in FltpGetStreamListCtrl() and dies due to access to 0xdeadbeef.
So why is it still rogering around in “my memory”? Which part is it trying to access? As it says StreamList, I would guess the AdvancedHeader is in play, but I call FsRtlTeardownPerStreamContexts()!
Is there something I have missed in my MJ_CLOSE “can we free memory conditional” ?
If I never release memory, we do not crash - but I don’t see that as a great long term plan.