NVMe I/O Error Fehlermeldung unter Linux analysieren

Aus Thomas-Krenn-Wiki
Zur Navigation springen Zur Suche springen

Kommt es auf einem Linux System zu NMVe I/O Error Situationen, protokolliert der Kernel Fehlerinformationen welche mittels dmesg Kommando abgefragt werden können. In diesem Artikel zeigen wir, wie Sie eine NVMe I/O Error Fehlermeldung analysieren.

Beispielfehler I/O Error sct 0x0 sc 0x4 DNR

Completion Queue Entry Status Field: In Figure 100 der NVM Express® Base Specification Revision 2.3[1] wird die Bedeutung der Bits Do Not Retry (DNR), More (M), Command Retry Delay (CRD), Status Code Type (SCT) und Status Code (SC) erklärt.

Auf einem Testsystem mit Linux-Kernel 6.8.0-55-generic #57-Ubuntu kommt es im Zuge von I/O Tests mit fio zu einem Abbruch des fio-Tests durch einen I/O Error. In der dmesg Ausgabe ist zu sehen:

Die erste Zeile enthält folgende Informationen:

[74942.261934] nvme0c0n1: I/O Cmd(0x1) @ LBA 218630656, 256 blocks, I/O Error (sct 0x0 / sc 0x4) DNR
[74942.262623] I/O error, dev nvme0c0n1, sector 218630656 op 0x1:(WRITE) flags 0x2008800 phys_seg 17 prio class 0

Speziell interessant sind dabei folgende Teile der Meldung:

  • I/O Error
  • sct 0x0
  • sc 0x4
  • DNR

Die Bedeutung dieser Werte sind in der NVMe Express Base Specification[2] dokumentiert. In Kapitel 4.2.3 (Status Field Definition) der NVM Express® Base Specification Revision 2.3[1] werden die einzelnen Elemente des Status Field folgendermaßen beschrieben:

  • SCT (3 bits) - Status Code Type - Gibt den Typ des Statuscodes an, den der Controller (der NVMe SSD) zurückgibt.
  • SC (8 bits) - Status Code - (Details siehe weiter unten.)
  • CRD (2 bits) - Command Retry Delay - Wenn das DNR-Bit im Statusfeld auf „1“ gesetzt ist, ist dieses Feld reserviert. (Weitere Details siehe NVM Express Base Specification.)
  • M (1 bit) - More - Wenn dieses Bit auf „1“ gesetzt ist, gibt es weitere Statusinformationen zu diesem Befehl als Teil der Seite „Error Information log page“, die mit dem Befehl „Get Log Page“ abgerufen werden können. Wenn dieses Bit auf „0“ gesetzt ist, gibt es keine zusätzlichen Statusinformationen zu diesem Befehl.
  • DNR (1 bit) - Do Not Retry - Wenn dieses Bit auf „1“ gesetzt ist, bedeutet dies, dass derselbe Befehl, wenn er erneut an einen Controller im NVM-Subsystem gesendet wird, voraussichtlich fehlschlagen wird. Wenn dieses Bit auf „0“ gesetzt ist, bedeutet dies, dass derselbe Befehl bei einer Wiederholung erfolgreich sein kann.

Status Code Type

In Figure 101 werden die vier Status Code Types Generic Command Status, Command Specific Status, Media and Data Integrity Errors und Path Related Status erklärt.

Die NVM Express Base Specification definiert mehrere Status Code Types:

Status Code Type (sct) Definition
0 Generic Command Status
1 Command Specific Status
2 Media and Data Integrity Errors
3 Path Related Status
4, 5, 6 reserviert
7 Hersteller-spezifisch

Im Beispiel oben (I/O Error (sct 0x0 / sc 0x4) DNR) lautet der Status Code Type 0 (sct 0x0).

Status Code

Abhänging vom jeweiligen Status Code Type, hat der zusätzlich mit übermittelte Status Code eine unterschiedliche Bedeutung.

Status Code (Generic Command Status)

Figure 102: Status Code Bedeutungen von Generic Command Status Informationen. Im Beispiel lautet der Status Code sc 0x4, das bedeutet Data Transfer Error.

Die Bedeutung des Status Codes bei einem Generic Command Status (sct = 0) ist in Kapitel 4.2.3.1 definiert. Hier dazu ein Auszug:

