Wie Linux Nicht-System-Software-RAID-Arrays beim Booten unter systemd startet
April 15, 2019
Theoretisch muss sich der Benutzer nicht darum kümmern, wie Linux-Software-RAID-Arrays beim Booten zusammengesetzt und gestartet werden, weil alles einfach funktioniert. In der Praxis ist das manchmal der Fall, und bei einem modernen systemd-basierten Linux scheint dies eine ungewöhnlich verworrene Situation zu sein. Hier ist also, was ich bisher darüber herausgefunden habe, wie es mit Software-RAID-Arrays funktioniert, die außerhalb des initramfs zusammengebaut und gestartet werden, nachdem das System das echte Root-Dateisystem gemountet hat und von diesem aus läuft.
(Wie die Dinge beim Starten von Software-RAID-Arrays im initramfs funktionieren, ist von Linux-Distribution zu Linux-Distribution sehr unterschiedlich. Es gibt sogar einige Unterschiede zwischen den Distributionen, was das Booten nach dem initramfs betrifft, aber heutzutage liefert die Master-Version von mdadm kanonische udev- und systemd-Skripte, Dienste usw. aus, und ich denke, die meisten Distributionen verwenden sie fast unverändert).
Wie schon seit einiger Zeit üblich, wird die grundlegende Arbeit durch udev-Regeln erledigt. Auf einem typischen Linux-System heißt die wichtigste udev-Regeldatei für die Assemblierung etwa 64-md-raid-assembly.rules und ist im Grunde die Upstream-Version von mdadm. Udev selbst identifiziert Blockgeräte, die potenziell Linux-RAID-Mitglieder sind (wahrscheinlich hauptsächlich aufgrund des Vorhandenseins von RAID-Superblöcken), und die udev-Regeln von mdadm führen mdadm dann in einem speziellen inkrementellen Assemblierungsmodus auf ihnen aus. Um die Manpage zu zitieren:
Dieser Modus ist dafür gedacht, in Verbindung mit einem Geräteerkennungssystem verwendet zu werden. Wenn Geräte in einem System gefunden werden, können sie an mdadm --incremental übergeben werden, um einem entsprechenden Array hinzugefügt zu werden.
Wenn Array-Komponenten für udev sichtbar werden und es veranlassen, mdadm --incremental auf ihnen auszuführen, fügt mdadm sie schrittweise dem Array hinzu. Wenn das letzte Gerät hinzugefügt ist, startet mdadm das Array. Dies macht das Software-RAID-Array und seinen Inhalt für udev und systemd sichtbar, wo es verwendet wird, um Abhängigkeiten für Dinge wie /etc/fstab-Einhängungen zu erfüllen und sie somit auszulösen.
(Es gibt zusätzliche mdadm-udev-Regeln für die Einrichtung von Gerätenamen, den Start der mdadm-Überwachung und so weiter. Und dann gibt es noch eine ganze Sammlung allgemeiner udev-Regeln und anderer Aktivitäten, um Dinge wie das Lesen der UUIDs von Dateisystemen aus neuen Blockgeräten zu erledigen).
All dies geschieht jedoch nur, wenn alle Geräte der Array-Komponenten in udev auftauchen (und schnell genug auftauchen); wenn nur einige der Geräte auftauchen, wird das Software-RAID teilweise von mdadm --incremental zusammengestellt, aber nicht gestartet, weil es nicht vollständig ist. Um mit dieser Situation umzugehen und schließlich Software-RAID-Arrays im degradierten Modus zu starten, starten die udev-Regeln von mdadm eine systemd-Timer-Unit, wenn genügend Geräte des Arrays vorhanden sind, um es degradiert laufen zu lassen, speziell die Template-Timer-Unit mdadm-last-resort@.timer (für md0 ist die spezifische Unit also
mdadm-last-resort@md0.timer). Wenn das RAID-Array nicht zusammengebaut ist und der Timer abläuft, wird die entsprechende systemd-Diensteinheit mit mdadm-last-resort@.service ausgelöst, die 'mdadm --run' auf dem degradierten Array ausführt, um es zu starten.
(Die Timer-Einheit wird nur gestartet, wenn die inkrementelle Assemblierung von mdadm zurückmeldet, dass es "unsicher" ist, das Array zu assemblieren, im Gegensatz zu "unmöglich". Mdadm meldet dies erst, wenn genügend Komponentengeräte vorhanden sind, um das Array in einem degradierten Modus zu betreiben; wie viele Geräte benötigt werden (und welche Geräte), hängt vom jeweiligen RAID-Level ab. RAID-1-Arrays zum Beispiel benötigen nur ein Komponentengerät, um "unsicher" zu sein).
Da es hier ein offensichtliches Wettrennen gibt, arbeiten sowohl der systemd-Timer als auch der Dienst hart daran, nicht zu handeln, wenn das RAID-Array tatsächlich vorhanden und bereits gestartet ist. Der Timer kollidiert mit 'sys-devices-virtual-block-<array>.device', der systemd-Geräteeinheit, die das RAID-Array repräsentiert, und als zusätzliche Sicherheitsmaßnahme weigert sich der Dienst, zu laufen, wenn das RAID-Array in /sys/devices vorhanden zu sein scheint. Darüber hinaus wird die udev-Regel, die systemd dazu veranlasst, die Timer-Unit zu starten, nur auf Software-RAID-Geräte wirken, die zu diesem System zu gehören scheinen, entweder weil sie in Ihrer mdadm.conf aufgelistet sind oder weil ihr Heimathost dieser Host ist.
(Dies ist die MD_FOREIGN-Übereinstimmung in den udev-Regeln. Die Umgebungsvariablen stammen aus der --export-Option von mdadm, die während der inkrementellen Assemblierung von udev verwendet wird. Mdadms Code für die inkrementelle Assemblierung, der auch diese Umgebungsvariablen erzeugt, befindet sich in Incremental.c. Die wichtige enough()-Funktion ist in util.c.)
Soweit ich weiß, ist nichts davon dokumentiert oder offiziell; es ist nur die Art und Weise, wie sich mdadm, udev und systemd im Moment verhalten und interagieren. Allerdings scheint dies ziemlich stabil und langjährig zu sein, so dass es wahrscheinlich auch in Zukunft so sein wird.
PS: Soweit ich das beurteilen kann, bedeutet all dies, dass es keine echte, vom Benutzer erreichbare Kontrolle darüber gibt, ob degradierte Software-RAID-Arrays beim Booten gestartet werden oder nicht. Wenn Sie speziell den Start von degradierten RAID-Arrays blockieren wollen, könnte es funktionieren, den Last-Resort-Timer oder die Service-Unit für das Array mit 'systemctl mask' zu maskieren. Wenn Sie degradierte Arrays immer starten wollen, dann ist die gute Nachricht, dass dies automatisch geschehen soll.
Kommentare zu dieser Seite:
Von x am 2022-10-13 18:12:22:
Noch mehr "Spaß" gibt es mit Software-Raids. Angenommen, ein Software-Raid besteht aus ein paar Festplatten, die an einen KVM-VM angeschlossen sind und dort zu einem Array zusammengesetzt werden.
systemd/udev/mdadm auf dem Host wird ... dieses Array ebenfalls zusammen.
Wie auch immer werden dabei die Dateisysteme auf dem Array nicht beschädigt (was überrascht).