Flush Cache from IRP_MJ_CLEANUP

Hello everybody!

I am trying to fix a problem with a minifilter driver. The problem is the following

I need to release some allocated resources (contexts and opened files) when an end-application closes the last handle to a file. These resources are needed to perform any read/write operation, that is, are needed by IRP_MJ_READ and IRP_MJ_WRITE, and I release them in the IRP_MJ_CLEANUP callback.

The problem appears when I open a file with notepad. Using ProcMon I saw there is a IRP_MJ_READ after the the IRP_MJ_CLEANUP, which means this read operation can?t be acomplished since the needed resources have been previously released (in the IRP_MJ_CLEANUP callback).

I think this “lazy read” is initiated by the CacheManager, so I was wondering how I could synchronously flush cache in the IRP_MJ_CLEANUP callback. This way the IRP_MJ_READ callback would be called before the needed resources are deallocated.

I have seen a previous post which suggests to use the following functions:

  • CcFlushCache
  • MmFlushImageSection
  • CcPurgeCacheSection
  • CcUninitializeCacheMap

I tried so, but CcPurgeCacheSection fails (maybe because the file is not opened exclusively, but this is something I can?t change…)

Any help is appreciated! Thanks a lot!!

Santiago

Release the resources in CLOSE and not CLEANUP.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

wrote in message news:xxxxx@ntfsd…
Hello everybody!

I am trying to fix a problem with a minifilter driver. The problem is the following

I need to release some allocated resources (contexts and opened files) when an end-application closes the last handle to a file. These resources are needed to perform any read/write operation, that is, are needed by IRP_MJ_READ and IRP_MJ_WRITE, and I release them in the IRP_MJ_CLEANUP callback.

The problem appears when I open a file with notepad. Using ProcMon I saw there is a IRP_MJ_READ after the the IRP_MJ_CLEANUP, which means this read operation can?t be acomplished since the needed resources have been previously released (in the IRP_MJ_CLEANUP callback).

I think this “lazy read” is initiated by the CacheManager, so I was wondering how I could synchronously flush cache in the IRP_MJ_CLEANUP callback. This way the IRP_MJ_READ callback would be called before the needed resources are deallocated.

I have seen a previous post which suggests to use the following functions:

- CcFlushCache
- MmFlushImageSection
- CcPurgeCacheSection
- CcUninitializeCacheMap

I tried so, but CcPurgeCacheSection fails (maybe because the file is not opened exclusively, but this is something I can?t change…)

Any help is appreciated! Thanks a lot!!

Santiago

> CcFlushCache

MmFlushImageSection
CcPurgeCacheSection
CcUninitializeCacheMap

In general all of these are unsafe unless you own the cache (== an FSD, a pseudo FSD, or an isolation filter). You are borrowing data structures which do not belong to you and need to make assumptions about the locking used. This will eventually bite the code. You could be lucky and be working on another project (perhaps in another company maybe on another continent) when this happens, but someone will be unhappy and there are too many unhappy people in the world for you to add to their number.

Also, if you must use these calls, bear in mind that they throw exceptions rather than return error statuses so you should bung them inside a try/except/finally.

Anyway.

Using ProcMon I saw there is a IRP_MJ_READ after the the IRP_MJ_CLEANUP, which means
this read operation can´t be acomplished since the needed resources have been previously released
(in the IRP_MJ_CLEANUP callback).

You can get writes as well (indeed that is quite common).

And related:

I tried so, but CcPurgeCacheSection fails (maybe because the file is not opened exclusively, but this is something I can´t change…)

Consider a user application that opens a file, opens a section back by that file, maps a view to that section, then closes the file handle. It can then party over the mapped view to its heart’s content causing you any number of reads and writes. There is also (I don’t have the notes) an API that the kernel has been known to issue to change the length of the section (and hence the file). All after MJ_CLEANUP.

You need to consider your design…

Maxim is right (as usual). I’d only like to elaborate a bit on the point he
made.

As a general approach I try to mimic what the file system is doing… So that
if you have additional files open that you need to use for IO (IRP_MJ_READ
and IRP_MJ_WRITE) then you might want to close the handles to those files
during IRP_MJ_CLEANUP (that is if you kept open handles… you might not need
to depending on your design) but keep references to them
(ObReferenceObject()) until IRP_MJ_CLOSE. As you have noticed, it is pretty
common for the Cache Manager (also known as Cc) to hang on to FILE_OBJECTs
after their handles have been closed and use them for IO so if someone still
has a reference to the FILE_OBJECT then your minifilter would better be
prepared to handle that FILE_OBJECT being used for IO (which is just a
reiteration of Maxim’s advice that you need to keep whatever resources you
need to process IO around until IRP_MJ_CLOSE).

I’m also not sure about the need to release contexts in cleanup. Normally if
you don’t leak references contexts will be cleaned up when appropriate and
you don’t need to worry about their life cycle. The Ctx minifilter sample in
the WDK shows that all you need to do is make sure you reference and
dereference them properly and they will go away when the time is right.

Thanks,
Alex.

Thanks a lot to all of you!! I really appreciate it. I?ve been studing and I now I think my design is wrong.
As you have suggested I am releasing the resources in IRP_MJ_CLOSE, but I have one more concern. Because of design requirements, I would like to close the file as soon as possible, so I wonder if there is a way to make the Cc to close the file, so the IRP_MJ_CLOSE is called inmediately.

I have tried CcFlushCache but it does not work. According to what Rod Widdowson says, why is it unsafe to use this function? (there should be a way to flush the cache, as there is an utility called Sync from Sysinternals to flush the entire system cache). I am missing something?

Thanks a lot!!

Santi

> I have tried CcFlushCache but it does not work. According to what Rod

Widdowson says, why is it unsafe
to use this function?

You do not own the cache. The file system does. It is quite likely that
the file system (or cache manager) require some lock state prior to calling
CcFlushCache (I always take the paging lock in my file systems, but that’s a
whim based on experience). If you don’t do what the file system expects it
is at liberty to react badly. Because it is to do with locking react badly
probably means “crash or corrupt under load”.

If you want to flush the cache you can use IRP_MJ_FLUSH_BUFFERS.

I suspect however that yo want to purge the cache, I had thought that there
was a call to expose CcConherencyFlushAndPurgeCache (in Win7), but I cannot
find it…