Aus Linux-Magazin 04/2016

Kernel- und Treiberprogrammierung mit dem Linux-Kernel – Folge 85

© psdesign1, Fotolia

Zwar kann der Linux-Kernel SSDs der Einfachheit halber wie konventionelle Festplatten ansprechen, schöpft damit die mechanikfreien Blockgeräte aber nicht annähernd aus. Seit einem Umbau ist Linux bereit für die neue Technik. Mehr noch: Die Entwickler würden gern den Job der Firmware übernehmen.

Mehr als zwei Jahrzehnte lang hat die von Linus Torvalds angeführte Truppe Code optimiert, damit Linux klassische Festplatten optimal handhabt. Die Schwächen in der Technologie machte es den Entwicklern nicht leicht: rotierende und darum stoßempfindliche Platten, mechanisch aufwändig zu positionierende Köpfe, wechselnde Transferraten, modellabhängige Cachingstrategien, die hohen Latenzzeiten beim Lesen und Schreiben von rückwärtigen Daten sowie Integritätsprobleme wegen des verzögerten Schreibens.

Das Resultat sind auf Magnetplatten optimierte Dateisysteme, diverse Caches und passende I/O-Schedulingmechanismen. Damit hält der Kernel I/O-Aufträge zurück, sortiert sie um und reicht sie erst im geeigneten Moment an die drehenden Scheiben weiter.

Flashspeicher kommen dagegen ohne mechanische Komponenten aus, und die Latenzzeiten bewegen sich statt im Millisekunden- im Mikrosekunden-Bereich. Kann das Betriebssystem pro Sekunde mehrere Hundert I/O-Zugriffe (IOPS) auf eine Festplatte absetzen, sind es bei einer SSD mehrere Hunderttausend und im Idealfall bis zu 15 Millionen.

Flashmemory liest und schreibt Daten unabhängig von der Position im Speicher gleich schnell, fragmentiert abgelegte Daten bedeuten keine Performance-Einbußen mehr. Andererseits lassen sich die einzelnen Speicherblöcke eines Flashspeichers nicht beliebig oft beschreiben. Technisch besteht das Schreiben aus dem Löschen eines Blockes und dem nachfolgenden Rücksetzen einzelner Bits.

Der Flash Translation Layer

Die Hersteller begegnen den Flash-Eigenheiten in ihren Solid State Drives (SSDs) mit einer Softwareschicht (Flash Translation Layer, FTL), die auf dem SSD-Controller läuft. Sie vermeidet das häufige Schreiben von einzelnen Blöcken und bringt ein ausgefuchstes Bad-Block-Management mit. Es ersetzt als fehlerhaft erkannte Blöcke durch Reserveblöcke – von denen die SSD eine ausreichend große Anzahl vorhält.

Mit einem SATA-Hardware-Interface ausgestattet, haben die Hersteller unter dem Diktat der Kompatibilität Solid State Drives hergestellt, die sich von den alten Festplatten im Wesentlichen nur durch ihre erheblich besseren Zugriffszeiten auszeichnen. Praktisch für den Anwender: Die neue schnelle Hardware funktioniert mit der bewährten Systemsoftware.

Entschlackungskur

Die jahrelangen Forschungs-, Test- und Implementierungsarbeiten am Festplatten-Subsystem verlieren mit dem Aufkommen von Flashspeichern, insbesondere von SSDs, an praktischer Bedeutung. Der Kernel für Rechner ohne konventionelle Festplatte lässt sich um einen gehörigen Batzen Code entschlacken und damit natürlich beschleunigen.

Andererseits vermag die Firmware der SSDs prinzipbedingt keine hundertprozentige Kompatibilität zu konventionellen Festplatten herzustellen: Ob ein Block auf dem Speichermedium noch belegt ist oder nicht, wissen nur das Betriebssystem oder das konkrete Dateisystem – unter Linux zumeist Ext 4. Aus diesem Grund muss Linux der SSD allwöchentlich per Trim-Kommando die nicht mehr verwendeten Blöcke mitteilen (Abbildung 1). Ob SSDs im System vorhanden sind, lässt sich im Sys-Filesystem herausfinden (Abbildung 2).

Abbildung 1: In wöchentlichem Abstand teilt Linux der SSD die nicht mehr genutzten Blöcke mit.

