How the Linux kernel works: processes, memory, files and networks

Updated November 2026

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.

User space: applications, shells, services, C library (glibc, musl) System call interface (read, write, clone, mmap, socket, bpf …) Scheduler EEVDF, RT Memory pages, cache VFS ext4, btrfs … Network TCP/IP, sockets eBPF verified hooks Device drivers and loadable modules Hardware: CPUs, RAM, disks, network cards, GPUs, USB
The main layers. Everything below the system call line runs in kernel mode, with full access to the hardware.

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:

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:

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