Aufbau eines fehlertoleranten Embedded Linux-Systems auf Basis des Mars ZX3-Moduls von Enclustra

Aufgrund der vielen Spezialisten mussten wir vor einigen Jahren Gegenparteien eine Entwicklung anbieten. Die Entwicklung wurde für das Enclustra Mars ZX3-Modul durchgeführt, das das SOC ARM + FPGA Zynq-7020 verwendet. Zum Erstellen von Linux haben wir Bcl von Enclustra (bsp-xilinx) verwendet, das leicht modifiziert wurde.

Beim Testen der entwickelten Software sind beim Ausschalten sofort Softwarefehler aufgetreten. Bei der Analyse wurde festgestellt, dass die über das Netzwerk an das Gerät gesendeten Konfigurationsbefehle in Dateien geschrieben wurden, die sich bei einem Stromausfall manchmal als leer oder gar nicht vorhanden erwiesen. Dies zwang uns, die Ideologie des Aufbaus der Linux-Assembly, die uns übergeben wurde, zu überdenken. Der Prozess des Aufbaus des Systems selbst ist auf der Website des Herstellers des Moduls ausführlich beschrieben, sodass ich nicht weiter darauf eingehen werde. Ich werde nur beschreiben, was es uns ermöglicht hat, die vor uns liegende Aufgabe, die Zuverlässigkeit zu erhöhen und Ausfälle zu verhindern, zu lösen.

Das Mars ZX3-Modul verfügt über QSPI-Flash- und NAND-Flash-Chips. In unserem Fall ist das Modul mit QSPI Flash geladen, in das U-Boot geschrieben wurde. Da beide Chips dieselben Zynq-7020-Pins verwenden, werden die Pins nach dem Laden von U-Boot auf NAND-Flash umgeschaltet, auf dem das Boot-Skript, der Gerätebaum, der Linux-Kernel, das ubifs-Dateisystem und die Umgebungsvariablen in separate Abschnitte geschrieben werden. Außerdem waren alle Abschnitte mit Ausnahme des Abschnitts mit Umgebungsvariablen reserviert (dh es gab zwei solche Abschnitte). Das Folgende ist ein Fragment der Device Tree-Datei, das zeigt, wie NAND Flash in der von den Auftragnehmern übermittelten Version beschädigt wurde:

partition@nand-linux { label = "nand-linux"; reg = <0x0 0x500000>; }; partition@nand-device-tree { label = "nand-device-tree"; reg = <0x500000 0x100000>; }; partition@nand-bootscript { label = "nand-bootscript"; reg = <0x600000 0x100000>; }; partition@nand-linux-second { label = "nand-linux-second"; reg = <0x700000 0x500000>; }; partition@nand-device-tree-second { label = "nand-device-tree"; reg = <0xC00000 0x100000>; }; partition@nand-bootscript-second { label = "nand-bootscript"; reg = <0xD00000 0x100000>; }; partition@nand-rootfs { label = "nand-rootfs"; reg = <0xE00000 0xF500000>; }; partition@nand-rootfs-second { label = "nand-rootfs"; reg = <0x10300000 0xF500000>; }; partition@boot-env { label = "nand-env"; reg = <0x1F800000 0x100000>; }; 

Die zweiten Abschnitte sollten verwendet werden, wenn die Hauptabschnitte versagten. Dazu musste Linux einen Prozess implementieren, der die Integrität des Systems überwacht und im Falle eines Fehlers einen Wert in die Umgebungsvariable schreibt, der anweist, das System von den Sicherungspartitionen aus zu starten. Dieser Algorithmus sollte in Zukunft implementiert werden.

Die Konfigurationsdaten wurden zur Sicherung in zwei Ordnern gespeichert, dies hat jedoch die Situation nicht gerettet. Es wird davon ausgegangen, dass bei Fehlen von Konfigurationsdateien diese automatisch mit den Standardeinstellungen neu erstellt werden.

Das Problem ist, dass NAND Flash Daten seitenweise schreibt und das Löschen blockweise erfolgt. Wenn während der Datenaufzeichnung ein Stromausfall auftritt, werden nicht nur diese Daten beschädigt, sondern auch das Dateisystem kann beschädigt werden. Das Starten eines Backup-Systems kann das Auftreten eines Problems nur verzögern. In diesem Fall ist es jedoch möglich, die Wiederherstellung der Hauptpartitionen aus den Sicherungspartitionen zu realisieren.

Wir entschieden uns für den umgekehrten Weg, indem wir rootfs als schreibgeschütztes Dateisystem bereitstellten und Konfigurationsdateien in separate Daten- und Sicherungsabschnitte schrieben, die zum Lesen und Schreiben bereitgestellt wurden. In diesem Fall sind keine Backup-Partitionen mehr erforderlich, wir haben sie jedoch für die Zukunft reserviert, da dies aufgrund des verfügbaren Arbeitsspeichers möglich war. Bei Bedarf können sie gelöscht werden.

