Thursday, June 28, 2012

The Flags of FILE_OBJECTs - Part IV

This is the last part in the series of posts on the flags of the FILE_OBJECT. The previous posts can be found here:

  1. The Flags of FILE_OBJECTs - Part I
  2. The Flags of FILE_OBJECTs - Part II
  3. The Flags of FILE_OBJECTs - Part III

And here is the final set of flags:

  • FO_FILE_FAST_IO_READ - 0x00080000 - according to the documentation page for the FILE_OBJECT structure, this flag is set to indicate that a fast I/O read was performed on this FILE_OBJECT. However, looking at the FastFat source code reveals more. First, the flag can be set when the file is read through a regular request as well, not only through fast IO (see FatCommonRead and FatMultiAsyncCompletionRoutine). There is also an interesting bit in the create path (FatCommonCreate), where the flag is set if the caller requested EXECUTE access. So it appears that in fact this flag is set when the user performs a read on the file, but not for paging reads (which makes sense, paging reads are, in a way, the system reading from a file and not exactly the user). The reason for this becomes clear when looking at where the flag is used in FastFat: in the FatUpdateDirentFromFcb function, which uses the flag to figure out if it needs to update the last access time on the file.
  • FO_RANDOM_ACCESS - 0x00100000 - this flag is set to indicate that the caller intends to use this FILE_OBJECT for random access (forward and backward seeks). It maps to the FILE_RANDOM_ACCESS flag and is set when creating the handle. The flag is pretty similar to the FO_SEQUENTIAL_ONLY but works in the opposite way: it's an indication to the cache manager that it can't assume that once a location in the file was touched once it won't be touched again so it shouldn't be overly aggressive in removing things from the cache. Unlike FO_SEQUENTIAL_ONLY this flag can't be set or queried using the FileModeInformation.
  • FO_FILE_OPEN_CANCELLED - 0x00200000 - this flag indicates that the IRP_MJ_CREATE for the FILE_OBJECT was cancelled. In other words, someone called IoCancelFileOpen or FltCancelFileOpen. The flag is set in IoCancelFileOpen and is used in IopParseDevice where the IO manager needs to figure out if it should cleanup the FILE_OBJECT (by issuing an IRP_MJ_CLOSE) or not. The documentation for the FltCancelFileOpen routine is also a pretty good source of information for this flag.
  • FO_VOLUME_OPEN - 0x00400000 - this flag indicates that the FILE_OBJECT is an open for a volume. Interestingly enough this flag is set by the IO manager after the IRP_MJ_CREATE IRP completes, so it would not be available in preCreate. However, preCreate is where it's most useful (see the simrep and MetadataManager minifilter samples in the WDK) and so FltMgr parses the IRP_MJ_CREATE parameters and set the FO_VOLUME_OPEN flag when appropriate so that it's available even in preCreate (see this NTFSD post). This means that this flag is usable by minifilters for all operations. For legacy filters things are more complicated (as usual): they might see the flag set if there is a FltMgr frame above them but they might not see it otherwise (so I guess legacy filters shouldn't expect to see this flag set).
  • FO_REMOTE_ORIGIN - 0x01000000 - this is a flag that indicates that the FILE_OBJECT was created to satisfy a remote request, which is something done by remote file systems. There are two functions that deal with this flag: IoIsFileOriginRemote which pretty much just queries this flag, and IoSetFileOrigin which sets it. The documentation for both functions mentions this connection (between these functions and FO_REMOTE_ORIGIN) but fails to explain why this is done. The reason is that the cache manager handles files coming from a remote file system differently and so this flag is a hint to the cache manager.
  • FO_DISALLOW_EXCLUSIVE - 0x02000000 - this flag is set during the create processing if the FILE_DISALLOW_EXCLUSIVE flag was set on the request. It would appear that this flag can only be set during an IRP_MJ_CREATE operation (there is a definition for FO_FLAGS_VALID_ONLY_DURING_CREATE which is what I'm basing this on). I don't know exactly what this flag does and looking over my notes I've never actually used it or had to interact with it so I guess I'll have to investigate this and write a post on it :).
  • FO_SKIP_COMPLETION_PORT - 0x02000000 - this flag is pretty well explained in the FILE_OBJECT structure page. Additionally, the documentation for SetFileCompletionNotificationModes also explains how this flag might be used (this flag maps to the FILE_SKIP_COMPLETION_PORT_ON_SUCCESS flag). There is also this post that explains a bit more about the flags that affect behavior of IO completion (the following flags): Designing Applications for High Performance - Part III. I'm guessing this flag can be set using the FILE_IO_COMPLETION_NOTIFICATION_INFORMATION structure and respective information class.
  • FO_SKIP_SET_EVENT - 0x04000000 - this flag is similar to FO_SKIP_COMPLETION_PORT. It maps to the FILE_SKIP_SET_EVENT_ON_HANDLE (as per the page for the SetFileCompletionNotificationModes function).
  • FO_SKIP_SET_FAST_IO - 0x08000000 - this flag appears to be similar to the previous ones but doesn’t seem to be something that can be set using SetFileCompletionNotificationModes(). Based on the documentation page for the FILE_OBJECT structure it seems that this flag controls whether the FILE_OBJECT event should be signaled when an operation goes through a fast IO call and therefore completes inline. Naturally in that case there is no need to set the event. Looking at wdm.h it would seem that this flag maps to the FILE_SKIP_SET_USER_EVENT_ON_FAST_IO.