Handling fast I/O in a minifilter

Hi everyone. The Filter Manager does a good job of making fast I/O calls look like IRPs. With that in mind I’ve got some nuance questions I can’t find answered anywhere:

  1. If the minfilter does NOT reply with FLT_PREOP_DISALLOW_FASTIO to IRP_MJ_CREATE (thus allowing the fast I/O calls for that file I/O?), but then after zero or more IRP_MJ_READ calls determines it can’t handle an IRP_MJ_READ (perhaps it needs to pend the operation), can it return FLT_PREOP_DISALLOW_FASTIO at that point (in the PreOp)?

  2. What is different in IRP_MJ_READ between an IRP-based and fast I/O based request? (I assume differences will be similar for IRP_MJ_WRITE?) Does it boil down to IRQL or buffer management?

Thanks for any help, I appreciate it.

Mostly you cannot pend a fastio operation.

What is different in IRP_MJ_READ between an IRP-based and fast I/O based request?

Hmmmm… pretty much what Mr. Widdowson said so very succinctly.

Fast I/O is just an “express processing” callback that asks the file system “Can you completely handle this request right now, or do you want me to build you an IRP so you can handle this at your convenience?”

For just a bit more detail, from the ancient, and classic, article on OSR Online that first explained Fast I/O to the world (this was 1996!):

A fast I/O routine can do one of two things: it can complete the operation, set the IoStatus field to indicate the result codes for the operation and return TRUE to the I/O manager. If that is the case, the I/O manager will complete the I/O operation. Alternatively, the routine can return FALSE, in which case the I/O manager will simply create an IRP and call the standard dispatch entry point.

Note that returning TRUE doesn’t always guarantee the data has been transferred. For example, a read which starts past the end of file causes the IoStatus.Results field to be set to STATUS_END_OF_FILE, with no data copied. A read which crosses over the end of file will cause a TRUE to be returned, again with STATUS_END_OF_FILE set in the Results field, but this time with all remaining data in the file copied to the buffer.

Similarly, returning FALSE doesn’t always guarantee that some data has not been transferred. While less likely, it is possible for some data to be successfully copied but then to experience an I/O error, or to have the memory of the buffer become inaccessible.

In either case a number of secondary effects can occur. For example, while reading from the cache, it is possible that some of the data being read is not currently resident. This will result in a page fault which will result in a call back into the file system to satisfy the page fault.

@Doug_N said:
Hi everyone. The Filter Manager does a good job of making fast I/O calls look like IRPs. With that in mind I’ve got some nuance questions I can’t find answered anywhere:

  1. If the minfilter does NOT reply with FLT_PREOP_DISALLOW_FASTIO to IRP_MJ_CREATE (thus allowing the fast I/O calls for that file I/O?), but then after zero or more IRP_MJ_READ calls determines it can’t handle an IRP_MJ_READ (perhaps it needs to pend the operation), can it return FLT_PREOP_DISALLOW_FASTIO at that point (in the PreOp)?

Note that returning FLT_PREOP_DISALLOW_FASTIO to IRP_MJ_CREATE does not disable Fast I/O processing for that File Object. This return value is only usable when FLT_IS_FASTIO_OPERATION returns TRUE and results in the specific operation being retried as an IRP.

Thanks @Scott_Noone_(OSR) - that’s exactly the info I was looking for on that one.