[PR #57] [MERGED] feat(daemon): disk-pressure guardrail to stop runaway writes filling the host #57

Closed
opened 2026-10-15 12:51:41 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/games-on-whales/LXC2Docker/pull/57
Author: @JBailes
Created: 6/5/2026
Status: ✅ Merged
Merged: 6/5/2026
Merged by: @JBailes

Base: main ← Head: feat/disk-pressure-guardrail


📝 Commits (1)

  • 507b8ec feat(daemon): disk-pressure guardrail to stop runaway writes filling the host

📊 Changes

7 files changed (+302 additions, -3 deletions)

View changed files

📝 cmd/docker-lxc-daemon/main.go (+9 -1)
📝 internal/api/events.go (+35 -0)
📝 internal/api/router.go (+2 -2)
➕ internal/lxc/diskspace.go (+167 -0)
➕ internal/lxc/diskspace_test.go (+82 -0)
📝 internal/lxc/manager.go (+6 -0)
📝 readme.md (+1 -0)

📄 Description

Why

A container bind-mounting a host directory — e.g. Wolf mounting a Steam game library into the Steam container — can fill the underlying filesystem with no warning. When that filesystem is the host root (as on a PVE node where /etc/wolf/profile-data lives on a small root pool), a game download silently fills it and destabilizes the whole node. The daemon had zero visibility into this.

What

A free-space guardrail, --min-free-disk-gb (default 2, 0 disables):

  • Create pre-flight — refuse a container create when one of its writable bind sources is already below the threshold, failing loudly instead of wedging the host.
  • Background watcher — every 30s, statfs each filesystem the daemon writes to (state dir, LXC path, ZFS pool mountpoint, and running containers' writable bind sources, deduped by device) and emit an edge-triggered warning when one crosses below the threshold: a log line + a daemon-scoped disk_pressure event on the Docker event stream (and a disk_pressure_recovered event when it clears).

Note: this catches the runtime fill (downloads during gameplay), which a create-time check alone would miss.

Implementation

  • internal/lxc/diskspace.go — FreeBytes, watchedPaths, StartDiskPressureWatcher, checkCreateDiskPressure, humanBytes.
  • internal/api/events.go — DiskPressureEmitter, wired through NewHandlerWithHooks.
  • cmd/.../main.go — flag + SetMinFreeBytes + watcher start.

Tests

Unit tests cover FreeBytes (real fs + missing path), the create pre-flight (over-threshold reject, read-only skip, disabled, under-threshold allow), and humanBytes. make test (unit + integration) green.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/games-on-whales/LXC2Docker/pull/57 **Author:** [@JBailes](https://github.com/JBailes) **Created:** 6/5/2026 **Status:** ✅ Merged **Merged:** 6/5/2026 **Merged by:** [@JBailes](https://github.com/JBailes) **Base:** `main` ← **Head:** `feat/disk-pressure-guardrail` --- ### 📝 Commits (1) - [`507b8ec`](https://github.com/games-on-whales/LXC2Docker/commit/507b8ec7ef89145d62e56e2258e81a079944fd55) feat(daemon): disk-pressure guardrail to stop runaway writes filling the host ### 📊 Changes **7 files changed** (+302 additions, -3 deletions) <details> <summary>View changed files</summary> 📝 `cmd/docker-lxc-daemon/main.go` (+9 -1) 📝 `internal/api/events.go` (+35 -0) 📝 `internal/api/router.go` (+2 -2) ➕ `internal/lxc/diskspace.go` (+167 -0) ➕ `internal/lxc/diskspace_test.go` (+82 -0) 📝 `internal/lxc/manager.go` (+6 -0) 📝 `readme.md` (+1 -0) </details> ### 📄 Description ## Why A container bind-mounting a host directory — e.g. Wolf mounting a Steam game library into the Steam container — can fill the underlying filesystem with **no warning**. When that filesystem is the host root (as on a PVE node where `/etc/wolf/profile-data` lives on a small root pool), a game download silently fills it and destabilizes the whole node. The daemon had zero visibility into this. ## What A free-space guardrail, `--min-free-disk-gb` (default **2**, `0` disables): - **Create pre-flight** — refuse a container create when one of its *writable* bind sources is already below the threshold, failing loudly instead of wedging the host. - **Background watcher** — every 30s, `statfs` each filesystem the daemon writes to (state dir, LXC path, ZFS pool mountpoint, and running containers' writable bind sources, deduped by device) and emit an **edge-triggered** warning when one crosses below the threshold: a log line + a daemon-scoped `disk_pressure` event on the Docker event stream (and a `disk_pressure_recovered` event when it clears). Note: this catches the *runtime* fill (downloads during gameplay), which a create-time check alone would miss. ## Implementation - `internal/lxc/diskspace.go` — `FreeBytes`, `watchedPaths`, `StartDiskPressureWatcher`, `checkCreateDiskPressure`, `humanBytes`. - `internal/api/events.go` — `DiskPressureEmitter`, wired through `NewHandlerWithHooks`. - `cmd/.../main.go` — flag + `SetMinFreeBytes` + watcher start. ## Tests Unit tests cover `FreeBytes` (real fs + missing path), the create pre-flight (over-threshold reject, read-only skip, disabled, under-threshold allow), and `humanBytes`. `make test` (unit + integration) green. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-15 12:51:41 +00:00
Sign in to join this conversation.
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
games-on-whales/LXC2Docker#57
No description provided.