Understanding Cache, Non-Cache, and Paging Read/Write Operations

 

If you are developing a file system filter driver—whether for data protection, continuous data protection (CDP), auditing, or encryption—understanding how Windows handles file Input/Output (I/O) is absolutely critical.

When an application reads or writes to a file, the request doesn't always go straight to the hard drive. Windows uses a complex architecture involving the Cache Manager, the Memory Manager, and the File System to optimize performance. As a result, a single file operation can trigger multiple different types of I/O requests.

In this post, we will break down the differences between Cache Read/Write, Non-Cache Read/Write, and Paging I/O Read/Write, and explain exactly how to intercept and handle them using the EaseFilter File Monitor SDK and File Control SDK.

1. The Core Component: The Windows Cache Manager

Before diving into the specific I/O types, it is important to understand the role of the Windows Cache Manager. To speed up file access, Windows attempts to keep frequently accessed file data in physical RAM. When an application requests file data, the system first checks the Cache Manager.

If the data is there, it is served immediately from memory (a "cache hit"). If it isn't, the system must fetch it from the physical disk (a "cache miss"). This multi-layered architecture is the reason filter drivers see several distinct types of read and write requests for a single user action.

2. Cache Read and Write

These are the standard, everyday I/O requests generated by user-mode applications, like opening a document in Word or saving a text file in Notepad using standard ReadFile or WriteFile APIs.

Cache Read (PRE_CACHE_READ / POST_CACHE_READ): The application is asking to read data, and this request is directed to the Cache Manager. If the data is already cached, it is returned to the user immediately. If not, the Cache Manager pauses the request and asks the system to fetch the data from the disk (triggering a Paging I/O Read).

Cache Write (PRE_CACHE_WRITE / POST_CACHE_WRITE): The application is saving data. Instead of writing directly to the slow physical disk, the data is written straight into the Cache Manager's memory. The Cache Manager marks these memory pages as "dirty" and will quietly flush them to the physical disk later in the background (triggering a Paging I/O Write).

Note on Fast I/O: You may also intercept PRE_FASTIO_READ or PRE_FASTIO_WRITE. Fast I/O is simply an optimized, high-speed path to the Cache Manager that bypasses standard I/O Request Packet (IRP) creation if the data is readily available in the cache.

3. Non-Cache Read and Write (Direct I/O)

Sometimes, an application needs to talk directly to the disk, completely ignoring the Cache Manager. This usually happens when an application (like a database engine or backup software) opens a file with the FILE_NO_INTERMEDIATE_BUFFERING flag.

Non-Cache Read (PRE_NONCACHE_READ / POST_NONCACHE_READ): The request bypasses the Cache Manager entirely and reads data directly from the physical storage volume.

Non-Cache Write (PRE_NONCACHE_WRITE / POST_NONCACHE_WRITE): The data is written directly to the physical disk.

Because non-cached I/O talks directly to the hardware block device, the data buffers, offsets, and read/write lengths must be perfectly aligned with the disk's physical sector size (usually 512 bytes or 4KB).

4. Paging I/O Read and Write

Paging I/O requests are system-level requests initiated by the Windows Memory Manager. You will rarely see a standard application trigger these directly using file APIs; instead, they are the underlying mechanism that supports the Cache Manager and memory-mapped files.

Paging I/O Read (PRE_PAGING_IO_READ / POST_PAGING_IO_READ): This is the system reading data from the physical disk into memory. You will typically see this request immediately following a Cache Read miss, because the Cache Manager needs the data to fulfill the user's request.

Paging I/O Write (PRE_PAGING_IO_WRITE / POST_PAGING_IO_WRITE): This is the system taking the "dirty" data currently sitting in the Cache Manager and flushing it down to the physical disk for permanent storage. This often happens in the background, long after the application that performed the original Cache Write has closed the file.

5. The Special Case: Memory-Mapped Files

One of the most important concepts to grasp when building a filter driver is how Windows handles memory-mapped files. This occurs when an application maps the contents of a file directly into its virtual memory address space (using APIs like CreateFileMapping and MapViewOfFile), or when Windows loads an executable (.exe) or library (.dll) into memory.

When a file is memory-mapped, the application does not use standard read/write APIs. Instead, it reads and writes directly to memory pointers. Because of this, memory-mapped I/O completely bypasses Cache Read and Cache Write operations.

Here is how the I/O flows for memory-mapped files:

Page Faults to Paging Reads: When the application tries to access a memory address corresponding to the file, and that piece of the file isn't in physical RAM yet, the CPU triggers a "page fault." The Memory Manager catches this fault and issues a Paging I/O Read to fetch exactly that page of data from the disk.

Dirty Pages to Paging Writes: When the application modifies the data via memory pointers, it updates the RAM directly. The Memory Manager marks that specific memory page as "dirty." Later, the system's lazy writer thread will issue a Paging I/O Write to flush that modified memory page back to the physical disk.

Why this matters to you: If you are building an auditing or encryption driver, you cannot rely solely on capturing PRE_CACHE_READ or PRE_CACHE_WRITE events. If an application uses memory mapping (like many modern text editors and databases do), you will never see those cache events. You will only see PRE_PAGING_IO_READ and PRE_PAGING_IO_WRITE.

6. Intercepting I/O Operations with the EaseFilter SDK

Now that you understand the different types of I/O, how do you actually intercept them? The EaseFilter File Monitor SDK and File Control SDK operate via a kernel-mode filter driver (EaseFlt.sys) that communicates with your user-mode application.

To intercept specific I/O requests, you must set up a filter rule, register the required file events, and handle the requests in a callback function.

Step 1: Setting up the Filter Rule

In your user-mode C# application, create a FileFilter object. When configuring this rule, you tell the driver exactly which I/O events to capture by setting the control flags.

Step 2: Handling the I/O in the Callback

Once registered, the kernel-mode driver will pause matching I/O requests and send a message to your user-mode event handler. Inside your handler, examine the MessageType property to determine exactly what type of I/O is occurring and how to process it.

8. Key Development Takeaways

Knowing when to act on a specific I/O type defines the success of your filter driver:

Paging I/O for Data Transformation: If you are encrypting or decrypting data on-the-fly, do it during PRE_PAGING_IO_READ and PRE_PAGING_IO_WRITE. This ensures the application sees plaintext in the cache or via memory maps, but only ciphertext is ever written to the physical disk. Attempting to encrypt during a Cache Write means the application will read ciphertext back from the cache.

Beware the Memory Map Bypass: Remember that memory-mapped files (like .exe execution or database reads) will not trigger Cache I/O events. If your security driver only monitors Cache I/O, it has a massive blind spot. Always account for Paging I/O.

Alignment Strictness for Non-Cache I/O: If you intercept PRE_NOCACHE_READ or PRE_NOCACHE_WRITE and decide to modify the data buffers, your offset and buffer length must be multiples of the sector size. Failing to align non-cached I/O will result in a Blue Screen of Death (BSOD) or hard crashes.

User Intent Maps to Cache I/O: Intercept PRE_CACHE_READ` and `PRE_CACHE_WRITE if your goal is to track user behavior, audit file access from standard programs, or block unauthorized applications from viewing a file. This is the layer closest to the actual user process.

Comments

Popular posts from this blog

EaseTag Cloud Storage Connect

EaseFilter Comprehensive Complete File Security SDK