Status Code Definition
0 Successful Completion: Der Befehl wurde ohne Fehler ausgeführt.
1 Invalid Command Opcode: Ein reservierter codierter Wert oder ein nicht unterstützter Wert im Befehls-Opcode-Feld.
2 Invalid Field in Command: Ein reservierter codierter Wert oder ein nicht unterstützter Wert in einem definierten Feld (außer dem Opcode-Feld).
3 Command ID Conflict: Die Befehlskennung (Command ID) wird bereits verwendet. Hinweis: Wie viele Befehle nach einem Konflikt durchsucht werden, hängt von der jeweiligen Implementierung ab.
4 Data Transfer Error: Beim Übertragen der mit einem Befehl verbundenen Daten oder Metadaten ist ein Fehler aufgetreten.
...

Im Beispiel oben (I/O Error (sct 0x0 / sc 0x4) DNR) lautet der Status Code 4 (sc 0x4). Es handelt sich damit um einen Data Transfer Error.

Status Code (Command Specific Status)

Die Bedeutung des Status Codes bei einem Command Specific Status (sct = 1) ist in Kapitel 4.2.3.2 definiert. In diesem Beispiel gehen wir nicht näher darauf ein.

Interpretation der Statusinformation

Die Statusinformation "Data Transfer Error" deutet auf Probleme bei der Datenübertragung hin. Potentiell können beispielsweise Kabel, Steckverbindungen oder Backplane die Ursache sein.

Die Detail-Ausgabe von lspci zeigt, dass die betroffene NVMe SSD via PCIe 5.0 (32GT/s) angebunden ist:

# lspci -s 81:00.0 -vvv
81:00.0 Non-Volatile memory controller: KIOXIA Corporation Device 0013 (rev 01) (prog-if 02 [NVM Express])
        Subsystem: KIOXIA Corporation Device 0045
        Physical Slot: 1
        [...]
        Capabilities: [70] Express (v2) Endpoint, MSI 00
                [...]
                LnkCap: Port #0, Speed 32GT/s, Width x4, ASPM not supported
                        ClockPM- Surprise- LLActRep- BwNot- ASPMOptComp+
                LnkCtl: ASPM Disabled; RCB 64 bytes, Disabled- CommClk+
                        ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
                LnkSta: Speed 32GT/s, Width x4
                        TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
                [...]
                LnkCap2: Supported Link Speeds: 2.5-32GT/s, Crosslink- Retimer+ 2Retimers+ DRS-
                LnkCtl2: Target Link Speed: 32GT/s, EnterCompliance- SpeedDis-
                         Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
                         Compliance Preset/De-emphasis: -6dB de-emphasis, 0dB preshoot

In diesem Beispiel kommt jedoch eine Backplane mit Oculink Buchse zum Einsatz. Oculink unterstützt laut Spezifikation PCIe 4.0, jedoch nicht PCIe 5.0.

Um die Verbindung auf PCIe 4.0 Geschwindigkeit (16GT/s) zu limitieren, kann man entweder das Tool setpci direkt mit den entsprechenden Parametern verwenden, oder das Skript pci_set_speed.sh von Alex Forenchich nutzen:[3]

# ./pci_set_speed.sh 0000:81:00.0 4
Link capabilities: 007b7845
Max link speed: 5
Link status: 7045
Current link speed: 5
Configuring 0000:80:01.1...
Original link control 2: 001e0005
Original link target speed: 5
New target link speed: 4
New link control 2: 001e0004
Triggering link retraining...
Original link control: 70450040
New link control: 70450060
Link status: 7044
Current link speed: 4

Nach dem Ausführen des Skriptes ist die PCIe Link Geschwindigkeit reduziert (LnkSta: Speed 16GT/s (downgraded)):

root@xfuel:~# lspci -s 81:00.0 -vvv
81:00.0 Non-Volatile memory controller: KIOXIA Corporation Device 0013 (rev 01) (prog-if 02 [NVM Express])
        Subsystem: KIOXIA Corporation Device 0045
        Physical Slot: 1
        [...]
        Capabilities: [70] Express (v2) Endpoint, MSI 00
                [...]
                LnkCap: Port #0, Speed 32GT/s, Width x4, ASPM not supported
                        ClockPM- Surprise- LLActRep- BwNot- ASPMOptComp+
                LnkCtl: ASPM Disabled; RCB 64 bytes, Disabled- CommClk+
                        ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
                LnkSta: Speed 16GT/s (downgraded), Width x4
                        TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
                [...]
                LnkCap2: Supported Link Speeds: 2.5-32GT/s, Crosslink- Retimer+ 2Retimers+ DRS-
                LnkCtl2: Target Link Speed: 32GT/s, EnterCompliance- SpeedDis-
                         Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
                         Compliance Preset/De-emphasis: -6dB de-emphasis, 0dB preshoot

