What Linux actually does when you read a file

2026年8月7日1 次浏览来源:Dev.to阅读原文

I asked Linux for one 4 KiB page from the start of a cold file.

Four pages came back.

I moved the same read one page further in, ran it again, and got one.

Same file, same syscall, same kernel.

The only thing that changed was where I started reading, and I spent twenty minutes assuming the tool I'd just written was miscounting.

It wasn't.

A read that starts at byte zero is treated as a promise.

There's a branch in that reads, in full, .

Offset zero means the kernel takes you for a program that's about to stream the whole file, and it fetches ahead immediately.

Start anywhere else and you're assumed to be seeking randomly until a pattern proves otherwise.

Nothing in my call said a word about my intentions.

It inferred them from an offset.

I spent two weeks on this sort of thing recently.

Not for work, and not toward anything shippable.

The short version of what I found is that a surprising amount of the machinery under a running program isn't carrying out instructions at all.

It's guessing.

The bench, because it changes how you should read every number here: an ext4 filesystem on a loop device, inside an OrbStack Linux VM on an Apple Silicon Mac, kernel 7.0.14, 4 KiB pages, at

128.

That's a container sharing the host's kernel, not bare metal, and the host reclaims memory aggressively enough that a fully cached file can go cold in fifteen seconds.

Reads came from ; the page-by-page counting came from a small C tool I wrote that s a file and asks which of its pages are resident.

You're not addressing the disk, you're addressing the page cache The model most of us carry is that goes and gets bytes off a device.

It doesn't.

It copies bytes out of the page cache into your buffer, and the page cache is just RAM the kernel uses to remember parts of files.

If what you want is already there, no device is involved.

If it isn't, the kernel fills the cache first and then copies.

Either way the thing your program talks to is memory, and the disk is somebody else's problem one layer down.

You can watch this from outside.

Drop the caches, read one page, and count: four pages resident.

Read nothing at all and count again: zero.

The file didn't change and neither did the syscall.

How much it fetches depends on what it thinks you're doing Once the kernel does have to go to the device, it faces a question your call never answered: how much should it bring back?

Fetching exactly what you asked for is the honest answer and usually the wrong one, because the kernel is built on the assumption that a program reading one block will want the next.

So it speculates, and how far it speculates depends on how much evidence it has.

Reading sequentially from cold, one page at a time, the window opened up like this: four pages, then twelve, twelve, twelve, thirty-one, thirty-one.

Then it stopped.

The configured ceiling should be thirty-two, which is at 128 KiB over a 4 KiB page.

I measured thirty-one, twice, and I haven't chased down the missing page.

If you know why, I'd like to hear it.

The part that genuinely surprised me is where the evidence lives.

Each read was a separate process with a fresh file descriptor and no history of its own, so per-descriptor state can't explain a window that grows across independent invocations.

It works because looks backwards through the page cache for the traces a sequential reader leaves behind.

The cache is shared.

Access patterns leak between processes that know nothing about each other, and one program's reads change the shape of another's.

Two doors to the same bytes, two different answers isn't the only way in.

You can a file and touch the memory, and the same page cache serves you through a different door.

The doors don't behave alike.

One touch of a mapped page brought back thirty-two pages where the equivalent brought four.

And the window was centred on the page I touched rather than starting there: I faulted page 100 and got pages 84 through

115.

That centring is the kernel admitting how little it has to work with

分享
Baike.dev

baike.dev helps you discover great languages, frameworks, databases, DevOps and cloud-native tools.

Quick links

About

Contribute

Found a great developer tool? Share it with the community.

Submit a tool
© 2026 baike.dev Developer EncyclopediaUpdated daily · Discover great developer tools