All posts

linux

23 posts
AI

An AI Coworker in an LXC Container

A dedicated container on my Proxmox host runs a coding agent that writes, reviews, and ships changes to this site — through the same git-push pipeline I use. The interesting engineering isn't the model; it's the guardrails around it.

LINUX

The Fleet: Six Machines, and What the Hypervisor Can't Do

The plan was to consolidate everything onto one Proxmox box. Then a perf tool needed real PMU counters, a firmware flash needed a real serial port, and testing on ARM meant a phone running a custom kernel. Meet the fleet — and what each machine taught me.

PERFORMANCE

Reading Flame Graphs: Where Your CPU Time Actually Goes

A flame graph turns thousands of stack samples into one picture where width is time and the widest boxes are your problem. How sampling profilers work, how to read the graph in ten seconds, and the traps — inlining, wait time, broken stacks — that mislead beginners.

LINUX

mmap vs read(): When Mapping a File Actually Wins

mmap is sold as the fast way to read files, but it loses as often as it wins. The deciding factor is page faults versus syscalls — and whether you touch the data once or many times.

OBSERVABILITY

eBPF: Running Your Code in the Kernel Without a Module

For decades, changing kernel behavior meant writing a kernel module and risking a panic. eBPF lets you load sandboxed programs into a running kernel safely — and it's quietly become the backbone of modern observability and networking.

CONTAINERS

What a Container Actually Is: Namespaces and cgroups

A container isn't a lightweight VM — there's no guest kernel, no virtual hardware. It's just a normal Linux process wearing two kernel features as a disguise. Strip away Docker and the magic is surprisingly small.

KERNEL

Interrupts: How Hardware Taps the Kernel on the Shoulder

A packet arrives, a key is pressed, a timer fires — and the CPU drops everything, mid-instruction-stream, to run kernel code. How interrupts work, why handlers are split in half, and how NAPI killed the interrupt storm.

LINUX

epoll: The Syscall Under Every Event Loop

nginx, Node, Redis, and every async runtime you use sit on one Linux primitive. Why select died at scale, how epoll inverts the cost model, the level- vs edge-triggered trap, and the thundering herd that took years to fix.

PERFORMANCE

Zero-Copy I/O: Stop Paying to Move Bytes You Never Touch

A naive file-to-socket server copies every byte four times and crosses the kernel boundary twice per chunk. sendfile collapses it to zero user-space copies — and the lineage from there (splice, MSG_ZEROCOPY, io_uring) is the story of modern fast I/O.

LINUX

The VFS: How 'Everything Is a File' Actually Works

The same read() works on ext4 files, /proc fictions, sockets, and pipes because Linux routes every file operation through one dispatch layer. The VFS is the kernel's biggest interface — and its object model is worth stealing.

KERNEL

How Linux Decides What Runs Next: CFS to EEVDF

For 15 years Linux picked the next task with a red-black tree of virtual runtimes. In 6.6 that changed for the first time since 2007. What fairness actually means, how nice values work, and why latency-sensitive tasks forced a redesign.

LINUX

Anatomy of a System Call: What read() Really Costs

A function call costs ~2ns. A syscall costs ~100ns before doing any work — and that's after decades of optimization plus a Spectre-era tax. Where the time goes, why vDSO exists, and what that means for API design.

NETWORKING

NAT and conntrack: The Stateful Lie Your Router Tells

NAT rewrites addresses; connection tracking is the memory that makes the rewrite reversible. Together they're why the internet survived IPv4 exhaustion — and why your idle SSH session dies, your table overflows, and P2P needs hole-punching.

LINUX

Unix Signals: The API Everyone Uses and Nobody Uses Safely

Signals interrupt your program between any two instructions and run your handler in the wreckage. Why almost everything is illegal inside a handler, what async-signal-safe really means, and the self-pipe/signalfd escape hatches.

KERNEL

How the Kernel Allocates Memory: Buddy and Slab

malloc has a supplier: the kernel's own allocators. The buddy system deals in power-of-two page blocks and fights fragmentation with math; the slab layer turns pages into typed object caches. Between them, every allocation on your machine.

LINUX

From ./a.out to main(): What exec Actually Does

Between pressing enter and your first line of code, the kernel parses an ELF file, maps segments, loads an interpreter you didn't know existed, and that interpreter relocates half your program. A tour of the machinery under ./a.out.

CONCURRENCY

Spinlocks vs Mutexes: When Burning CPU Is the Right Call

One lock burns CPU while it waits; the other pays a syscall to sleep. The right choice depends on hold time versus context-switch cost — and the best answer, futexes and adaptive locks, is 'both, in that order'.

NETWORKING

DNS Resolution: Every Hop Between You and an IP Address

A 'simple' name lookup traverses your language runtime, nsswitch, a stub resolver, a recursive resolver, and up to three tiers of authoritative servers — with caches at every layer that disagree. Map the path once and DNS bugs become findable.

SECURITY

ASLR: Security by Shuffling the Address Space

Every exploit needs an address; ASLR's bet is that the attacker shouldn't know any. How Linux randomizes stack, heap, and libraries, why PIE took years to become default, and the leak-one-pointer reality that keeps ASLR a speed bump, not a wall.

LINUX

fork() and Copy-on-Write: Duplicating a Process for Free

fork clones a 10 GB process in under a millisecond by copying nothing — just page tables, marked read-only. The first write to any page pays the real cost. Elegant, and the source of Redis's most famous operational trap.

NETWORKING

The TCP State Machine: Where Connections Actually Live

Eleven states, two of which cause most production incidents. Implementing TCP taught me the state diagram isn't trivia — TIME_WAIT port exhaustion, SYN backlogs, and orphaned FIN_WAIT_2 are all right there in the RFC 793 figure.