Ashok G

Kernel, Traced

Read the path. Trace the path. Change the path.

Linux, Observed builds a system and watches it from the outside. This series goes inside. Each chapter takes one thing the kernel does — open a file, create a process, pick the next task, fault a page in, send a packet, verify a BPF program — and follows it through the actual source, file and function, from the system-call boundary to the point where the work happens. Then it does two things most kernel write-ups don’t:

The kernel is a 30-million-line codebase. The trick is that any one path through it is a few dozen functions, and the paths you care about are the ones your programs exercise every millisecond. Read twelve of them properly and the rest of the tree stops being a wall.

Format of every chapter

  1. The question — the one-sentence thing we want to know. “When a process calls connect(), where exactly does the kernel decide where the SYN goes?”
  2. The path — the annotated call chain: file.c:function() at each step, what it does in one line, and the one data structure it works on. Kernel version pinned (6.12 LTS unless stated); line numbers avoided because they rot, function names kept because they don’t (much).
  3. Trace it — a step-by-step lab with the function_graph filter or bpftrace script for that path, and what to look for.
  4. Change it — the patch or BPF program, with the prediction you should test.
  5. The takeaway — the one design idea the path embodies, stated once.

Prerequisites

Start with chapter 0, which builds the kernel and virtual machine every experiment uses. You can read C and aren’t afraid of a macro. You have the source tree checked out at the tag you’re running, and cscope or an LSP (clangd with compile_commands.json from scripts/clang-tools/gen_compile_commands.py) so you can jump to definitions. That last one is not optional; reading the kernel without jump-to-definition is reading it blind.

The map

Keep one text file, map.txt, throughout: every function you’ve read, one line each — file, name, what it does, which chapter. By chapter 12 it will be the most useful kernel document you own, because it’s the kernel you have walked. There’s a version at /kernel/map as a starting point and a cross-check.

The chapters name the kernel version they were checked against.

Chapters

  1. 0Set up the machineBuild Linux 6.12 with tracing turned on, boot it under QEMU, and check everything before you start.Draft
  2. 1A system call, from syscall to returnThe instruction, the entry stub, the dispatch, the work, and the long way back to user mode.Draft
  3. 2open(): the path walkFrom a string to a struct file: namei, the dentry cache, mount crossing, permission checks, and the filesystem's turn.Draft
  4. 3fork() and exec(): making a processcopy_process line by line, what a new task shares and what it owns, and the moment exec throws it all away.Draft
  5. 4The scheduler picks the next taskschedule(), the runqueue, EEVDF as completed in 6.12, the context switch, sched_ext, and a prediction you can check.Draft
  6. 5A page faultFrom the CPU's #PF exception to a mapped page: the fault handler, the VMA lookup, the three kinds of fault, and a patch that makes copy-on-write visible.Draft
  7. 6The page cache and readaheadread() from the top: the folio lookup, the readahead window, the filesystem's read path, and the block layer underneath.Draft
  8. 7connect(): where the SYN is bornFrom the connect() system call to the first segment on the wire: every function on the path, the places policy can speak, and a BPF program that moves the destination before the route exists.Draft
  9. 8A packet out: send() to the NICtcp_sendmsg to ndo_start_xmit: segmentation, the egress BPF hook, netfilter, the qdisc, the driver ring, and one program that drops a flow.Draft
  10. 9A packet in: NIC to recv()Interrupt, NAPI, XDP, GRO, the protocol demux, the socket queue and the wakeup, with the two earliest places a program can run.Draft
  11. 10bpf(): the verifierHow a BPF program goes from bytes to running kernel code: the load, the verifier's symbolic execution, the helper checks, the JIT, and a program you fix one line at a time.Draft
  12. 11LSM hooks and cgroups: where policy attachessecurity_* calls, static-call slots, BPF LSM; css_set, cgroup migration, and how a program attached to a parent runs for every child.Draft
  13. 12Signals, timers and RCU: three mechanisms every path usesHow a signal is queued and delivered on the way back to user mode; how nanosleep() turns into an hrtimer and a schedule(); and what synchronize_rcu() is actually waiting for.Draft
  14. ·The mapEvery function read in the series, one line each: file, name, what it does, chapter. The kernel you have walked.