Files
felhom.eu/documentation/audits/storage-identity-2026-10-15
admin 3038b23ec7
gates / gates (push) Successful in 6m43s
Storage that knows its physical disks: design draft 16 + spike; R-1074..R-1079; STATUS D10
Spike (read-only probe, tools/physdisk_probe.py): the agent-side walk (partition -> disk, dm/LVM
slaves, loop -> backing file) names the right physical disk for one-disk boxes, two disks, two
partitions of one disk and a pass-through USB bridge; inside a VM (Tester 1) every disk is "unknown".
Today's agent lists whole disks only and calls an empty partition table "data-bearing"; the
controller's Tier-2 "different disk" is st_dev. sys_drive is a folder of mp0 (backup=1), so the
design gives one-disk boxes a separate internal data place outside the whole-guest copy instead.
Draft only; waits on the operator's rulings D1-D6 (16 section 12). 07 section 6.1's stale mp1 cell
corrected. Register 163 -> 169. Scratch loop disk and Tester 1 scratch disk removed.

Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
2026-10-15 20:08:08 +02:00
..
…

Spike — can the agent name the physical disk under every storage place? (2026-10-15)

For architecture/16-storage-physical-identity.md (draft). Method: tools/physdisk_probe.py — read-only, run as root on each Proxmox host. It follows the block chain down to whole disks — partition → parent (/sys/class/block/<p>/partition, the same as lsblk PKNAME), device-mapper / LVM thin → /sys/class/block/<dm>/slaves/* recursively, loop → loop/backing_file → the filesystem that holds the file — and reads each disk's ID_WWN, ID_SERIAL_SHORT, ID_BUS, vendor and model from udev, plus systemd-detect-virt. tools/summarize.py prints the tables. The agent already has most of this chain (role.go walkSlaves/physicalDisksOf, hostread.go parentDisk); it lacks the loop step and a per-place report.

Results

# Case Where The probe's answer Truth Right? Evidence
1 One disk: host root, local, the thin pool, guest rootfs and mp0 (sys_drive is a folder of mp0) N100 all → wwn:0x5000000123456f1f (AirDisk 512 GB SSD), proven one SATA SSD yes B-n100.txt
1b The same on demo-hp demo-hp all system places → wwn:0x5001b448b60a9d6e (SanDisk 128 GB) one SSD yes B-demo-hp.txt
2 Two disks: system + enrolled data drive demo-hp, N100 system → SanDisk / AirDisk; /mnt/felhom-drives/hdd_1 → Toshiba NVMe (eui…46c07b) / Toshiba MQ04 on USB (0x5000039ddb108568) two disks each yes B-demo-hp.txt, B-n100.txt
3 One disk, two partitions, two places demo-hp, a 4 GB scratch file as a loop disk, p1 and p2 ext4, mounted both → the NVMe that holds the file, via loop2pN → loop2 → file on nvme0n1 the same disk yes (after a probe fix: the partition step must run before the loop step) B-case3-loop.*
4a A USB enclosure that passes the disk's identity N100's backup drive ID_BUS=ata, real model, serial 65NOP3HDT, WWN; ID_USB_DRIVER=usb-storage the real Toshiba disk yes B-n100.txt
4b A USB enclosure that hides or fakes the serial — not measured — no such device at hand, none in earlier evidence (searched documentation/, agent, controller) — — R-1077
4c A cheap SSD with a generic WWN N100 system SSD ID_WWN=0x5000000123456f1f: NAA-5 with OUI 000000 (no registered vendor) — the serial QDF922W009654S30EX looks real unknown whether two units share the WWN probably weak R-1076
5 Inside a VM: virtual disks on the same host disk Tester 1 (VM 341): scsi0, scsi1, scsi2 inside: QEMU HARDDISK, serials drive-scsi0/1/2, systemd-detect-virt=kvm → unknown host: all three are files on demo-hp's NVMe (B-case56-host-truth.txt) yes — „unknown" B-tester1.txt, B-case56-*
6 Inside a VM: a virtual disk on a different host disk Tester 1, scratch scsi6 (4 GB on local-lvm = demo-hp's SanDisk), hot-added and removed inside: QEMU HARDDISK, ID_SERIAL_SHORT=drive-scsi6 (the set serial SCRATCHSID6 shows only as ID_SCSI_SERIAL) → unknown host: the SanDisk yes — „unknown" B-case56-*
7 A network share — (no box has one mounted now; the OMV run mounted one at /mnt/felhom-drives/omv-filmek) the probe classes cifs/nfs sources as network → unknown, no disk a disk on another machine yes by rule (not run on a live share) ../omv-vm-2026-10-15/B6-omv-share.txt

The VM cases in one sentence: from inside a VM, two virtual disks on the same host disk and two on different host disks look exactly alike (same vendor, same model, serial = the hypervisor's slot name), so the agent can only say „unknown"; only the hypervisor's host knows.

What today's agent does with a partitioned disk (Tester 1, scratch sdg, read-only GET /disks/candidates)

Disk state Agent answer Evidence
blank initialize: /dev/sdg, data_bearing:false, mountable:false B-case56-agent-blank.txt
GPT, p1 empty (no fs), p2 empty ext4 attach and initialize: one row /dev/sdg, fstype ext4, mount_source /dev/sdg2, data_bearing:true; p1 is not offered at all B-case4b-partitions-empty.txt, B-case4b-partitions.txt
GPT, both partitions empty initialize only: /dev/sdg, data_bearing:true, mountable:false — the only way to use it is to wipe the whole disk B-case4b-partitions.txt

So today a place is always a whole disk (or the one partition the agent picks), an empty filesystem counts as data, and a partition table alone makes the whole disk „data-bearing".

Also found while reading (code, not run)

  • The controller's „same disk" test is stat().st_dev (felhom-controller/controller/internal/system/mounts_linux.go:225-245; its own comment: „two partitions on one physical disk look "different" here"). Tier-2 target choice (internal/backup/tier2.go:83-179) and the one-copy warning (internal/backup/backup.go:1387-1410) use it.
  • Tester 1 today makes Tier-2 copies between media_a / adatlemez / … — all files on one host NVMe — and counts them as off-drive copies (case 5). R-1074.
  • hasOffDriveTarget (backup.go:1390-1402) does not skip network paths, and a NAS is registered Schedulable:true (internal/web/netstorage_job.go:267-273), so adding a NAS would remove the „Csak egy másolat…" warning while Tier-2 refuses a NAS (tier2.go:141-143). Read in code, not run. R-1075.
  • sys_drive is a folder of mp0 (/var/lib/felhom, backup=1), next to Docker — not a separate mp1 (all three boxes, pct config 9201; 07-backup-architecture.md §7.5.1). Anything stored there rides in every whole-guest copy.

Put back

  • demo-hp: the 4 GB scratch file and its loop device removed (checked: losetup -a 0 lines, file absent). A first try left them for ~1 minute (a missing partprobe); removed at once, nothing else touched.
  • Tester 1: scratch scsi6 partitioned, wiped (wipefs -a, sgdisk -Z — the scratch disk only, matched by its serial before every write), hot-removed, its LV vm-341-disk-0 destroyed; sdg gone; VM 341 still running.
  • Probe files deleted from all hosts. No disk that holds anything was written. DooPlex and ep0 not touched.