Abbildung 1: In wöchentlichem Abstand teilt Linux der SSD die nicht mehr genutzten Blöcke mit.

Abbildung 2: Ist der Inhalt der Pseudodatei »rotational« gleich null, handelt es sich um einen Flashspeicher.

Abbildung 2: Ist der Inhalt der Pseudodatei »rotational« gleich null, handelt es sich um einen Flashspeicher.

Das große Potenzial der Flashspeichertechnik schöpft der Festplatten-Kompatibilitätsmodus jedoch bei Weitem nicht aus. Die Kernelentwickler arbeiten seit einigen Jahren eng mit SSD-Herstellern zusammen, um mehr Effizienz zu erreichen. Neben mehreren kleineren Maßnahmen unterstützt der Kernel hochperformante Solid State Drives mit drei Technologien: durch den Multiqueue-Blocklayer, durch Polling für Blockgeräte sowie für Open-Channel-SSDs durch Light NVM (Abbildung 3).

Während die beiden letzten Technologien erst kürzlich mit Kernel 4.4 den Weg in den Betriebssystemkern fanden, feierte der Multiqueue-Blocklayer bereits mit Version 3.13 sein Debüt [1]. Traditionell sequenzialisiert der Blocklayer I/O-Aufträge an die Festplatte (siehe Kasten “Das Blockgeräte-Subsystem”). Der Multiqueue-Blocklayer bietet zusätzlich die Möglichkeit der Parallelverarbeitung. Das ist aus zwei Gründen bedeutsam: Erstens arbeiten hochperformante SSDs mehrere I/O-Aufträge parallel ab, und zweitens sind moderne Systeme zunehmend Multicore.

Abbildung 3: Linux bedient konventionelle Festplatten mit einer Warteschlange (oben links), SSDs steuert es über seinen Multiqueue-Blocklayer an (oben rechts).

Abbildung 3: Linux bedient konventionelle Festplatten mit einer Warteschlange (oben links), SSDs steuert es über seinen Multiqueue-Blocklayer an (oben rechts).

Das Blockgeräte-Subsystem

Festplatten, DVD- und CD-ROM-Laufwerke, USB-Sticks, Speicherkarten und eben auch SSDs arbeiten grundsätzlich blockweise. Selbst wenn die CPU nur ein einzelnes Byte von einem solchen Gerät lesen möchte, bekommt sie einen ganzen Block geliefert, klassischerweise 512 Byte. Das Betriebssystem fordert einen Block über dessen Blocknummer an, während die Anwender auf logischer Ebene Dateisysteme mit Verzeichnissen und Dateien sehen.

Das Umsetzen von einem Dateinamen zu den physischen Blocknummern ebenso wie den eigentlichen Zugriff erledigt das Blockgeräte-Subsystem. Die für normale Festplatten generierten I/O-Aufträge schreibt der Singlequeue-Blocklayer in eine für die Festplatte reservierte Queue. Die dort eine Zeitlang gesammelten Aufträge sortiert ein I/O-Scheduling-Algorithmus um und fasst sie so zusammen, dass die Festplatte mit ihren drehenden Magnetscheiben die Blöcke möglichst effizient lesen beziehungsweise speichern kann.

Die Festplatte ihrerseits transferiert die Daten typischerweise per DMA in den RAM und löst dann einen Interrupt aus. Die Interrupt-Service-Routine weckt am Ende die Applikationen, welche die Daten angefordert hatten. Wie leicht nachzuvollziehen ist, bildet die Auftrags-Queue pro Festplatte einen Engpass. Denn die Queue verhindert, dass das System mit einer zunehmenden Anzahl von Prozessorkernen (Multi- und Manycore-Systeme) skaliert, weil das System das parallele Zugreifen über Spinlocks verhindern muss.

Je mehr Prozesse zugreifen, desto häufiger entstehen Wartezeiten, wie die Messungen von Blockgeräte-Subsystem-Maintainer Jens Axboe eindrucksvoll zeigen. Selbst auf einer idealisierten Festplatte mit optimalen Eigenschaften konnte Axboe auf einem hochperformanten Rechner nicht mehr als eine Million I/O-Aufträge pro Sekunde absetzen.

Schlangen statt Schlange

