Interview Prep Zoneby CuriouserLabs

Question 1 of 5 · senior level

Walk through what actually happens when a process calls read() on a file.

🎤 Say this first

read(fd, buf, n) traps into the kernel; the FD indexes the process's file table to the inode; the kernel checks the page cache first — hit: memcpy to your buffer, return (µs, no disk). Miss: the file system maps file offset → disk blocks (via inode/extents), submits a request through the block layer (merged, scheduled), DMA moves data into page-cache pages, an interrupt signals completion, then the copy to user space happens and your thread — which was blocked (WAITING, not consuming CPU) the whole time — becomes runnable. Plus readahead: the kernel detects sequential patterns and prefetches, which is why sequential reads of warm files feel like RAM.

The full picture

  • Layer stack to narrate: syscall → VFS (the polymorphic interface every FS implements — 'file systems are strategy objects') → page cache → concrete FS (ext4/XFS: offset→extent mapping) → block layer (merge/sort/schedule) → driver → device (DMA + interrupt).
  • The page cache is why 'disk reads' are usually memory reads: free RAM is spent caching file pages (that's the confusing free -h buff/cache column — it's available). Second read of a file = pure memcpy. Databases either embrace it (Postgres) or bypass it with O_DIRECT to manage their own (Oracle, and Kafka's design leans on the cache deliberately).
  • 'Blocked' is free: while the disk works, your thread is off the run queue — the CPU runs someone else. Blocking I/O wastes a thread, not a core — the precise statement that motivates both epoll and virtual threads (they attack the wasted-thread problem, not a wasted-CPU problem).
  • Writes are the mirror with a twist: write() usually just dirties page-cache pages and returns — the disk write happens later (writeback). Durability is a separate contract — the fsync question, two questions down.

🔄 Likely follow-up questions

  • What changes with O_DIRECT, and why do some databases want it?
  • How does readahead detect and exploit sequential access?
  • Where do short reads come from, and why must robust code loop on read()?