Luther Monson, Staff Software Engineer at SUSE

Luther Monson

Go by way of PHP · Containers · VMs · Windows · Kubernetes

Atomic File Replacement on NTFS Is Not rename + fsync

The Unix recipe for durable atomic file replacement doesn't translate to Windows. This is what shipmates uses instead, plus the delete-pending window that made an 8-way test fail only when the whole suite ran.

7-Minute Read

How long a losing concurrent replacer waits on NTFS, idle disk vs a disk under fsync load

shipmates writes a lot of small state files that other processes read. Voyage plans and state, tracker files. Each of them has to be replaced atomically, so a reader sees the old file or the new one and never half of each. Each also has to be replaced durably. When the function returns success, a power cut doesn’t take it back. Every Unix programmer knows the recipe for that. It doesn’t work on Windows, and the reasons are more interesting than “Windows is different”.

Rescuing a Windows Dynamic Disk Over USB with WSL2 and USB/IP

Windows refused to bring an old dynamic disk online over USB. Handing the raw USB device to WSL2's Linux kernel with usbipd-win got every file back.

10-Minute Read

GPT layout of the 1 TB drive with LDM metadata and a 930 GiB LDM data partition, and the two paths: the Windows storage stack refusing it and usbipd passing it to WSL2

I pulled a 1 TB NVMe out of an old Windows box, dropped it in a USB enclosure and plugged it in. Windows showed nothing. No drive letter, no “initialize this disk” prompt, nothing in Explorer. Disk Management listed it as Invalid. The enclosure’s booklet said to “bring the disk online”, which silently did nothing. The data was completely intact. Windows was refusing on policy grounds, not because anything was broken. Getting it back meant going around the Windows…

Fixing Windows Archive Extraction in SPC

"The pipe has been ended" wasn't a pipe problem. It was the wrong tar program and Windows symlinks, and fixing one line of static-php-cli took three tries.

7-Minute Read

Diagram: 7za decompressing into a pipe read by MinGW tar, which exits on a C:\ path and leaves 7za reporting The pipe has been ended

One of the first things that broke when I started building PHP on Windows with static-php-cli (SPC) wasn’t PHP at all. It was unpacking the source tarballs. libxml2, xz and a couple of others would die partway through extraction with:

Escaping WSL: Booting My Own Linux VM Through Hyper-V's HCS API

WSL2 refuses to run under LocalSystem, so ephemerd boots an Alpine kernel directly through vmcompute.dll instead.

9-Minute Read

Diagram of ephemerd booting a Linux VM through HCS and reading its IP from the serial console

I’ve been building ephemerd, a daemon that runs self-hosted GitHub Actions runners with a fresh environment per job. On a Windows host, Windows jobs run in Hyper-V isolated containers. Linux jobs still need a Linux kernel from somewhere. The obvious answer on Windows in 2026 is WSL2, and that’s what I used first. It worked great from my terminal and fell over the moment ephemerd became a real Windows service.

go-diskfs: Getting Rock Ridge Working for Joliet on Windows

I fixed Rock Ridge and added Joliet to go-diskfs so a Go-built cloud-init ISO works for cloudbase-init. Then I found out what Windows actually wanted.

10-Minute Read

Sector map of a cidata ISO built by go-diskfs with a Rock Ridge primary tree and a Joliet supplementary tree sharing the same file extents

go-proxmox has had a CloudInit() helper since 2023. It builds a small nocloud ISO in Go, uploads it to Proxmox and mounts it on the VM as a CD-ROM. It’s always worked fine for Linux guests. It has never worked for Windows guests running cloudbase-init. The reason is a filesystem extension from 1995 called Joliet.

Maintaining a Go Tool That Edits /etc/hosts on Every OS

Notes from maintaining goodhosts, the hosts file CLI and Go library behind vagrant-goodhosts and ddev. It covers Windows quirks, a HostsPerLine bug, and making the CLI testable.

8-Minute Read

hosts file output from hostsfile v0.1.4, v0.1.5 and v0.1.6 for the same sequence of adds

Editing the hosts file sounds like the most boring problem in software. Read a text file, add a line, write it back. Then you find out your binary is being shelled out to from a Ruby Vagrant plugin on a Windows laptop with UAC prompts. Your library is being called in a loop by ddev. And every hosts file you parse was hand-edited by somebody at some point. I’ve been maintaining goodhosts for a few years now. I just spent a chunk of the fall and the holidays on it, so here’s what that…

Recent Posts

Categories

About

Luther is a 20+ year software veteran specializing in backend APIs and architecting products. Employed at SUSE as the Team Lead for the Containers on Windows Team working on Rancher + Kubernetes