Warum du eines wollen würdest
QEMU kann einen echten NVMe-Controller emulieren — kein paravirtuelles Gerät, das einen Treiber braucht, den du mitbringst, sondern einen PCIe-NVMe-Controller, den ein Gast als normale SSD erkennt und mit der NVMe-Unterstützung ansteuert, die er schon hat.
Das ist der ganze Reiz, und er ist mehr wert, als er klingt.
Linux hat seit Jahren einen eingebauten nvme-Treiber. Windows liefert stornvme seit Windows 8.1 und Server 2012 R2. Ein Gast startet also, zählt einen PCIe-NVMe-Controller auf, lädt seinen eigenen Treiber und findet eine Platte. Kein VirtIO-ISO, keine Treiber-Einspeisung bei der Installation, und kein Bildschirm „keine Laufwerke gefunden“ mitten im Windows-Installationsprogramm.
Wer je vor diesem Bildschirm gesessen hat, mit eingebundenem VirtIO-ISO und einem Installationsprogramm, das trotzdem darauf beharrt, es gäbe keine Platten, wird den Reiz sofort sehen.
Der zweite Grund ist, dass es sich bis nach oben wie NVMe verhält. nvme-cli funktioniert. Namespaces sind echt. LBA-Formate, Metadaten-Byte und Schutzinformationen sind alle einstellbar. Das macht es zu einem sehr guten Ort, um die Handgriffe zu üben, die du auf Hardware mit Daten darauf nicht üben solltest.
Wie man eines hinzufügt
Proxmox hat dafür kein Häkchen in der GUI und keinen Konfigurationsschlüssel. Es ist ein rohes QEMU-Gerät, es kommt also in args: in /etc/pve/qemu-server/<vmid>.conf.
Die QEMU-Dokumentation gibt das minimale Paar: ein unterlegtes Laufwerk ohne Schnittstelle und den Controller, der es verbraucht. Direkt in /etc/pve/qemu-server/<vmid>.conf geschrieben, ohne Anführungszeichen:
args: -drive file=/var/lib/vz/images/100/nvm.img,if=none,id=nvmidentifier -device nvme,serial=LAB-NVME-01,drive=nvmidentifier
if=none zählt: es sagt QEMU, das Laufwerk nicht an einen voreingestellten Controller zu hängen, denn die Zeile -device nvme wird es beanspruchen. Das id= am Laufwerk und das drive= am Gerät müssen übereinstimmen. Diese Paarung ist es, die die zwei Hälften verbindet.
Das serial= ist Pflicht; QEMU weigert sich, die VM ohne eines zu starten. Wähl etwas, das du wiedererkennst, denn es ist genau das, was der Gast in nvme list und smartctl zurückmeldet, und „welches dieser vier gleichen virtuellen Laufwerke ist welches“ ist eine Frage, die du irgendwann stellen wirst.
Anführungszeichen: der Teil, der alle erwischt
Ob du diese Zeichenkette in Anführungszeichen setzt, hängt davon ab, wo du sie tippst, und es verdreht zu bekommen ist der häufigste Grund, warum eines davon beim ersten Versuch nicht geht.
Proxmox speichert den Wert von args: und teilt ihn später mit Text::ParseWords::shellwords. In der Konfigurationsdatei werden Anführungszeichen also beachtet und entfernt. Eine vollständig eingefasste Zeichenkette wird zu einem einzigen 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"
Durch shellwords gelaufen gibt das genau ein Element. Ohne Anführungszeichen gibt dieselbe Zeile die vier, die QEMU wirklich braucht: -drive, ihren Parameterklumpen, -device, seinen Parameterklumpen.
Auf der Kommandozeile ist es umgekehrt, denn dort setzt du für deine Shell in Anführungszeichen und nicht für Proxmox. Hier sind die Anführungszeichen nötig, und was in der Konfiguration landet, ist der Wert ohne sie:
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"
Beides ist richtig. Sie sind bloß nicht austauschbar. Baust du die Zeile mit qm set, prüf das Ergebnis danach mit qm config 100, und du wirst sie nackt gespeichert sehen. Das ist die Form, die die Konfigurationsdatei will.
Leg das unterlegte Abbild zuerst an, wenn es nicht existiert:
qemu-img create -f raw /var/lib/vz/images/100/nvm.img 32G
Mehr als ein Namespace
Für alles jenseits einer einzelnen Platte trenn den Controller von seinen 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-Kennungen werden von 1 aufwärts automatisch vergeben. Das ist die Aufstellung, die das Gerät zum Lernen wirklich nützlich macht, denn Namespace-Verwaltung ist der Teil von NVMe, an den die meisten Leute nie kommen.
Ein 4Kn-Namespace, virtuell
Das Namespace nimmt die üblichen Eigenschaften zur Blockgröße, und QEMU leitet die LBA-Datengröße direkt daraus ab. hw/nvme/ns.c berechnet den Formatexponenten als ds = 31 - clz32(ns->blkconf.logical_block_size). Das gibt dir also ein richtiges 4-K-natives Namespace:
-device nvme-ns,drive=nvm-1,logical_block_size=4096,physical_block_size=4096
Das Namespace-Gerät nimmt außerdem ms für Metadaten-Byte pro LBA, mset für erweiterte LBAs und pi und pif für Art und Wächterformat der Schutzinformationen.
Das ist ein vollständiges Labor für alles in dem Beitrag über 4Kn und 512e — logische Blöcke von 512 gegen 4096 Byte, Formate mit Metadaten, T10-PI — auf einem Gerät, das du so oft zerstören kannst, wie du willst.
Prüfen, dass es gelandet ist
Im Gast:
lsblk -o NAME,MODEL,SIZE,LOG-SEC,PHY-SEC
nvme list
nvme id-ns -H /dev/nvme0n1 | grep -i "lbaf\|data size"
Du solltest ein echtes NVMe-Namespace sehen, mit den Blockgrößen, die du verlangt hast.
Was du aufgibst
Drei Dinge, und die ersten zwei sind keine Abwägungen bei der Leistung. Es sind entfernte Fähigkeiten. Kenne sie, bevor du irgendetwas auf das Gerät legst.
1. Live-Migration ist aus
Das ist keine Grenze von Proxmox und kein Versehen. QEMU erklärt das Gerät im Gerätemodell selbst für nicht migrierbar. Aus hw/nvme/ctrl.c in QEMU 10.2:
static const VMStateDescription nvme_vmstate = {
.name = "nvme",
.unmigratable = 1,
};
Drei Zeilen, und die mittlere ist die ganze Geschichte. Der Controller hat keinen Migrationszustand, QEMU weist die Migration also ab, statt sie zu versuchen. Das ist das richtige Scheitern. Du bekommst einen Fehler, keinen Gast, der auf einem anderen Knoten mit einer verwirrten Platte weiterläuft.
Es gibt einen zweiten, unabhängigen Grund, warum es nicht gehen kann: Proxmox weiß nicht, dass die Platte existiert. Selbst wenn QEMU den Gerätezustand bewegen könnte, würde nichts in der Migrationslogik von PVE dafür sorgen, dass das unterlegte Volume auf dem Ziel verfügbar ist.
Es lohnt sich aber, das zu beobachten: der Entwicklungszweig von QEMU hat das pauschale Flag durch eine Funktion nvme_set_migration_blockers() ersetzt, die Migration erlaubt und sie nur für bestimmte Funktionen sperrt. Mehr als ein Namespace zum Beispiel, wo der Kommentar festhält „we don’t handle this in migration code yet“, das sei im Migrationscode noch nicht behandelt. Das ist in keiner Ausgabe bis einschließlich 10.2 erschienen, es hilft dir also heute nicht, aber diese Einschränkung sieht danach aus, als würde sie weicher. Prüf deine eigene QEMU-Version, statt einem Beitrag zu trauen.
2. Proxmox-Sicherungen werden es nicht sehen
vzdump und der Proxmox Backup Server sichern die Volumes, die in der VM-Konfiguration als Platten erscheinen — scsi0, virtio0 und so weiter. Eine über args: angehängte Platte ist keine davon. Es ist ein rohes QEMU-Gerät, von dem PVE nichts weiß.
Die Sicherung läuft also, meldet Erfolg und enthält das Gerät nicht.
Dieser Fehlerfall ist schlimmer als ein Fehler, denn nichts sagt es dir. Dasselbe gilt auf ganzer Linie: keine PVE-Snapshots, keine Größenänderung der Platte aus der GUI, kein Move Disk, keine Buchung in der Speicheransicht. Hast du das Volume über PVE angelegt und dann abgehängt, räumt PVE es vielleicht auch nicht auf. Ein Waisenkind, das darauf wartet, später jemanden zu verwirren.
Sollen Daten auf einem davon leben, sichere sie im Gast, und schreib irgendwo auf, dass der Hypervisor sie nicht abdeckt.
3. Es ist nicht schneller als VirtIO SCSI
Das überrascht Leute, denn „NVMe“ liest sich wie eine Leistungsfunktion. Hier ist es keine.
VirtIO SCSI und VirtIO Block sind paravirtuell: der Treiber im Gast und der Hypervisor teilen einen Ringpuffer, der für genau diese Aufgabe entworfen ist, und der Gast weiß, dass er mit einem Hypervisor redet.
Der emulierte NVMe-Controller ist von Entwurf her das Gegenteil. Er zeigt echte NVMe-Register, der Gast programmiert ihn also, als wäre er Hardware. Jeder Schreibvorgang auf eine Türklingel ist ein MMIO-Zugriff, der in den Hypervisor fällt. Korrekt, und pro IO teurer, als einen Deskriptor auf einen Ring zu legen.
QEMUs eigene Dokumentation ist über die rauen Kanten des Geräts auch offen: die Zusammenfassung von Interrupts „is not supported and is disabled by default“, sie ist nicht unterstützt und aus, und die Zählwerte in der SMART-/Health-Log-Seite „are reset when the device is power cycled“, sie werden beim Aus- und Einschalten des Geräts zurückgesetzt.
Nichts davon macht es absolut gesehen langsam. Es ist völlig brauchbar. Es heißt bloß, dass du es nie in der Hoffnung auf mehr Durchsatz als VirtIO SCSI wählen solltest. Wähl es wegen des Treibers, oder wegen der NVMe-Semantik.
Wo es seinen Platz wirklich verdient
- Einen Gast ohne VirtIO-Medium installieren. Ein Windows-Installationsprogramm, das keine VirtIO-SCSI-Platte sieht, sieht eine NVMe-Platte, denn der Treiber ist schon im Abbild. Installiere darauf, und entscheide dann, ob du danach auf VirtIO wechselst.
- Appliances und Abbilder, die dir nicht gehören. Alles, was als festes Abbild ausgeliefert wird, dem VirtIO-Treiber fehlen und das du lieber nicht neu bauen willst.
- Lernen und Laborarbeit.
nvme format --lbaf, Namespaces anlegen und anhängen, Metadaten und Schutzinformationen — die Handgriffe, die auf echter Hardware zerstörend und herstellerabhängig sind, sind hier kostenlos. Das ist der sicherste Weg, das Muskelgedächtnis aufzubauen, bevor du ein Laufwerk anfasst, auf das es ankommt. - Die Topologie eines anderen nachbauen. Suchst du einen Fehler im NVMe-Aufbau eines Kunden, ist ein emulierter Controller mit passenden Namespaces und Blockgrößen eine viel schnellere Schleife, als sich dessen Hardware zu leihen.
Was man produktiv stattdessen nimmt
Für eine VM, die Leistung, PVE-Funktionen und ein ruhiges Leben braucht: VirtIO SCSI single, mit iothread=1, discard=on und ssd=1, auf cache=none. Das ist die Anordnung, die Live-Migration, Sicherungen, Snapshots und die Speicheransicht alle am Laufen hält.
Für eine VM, die die letzten Prozent braucht und diese Funktionen bewusst aufgeben kann, ist die Antwort kein emuliertes NVMe-Gerät. Es ist echtes Passthrough, mit seinen eigenen harten Abwägungen, behandelt in dem Beitrag über die IOMMU-Steuer.
Das emulierte NVMe-Gerät sitzt in keinem der beiden Lager. Damit ist es ein Werkzeug für Kompatibilität und fürs Labor, und darin ist es sehr gut.
Nimm es für die Aufgabe, in der es gut ist, und es wird dich nicht enttäuschen. Verlang von ihm eine Leistungsfunktion, und es enttäuscht dich sehr schnell.
Quellen
- QEMU — NVMe Emulation — die Syntax von
-drive/-device nvme,nvme-nsfür mehrere Namespaces, die Namespace-Parameterms/mset/pi/pifund die angegebenen Grenzen bei Interrupt-Zusammenfassung und SMART-Zählung - QEMU-Quelltext —
hw/nvme/ctrl.c— die Deklarationnvme_vmstatemit.unmigratable = 1in der Ausgabe 10.2 - QEMU-Quelltext —
hw/nvme/ns.c— das Namespace, das sein LBA-Format auslogical_block_sizeableitet - Proxmox VE — Backup and Restore — was
vzdumpabdeckt, und die Sicherungsoptionen pro Volume, die es für Platten gibt, die PVE verwaltet - Proxmox VE — Qemu/KVM Virtual Machines — VirtIO SCSI,
iothread,discardund die unterstützten Plattenoptionen