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.

Waar elke kernel-bootflag thuishoortAlleen hostechte hardware woont hieriommu=ptamd_iommu=pgtbl_v2pcie_acs_override=…pcie_aspm=offpci=pcie_bus_perf→ pcie_bus_safe bij USB4processor.max_cstate=1+ intel_idle.max_cstate op Intelamd_pstate=disablezet ook een governorDe gast heeft geen PCIe-links,geen C-states en geen cpufreq.Alleen gasthou op te doen alsof het hardware iscpuidle.off=1gast-idle-toestanden zijn fictienmi_watchdog=0een gedescheduleerde vCPU triggert hemsoftlockup_panic=0de stall was de schuld van de hostLaat kvm-clock met rust.Forceer geen tsc of hpet —de counters zijn niet de jouwe.Op de host betekenen deze drieallemaal iets anders,en twee ervan kosten jeiets echts.Beide — verschillende redenendezelfde flag, aparte beslissingmitigations=offhost: gast-naar-host-lekkengast: procesisolatiedefault_hugepagesz + hugepageshost: ondersteunt gast-RAMgast: ondersteunt een applicatiekies één laag, niet beidewatchdog_thresh / nowatchdoghost: ruis die je accepteerdegast: nooit betrouwbaar"Beide" betekent niet dat jehet op beide plekken zou moeten zetten.Het betekent dat de beslissingtwee keer gemaakt moet worden.Geen van beide — deze doen nietsamd_iommu=ongeen geldige optie; de kernel logt "Unknown option - 'on'" en gaat doorconsoleblank=0al de kernel-standaardAls een gekopieerde bootregel een van deze bevat, is hij nooit geverifieerd tegen /proc/cmdline —wat de goedkoopste beschikbare controle is, en degene die ook de verkeerde-bootloader-foutvangt.
De flags in omloop, gesorteerd. Twee van de populaire doen aan geen van beide kanten iets, en de watchdog-rij is een echte afweging in plaats van een regel.

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.

Waarom hot-plug het MPS-beleidsantwoord verandertBij boot, pcie_bus_perf configureert de bridge vanuit wat hij kan zienbridge — MPS 512apparaat A · 512apparaat B · 512aanwezig bij boothot-added · alleen 256mismatchniets heronderhandeldIn een chassis gebeurt dat nooit — de topologie bij boot is de topologie voor altijd. Op een USB4-poortis het het normale geval.De vier beleidsregels, en welke de kernel hot-plug-veilig noemtpcie_bus_tune_offlaat de BIOS-waarden met rustpcie_bus_safegrootste waarde die alle apparaten onder het root-complex ondersteunenpcie_bus_perfgrootste die de parent bus toestaat, per apparaat — plus MRRSpcie_bus_peer2peer128 B overal —"guarantees that hot-added devices will work"Slechts één beleid draagt die garantie, en het is degene die de payload-grootte weggooit waarvoor jeafstelde.
De bridge wordt één keer geconfigureerd, bij boot, vanuit de apparaten die er dan zijn. Alles daarna moet met de beslissing leven — wat prima is in een chassis en niet prima op een poort.

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

FlagHostGastOpmerkingen
iommu=ptjaneeHost bezit de IOMMU. Geldt alleen in een gast als je nested passthrough met een vIOMMU draait
amd_iommu=pgtbl_v2janeeHost-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=…janeeProxmox-patch, alleen host-topologie. Verzwakt isolatie per ontwerp
pcie_aspm=offjaneeEr zijn geen echte PCIe-links in een gast; de host bezit de fysieke link
pci=pcie_bus_perfjaniet betrouwbaarHost zet MPS op de draad. Gebruik in plaats daarvan pcie_bus_safe als apparaten over USB4 aankomen
processor.max_cstate=1janeeEchte idle-toestanden zijn die van de host. Voeg intel_idle.max_cstate=1 toe op Intel
amd_pstate=disablejaneeGasten beheren de CPU-frequentie niet
cpuidle.off=1met zorgjaGratis in een gast. Op de host kost het boost-ruimte en overlapt het max_cstate
nmi_watchdog=0afwegingjaJuist in een gast. Op de host: doe het voor de PMU-counter, niet voor de ruis
softlockup_panic=0neejaGast-stalls zijn vaak de scheduler van de host. Doorgaans al de standaard
consoleblank=0——No-op. Kernel-standaard is al 0
mitigations=offbeidebeideGeldig op beide, andere risicoberekening: gast-naar-host-lekken op de host, procesisolatie in de gast
default_hugepagesz + hugepages=beidebeideHost: VM-geheugen ondersteunen. Gast: een workload binnen de VM die ze wil. Verschillende doelen, dezelfde flags
watchdog_thresh= / nowatchdogbeidebeideHost: 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=off op 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 door
  • consoleblank=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