Nix solves the package manager ejection problem
This blog post operates on two levels.
On a very direct level, I built a desktop machine with an AMD Radeon RX 5600 XT graphics card and I’ve been fighting a rather annoying interaction with dual monitors on Linux. Here’s how it goes:
- After some defined period of inactivity, the system tries to standby / suspend / turn off both monitors.
- Both monitors respond to the DPMS commands and briefly blank.
- After a few seconds, one of them comes on again, quickly followed by the other one, in an arbitrary order.
- XFCE “helpfully” detects this as a monitor hotplug event and pops open a display configuration dialog.
Stepping away to make a coffee now means periodic flickering and coming back to 5 - 10 XFCE monitor configuration dialogs taking over my screen. Very annoying!
Googling around finds this Ubuntu issue from 2018 that seems to describe the same problem, but the documented workaround of amdgpu.dc=0
as a kernel parameter does not work. My graphics card decides to go into a glitchfest and the kernel doesn’t even make it past initrd.
That Ubuntu issue links to this upstream Freedesktop issue, which is old enough to get migrated to this new Freedesktop issue, where some kind soul has put together a patch that applies cleanly on recent kernels. My understanding is that the monitor starts polling its inputs when it enters a DPMS mode, and the patch adjusts the timeouts on the driver to ignore the polling pulses instead of treating them as hotplug events.
So that’s one level: write a blog post, stuff it with enough keywords that other affected users can find it, tell them to USE THE KERNEL PATCH until a fix is integrated into the mainline. A decent public service, but on its own not interesting.
On a second level, I’ve recently been experimenting with NixOS as my daily driver and it rises to this challenge in ways that ArchLinux never could.
Package management on Linux has a colourful history, with various distributions intermixing technology with philosophy to produce whole system configurations that real people can run on real machines with varying amounts of productivity. You have the Slackware “our packages are just tarballs you can extract over /
”, the slightly more principled dpkg and RPM’s of the world, the source-first approach preferred ArchLinux, and the “invent the universe to bake a pie” doctrine that is Linux From Scratch.
However, all of them share the fundamental notion of what it means to be a package: a monolithic reusable artifact that can be installed on a user’s machine. (Okay, Linux From Scratch doesn’t really belong in this category, but does it really belong anywhere?)
And there lies the dilemma: if the user needs to go off the beaten path, like patch the damn Linux kernel, they must roll their own package. Sure, some distributions will let you reuse their package building recipe and make the process straightforward, but:
- You are now no longer a package consumer, you are now a package developer, which is considered its own distinct category.
- Which means you get none of the nice workflows that package consumers enjoy. You are responsible for tracking security disclosures, software updates, and rebasing your changes on top of whatever base you’re building off.
Put another way: the package development workflow does not compose.
In contrast, NixOS makes patching the kernel a four liner:
boot.kernelPatches = [{
name = "amdgpu-sleep-fix";
patch = ./amdgpu-sleep-fix.patch;
}];
And the “contrast” here isn’t how easy NixOS makes this (though that is appreciated), it’s that the intention of “build the existing NixOS kernel with just this patch applied” is being purely captured. That’s only possible here because the package management strategy is underpinned by a real programming language where it is derivations all the way down.
There is no distinction between being a “package consumer” and a “package developer” here. I get all the updates that the people responsible for the NixOS kernel put out with no continuous maintenance on my part.
The JavaScript community has a good word for this kind of “stay on the beaten path and get updates” or “do your own thing but carry the maintenance and complexity burden”. They call it ejection.
NixOS (and Nix, which is the practical underpinning that makes this all possible) present a composable solution to this package management ejection problem. And that is interesting!
On Gentoo
An earlier version of this article lumped Gentoo into the same source-first approach as ArchLinux. John Helmert III reached out over email and totony on HackerNews pointed out that Portage has grown to be far more sophisticated than I gave it credit for.
Portage supports a generalized mechanism for patching software that seems like it would have worked just as well here (with fewer lines of code if you will).
I only have a surface level understanding, but it seems like the ebuild itself cannot be patched, so there is no analogue to the Nix override design pattern; meaning there is still some distinction between “package consumer” and “package developer”. However, this is a pragmatic blog post motivated by a real problem, and it seems like Gentoo is quite capable of rising to the specifics of this situation. Fair play!
Changelog
2021-06-06: Credit John Helmert III by name.
2021-05-31: Added a section on Gentoo and Portage.
2021-05-30: Published.