From f8cc57f146f0bf84ebf3797763bcd9d6a80eda99 Mon Sep 17 00:00:00 2001 From: Else Someone Date: Wed, 11 Mar 2026 17:38:49 +0200 Subject: [PATCH 1/8] fixup! uvms: churn --- pkgs/uvms/uvms.py | 2 +- profiles/baseImage.nix | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/pkgs/uvms/uvms.py b/pkgs/uvms/uvms.py index ec4a139..d58fb28 100644 --- a/pkgs/uvms/uvms.py +++ b/pkgs/uvms/uvms.py @@ -354,7 +354,7 @@ class Processes: "--wayland-sock", f'{PASSTHRU_ENV["XDG_RUNTIME_DIR"]}/{PASSTHRU_ENV["WAYLAND_DISPLAY"]}', # noqa: E501 "--params", - '{ "context-types": "cross-domain" }', + '{ "context-types": "cross-domain:virgl2" }', ] with self.popen( *args, diff --git a/profiles/baseImage.nix b/profiles/baseImage.nix index 683f061..294c58e 100644 --- a/profiles/baseImage.nix +++ b/profiles/baseImage.nix @@ -16,6 +16,7 @@ let kernelTarget = pkgs.stdenv.hostPlatform.linux-kernel.target; waylandSock = "/run/user/1000/wayland-1"; env = { + DBUS_SESSION_BUS_ADDRESS = "unix:path=/run/user/1000/bus"; XDG_RUNTIME_DIR = "/run/user/1000"; WAYLAND_DISPLAY = "wayland-1"; @@ -104,6 +105,7 @@ in }; }; + programs.dconf.enable = true; systemd.mounts = [ { type = "virtiofs"; @@ -210,6 +212,7 @@ in }; environment.profileRelativeSessionVariables.PATH = lib.mkForce [ "/bin\${PATH:+:}$PATH" ]; + environment.sessionVariables = env; environment.variables = env; systemd.globalEnvironment = env; @@ -302,9 +305,9 @@ in uvms.ch.settings = mkOption { default = { }; type = types.submodule ( - let - osConfig = config; - in + let + osConfig = config; + in { config, ... }: { freeformType = jsonType; From 42fca624741704a2841e525bbeb3c2435f5f70a7 Mon Sep 17 00:00:00 2001 From: Else Someone Date: Wed, 11 Mar 2026 17:39:00 +0200 Subject: [PATCH 2/8] uvms: init app urls, kinda --- pkgs/uvms/uvms.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/pkgs/uvms/uvms.py b/pkgs/uvms/uvms.py index d58fb28..d89a6ff 100644 --- a/pkgs/uvms/uvms.py +++ b/pkgs/uvms/uvms.py @@ -13,6 +13,7 @@ import json import re from argparse import ArgumentParser from contextlib import contextmanager, closing, ExitStack +from urllib import urlparse parser = ArgumentParser("supervise-vm") @@ -517,11 +518,24 @@ def main(args, args_next, cleanup, ps): app_paths = [] for a in args.app: + a = urlparse(a) + nix_file = None + attr = None + if a.scheme == "": + nix_file = "" + attr = a.path + elif a.scheme == "getexe": + nix_file = a.netloc or "./." + attr = a.path.lstrip("/") + else: + raise RuntimeError("Unknown app url", a) + assert nix_file is not None, a + assert attr is not None, a out_path = ps.exec( "nix-build", - "", + nix_file, "-A", - a, + attr, "--no-out-link", capture_output=True, text=True, From a13e9c9393421e3df6d1daacb1e8c3baa18e84ce Mon Sep 17 00:00:00 2001 From: Else Someone Date: Sun, 15 Mar 2026 01:30:18 +0200 Subject: [PATCH 3/8] uvms: support args in app urls --- pkgs/uvms/uvms.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/pkgs/uvms/uvms.py b/pkgs/uvms/uvms.py index d89a6ff..9a8582c 100644 --- a/pkgs/uvms/uvms.py +++ b/pkgs/uvms/uvms.py @@ -13,7 +13,7 @@ import json import re from argparse import ArgumentParser from contextlib import contextmanager, closing, ExitStack -from urllib import urlparse +from urllib.parse import urlparse, parse_qs parser = ArgumentParser("supervise-vm") @@ -519,16 +519,21 @@ def main(args, args_next, cleanup, ps): app_paths = [] for a in args.app: a = urlparse(a) - nix_file = None + nix_file = "./." attr = None if a.scheme == "": nix_file = "" attr = a.path - elif a.scheme == "getexe": - nix_file = a.netloc or "./." - attr = a.path.lstrip("/") else: - raise RuntimeError("Unknown app url", a) + assert a.fragment, a + attr = a.fragment + nix_file = a.path or "./." + arglist = [] + for k, v in parse_qs(a.query).items(): + arglist.append("--arg") + arglist.append(k) + arglist.append(v) + assert nix_file is not None, a assert attr is not None, a out_path = ps.exec( @@ -536,7 +541,9 @@ def main(args, args_next, cleanup, ps): nix_file, "-A", attr, + *arglist, "--no-out-link", + cwd=os.getcwd(), capture_output=True, text=True, ).stdout.strip() From 0692a20ae93be8801d39a04c5ba280b4edf339db Mon Sep 17 00:00:00 2001 From: Else Someone Date: Sun, 15 Mar 2026 01:30:27 +0200 Subject: [PATCH 4/8] uvms: do not hang on communicate() --- pkgs/uvms/uvms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/uvms/uvms.py b/pkgs/uvms/uvms.py index 9a8582c..4833752 100644 --- a/pkgs/uvms/uvms.py +++ b/pkgs/uvms/uvms.py @@ -158,7 +158,7 @@ class Processes: print(f"Releasing {args}") finally: if subprocess.PIPE in (kwargs["stderr"], kwargs["stdout"]): - print(proc.communicate()) + print(proc.communicate(timeout=0.125)) while alive_after(proc, 0.125): try: proc.terminate() From 90614bdf749d48df8292cab215e4c25f42ab04b2 Mon Sep 17 00:00:00 2001 From: Else Someone Date: Sun, 15 Mar 2026 01:32:28 +0200 Subject: [PATCH 5/8] uvms: do not rm vsock.sock until vmm is down --- pkgs/uvms/uvms.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkgs/uvms/uvms.py b/pkgs/uvms/uvms.py index 4833752..b7443b4 100644 --- a/pkgs/uvms/uvms.py +++ b/pkgs/uvms/uvms.py @@ -464,7 +464,7 @@ def connect_ch_vsock( s.setblocking(blocking) s.connect(vsock_sock_path) - with removing(vsock_sock_path): + with closing(s): s.send(b"CONNECT %d\n" % port) yield s @@ -662,6 +662,7 @@ def main(args, args_next, cleanup, ps): assert ready + cleanup.enter_context(removing(ps.prefix + "/vsock.sock")) with connect_ch_vsock(ps.prefix + "/vsock.sock", 24601) as guest: for r in args.run: res = {} From 3540b5aba24fe933403d8afb3855af9a188df896 Mon Sep 17 00:00:00 2001 From: Else Someone Date: Sun, 15 Mar 2026 02:15:58 +0200 Subject: [PATCH 6/8] uvms: support .desktop applications --- pkgs/uvms/uvms.py | 3 +++ pkgs/uvmslib/uvmslib.py | 11 +++++++++++ profiles/baseImage.nix | 1 + 3 files changed, 15 insertions(+) diff --git a/pkgs/uvms/uvms.py b/pkgs/uvms/uvms.py index b7443b4..72d941c 100644 --- a/pkgs/uvms/uvms.py +++ b/pkgs/uvms/uvms.py @@ -678,6 +678,9 @@ def main(args, args_next, cleanup, ps): "EXTRA_PATH": [ f"{a}/bin" for a in app_paths ], # noqa: E501 + "EXTRA_XDG_DATA_DIRS": [ + f"{a}/share" for a in app_paths + ], # noqa: E501 } } ).encode("utf8") diff --git a/pkgs/uvmslib/uvmslib.py b/pkgs/uvmslib/uvmslib.py index d6279ae..9428edb 100644 --- a/pkgs/uvmslib/uvmslib.py +++ b/pkgs/uvmslib/uvmslib.py @@ -55,6 +55,16 @@ class Processes: "/run/current-system/sw/bin", ], ), + "XDG_DATA_DIRS": ":".join( + [ + *os.environ.get("XDG_DATA_DIRS", "").split(":"), + *run.get( + "EXTRA_XDG_DATA_DIRS", + [], + ), + "/run/current-system/sw/share", + ], + ), } proc = None try: @@ -116,6 +126,7 @@ def guest_main(): # IDK why but I keep getting empty messages if req == b"": print(f"Lost [{con.fileno()}]") + ps.sources = [s for s in ps.sources if s.fileno() != con.fileno()] continue try: req = json.loads(req) diff --git a/profiles/baseImage.nix b/profiles/baseImage.nix index 294c58e..66e95b8 100644 --- a/profiles/baseImage.nix +++ b/profiles/baseImage.nix @@ -212,6 +212,7 @@ in }; environment.profileRelativeSessionVariables.PATH = lib.mkForce [ "/bin\${PATH:+:}$PATH" ]; + environment.profileRelativeSessionVariables.XDG_DATA_DIRS = lib.mkForce [ "/run/current-system/sw/share/\${XDG_DATA_DIRS:+:}$XDG_DATA_DIRS" ]; environment.sessionVariables = env; environment.variables = env; systemd.globalEnvironment = env; From 42180096aff11da18e2fdac0c8695f1e36dc2098 Mon Sep 17 00:00:00 2001 From: Else Someone Date: Sun, 22 Mar 2026 16:19:11 +0200 Subject: [PATCH 7/8] baseImage: tinkering with overcommit --- pkgs/uvmslib/uvmslib.py | 4 ++-- profiles/baseImage.nix | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/pkgs/uvmslib/uvmslib.py b/pkgs/uvmslib/uvmslib.py index 9428edb..f7319bc 100644 --- a/pkgs/uvmslib/uvmslib.py +++ b/pkgs/uvmslib/uvmslib.py @@ -73,8 +73,8 @@ class Processes: text=text, env=env, cwd="/home/user", - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, + stdin=None, + stdout=None, ) res["status"] = "exec succeeded" except Exception as e: diff --git a/profiles/baseImage.nix b/profiles/baseImage.nix index 66e95b8..60a8cc5 100644 --- a/profiles/baseImage.nix +++ b/profiles/baseImage.nix @@ -45,6 +45,11 @@ in hardware.graphics.enable = true; # boot.kernelPackages = pkgs.linuxPackagesFor uvmsPkgs.linux-uvm; # boot.isContainer = true; + boot.kernel.sysctl = { + "vm.overcommit_memory" = 1; # "always" + # "vm.overcommit_memory" = 2; # "never" + "vm.panic_on_oom" = 1; + }; boot.initrd.kernelModules = [ "drm" "virtio_blk" From 8fb586c8b67d2a3d61dbbcf8742f7368c0ed0e72 Mon Sep 17 00:00:00 2001 From: Else Someone Date: Sun, 22 Mar 2026 21:25:48 +0200 Subject: [PATCH 8/8] cloud-hypervisor: clean up the short-circuiting logic --- pkgs/cloud-hypervisor-gpu.nix | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkgs/cloud-hypervisor-gpu.nix b/pkgs/cloud-hypervisor-gpu.nix index a99ce6f..6553b0e 100644 --- a/pkgs/cloud-hypervisor-gpu.nix +++ b/pkgs/cloud-hypervisor-gpu.nix @@ -34,10 +34,10 @@ cloud-hypervisor.overrideAttrs ( patches = patchesFromDir (spectrum + "/pkgs/cloud-hypervisor"); vhostPatches = patchesFromDir (spectrum + "/pkgs/cloud-hypervisor/vhost"); }; - previouslyPatched = oldAttrs ? spectrumPatches; - patchPhases = !previouslyPatched; + oldPatchesStruct = oldAttrs.passthru.spectrumPatches or { }; + missingPatchPhases = previouslyPatched != { }; isNewer = lib.versionOlder oldAttrs.spectrumPatches.version or "2000-00-00" spectrumPatches.version; - oldPatches = oldAttrs.spectrumPatches.patches or [ ]; + oldPatches = oldPatchesStruct.patches or [ ]; removeAll = removeElts: lst: builtins.filter (x: !(builtins.elem x removeElts)) lst; in optionalAttrs isNewer { @@ -47,7 +47,7 @@ cloud-hypervisor.overrideAttrs ( # Verbatim from spectrum postUnpack = oldAttrs.postUnpack or "" - + optionalString patchPhases '' + + optionalString missingPatchPhases '' unpackFile $vhost chmod -R +w vhost ''; @@ -58,7 +58,7 @@ cloud-hypervisor.overrideAttrs ( # Verbatim copy from spectrum postPatch = oldAttrs.postPatch or "" - + optionalString patchPhases '' + + optionalString missingPatchPhases '' pushd ../vhost for patch in $vhostPatches; do echo applying patch $patch