Waarom Je Er Een Zou Willen
QEMU kan een echte NVMe-controller emuleren — geen paravirtueel apparaat dat een driver nodig heeft die jij levert, maar een PCIe-NVMe-controller die een gast als een gewone SSD herkent en aanstuurt met de NVMe-ondersteuning die hij al heeft.
Dat is de hele aantrekkingskracht, en het is meer waard dan het klinkt.
Linux heeft al jaren een ingebouwde nvme-driver. Windows levert stornvme sinds Windows 8.1 en Server 2012 R2. Dus een gast boot, enumereert een PCIe-NVMe-controller, laadt zijn eigen driver en vindt een schijf. Geen VirtIO-ISO, geen driver-injectie bij installatie, en geen “no drives found”-scherm halverwege een Windows-installer.
Iedereen die naar dat scherm heeft zitten kijken, met de VirtIO-ISO gemount en de installer nog steeds vasthoudend dat er geen schijven zijn, ziet de aantrekkingskracht meteen.
De tweede reden is dat het zich helemaal naar boven als NVMe gedraagt. nvme-cli werkt. Namespaces zijn echt. LBA-formaten, metadata-bytes en protection information zijn allemaal configureerbaar. Wat het een zeer goede plek maakt om de operaties te oefenen die je niet zou moeten oefenen op hardware die data bevat.
Hoe Je Er Een Toevoegt
Proxmox heeft hier geen GUI-vinkje of config-sleutel voor. Het is een raw QEMU-apparaat, dus het gaat in args: in /etc/pve/qemu-server/<vmid>.conf.
De QEMU-documentatie geeft het minimale paar: een backing-drive zonder interface, en de controller die het verbruikt. Rechtstreeks in /etc/pve/qemu-server/<vmid>.conf bewerkt, zonder quotes:
args: -drive file=/var/lib/vz/images/100/nvm.img,if=none,id=nvmidentifier -device nvme,serial=LAB-NVME-01,drive=nvmidentifier
if=none doet ertoe: het vertelt QEMU de drive niet aan een standaardcontroller te koppelen, want de -device nvme-regel gaat hem claimen. De id= op de drive en de drive= op het apparaat moeten overeenkomen. Die koppeling is wat de twee helften verbindt.
De serial= is verplicht; QEMU weigert de VM zonder er een te starten. Kies iets dat je herkent, want het is precies wat de gast terugrapporteert in nvme list en smartctl, en “welke van deze vier identieke virtuele schijven is welke” is een vraag die je uiteindelijk zult stellen.
Quoten: Het Stuk Dat Iedereen Verrast
Of je die string quote hangt af van waar je hem typt, en het verkeerd om krijgen is de meest voorkomende reden dat een van deze bij de eerste poging faalt.
Proxmox slaat de args:-waarde op en splitst hem later met Text::ParseWords::shellwords. Dus in het configbestand worden quotes gehonoreerd en verwijderd. Een volledig gequote string wordt een enkel argument:
# WRONG in the config file — collapses to one argv element QEMU cannot parse
args: "-drive file=…,if=none,id=nvmidentifier -device nvme,serial=…,drive=nvmidentifier"
Door shellwords gehaald levert dat precies één element op. Zonder quotes levert dezelfde regel de vier die QEMU werkelijk nodig heeft: -drive, zijn parameterblok, -device, zijn parameterblok.
Op de commandoregel is het andersom, want daar quote je voor je shell, niet voor Proxmox. Hier zijn de quotes vereist, en wat in de config wordt opgeslagen is de gequote-vrije waarde:
qm set 100 --args "-drive file=/var/lib/vz/images/100/nvm.img,if=none,id=nvmidentifier -device nvme,serial=LAB-NVME-01,drive=nvmidentifier"
Beide zijn correct. Ze zijn alleen niet uitwisselbaar. Als je de regel bouwt met qm set, controleer het resultaat daarna met qm config 100 en je zult zien dat hij kaal is opgeslagen. Dat is de vorm die het configbestand wil.
Maak eerst het backing-image aan als het niet bestaat:
qemu-img create -f raw /var/lib/vz/images/100/nvm.img 32G
Meer Dan Eén Namespace
Voor alles voorbij een enkele schijf, splits de controller van zijn namespaces:
-device nvme,id=nvme-ctrl-0,serial=deadbeef
-drive file=nvm-1.img,if=none,id=nvm-1
-device nvme-ns,drive=nvm-1
Namespace-identifiers worden automatisch vanaf 1 omhoog toegewezen. Dit is de configuratie die het apparaat werkelijk nuttig maakt om te leren, want namespace-beheer is het deel van NVMe dat de meeste mensen nooit aanraken.
Een 4Kn Virtuele Namespace
De namespace neemt de gebruikelijke blokgrootte-eigenschappen, en QEMU leidt de LBA-datagrootte er rechtstreeks uit af. hw/nvme/ns.c berekent de format-exponent als ds = 31 - clz32(ns->blkconf.logical_block_size). Dus dit geeft je een echte 4K-native namespace:
-device nvme-ns,drive=nvm-1,logical_block_size=4096,physical_block_size=4096
Het namespace-apparaat accepteert ook ms voor metadata-bytes per LBA, mset voor extended LBAs, en pi en pif voor protection-information-type en guard-formaat.
Dat is een compleet laboratorium voor alles in het 4Kn- en 512e-artikel — logische blokken van 512 byte versus 4096 byte, metadata-dragende formaten, T10-PI — op een apparaat dat je zo vaak kunt vernietigen als je wilt.
Controleer Dat Het Aankwam
Van binnen de gast:
lsblk -o NAME,MODEL,SIZE,LOG-SEC,PHY-SEC
nvme list
nvme id-ns -H /dev/nvme0n1 | grep -i "lbaf\|data size"
Je zou een echte NVMe-namespace moeten zien, met de blokgroottes waar je om vroeg.
Wat Je Opgeeft
Drie dingen, en de eerste twee zijn geen prestatie-afwegingen. Het zijn capability-verwijderingen. Ken ze voordat je iets op het apparaat zet.
1. Live Migratie Is Uit
Dit is geen Proxmox-beperking of een omissie. QEMU verklaart het apparaat niet-migreerbaar in het device model zelf. Uit hw/nvme/ctrl.c in QEMU 10.2:
static const VMStateDescription nvme_vmstate = {
.name = "nvme",
.unmigratable = 1,
};
Drie regels, en de middelste is het hele verhaal. De controller heeft geen migratiestatus, dus QEMU weigert de migratie in plaats van hem te proberen. Dat is de juiste fout. Je krijgt een foutmelding, geen gast die op een andere node hervat met een verwarde schijf.
Er is een tweede, onafhankelijke reden dat het niet kan werken: Proxmox weet niet dat de schijf bestaat. Zelfs als QEMU de apparaattoestand kon verplaatsen, zou niets in de migratielogica van PVE ervoor zorgen dat het backing-volume beschikbaar is op het doel.
De moeite waard in de gaten te houden echter: de ontwikkeltak van QEMU heeft de allesomvattende flag vervangen door een nvme_set_migration_blockers()-functie die migratie toestaat en die alleen voor specifieke features blokkeert. Meer dan één namespace bijvoorbeeld, waar het commentaar opmerkt “we don’t handle this in migration code yet”. Dat is niet verschenen in een release tot en met 10.2, dus het helpt je vandaag niet, maar deze beperking lijkt waarschijnlijk te verzachten. Controleer je eigen QEMU-versie in plaats van een artikel te vertrouwen.
2. Proxmox-Backups Zullen Het Niet Zien
vzdump en Proxmox Backup Server backuppen de volumes die in de VM-config als drives verschijnen — scsi0, virtio0, enzovoort. Een schijf gekoppeld via args: is niet een daarvan. Het is een raw QEMU-apparaat waar PVE niks van weet.
Dus de backup draait, meldt succes, en bevat het apparaat niet.
Die faalmodus is erger dan een foutmelding, want niets vertelt het je. Hetzelfde geldt over de hele linie: geen PVE-snapshots, geen schijfvergroting vanuit de GUI, geen Move Disk, geen boekhouding in de storageweergave. Als je het volume via PVE aanmaakte en het daarna loskoppelde, ruimt PVE het mogelijk ook niet op. Een wees die wacht om iemand later te verwarren.
Als er data op een van deze gaat leven, backup het van binnen de gast, en schrijf ergens op dat de hypervisor het niet dekt.
3. Het Is Niet Sneller Dan VirtIO SCSI
Deze verrast mensen, want “NVMe” leest als een prestatiefeature. Hier is het er geen.
VirtIO SCSI en VirtIO block zijn paravirtueel: de gastdriver en de hypervisor delen een ring buffer die precies voor deze klus is ontworpen, en de gast weet dat hij met een hypervisor praat.
De geëmuleerde NVMe-controller is per ontwerp het tegenovergestelde. Hij presenteert echte NVMe-registers, dus de gast programmeert hem alsof het hardware was. Elke doorbell-write is een MMIO-toegang die naar de hypervisor trapt. Correct, en duurder per IO dan een descriptor op een ring zetten.
QEMU’s eigen documentatie is ook openhartig over de ruwe randjes van het apparaat: interrupt coalescing “is not supported and is disabled by default”, en de boekhoudgetallen in de SMART/Health-logpagina “are reset when the device is power cycled”.
Niets daarvan maakt het traag in absolute termen. Het is prima bruikbaar. Het betekent alleen dat je het nooit zou moeten kiezen in de hoop op meer doorvoer dan VirtIO SCSI je geeft. Kies het voor de driver, of voor de NVMe-semantiek.
Waar Het Zijn Plaats Werkelijk Verdient
- Een gast installeren zonder VirtIO-media. Een Windows-installer die geen VirtIO SCSI-schijf kan zien, ziet een NVMe-schijf, want de driver zit al in het image. Installeer erop, en beslis dan of je daarna naar VirtIO overschakelt.
- Appliances en images die je niet beheert. Alles wat als vast image wordt geleverd en VirtIO-drivers mist, en dat je liever niet herbouwt.
- Leren en labwerk.
nvme format --lbaf, namespace-aanmaak en -koppeling, metadata en protection information — de operaties die destructief en vendorafhankelijk zijn op echte hardware zijn hier gratis. Dit is de veiligste manier om het spiergeheugen op te bouwen voordat je een schijf aanraakt die ertoe doet. - De topologie van iemand anders reproduceren. Als je de NVMe-indeling van een klant debugt, is een geëmuleerde controller met bijpassende namespaces en blokgroottes een veel snellere lus dan hun hardware lenen.
Wat Te Gebruiken In Productie In Plaats Daarvan
Voor een VM die prestatie, PVE-features en een rustig leven nodig heeft: VirtIO SCSI single, met iothread=1, discard=on en ssd=1, op cache=none. Dat is de regeling die live migratie, backups, snapshots en de storageweergave allemaal aan het werk houdt.
Voor een VM die de laatste paar procent nodig heeft en die features met opzet kan opgeven, is het antwoord geen geëmuleerd NVMe-apparaat. Het is echte passthrough, met zijn eigen harde afwegingen, behandeld in het IOMMU-tax-artikel.
Het geëmuleerde NVMe-apparaat zit in geen van beide kampen. Het is dan ook een compatibiliteits- en labgereedschap, en het is daar heel goed in.
Gebruik het voor de klus waar het goed in is en het zal je niet in de steek laten. Vraag het een prestatiefeature te zijn en het zal je zeer prompt in de steek laten.
Referenties
- QEMU — NVMe Emulation — de
-drive/-device nvme-syntaxis,nvme-nsvoor meerdere namespaces, dems/mset/pi/pif-namespace-parameters, en de vermelde beperkingen op interrupt coalescing en SMART-boekhouding - QEMU-bron —
hw/nvme/ctrl.c— denvme_vmstate-declaratie met.unmigratable = 1in de 10.2-release - QEMU-bron —
hw/nvme/ns.c— de namespace die zijn LBA-formaat afleidt uitlogical_block_size - Proxmox VE — Backup and Restore — wat
vzdumpdekt, en de backup-opties per volume die bestaan voor drives die PVE beheert - Proxmox VE — Qemu/KVM Virtual Machines — VirtIO SCSI,
iothread,discarden de ondersteunde schijfopties