Als Ergebnis wurde die folgende NAND-Flash-Partitionierung durchgeführt:

  partition@nand-linux { label = "nand-linux"; reg = <0x0 0x500000>; }; partition@nand-device-tree { label = "nand-device-tree"; reg = <0x500000 0x100000>; }; partition@nand-bootscript { label = "nand-bootscript"; reg = <0x600000 0x100000>; }; partition@nand-linux-second { label = "nand-linux-second"; reg = <0x700000 0x500000>; }; partition@nand-device-tree-second { label = "nand-device-tree"; reg = <0xC00000 0x100000>; }; partition@nand-bootscript-second { label = "nand-bootscript"; reg = <0xD00000 0x100000>; }; partition@nand-rootfs { label = "nand-rootfs"; reg = <0xE00000 0x9600000>; }; partition@nand-rootfs-second { label = "nand-rootfs"; reg = <0xA400000 0x9600000>; }; partition@nand-data { label = "nand-data"; reg = <0x13A00000 0x5F00000>; }; partition@nand-data-backup { label = "nand-data-backup"; reg = <0x19900000 0x5F00000>; }; partition@boot-env { label = "nand-env"; reg = <0x1F800000 0x100000>; }; 

Wenn Sie NAND Flash mit dem U-Boot-Befehl flashen, werden die Abschnitte nand-data und nand-data-backup gelöscht :

 u-boot>nand erase.part nand-data u-boot>nand erase.part nand-data-backup 

Im Linux-Boot-Skript haben wir das Mounten des Root-Dateisystems als schreibgeschützt implementiert und die Zeile in der Datei / etc / inittab in der Linux-Assembly ersetzt:

 ::sysinit:/bin/mount -o remount,rw / 

auf

 ::sysinit:/bin/mount -o remount,ro / 

Wir haben dem Ordner /etc/init.d/ ein Boot-Skript hinzugefügt , das die Abschnitte nand-data und nand-data-backup zum Lesen und Schreiben bereitstellt . Im Falle eines Bereitstellungsfehlers (beim ersten Start oder wenn das Dateisystem beschädigt ist) werden diese Partitionen formatiert und neu bereitgestellt. Die Ordner / mnt / data / und / mnt / backup / müssen zuvor im Root-Dateisystem erstellt worden sein.

 #!/bin/sh # # datafs Mount datafs. # umask 077 start() { printf "Starting mount datafs..." /usr/sbin/ubiattach /dev/ubi_ctrl -m 8 /usr/sbin/ubiattach /dev/ubi_ctrl -m 9 mount_datafs_err=0; mount_datafs_backup_err=0; /bin/mount -t ubifs ubi1:datafs /mnt/data mount_datafs_err=$? if [ $mount_datafs_err -ne 0 ]; then /usr/sbin/ubidetach -p /dev/mtd8 /usr/sbin/ubiformat /dev/mtd8 -y /usr/sbin/ubiattach /dev/ubi_ctrl -m 8 /usr/sbin/ubimkvol /dev/ubi1 -N datafs -s 81MiB /bin/mount -t ubifs ubi1:datafs /mnt/data mount_datafs_err=$? fi /bin/mount -t ubifs ubi2:datafs /mnt/backup mount_datafs_backup_err=$? if [ $mount_datafs_backup_err -ne 0 ]; then /usr/sbin/ubidetach -p /dev/mtd9 /usr/sbin/ubiformat /dev/mtd9 -y /usr/sbin/ubiattach /dev/ubi_ctrl -m 9 /usr/sbin/ubimkvol /dev/ubi2 -N datafs -s 81MiB /bin/mount -t ubifs ubi2:datafs /mnt/backup mount_datafs_backup_err=$? fi printf "Mount datafs: " if [ $mount_datafs_err -ne 0 ]; then echo "Error" else echo "OK" fi printf "Mount backup datafs: " if [ $mount_datafs_backup_err -ne 0 ]; then echo "Error" else echo "OK" fi touch /var/lock/datafs } stop() { /bin/umount /mnt/data /bin/umount /mnt/backup rm -f /var/lock/datafs } restart() { stop sleep 1 start } case "$1" in start) start ;; stop) stop ;; restart|reload) restart ;; *) echo "Usage: $0 {start|stop|restart|reload}" exit 1 esac exit 0 

Wenn beim Herunterladen die Konfigurationsdateien im Ordner / mnt / data / fehlen, werden sie aus dem Ordner / mnt / backup / heruntergeladen. Wenn sich in / mnt / backup / keine Konfigurationsdateien befinden, werden diese automatisch mit den Standardparametern aus der Software erstellt. Befinden sich die Dateien in / mnt / data /, jedoch nicht in / mnt / backup / , werden sie von / mnt / data / nach / mnt / backup / kopiert. Alle diese Vorgänge werden von der Anwendersoftware ausgeführt.

In der nächsten Phase haben wir uns aus Gründen der Zuverlässigkeit geweigert, die Konfiguration für jeden Befehl in eine Datei zu schreiben. Die gesamte Konfiguration wird nun im RAM gespeichert und kann bei Bedarf durch einen separaten Befehl in Dateien in den Ordnern / mnt / data / und / mnt / backup / gespeichert werden.

Wenn Sie während der Arbeit Änderungen am Root-Dateisystem vornehmen müssen, ohne das Gerät erneut zu flashen, können Sie das System über die Konsole erneut zum Lesen und Schreiben mit dem Befehl bereitstellen

 mount -o remount,rw / 

Nehmen Sie die gewünschten Änderungen vor und hängen Sie sie schreibgeschützt erneut ein:

 mount -o remount,ro / 

Source: https://habr.com/ru/post/de483900/


All Articles