Folgende Tests mit fio zeigten keine Probleme mehr. Die Ursache für die Data Transfer Error war also die höhere (32GT/s) Übertragungsgeschwindigkeit von PCIe 5.0 über Komponenten (Backplane), die nur bis PCIe 4.0 freigegeben sind.

Skript zum Limitieren der PCIe Übertragungsrate

Hier ist zur Information der vollständige Code des Bash-Scripts von Alex Forenchich (Lizenz: [https://creativecommons.org/licenses/by-sa/4.0/ CC-BY-SA 4.0):<ref name=pcispeed>

    #!/bin/bash
     
    dev=$1
    speed=$2
     
    if [ -z "$dev" ]; then
        echo "Error: no device specified"
        exit 1
    fi
     
    if [ ! -e "/sys/bus/pci/devices/$dev" ]; then
        dev="0000:$dev"
    fi
     
    if [ ! -e "/sys/bus/pci/devices/$dev" ]; then
        echo "Error: device $dev not found"
        exit 1
    fi
     
    pciec=$(setpci -s $dev CAP_EXP+02.W)
    pt=$((("0x$pciec" & 0xF0) >> 4))
     
    port=$(basename $(dirname $(readlink "/sys/bus/pci/devices/$dev")))
     
    if (($pt == 0)) || (($pt == 1)) || (($pt == 5)); then
        dev=$port
    fi
     
    lc=$(setpci -s $dev CAP_EXP+0c.L)
    ls=$(setpci -s $dev CAP_EXP+12.W)
     
    max_speed=$(("0x$lc" & 0xF))
     
    echo "Link capabilities:" $lc
    echo "Max link speed:" $max_speed
    echo "Link status:" $ls
    echo "Current link speed:" $(("0x$ls" & 0xF))
     
    if [ -z "$speed" ]; then
        speed=$max_speed
    fi
     
    if (($speed > $max_speed)); then
        speed=$max_speed
    fi
     
    echo "Configuring $dev..."
     
    lc2=$(setpci -s $dev CAP_EXP+30.L)
     
    echo "Original link control 2:" $lc2
    echo "Original link target speed:" $(("0x$lc2" & 0xF))
     
    lc2n=$(printf "%08x" $((("0x$lc2" & 0xFFFFFFF0) | $speed)))
     
    echo "New target link speed:" $speed
    echo "New link control 2:" $lc2n
     
    setpci -s $dev CAP_EXP+30.L=$lc2n
     
    echo "Triggering link retraining..."
     
    lc=$(setpci -s $dev CAP_EXP+10.L)
     
    echo "Original link control:" $lc
     
    lcn=$(printf "%08x" $(("0x$lc" | 0x20)))
     
    echo "New link control:" $lcn
     
    setpci -s $dev CAP_EXP+10.L=$lcn
     
    sleep 0.1
     
    ls=$(setpci -s $dev CAP_EXP+12.W)
     
    echo "Link status:" $ls
    echo "Current link speed:" $(("0x$ls" & 0xF))

Weitere Informationen

Einzelnachweise


Autor: Werner Fischer

Werner Fischer arbeitet im Product Management Team von Thomas-Krenn. Er evaluiert dabei neueste Technologien und teilt sein Wissen in Fachartikeln, bei Konferenzen und im Thomas-Krenn Wiki. Bereits 2005 - ein Jahr nach seinem Abschluss des Studiums zu Computer- und Mediensicherheit an der FH Hagenberg - heuerte er beim bayerischen Server-Hersteller an. Als Öffi-Fan nutzt er gerne Bus & Bahn und genießt seinen morgendlichen Spaziergang ins Büro.

 

Das könnte Sie auch interessieren

Linux Cluster Management Console (LCMC)
Netzwerkdiagramme mit LibreOffice erstellen
OpenVPN Grundlagen