CcFlushCache() or IRP_MJ_FLUSH_BUFFERS

To flush cache, should a Windows file system filter driver use CcFlushCache() directly or create/send a FSD request with major function IRP_MJ_FLUSH_BUFFERS? After searching online, we got two completely opposite answers:

  1. From https://www.osronline.com/ShowThread.cfm?link=151058

"The first thing to note is that CcFlushCache and CcPurgeCache are not
for use by filters. They are there for Filesystems to take advantage of.
This doesn’t stop people from using them and it “mostly” works, but callers
of these functions should be aware that Cc Expects you to hold “the right
locks” when they are called and you will eventually deadlock or crash
otherwise.

?

Subject to certain restrictions that the FSD may impose, yes. Remember
however you have no guarantee that when this returns someone won’t have
written to a mapped file and dirtied it again. Filters would be better
sending an IRP_MJ_FLUSH IRP"

  1. From http://msdn.microsoft.com/en-us/library/windows/hardware/ff549235(v=vs.85).aspx

“The IRP_MJ_FLUSH_BUFFERS request is sent by the I/O Manager and other operating system components, as well as other kernel-mode drivers, when buffered data needs to be flushed to disk. It can be sent, for example, when a user-mode application has called a Microsoft Win32 function such as FlushFileBuffers. (For file system drivers and file system filter drivers, calling CcFlushCache is usually preferable to sending an IRP.)”

I would appreciate your opinion or suggestions.

> To flush cache, should a Windows file system filter driver use CcFlushCache() directly or

create/send a FSD request with major function IRP_MJ_FLUSH_BUFFERS?

Second.

CcFlushCache requires some lock IIRC, which is not known to a filter.

Why do you need this in a filter? for some filter’s metadata file? then, in terms of this file, the filter is a client of the FSD, just like a user app, and should use the same facilities (flushing included) which the user apps use.


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com

I agree with the concerns voiced in the original thread (indeed, I wondered if I had said them, as they sound much like what I’ve said in the past on this issue). But let’s make this more concrete, since we see this question periodically.

Here is the code from FastFAT for IRP_MJ_FLUSH_BUFFERS:

case UserFileOpen:

DebugTrace(0, Dbg, “Flush User File Open\n”, 0);

(VOID)FatAcquireExclusiveFcb( IrpContext, Fcb );

FcbAcquired = TRUE;

FatVerifyFcb( IrpContext, Fcb );

//
// If the file is cached then flush its cache
//

Status = FatFlushFile( IrpContext, Fcb, Flush );

The actual call to CcFlushCache is in FatFlushFile.

NOTE: this has acquired the FCB lock for this file EXCLUSIVE. A file system filter driver that calls CcFlushCache cannot (safely) acquire this FCB.

So perhaps you say “well, I can grab the FCB lock exclusive” to which I would ask: “How do you know this is the way that other file systems you are filtering function?”

Perhaps you are only filtering a single file system (e.g., ReFS) and you use the debugger to carefully analyze the behavior of this file system in this path and implement comparable logic. You’ve ensured that CcFlushCache isn’t going to break - but you’ve done so at creating a dependence on the implementation in ReFS.

Next year, your company assigns you to a different project. Someone ELSE is given the task of making your filter work on NTFS. When this breaks, they won’t understand why.

Bottom line: if *you* don’t own the cache for a given FileObject, you should not call Cc* functions against that file object. It might work. It might not work. But in either case it violates the ownership rights of the file system that controls that file object and when it breaks you will be at fault.

Tony
OSR

Maxim and Tony, thanks a lot for your very helpful reply.