Während zwischen den zugreifenden Applikationen und der Festplatte klassisch eine Queue die I/O-Aufträge verarbeitet, unterteilt sich der Multiqueue-Blocklayer mit der Software- und der Hardware-Schicht auf zwei Ebenen (Abbildung 3). Auf der Software-Ebene existiert pro CPU-Kern eine eigene Software Staging Queue. In sie trägt Linux die I/O-Aufträge der auf dem Core arbeitenden Jobs ein. Die Mehrfachauslegung pro CPU-Kern spart den ansonsten notwendigen Sperrmechanismus (Abbildung 4). Der entscheidende Effekt ist, dass die früher um die Queue konkurrierenden Rechenprozesse bei der neuen Lösung nicht auf andere Jobs warten müssen – sie können die I/O-Aufträge direkt ablegen. Außerdem vermeidet die Architektur Cacheprobleme (Stichwort: Kohärenz).

Abbildung 4: Für klassische Magnetplatten eingesetztes Blockgeräte-Subsystem.

Abbildung 4: Für klassische Magnetplatten eingesetztes Blockgeräte-Subsystem.

Innerhalb der Software Staging Queue sammelt der Kernel asynchrone I/O-Aufträge kurzzeitig und fasst sie falls möglich zusammen. Denn auch SSDs arbeiten einen kombinierten Auftrag, mehrere sequenzielle Blöcke zu transferieren, schneller ab als das Äquivalent der Einzel-I/O-Aufträge. I/O-Aufträge lassen sich aber auch ohne Sammeln und Zusammenfassen – der Fachmann spricht von “synchron” – an die zweite Ebene weiterleiten. Diese besteht aus den Hardware Dispatch Queues.

Das Zusammenfassen von I/O-Aufträgen findet nur innerhalb einer einzelnen Software Staging Queue statt. Die Weiterleitung dieser Aufträge an die Hardware Dispatch Queue passiert entweder nach Ablauf einer festgelegten Zeitspanne oder dann, wenn andere I/O-Aufträge für dieselbe Hardware Dispatch Queue in einer Software Staging Queue abgelegt werden. Pro SSD (oder auch Festplatte) ist mindestens eine Hardware Dispatch Queue vorhanden – falls die SSD das unterstützt, gibt es auch mehrere.

Low-Level-Treiber

Mit der Übernahme der I/O-Aufträge in die Hardware Dispatch Queue reicht Linux diese an den Low-Level-Treiber für die SSD weiter und führt sie damit aus. Abbildung 5 zeigt die vom Multiqueue-Blocklayer bereitgestellten Queues für ein Quadcore-System, das mit zwei SSDs bestückt ist. Für SSD 1 arbeitet eine Hardware-Queue, für SSD 2 zwei.

Mit diesem Mechanismus vereinfacht sich das Schreiben eines Gerätetreibers für ein hochperformantes Blockgerät. Der Treiber implementiert Funktionen für die direkte Kommunikation mit dem Gerät (Low-Level-Treiber), für das Mapping zwischen den Software Staging Queues und den Hardware Dispatch Queues und die Initialisierung der SSD-Geräte. Für jede SSD im System legt er Anzahl und Umfang der Queues fest [2].

Die Kernelentwickler stellen mit dem »null_blk.c« einen Beispieltreiber bereit, der sich auch als Testgerät für den alten Singlequeue- und den neuen Multiqueue-Blocklayer eignet [3]. Er simuliert optimale SSDs, also solche ohne Latenz. Damit lässt sich das Blockgeräte-Subsystem zeitlich ausmessen. Ergebnis: Auf einem leistungsstarken Rechenboliden sind mit dem alten Singlequeue-Blocklayer (SQ) maximal eine Million I/O-Operationen pro Sekunde (IOPS) realisierbar, mit dem neuen Multiqueue-Blocklayer (MQ) dagegen 15 Millionen IOPS [4]!

Abbildung 5: Über ein zweistufiges Verfahren übermittelt Linux die Aufträge an die Flashspeicher.

Abbildung 5: Über ein zweistufiges Verfahren übermittelt Linux die Aufträge an die Flashspeicher.

Kürzere Denkpausen

Auch bei den Latenzzeiten gibt es von signifikanten Verbesserungen zu berichten: Blocklayer-Maintainer Jens Axboe und seine Mitstreiter haben gemessen, dass auf dem SQ-System 20 Prozent der Requests mehr als 1 Millisekunden benötigen, für den MQ liegt dieser Prozentsatz bei nur 0,15. Die maximale Latenz verbessert sich von 750 Millisekunden auf 250 Millisekunden.

