On the interaction between the FILE_FLAG_NO_BUFFERING and FILE_FLAG_WRITE_THROUGH flags


The Create­File function has two related flags: FILE_FLAG_NO_BUFFERING and FILE_FLAG_WRITE_THROUGH. These flags can be set independently, but they sort of work together.

First, let’s look at FILE_FLAG_NO_BUFFERING. Setting this flag prevents operations on the handle from going through the disk cache. Reads come directly from the disk, and writes go directly to the disk.

The FILE_FLAG_WRITE_THROUGH flag increases the urgency with which write requests are sent to the disk. Setting this flag forces writes to go to the disk immediately, and combining this flag with FILE_FLAG_NO_BUFFERING adds the additional urgency of telling the disk controller to flush the data out of its internal cache.

So let’s fill out a table.

Clear Set
WRITE_THROUGH Clear Writes go into cache
Lazily written to disk
No hardware flush
Writes bypass cache
Immediately written to disk
No hardware flush
Set Writes go into cache
Immediately written to disk
Hardware flush
Writes bypass cache
Immediately written to disk
Hardware flush

Bonus reading: We’re currently using FILE_FLAG_NO_BUFFERING and FILE_FLAG_WRITE_THROUGH, but we would like our WriteFile to go even faster.


Comments are closed. Login to edit/delete your existing comments

  • aidtopia

    I think some of the confusion stems from the conceptual conflation of “buffering” with “caching.” Caching is keeping data in memory in anticipation of future reads–speeding up the reads by avoiding going back out to the slower media. Buffering is about collecting data in blocks that are compatible with the “sector size” of the media.

    Disk drives won’t let you read or write four bytes of data at an arbitrary offset. You can only read or write in chunks that are aligned to and a multiple of blocks. In disk drives, blocks are called sectors. They’re traditionally 512 bytes, but some drives can use 4096 bytes. So if you want to change four bytes, you have to read the entire block into a buffer, change the four bytes you care about, and write the entire block back out. But if you’re immediately going the change the next four bytes, then you don’t really want to re-read the block you just had and write it yet again. So the I/O system usually creates and manages buffers to minimize unnecessary physical operations by collecting logical i/o writes until it makes sense to issue the physical command.

    Buffering is necessary. When you tell the system “no buffering,” what you’re telling the system is that it does not have to manage the buffering because your program is going to do it. Your ReadFile and WriteFile calls can only operation at offsets and sizes that are a multiple of the block size (to and from memory buffers that are suitably aligned).

    The system implements buffering in the caching layer, because the requirements are similar even though the reasons are different and because it eliminates shuffling of data between the cache and i/o buffers. So when you say, “no buffering,” it also happens to mean no caching, but that’s kind of a side effect.

    • switchdesktopwithfade@hotmail.com

      What is the size of atomicity with a hard drive? I always wondered how journaling was possible.