In the previous article
we followed a read() all the way down through the VFS: from the syscall, to the struct file, to ext4, and into the page cache. And there was exactly one moment where we skipped over the details. When the page cache missed — the bytes weren’t in memory yet — the filesystem had to actually go and fetch them, and all we said was that it “reads the disk, through the block layer.” That’s the moment we’re going to open up now.
In the previous article
we saw how the scheduler decides which task gets the CPU — so at this point we know how programs get to run. But running isn’t enough: for a program to be useful, it almost always needs to read and store data — its config from /etc, a shared library from /usr/lib, the rows of a database file, the document you’re saving. So the natural next question is: what actually happens when a program opens a file?
In the previous article
we looked at how the kernel gives every process its own private view of memory. But memory is only half of what a process needs to actually run. The other half is the CPU itself — and there are only so many CPUs in a machine, while there are usually hundreds or thousands of things that want to run on them.
So somebody has to decide, constantly, who gets a CPU and for how long. That somebody is the scheduler. Every few milliseconds, on every core, the kernel asks itself the same question — of everything that wants to run right now, who runs next? — and the answer has to be fast, fair, and good enough that your text editor stays responsive even while a compile is pegging every core.
In the previous article
we looked at how a user program crosses the ring 3 → ring 0 boundary to ask the kernel for help. The example we used was read() — a file descriptor, a buffer pointer, a byte count. But we glossed over something important: what is that buffer? Who decided it existed? Who owns the physical RAM behind it?
Those questions are what the memory manager answers. And it answers them for every process on the machine, simultaneously, for every allocation that has ever happened since boot. It’s one of the most complex subsystems in the kernel, so I want to approach it the way you’d approach an unfamiliar library — start at the front desk with the catalog, then walk back through the stacks.
In the previous article
we followed the kernel from the very first instruction the bootloader handed us all the way to the moment kernel_init called execve() on /sbin/init. That was a long ride, but it ended with a quiet handover: the kernel stepped aside, userspace took the wheel, and /sbin/init started spawning the rest of the services.
Here’s the thing though. Those processes that just started don’t actually have keys to anything. They can’t touch the disk. They can’t talk to the network card. They can’t even draw a pixel on the screen. Every piece of hardware in the machine is still owned by the kernel, and the CPU itself enforces this: user programs run in a restricted execution mode (ring 3 — the unprivileged mode where hardware blocks direct access to kernel memory or devices). Userspace is sandboxed by hardware, on purpose.
Have you ever wondered what really happens between the moment you press the power button and the moment your login screen shows up? That gap—usually some seconds—hides one of the most intricate initialization sequences in computing. Today I want to walk you through it.
This is the first article in a series where I’ll try to make sense of the Linux kernel internals together with you. We’ll talk about how Linux boots, how it manages processes and memory, how it deals with hardware, and so on. If you’ve ever been curious about what’s happening under the hood, you’re in the right place.
This website uses cookies to analyze traffic and improve your experience.
Privacy Policy