Allerdings ist anzumerken, dass die erreichten Kennzahlen zwar die Leistung des neuen Blocklayers widerspiegeln, diese sich aber erst nach Umbauten der zuführenden Kernelkomponenten entfalteten. Bei den Messungen tauchten diverse Bottlenecks – insbesondere auf NUMA-Maschinen (Non Uniform Memory Architecture) – auf, welche die Tester erst beseitigen mussten.

Polling ist besser

Einen solchen Engpass bildet auch die Interruptverarbeitung im Blocklayer. Bei Festplatten setzt der Kernel einen I/O-Auftrag ab und die Platte quittiert den Abschluss (Completion) per Interrupt. Die Interrupt-Service-Routine (ISR) erledigt die Verarbeitung und weckt auch die auf die Daten wartende Applikation auf. Ein Interrupt ist eine effiziente Methode, denn – in Abgrenzung zum Polling – wird nur dann Code durchlaufen, wenn es auch notwendig ist.

Allerdings ist das Starten der ISR für die CPU ein zeitaufwändiger Vorgang. Beim Polling hingegen prüft sie periodisch, ob ein erwarteter Zustand erreicht ist. Würde der Pollingalgorithmus oft prüfen, würde das den Prozessor stark belasten. Schaut er nur selten nach, verpasst er möglicherweise das Trigger-Ereignis. Polling lohnt also nur, wenn Ereignisse häufig eintreten.

Bei hochperformanten SSDs ist diese Schwelle erreicht, wobei der Kernel in der Praxis – wie bereits im Netzwerk-Subsystem – eine Kombination von Interrupt und Polling betreibt [5]. Die zum SSD-Treiber gehörende ISR schaut in einer (Polling-)Schleife ständig nach, ob nicht irgendwelche I/O-Aufträge abgeschlossen sind. Ist das der Fall, führt sie die notwendigen Aktionen – etwa das Wecken der auf die Daten wartenden Applikationen – aus. Erst wenn die Hardware keine ausstehenden Aufträge signalisiert, beendet sich die ISR. Jens Axboe, der für diese Änderung verantwortlich ist, beschleunigt per Polling I/O-Kopieraktionen, die er mit dem Kopierprogramm »dd« benchmarkt, auf das Doppelte.

Flash in eingebetteten Systemen

In eingebetteten Systemen kommt Flashspeichern eine andere Bedeutung zu als in Server- und Desktoprechnern. In Minirechnern ist neben niedrigen Kosten häufig Robustheit, aber selten viel Speicherplatz für umfangreiche Datenbestände gefordert. Drehende Scheiben und Lüfter sind sowieso tabu.

Ein Flashchip dagegen kostet wenig, wenn der Entwickler auf schnelle Zugriffszeiten und ausgefeilte Controller verzichtet. Um die Forderungen nach Robustheit trotz der limitierten Schreibzugriffe einhalten zu können, offeriert Linux das MTD-Subsystem (Memory Technology Device, Abbildung 6). Es erlaubt bequem auf rohen Flashspeicher zuzugreifen und bietet spezielle Flash-Filesysteme, die den File Translation Layer implementieren. Zudem versuchen eingebettete Geräte Schreibzugriffe generell zu vermeiden, etwa indem sie das Root-Filesystem als RAM-Disk realisieren. Die Hintergründe und einige Empfehlungen hierzu liefert der Linux-Magazin-Artikel [8].

Abbildung 6: Das MTD-Subsystem des Linux-Kernels enthält zahlreiche Module für den Umgang mit Flashspeicher.

Abbildung 6: Das MTD-Subsystem des Linux-Kernels enthält zahlreiche Module für den Umgang mit Flashspeicher.

Altlast als Spaßbremse

Die Kernelentwickler sehen nicht nur Optimierungspotenzial im Kernel, sondern auch in den Flashspeichern selbst. Ihr Wunschrezept lautet “Less is more”: Weg mit der SSD-Firmware, dafür direkten Hardwarezugriff für den Kernel! Erstens kommt die SSD-Firmware ohnehin nicht gänzlich ohne die Mithilfe des Betriebssystems aus, zweitens ist sie auf bestimmte Filesysteme hin optimiert. Und das sind eher die alten FAT- als moderne Linux-Filesysteme. Last but not least: Updates der SSD-Firmware gestalten sich für den Anwender nicht trivial.

