From 12545b4b6dd17b81d5069b7bb669d7568b047fef Mon Sep 17 00:00:00 2001 From: henrygd Date: Tue, 24 Feb 2026 14:36:53 -0500 Subject: [PATCH] fix: dedupe root-mirrored extra filesystems during disk discovery (#1428) --- agent/disk.go | 51 ++++++++++++++++++++++++++++++++++++++++++++++ agent/disk_test.go | 34 +++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/agent/disk.go b/agent/disk.go index 5a30bb6b..6df5d73f 100644 --- a/agent/disk.go +++ b/agent/disk.go @@ -197,9 +197,60 @@ func (a *Agent) initializeDiskInfo() { a.fsStats[rootKey] = &system.FsStats{Root: true, Mountpoint: rootMountPoint} } + a.pruneDuplicateRootExtraFilesystems() a.initializeDiskIoStats(diskIoCounters) } +// Removes extra filesystems that mirror root usage (https://github.com/henrygd/beszel/issues/1428). +func (a *Agent) pruneDuplicateRootExtraFilesystems() { + var rootMountpoint string + for _, stats := range a.fsStats { + if stats != nil && stats.Root { + rootMountpoint = stats.Mountpoint + break + } + } + if rootMountpoint == "" { + return + } + rootUsage, err := disk.Usage(rootMountpoint) + if err != nil { + return + } + for name, stats := range a.fsStats { + if stats == nil || stats.Root { + continue + } + extraUsage, err := disk.Usage(stats.Mountpoint) + if err != nil { + continue + } + if hasSameDiskUsage(rootUsage, extraUsage) { + slog.Info("Ignoring duplicate FS", "name", name, "mount", stats.Mountpoint) + delete(a.fsStats, name) + } + } +} + +// hasSameDiskUsage compares root/extra usage with a small byte tolerance. +func hasSameDiskUsage(a, b *disk.UsageStat) bool { + if a == nil || b == nil || a.Total == 0 || b.Total == 0 { + return false + } + // Allow minor drift between sequential disk usage calls. + const toleranceBytes uint64 = 16 * 1024 * 1024 + return withinUsageTolerance(a.Total, b.Total, toleranceBytes) && + withinUsageTolerance(a.Used, b.Used, toleranceBytes) +} + +// withinUsageTolerance reports whether two byte values differ by at most tolerance. +func withinUsageTolerance(a, b, tolerance uint64) bool { + if a >= b { + return a-b <= tolerance + } + return b-a <= tolerance +} + // Returns matching device from /proc/diskstats. // bool is true if a match was found. func findIoDevice(filesystem string, diskIoCounters map[string]disk.IOCountersStat) (string, bool) { diff --git a/agent/disk_test.go b/agent/disk_test.go index 7ca58cae..b4a58624 100644 --- a/agent/disk_test.go +++ b/agent/disk_test.go @@ -372,3 +372,37 @@ func TestDiskUsageCaching(t *testing.T) { "lastDiskUsageUpdate should be refreshed when cache expires") }) } + +func TestHasSameDiskUsage(t *testing.T) { + const toleranceBytes uint64 = 16 * 1024 * 1024 + + t.Run("returns true when totals and usage are equal", func(t *testing.T) { + a := &disk.UsageStat{Total: 100 * 1024 * 1024 * 1024, Used: 42 * 1024 * 1024 * 1024} + b := &disk.UsageStat{Total: 100 * 1024 * 1024 * 1024, Used: 42 * 1024 * 1024 * 1024} + assert.True(t, hasSameDiskUsage(a, b)) + }) + + t.Run("returns true within tolerance", func(t *testing.T) { + a := &disk.UsageStat{Total: 100 * 1024 * 1024 * 1024, Used: 42 * 1024 * 1024 * 1024} + b := &disk.UsageStat{ + Total: a.Total + toleranceBytes - 1, + Used: a.Used - toleranceBytes + 1, + } + assert.True(t, hasSameDiskUsage(a, b)) + }) + + t.Run("returns false when total exceeds tolerance", func(t *testing.T) { + a := &disk.UsageStat{Total: 100 * 1024 * 1024 * 1024, Used: 42 * 1024 * 1024 * 1024} + b := &disk.UsageStat{ + Total: a.Total + toleranceBytes + 1, + Used: a.Used, + } + assert.False(t, hasSameDiskUsage(a, b)) + }) + + t.Run("returns false for nil or zero total", func(t *testing.T) { + assert.False(t, hasSameDiskUsage(nil, &disk.UsageStat{Total: 1, Used: 1})) + assert.False(t, hasSameDiskUsage(&disk.UsageStat{Total: 1, Used: 1}, nil)) + assert.False(t, hasSameDiskUsage(&disk.UsageStat{Total: 0, Used: 0}, &disk.UsageStat{Total: 1, Used: 1})) + }) +}