How the Linux kernel works: processes, memory, files and networks
The Linux kernel is the program that owns the hardware. It decides which process runs on which CPU, gives every process its own view of memory, turns disks into files and directories, moves network packets, and drives devices. Programs reach all of it through system calls. This page walks through each part as it works in current kernels (7.3.1 stable and 7.4-rc1 in testing, as of November 2026), with links to the official documentation at docs.kernel.org.
David Rusling's classic book The Linux Kernel, written for the 2.0 kernels of the late 1990s, is kept by the Linux Documentation Project at tldp.org. Its outline (processes, memory, file system, networks, modules) still matches the kernel's structure; most details inside have changed.
Kernel and user space
The CPU runs in two modes. Kernel code runs privileged; programs run unprivileged and cannot touch hardware or other processes' memory. A system call switches into the kernel and back. Linux is a monolithic kernel: the scheduler, file systems, network stack and drivers all run in one address space, for speed. Loadable modules add code to it at run time; see the kernel module guide.
Processes and scheduling
Inside the kernel, every thread is a task described by a task_struct: its state, memory map, open files, credentials and scheduling data. A process is a group of tasks that share memory and file descriptors. fork() and pthread_create() both end up in the clone() system call, with flags saying what to share.
The scheduler picks which runnable task gets each CPU. It has classes in strict order: deadline tasks (SCHED_DEADLINE), then real-time tasks (SCHED_FIFO, SCHED_RR, priorities 1 to 99), then normal tasks (SCHED_OTHER, SCHED_BATCH, SCHED_IDLE), which is where almost everything runs.
For normal tasks, Linux began moving from CFS (the Completely Fair Scheduler, used since 2.6.23) to EEVDF, "Earliest Eligible Virtual Deadline First", in version 6.6. The idea:
- Each task should get a fair share of CPU time, weighted by its nice value (-20 is the highest priority, +19 the lowest).
- The difference between the time a task was owed and the time it got is its lag. Positive lag means the task is owed time and is eligible to run; negative lag means it has had more than its share.
- Among eligible tasks, each gets a virtual deadline based on its time slice, and the one with the earliest deadline runs. Tasks that ask for shorter slices, typically latency-sensitive ones, get to run sooner, and a task can request a slice with
sched_setattr().
Since 6.12 the kernel also includes sched_ext, a scheduler class whose policy is written as eBPF programs loaded from user space. If such a scheduler fails or stalls, the kernel switches all tasks back to the fair scheduler. cat /sys/kernel/sched_ext/state shows whether one is active.
Control groups (cgroup v2) organize processes into a tree and share resources along it: cpu.max limits CPU time, memory.max sets a hard memory limit, pids.max limits the number of tasks. systemd puts every service in its own cgroup. Look at a task's scheduling statistics in /proc/PID/sched, and change a policy with chrt.
Memory management
Every process sees its own virtual address space. The CPU translates each virtual address to a physical one through multi-level page tables that the kernel maintains. Memory is handled in pages, whose size depends on the architecture (4 KB on x86-64 by default). Huge pages (2 MB or 1 GB on x86) cover more memory per page-table entry and reduce translation cost; Transparent Huge Pages (THP) use them automatically, hugetlbfs on request.
Memory is given out lazily (demand paging): malloc() or mmap() only reserves addresses, and real pages arrive on first use. Two big kinds of memory:
- Page cache: file data read from or written to disk is kept in RAM so the next access is fast. Changed ("dirty") pages are written back later. This is why
free -hshows most memory as "buff/cache" on a busy system: it is reusable. - Anonymous memory: heap, stack and private mappings not backed by a file. Under pressure it can only be moved to swap.
When free memory falls below a watermark, the kswapd thread reclaims pages in the background: it drops clean cache pages, writes back dirty ones and swaps out anonymous memory. If allocations still cannot be met, tasks reclaim directly, and as a last resort the OOM (out-of-memory) killer ends a process to keep the system alive. journalctl -k | grep -i oom shows when that happened. Physical memory is also divided into zones (for example memory usable for older DMA devices), and compaction moves pages to create large contiguous blocks.
The virtual file system
The VFS is the layer that lets open(), read() and write() work the same on ext4, XFS, btrfs, NFS, a USB stick or /proc. Each file system fills in tables of operations for four kinds of object:
- Superblock
- One mounted file system.
- Inode
- One file or directory: owner, permissions, size, where the data is.
- Dentry
- A name-to-inode link. Dentries exist only in RAM, in the dentry cache, so that path lookups are fast.
- File
- One open file in a process, with its current position. This is what a file descriptor points to.
Opening /home/ana/notes.txt walks the path one component at a time through the dentry cache, asks the file system's lookup() for any part not cached, then creates a file object and returns a descriptor. A file system registers itself with register_filesystem(); cat /proc/filesystems lists the registered types. Pseudo file systems use the same machinery to expose kernel data: /proc for processes, /sys for devices and drivers, cgroupfs for control groups.
The network stack
Programs use sockets. Below the socket layer, each packet travels in a struct sk_buff ("socket buffer") through the protocol layers (TCP or UDP, then IPv4 or IPv6) to a net_device, the kernel's view of a network interface, whose driver hands it to the hardware. Receiving works in reverse. With NAPI, a card raises an interrupt for the first packets and the kernel then polls it for more, which keeps the CPU from drowning in interrupts at high packet rates.
Along the way, netfilter hooks let nftables filter and rewrite packets, the traffic-control layer (tc) queues and shapes them, and XDP runs eBPF programs on packets straight off the driver, before an sk_buff is even built. Inspect the stack with ip and ss; see the Firewall HOWTO and Advanced Routing HOWTO.
eBPF: safe programs inside the kernel
eBPF lets you load small programs into the running kernel without writing a module. Before a program runs, the verifier checks it: it walks every possible path, rejects unbounded control flow and unreachable code, tracks what each register holds, and refuses memory accesses that are out of bounds or through invalid pointers. Programs attach to hooks (system calls, tracepoints, kernel functions, network devices, cgroups, the scheduler) and keep data in maps that user space can read.
Uses include tracing and observability tools (bpftrace, the BCC tools), fast packet processing with XDP, container networking, security policy, and sched_ext schedulers. Programs are usually written in C, compiled with Clang to BPF bytecode, and loaded with the libbpf library; BTF type information lets one compiled program run on many kernel versions. sudo bpftool prog list shows what is loaded on your system.
Devices and drivers
Drivers register with bus subsystems (PCI, USB, platform devices described by ACPI or device tree). When the kernel finds a device, it sends an event to user space; udev then loads the right module, creates the /dev node and applies rules. Interrupt handlers do the minimum, and the rest of the work runs later in softirqs, tasklets, workqueues or threaded interrupts. See the devices and drivers HOWTO.
Reading the source
The top-level directories of the kernel tree map onto this page: kernel/ (including kernel/sched/), mm/, fs/, net/, drivers/, arch/ for each CPU family, and Documentation/, which is published at docs.kernel.org. To try changes, build your own kernel and run it in a virtual machine.
Sources
- The Linux Kernel Archives: current releases
- EEVDF scheduler, Linux kernel documentation
- Extensible scheduler class (sched_ext), Linux kernel documentation
- Linux 6.12 release summary, KernelNewbies
- sched(7): scheduling policies, man7.org
- Control group v2, Linux kernel documentation
- Memory management concepts overview, Linux kernel documentation
- Overview of the Linux virtual file system, Linux kernel documentation
- Linux networking and network devices APIs (struct sk_buff), Linux kernel documentation
- NAPI, Linux kernel documentation
- BPF documentation index and eBPF verifier, Linux kernel documentation