Skip virtual block devices in host disk I/O collection

collectDiskIO hand-rolled a partial exclusion list (loop, ram, dm-) while
the two sibling paths, agent SMART collection and the server-side resource
registry, both use fsfilters.IsVirtualBlockDevice. ZFS zvols were therefore
collected as if they were physical disks: a Proxmox host with ZFS-backed
guest storage exposes one zd<N> device per zvol, so a few hundred guests
produced a few hundred phantom disks in every agent report, driving
sustained metrics and resource_changes growth.

Route the filter through the canonical helper so zd, zram, nbd, rbd, drbd,
md, pmem, vd and xvd are all excluded. md and dm- aggregates additionally
restated the I/O of their own physical members, so counting them alongside
those members double counted host disk I/O.

Refs #1671
This commit is contained in:
rcourtman
2026-08-03 09:43:11 +01:00
parent bab70cc177
commit 99ad8c2c4b
2 changed files with 21 additions and 10 deletions
+7 -6
View File
@@ -412,12 +412,13 @@ func collectDiskIO(ctx context.Context, diskExclude []string) []agentshost.DiskI
if isPartition(name) {
continue
}
// Skip loop devices and ram disks
if strings.HasPrefix(name, "loop") || strings.HasPrefix(name, "ram") {
continue
}
// Skip device-mapper and md devices (report at physical level)
if strings.HasPrefix(name, "dm-") {
// Skip virtual/pseudo block devices (loop, ram, dm-, md, zvols,
// zram, nbd, rbd, drbd, ...). ZFS-backed Proxmox hosts expose one
// zd<N> device per zvol, so without this a host with a few hundred
// guests reports a few hundred phantom disks on every collection
// cycle (issue #1671). The prefix list is shared with SMART
// collection and the server-side resource registry.
if fsfilters.IsVirtualBlockDevice(name) {
continue
}
// Skip user-excluded devices (issue #1142)
@@ -189,20 +189,30 @@ func TestCollectDiskIOFiltersAndError(t *testing.T) {
"ram0": {ReadBytes: 7},
"dm-0": {ReadBytes: 8},
"sdb": {ReadBytes: 9},
"md0": {ReadBytes: 10},
// Aggregate virtual devices whose counters restate the I/O of
// the physical members underneath them.
"md0": {ReadBytes: 10},
// ZFS zvols. A Proxmox host with ZFS-backed guest storage
// exposes one of these per zvol (issue #1671).
"zd0": {ReadBytes: 11},
"zd16": {ReadBytes: 12},
"zd160": {ReadBytes: 13},
"zram0": {ReadBytes: 14},
"nbd0": {ReadBytes: 15},
"rbd0": {ReadBytes: 16},
}, nil
}
disks := collectDiskIO(context.Background(), []string{"sdb"})
if len(disks) != 3 {
t.Fatalf("expected 3 disk I/O entries after filtering, got %d: %+v", len(disks), disks)
if len(disks) != 2 {
t.Fatalf("expected 2 disk I/O entries after filtering, got %d: %+v", len(disks), disks)
}
gotDevices := make([]string, 0, len(disks))
for _, disk := range disks {
gotDevices = append(gotDevices, disk.Device)
}
wantDevices := []string{"md0", "nvme0n1", "sda"}
wantDevices := []string{"nvme0n1", "sda"}
if !reflect.DeepEqual(gotDevices, wantDevices) {
t.Fatalf("unexpected disk I/O devices: got %v, want %v", gotDevices, wantDevices)
}