Het Probleem Met Gekopieerde Bootregels
Zoek naar Proxmox-afstelling en je vindt één lange GRUB_CMDLINE_LINUX-regel, gepresenteerd als een geheel, zonder enige aanwijzing van welke flags waar van toepassing zijn.
Dat doet er meer toe dan het klinkt. De hypervisor en de gast lossen tegengestelde problemen op.
De host wil deterministische toegang tot echte hardware: IOMMU-gedrag, PCIe-link-toestanden, fysieke idle-toestanden. De gast wil ophouden te doen alsof hij überhaupt hardware heeft — zijn timers zijn benaderingen, zijn idle-toestanden zijn fictie, en zijn stalls zijn doorgaans andermans scheduler. Dezelfde flag kan dan ook juist zijn aan de ene kant, zinloos aan de andere, en af en toe schadelijk.
Hieronder staat waar elk werkelijk thuishoort.
Eerst: Bewerk Je Wel Het Juiste Bestand?
Een Proxmox-installatie op ZFS-root boot met systemd-boot, waar /etc/default/grub door niemand wordt gelezen. Het bewerken en herstarten levert geen verandering en geen fout op. Dat is een frustrerend uur.
proxmox-boot-tool status # tells you which bootloader is in use
# systemd-boot: edit /etc/kernel/cmdline, then
proxmox-boot-tool refresh
# GRUB: edit /etc/default/grub, then
update-grub
Hoe dan ook, verifieer in plaats van aan te nemen:
cat /proc/cmdline
En aan de GRUB-kant, gebruik GRUB_CMDLINE_LINUX_DEFAULT, niet GRUB_CMDLINE_LINUX. De laatste geldt voor elke boot-entry inclusief recovery — en recovery is precies wanneer je standaardgedrag wilt, geen uitgeschakelde mitigations en vastgepinde C-states.
De Host-Regel
IOMMU en passthrough
iommu=pt amd_iommu=pgtbl_v2 pcie_acs_override=downstream,multifunction
iommu=pt zet de IOMMU in passthrough-modus: apparaten die aan VM’s worden toegewezen krijgen vertaling, host-native apparaten omzeilen vertaling. Het is echt en het wordt afgehandeld in arch/x86/kernel/pci-dma.c, dat iommu_set_default_passthrough(true) aanroept. De kernel documenteert het als equivalent aan iommu.passthrough=1.
amd_iommu=on is geen ding. Dit is de meest gekopieerde niet-bestaande parameter in Proxmox-gidsen. De parse_amd_iommu_options() van de kernel accepteert fullflush, force_enable, off, force_isolation, pgtbl_v1, pgtbl_v2, irtcachedis, nohugepages en v2_pgsizes_only. Al het andere landt hier:
pr_notice("Unknown option - '%s'\n", str);
AMD-Vi is standaard ingeschakeld wanneer de firmware het adverteert. Controleer je eigen log en je zult zien dat de parameter nooit de klus deed waarvoor hij werd gecrediteerd:
dmesg | grep -i "AMD-Vi\|Unknown option"
amd_iommu=pgtbl_v2 is geldig — het selecteert het v2-DMA-page-table-formaat, dat de CPU-page-table-structuur deelt in plaats van AMD’s eigen te gebruiken. Twee dingen om te weten: de documentatie beperkt het tot de DMA-API, wat betekent de eigen apparaatdomeinen van de host in plaats van de VFIO-domeinen die voor passthrough worden gebruikt; en het faalt veilig met een logregel waar je op zou moeten controleren:
if (amd_iommu_pgtable == PD_MODE_V2) {
if (!amd_iommu_v2_pgtbl_supported()) {
pr_warn("Cannot enable v2 page table for DMA-API. Fallback to v1.\n");
amd_iommu_pgtable = PD_MODE_V1;
}
}
Dus het is de moeite waard te meten op een node met zware host-side IO, en de moeite waard te verifiëren dat je het werkelijk kreeg.
pcie_acs_override=downstream,multifunction is Proxmox’ out-of-tree patch. Het splitst IOMMU-groepen door isolatie te beweren die de hardware niet adverteert, wat is wat passthrough mogelijk maakt op consumentenborden. Het is ook, precies, de kernel iets onwaars vertellen over de topologie. Prima op een machine waarvan je de gasten evenzeer vertrouwt als de host. Niet prima anders. Er is meer over waarom in het IOMMU-tax-artikel.
Latency en jitter
pcie_aspm=off processor.max_cstate=1 amd_pstate=disable
pcie_aspm=off houdt PCIe-links uit laag-vermogenstoestanden zodat een aankomende IO nooit op een wacht om te ontwaken. Het kost een paar watt per link en verwijdert een latency-staart die moeilijk te diagnosticeren is. Zie PCIe ASPM en passthrough.
processor.max_cstate=1 begrenst ACPI-idle op C1. Let op de driver: dit is de processor/acpi_idle-knop, dus op Intel heb je ook intel_idle.max_cstate=1 nodig, want intel_idle gaat voor. Op AMD is dit de juiste.
Er is een echt tegenargument. Diepe slaap op inactieve cores is wat het package thermische en vermogensruimte geeft om de drukke te boosten, dus alles op C1 vastpinnen kan je piek-single-thread-frequentie verlagen terwijl het de idle-opname verhoogt. Op een latency-gevoelige host is die afweging het doorgaans waard. Op een host die doorvoer najaagt misschien niet. Meet het in plaats van het te erven.
amd_pstate=disable valt terug op acpi-cpufreq. De moeite waard de gedocumenteerde alternatieven te kennen voordat je ernaar grijpt: passive (driver vraagt een prestatieniveau), active (de EPP-driver, met een voorkeur voor prestatie of efficiëntie), en guided. active met een prestatievoorkeur, of passive plus de performance-governor, haalt vaak dezelfde latency terwijl het de fijnere controle van CPPC behoudt. En als je het wel uitschakelt, zet dan bewust een governor — belanden op acpi-cpufreq met schedutil kan een stap terug zijn.
Geheugen
default_hugepagesz=1G hugepages=64
default_hugepagesz=1G op zichzelf reserveert niets. De kernel documenteert het als het instellen van “the size of the default HugeTLB page… the default hugetlb size used for shmget(), mmap() and mounting hugetlbfs” — een eenheid, geen allocatie. De allocatie komt van hugepages=, gedocumenteerd als “Number of HugeTLB pages to allocate at boot”.
Dat doet er veel meer toe voor 1 GiB dan 2 MiB-pagina’s, want aaneengesloten 1 GiB-regio’s zijn feitelijk onverkrijgbaar zodra de host up is geweest en het geheugen gefragmenteerd is. Boot is je enige betrouwbare kans.
Daarna moet de gast zich aanmelden (hugepages: 1024 in de VM-config). Gereserveerde pagina’s die niets gebruikt zijn gewoon geheugen dat je niet terug kunt krijgen, en je verliest ballooning en KSM op de VM’s die ze gebruiken.
De veiligheidsafweging
mitigations=off
Dit is niet één schakelaar. De kernel breidt het uit tot een lijst, en op een hypervisor zijn dit de entries die ertoe doen:
l1tf=off mds=off mmio_stale_data=off kvm.nx_huge_pages=off
gather_data_sampling=off retbleed=off spec_rstack_overflow=off
nospectre_v2 nopti indirect_target_selection=off
De eigen samenvatting van de kernel is “improves system performance, but it may also expose users to several CPU vulnerabilities”. L1TF, MDS en MMIO stale data zijn specifiek gast-naar-host- en gast-naar-gast-lekpaden, en kvm.nx_huge_pages is de iTLB-multihit-mitigation binnen KVM zelf.
Verdedigbaar op een single-tenant-machine waar elke gast even vertrouwd is als de host. Niet verdedigbaar waar gasten niet-vertrouwd zijn of aan verschillende tenants toebehoren. En merk op dat het stapelt met pcie_acs_override: twee onafhankelijke isolatiegaranties verwijderd op dezelfde regel. De moeite waard om met opzet te doen in plaats van door overerving.
PCIe Over USB4 Verandert Twee Hiervan
Als je PCIe-apparaten over USB4 of Thunderbolt aankomen — een externe GPU of NVMe-behuizing — veranderen twee van de antwoorden hierboven.
MPS-afstelling houdt op gratis te zijn
Op vaste slots is pci=pcie_bus_perf een kleine gratis winst. De kernel beschrijft het als:
Set device MPS to the largest allowable MPS based on its parent bus. Also set MRRS (Max Read Request Size) to the largest supported value… for best performance.
De haak is dat het bridges bij boot configureert, vanuit de topologie die bij boot aanwezig is. Over USB4 is hot-plug het normale geval, en een apparaat dat later wordt toegevoegd kan een kleinere MPS ondersteunen dan waarop de bridge al was ingesteld.
De kernel zegt het stille deel hardop terwijl hij een ander beleid adverteert:
pcie_bus_peer2peer— Set every device’s MPS to 128B, which every device is guaranteed to support… This also guarantees that hot-added devices will work.
Slechts één beleid draagt die garantie, en het is degene die alles op 128 bytes vastpint — precies wat MaxPayloadSize-afstelling probeert te ontvluchten. Voor een hot-plug-topologie is pcie_bus_safe (de grootste waarde die alle apparaten onder het root-complex ondersteunen) of simpelweg tune_off laten het veiligere startpunt. De eigen switch van de tunnel begrenst de haalbare MPS toch, dus het plafond was nooit het jouwe om te verhogen.
De veiligheidsstapeling wordt serieus
Externe PCIe betekent dat iemand een DMA-capabel apparaat in je hypervisor kan pluggen. De Thunderbolt-documentatie van de kernel is er direct over:
…the connected devices can be DMA masters and thus read contents of the host memory without CPU and OS knowing about it. There are ways to prevent this by setting up an IOMMU but it is not always available for various reasons.
De IOMMU is de verdediging. Tel nu wat de host-regel eraan doet. iommu=pt geeft host-eigen apparaten onvertaalde identity-domeinen, pcie_acs_override beweert isolatie die er niet is, en mitigations=off schakelt de gast-isolatie-mitigations uit. Elk is op zichzelf verdedigbaar. Samen, op een machine met een fysiek bereikbare USB4-poort, stapelen ze op.
Controleer waar je staat:
cat /sys/bus/thunderbolt/devices/domain*/security # none | user | secure | dponly | usbonly
none naast die bootregel is een open deur. Als de poorten bereikbaar zijn voor mensen aan wie je geen root zou geven, is iommu=pt het eerste dat ik zou heroverwegen.
De Gast-Regel
Dit zijn degene die binnen de VM horen, en drie ervan betekenen hier iets anders dan op de host.
nmi_watchdog=0 softlockup_panic=0 cpuidle.off=1
cpuidle.off=1 schakelt het cpuidle-subsysteem uit. In een gast is dat vrijwel gratis: de idle-toestanden van de gast zijn emulatie, en er is geen fysieke core om te laten slapen, dus alles wat het framework je oplevert is wektijd. Op de host is dezelfde flag een echte vermogens- en boost-ruimte-afweging, en het overlapt processor.max_cstate=1. Alleen aan de gastkant.
softlockup_panic=0 stopt een soft lockup ervan de gast te laten panieken. Dit is werkelijk beschermend in een VM, want een soft lockup daar is vaak niet de schuld van de gast. Een gedescheduleerde vCPU ziet er precies uit als een taak die weigerde te wijken. Dat is hetzelfde mechanisme achter waarom de klok van een VM niet te vertrouwen is. Controleer echter of je het nodig hebt. Het is standaard 0 op de meeste builds.
sysctl kernel.softlockup_panic
nmi_watchdog=0 is de interessante, en het verdient meer dan een regel.
De Watchdog-Vraag
Er zijn twee detectoren die één drempel delen:
watchdog_thresh=— Set the hard lockup detector stall duration threshold in seconds. The soft lockup detector threshold is set to twice the value. A value of 0 disables both. Default is 10 seconds.
Hard lockup (nmi_watchdog) vuurt wanneer een CPU helemaal stopt met het nemen van timer-interrupts. Soft lockup vuurt wanneer een taak een CPU twee keer zo lang bezet houdt zonder te schedulen.
In een gast is het uitschakelen van de hard-lockup-detector juist. Een gedescheduleerde vCPU kan hem buiten zijn eigen schuld triggeren, en het perf-counter-werk van de detector veroorzaakt VM exits voor een signaal dat niks dan ruis was.
Op de host is het een afweging, en het hangt af van welke ruis je werkelijk najaagt. Over-provisioning verhongert gasten, niet de host-kernel — de fysieke CPU’s van de host blijven interrupts nemen hoe vol de VM’s ook zijn. Dus de log-ruis die een drukke hypervisor uitwerpt is overweldigend soft lockup en RCU stall-berichten, geen NMI-hard-lockup-rapporten. Als dat de ruis is, zal nmi_watchdog=0 het niet stil krijgen, en softlockup_panic=0 ook niet — dat stopt de paniek, niet de berichten.
De gerichte knoppen zijn:
watchdog_thresh=30 # hard 30s, soft 60s — scale to taste
nowatchdog # honest single flag: disables both detectors
sysctl -w kernel.soft_watchdog=0 # runtime, keeps hard-lockup detection
Er is een aparte en betere reden om de hard-lockup-detector op een drukke host uit te schakelen, die niets met ruis te maken heeft: hij verbruikt een hardware-performance-counter per CPU. Daarom accepteert de parameter rNNN om een raw perf-event te configureren. Als je PMU-gebaseerde profiling doet, of een bewust over-geprovisioneerde machine draait waar je latency-variantie al hebt geaccepteerd als de prijs van dichtheid, is die counter teruggeven een redelijke afweging — en kleine stalls waarvoor je bewust hebt getekend zijn geen incidenten.
Maak de keuze alleen om die reden in plaats van om de ruis-reden, want maar een van beide is waar.
consoleblank=0 doet niets. De kernel documenteert de console-blank-timeout als “A value of 0 disables the blank timer. Defaults to 0.” Het staat al uit. Onschuldig, maar het is de tweede parameter in gangbare omloop die geen effect heeft, en het meedragen laat een regel doordacht lijken terwijl hij gekopieerd is.
Snelle Referentie: Waar Elke Flag Thuishoort
| Flag | Host | Gast | Opmerkingen |
|---|---|---|---|
iommu=pt | ja | nee | Host bezit de IOMMU. Geldt alleen in een gast als je nested passthrough met een vIOMMU draait |
amd_iommu=pgtbl_v2 | ja | nee | Host-DMA-API-domeinen. Verifieer dat je v2 kreeg in plaats van de v1-terugval |
amd_iommu=on | — | — | Geen geldige optie. Kernel logt “Unknown option - ‘on’” |
pcie_acs_override=… | ja | nee | Proxmox-patch, alleen host-topologie. Verzwakt isolatie per ontwerp |
pcie_aspm=off | ja | nee | Er zijn geen echte PCIe-links in een gast; de host bezit de fysieke link |
pci=pcie_bus_perf | ja | niet betrouwbaar | Host zet MPS op de draad. Gebruik in plaats daarvan pcie_bus_safe als apparaten over USB4 aankomen |
processor.max_cstate=1 | ja | nee | Echte idle-toestanden zijn die van de host. Voeg intel_idle.max_cstate=1 toe op Intel |
amd_pstate=disable | ja | nee | Gasten beheren de CPU-frequentie niet |
cpuidle.off=1 | met zorg | ja | Gratis in een gast. Op de host kost het boost-ruimte en overlapt het max_cstate |
nmi_watchdog=0 | afweging | ja | Juist in een gast. Op de host: doe het voor de PMU-counter, niet voor de ruis |
softlockup_panic=0 | nee | ja | Gast-stalls zijn vaak de scheduler van de host. Doorgaans al de standaard |
consoleblank=0 | — | — | No-op. Kernel-standaard is al 0 |
mitigations=off | beide | beide | Geldig op beide, andere risicoberekening: gast-naar-host-lekken op de host, procesisolatie in de gast |
default_hugepagesz + hugepages= | beide | beide | Host: VM-geheugen ondersteunen. Gast: een workload binnen de VM die ze wil. Verschillende doelen, dezelfde flags |
watchdog_thresh= / nowatchdog | beide | beide | Host: stalls die je accepteerde stil krijgen. Gast: de detector was nooit betrouwbaar |
Drie horen werkelijk aan beide kanten, en het is de moeite waard precies te zijn dat “beide” niet “om dezelfde reden” betekent:
mitigations=offop de host gaat over gast-naar-host- en gast-naar-gast-lekkage. Binnen een gast gaat het over procesisolatie binnen die VM. Je kunt het redelijkerwijs op de ene plek uitschakelen en op de andere niet.- Hugepages op de host ondersteunen gast-RAM; in een gast ondersteunen ze een applicatie. Ze twee keer reserveren voor hetzelfde geheugen is verspilling, dus beslis welke laag ze wil.
- Watchdog-afstelling is een ruis-beslissing op de host en een correctheids-beslissing in de gast.
Al het andere is de ene kant of de andere, en twee ervan zijn helemaal geen keuzes.
De Twee Regels
Host, op een AMD-machine die passthrough doet, single-tenant:
GRUB_CMDLINE_LINUX_DEFAULT="quiet amd_iommu=pgtbl_v2 iommu=pt pcie_acs_override=downstream,multifunction pcie_aspm=off pci=pcie_bus_perf default_hugepagesz=1G hugepages=64 processor.max_cstate=1 amd_pstate=disable mitigations=off"
Verwissel pci=pcie_bus_perf voor pcie_bus_safe als er iets over USB4 aankomt. Laat mitigations=off vallen als de gasten niet allemaal van jou zijn. Op Intel vervangt intel_iommu=on de AMD-flags en voegt intel_idle.max_cstate=1 zich bij de C-state-begrenzing.
Linux-gast:
GRUB_CMDLINE_LINUX_DEFAULT="quiet nmi_watchdog=0 softlockup_panic=0 cpuidle.off=1"
En laat kvm-clock met rust in de gast — forceer geen tsc of hpet. De paravirtuele klok bestaat juist omdat de counters niet de jouwe zijn. Dat is het hele argument in het VM-tijdregistratie-artikel.
Wat Te Verwijderen
Als je een regel van een forumpost erfde, zijn deze twee de eerste dingen om te verwijderen, want ze kosten je niks en bewijzen dat de regel nooit getest is:
amd_iommu=on— geen geldige optie; de kernel logt “Unknown option - ‘on’” en gaat doorconsoleblank=0— al de standaard
En controleer de rest tegen /proc/cmdline na een herstart. Elke flag op die regel zou er een moeten zijn waarvoor je een reden kunt noemen.
Als je niet kunt zeggen wat een flag doet, is het geen afstelling. Het is bijgeloof. En het wordt in de volgende build gekopieerd door iemand die je vertrouwt.
Referenties
- Linux-kernel — de commandoregelparameters van de kernel —
mitigations=,default_hugepagesz=,hugepages=,watchdog_thresh=,nowatchdog,consoleblank=,processor.max_cstate=,amd_pstate=,amd_iommu=en depci=pcie_bus_*-beleidsregels - Linux-kernel bron —
drivers/iommu/amd/init.c—parse_amd_iommu_options(), en de v2-page-table-capability-check die terugvalt op v1 - Linux-kernel bron —
arch/x86/kernel/pci-dma.c—iommu=ptdieiommu_set_default_passthrough()aanroept - Linux-kernel — Thunderbolt — beveiligingsniveaus, en verbonden apparaten als DMA-masters
- Proxmox VE — System Administration —
proxmox-boot-tool status, de kernel-commandoregel bewerken voor systemd-boot versus GRUB