Virtual File Systems: An Abstraction Over Real Storage
Building an Operating System Kernel: Concurrency, I/O & Synchronization
Chapter 8 · Virtual File Systems: An Abstraction Over Real Storage
Chapter 6 built one real device. A real system has many — RAM, disk, and often things that aren't devices at all but need to look like files anyway. A virtual file system is the layer that makes all of them answer to the same calls. This chapter builds a small, real one, then asks a genuine question: can this site's own Building a Database Engine project's real record-oriented storage be mounted underneath it?
Finding 1: One Interface, Two Genuinely Different Real Backends
MemoryBackend wraps a real page table plus physical memory frames — reusing Course 1's own translate() pattern directly. DiskBackend is a completely separate byte array standing in for disk sectors. The exact same vfs.read()/vfs.write() calls correctly reach both — b'HELLO FROM RAM' and b'HELLO FROM DISK', each round-tripped correctly through its own path. Calling code never needed to know which backend served which.
Finding 2: Real Mount-Point Isolation
b'AAAA' to /a at offset 0 and b'BBBB' to /b at the same offset 0 never collides — each mount resolves that offset through its own, completely independent page table. The VFS's own path-based routing is what keeps genuinely separate storage genuinely separate.
Finding 3: A Genuine Investigation — Does a HeapFile Mount Cleanly?
Building a Database Engine's own storage is fundamentally record-oriented: insert_record(data) → record_id, get_record(record_id) → data. A real, minimal version of that same interface, put directly to the test:
MinimalHeapFile directly under the VFS and calling read() raises: 'MinimalHeapFile' object has no attribute 'read'. Its own real interface has no byte-offset concept at all — record placement is chosen by the heap file itself, and records vary in length. "Offset 10" means nothing to a store with no stable, caller-addressable byte space in the first place.
Finding 4: A Real, Working Adapter Bridges the Two Interfaces
write() is deliberately unsupported and raises NotImplementedError — an honest scope limit, not a silent failure: records are inserted, never addressed by a caller-chosen byte offset. Mounting a genuinely different kind of storage under a uniform interface was possible — but it needed a real adapter, not a direct mount.
Where This Connects
| This chapter's finding | What it connects to |
|---|---|
| MemoryBackend's own translate() logic | Course 1 Chapter 6's own Syscall class — the identical page-table-translation pattern, reused directly |
| A genuine interface mismatch found by actually trying it | oskernel1's own capstone pick_next() mismatch — both real incompatibilities surfaced only by attempting the real integration, not by reasoning about it in the abstract |
| HeapFile's own record-oriented interface | Building a Database Engine's own Storage & Query Fundamentals Chapter 3 — the real course this adapter connects to |
| A deliberately read-only adapter | Chapter 5's own MessageQueue — both chapters scope an abstraction honestly rather than faking support for an operation that can't be done correctly |
Hands-On Exercises
Read from a path that was never mounted. Confirm it fails with a clear, immediate error rather than silently returning empty data, and explain why that distinction matters.
📄 View solutionMount a second, different backend at a path that's already mounted. Confirm what happens to the original backend's own data, and explain why this is a real, honest gap worth knowing about.
📄 View solutionRead a byte range through the HeapFileByteAdapter that falls entirely within a single record, rather than spanning two. Confirm it's handled correctly by the same unmodified read() method Finding 4 used for the cross-record case.
Chapter 8 Quick Reference
- VFS: one uniform
read(path, offset, length)/write(path, offset, data)interface, routing by mounted path - Verified Finding 1: the same calls correctly reach two genuinely different real storage media
- Verified Finding 2: mount-point routing keeps identical offsets on different paths genuinely isolated
- Verified Finding 3: a record-oriented HeapFile genuinely cannot mount directly — a real, confirmed interface incompatibility
- Verified Finding 4: a real, working (deliberately read-only) adapter bridges the two interfaces, verified across a real cross-record read
- Golden rule: a uniform interface doesn't mean every backend fits it for free — some genuinely need an adapter, and knowing which is a real, testable question, not a guess
- Next chapter: System Calls in Practice — a small syscall library tying process, memory, scheduling, and I/O together