Die Torvalds-Truppe ist der Überzeugung, dass sie die Aufgaben der SSD-Firmware besser handhaben kann, schließlich hat sie bei den eingebetteten Systemen mit ihren direkt angebundenen, meist proprietären Flashspeichern bereits viel Erfahrung gesammelt (siehe Kasten “Flash in eingebetteten Systemen”). Funkt ihm keine Firmware dazwischen, könnte der Kernel die SSD passend zum aktiven Lastprofil und zum aktuellen Filesystem ansteuern.

Diese Idee hat Kernel 4.4 mit der dort implementierten Spezifikation Light NVM [6] realisiert. Die Spezifikation zur Ansteuerung von so genannten Open-Channel-SSDs, also Flashspeichern, die den direkten Zugriff ermöglichen, ist offen.

Von Linux aus gesehen besteht eine Open-Channel-SSD aus dem Flash Translation Layer (FTL), dem Bad-Block-Management und den Hardware-Einheiten (Flashcontroller, Interfacecontroller und den Flashbausteinen). Dank der in der Spezifikation hinterlegten Flexibilität darf Linux alle Funktionen der Controller-Software oder aber auch nur Teile davon übernehmen.

Mit der Implementierung von Light NVM ist auch NVMe in den Kernel gelangt [7]. NVMe ist für “Non Volatile Memory” wie SSDs das, was SATA für Festplatten ist: die Hardware-Schnittstelle. Erst NVMe ermöglicht es, die SSD über mehrere Kanäle anzusprechen.

Quo vadis?

Während Linux heute aus Kompatibilitätsgründen auf den bewährten Code zur Ansteuerung von Magnetplatten noch nicht verzichtet, rüstet sich der Kernel schon für die noch schnelleren SSDs von morgen.

Obwohl in diesem Bereich noch viel zu entwickeln bleibt, haben die Kernelprogrammierer bereits mit den Arbeiten an der Unterstützung für die nächste Speichertechnologie begonnen: 64-Bit-Prozessoren haben einen ausreichend großen Adressraum, um Flashspeicher statt als Blockgerät über den SATA-Bus direkt an den CPU-Speichercontroller zu mappen. Die neuen persistenten Speicher werden wohl als RAM-ähnliche Riegel in den Rechner gesteckt werden. Denkbar sind dann Linux-Rechner, die ganz ohne Blockgeräte auskämen.

Infos

  1. Jonathan Corbet, “The multiqueue block layer”: https://lwn.net/Articles/552904/
  2. Arianna Avanzini, “The block I/O layer, part 4 – The multi-queue interface”: http://ari-ava.blogspot.de/2014/07/opw-linux-block-io-layer-part-4-multi.html
  3. Null-Block-Gerät, Quellcode im Linux-Kernel: http://lxr.free-electrons.com/source/drivers/block/null_blk.c
  4. Bjørling, Axboe, Nellans, Bonnet, “Linux Block IO: Introducing Multi-queue SSD Access on Multi-core Systems”: http://kernel.dk/systor13-final18.pdf
  5. Jonathan Corbet, “Block-layer I/O polling”: http://lwn.net/Articles/663879/
  6. Matias Bjørling, “Open-Channel Solid State Drive Interface Specification”: https://docs.google.com/document/d/1kedBY_1-hfkAlqT4EdwY6gz-6UOZbn7kIjWpmBLPNj0/edit?pref=2&pli=1#
  7. Jonathan Corbet, “Taking control of SSDs with LightNVM”: https://lwn.net/Articles/641247/
  8. Michael Opdenacker, “Linux-Dateisysteme für Flashspeicher”: Linux-Magazin 07/12,S. 34, https://www.linux-magazin.de/Ausgaben/2012/07/Flashspeicher

Der Autor

Eva-Katharina Kunst ist seit den Anfängen von Linux Fan von Open Source. Jürgen Quade, Professor an der Hochschule Niederrhein, hat mit “Embedded Linux lernen mit dem Raspberry Pi” letztes Jahr sein drittes Linux-Buch veröffentlicht. Das gemeinsame Buch “Linux-Treiber entwickeln” ist jüngst in vierter Auflage erschienen.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 5 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Nach oben