\input{confighandout} \subsection{Unsorted Block Images (UBI)} \subsubsection{Was ist UBI?} UBI kann am ehesten als Logical Volume Manager (LVM) für mtd-Devices bezeichnet werden. Beim Start scant UBI das mtd-Device und baut eine Liste der vorhandenen Eraseblöcke auf. Dabei werden auch Bad Blocks richtig behandelt, da das MTD-Subsystem, auf dem UBI aufsetzt, diese bereits erkennt. Dieser Gesamtvorrat an physikalischen Eraseblöcken wird jetzt im nächsten Schritt an sogenannte UBI-Volumes verteilt. \subsubsection{UBI-Volumes} UBI-Volumes entsprechen etwa den Partitionen anderer Systeme. Der von einem mtd-Device bereitgestellte Speicher wird also in mehrere unabhängige Einheiten aufgeteilt. Im Vergleich zu den Partitionen, die das MTD-Subsystem auf einem Flash anlegen kann, sind UBI-Volumes aber erheblich leistungsfähiger und flexibler. Aus diesem Grund empfiehlt es sich, so wenig wie möglich mtd-Partitionen anzulegen, und UBI eine möglichst große Partition zur Verwaltung zu übergeben. MTD-Partitionen haben eine strikt festgelegte Zuordnung von physikalischen Eraseblöcken zu Partitionen. UBI kann dagegen Eraseblöcke bei Bedarf beliebig zwischen den Volumes umverteilen. Dies geschieht beispielsweise beim Wear-Leveling, das UBI ebenfalls durchführt. Ebenso können defekte Eraseblöcke durch andere Blöcke ersetzt werden. Durch den von UBI verwendeten Algorithmus ist es selbst beim Neuanlegen eines Volumes kaum vorhersagbar, welche physikalischen Eraseblöcke auf dem Flash es belegt. Während eine MTD-Partition immer in denselben aufeinanderfolgenden Blöcken liegt, ändert sich die Zuordnung von physikalischen Eraseblöcken des Flash zu logischen Eraseblöcken des Volumes im laufenden Betrieb dynamisch. Ein UBI-Volume mit drei Eraseblöcken kann also durchaus die Blöcke 814, 27 und 1013 belegen. Aus diesem Ansatz ergibt sich auch der Name \emph{Unsorted Block Images}. \emph{Hinweis:} Auf klassischen Festplatten wird ein solches Verhalten als \emph{Fragmentierung} bezeichnet und ist dort unerwünscht, da eine mechanische Platte signifikante Seek-Zeiten aufweist. Man versucht dort, Daten möglichst in aufeinander folgenden Blöcken zu speichern, um zu verhindern, dass der mechanische Schreib-/Lesekopf von einem Ende der Platte zum anderen bewegt werden muss. Auf Flash-Speichern gibt es keine Seek-Zeiten, was UBI hier zugunsten eines auf Flash optimierten Designs ausnutzt. \paragraph{Statische Volumes} Statische Volumes sind für Anwendungen gedacht, die kein Dateisystem benötigen. Ein praktisches Beispiel ist ein kleines Volume, das lediglich einen Kernel enthält, der vom Bootloader geladen und gestartet wird. Mit einem statischen Volume muss der Bootloader keinerlei Dateisystem implementieren. Er muss lediglich aus den UBI-Headern herausfinden, welche physikalischen Eraseblöcke zu dem statischen Volume gehören. Ausserdem erfährt er von UBI, wie viele Bytes tatsächlich durch Daten belegt sind. Er lädt diese Daten, im Beispiel einen Kernel, ins RAM und springt sie an. Dies ist mit relativ wenig Code (einige kB) möglich. Statische Volumes enthalten also immer nur einen einzigen Datenblock, der in einem Vorgang geschrieben werden muss. \paragraph{Dynamische Volumes} Dynamische Volumes sind dafür gedacht, ein Dateisystem zu enthalten. Man verwendet sie also beispielsweise für ein Root-Filesystem oder für Volumes, die Nutzerdaten enthalten. Dynamische Volumes verwendet man am Besten mit dem Dateisystem ubifs. \paragraph{UBIGLUEBI} UBIGLUEBI ist ein Aufsatz auf UBI, der für jedes Volume wieder ein mtd-Device bereitstellt. Dies klingt zunächst überraschend, da UBI ja schon auf einem mtd-Device aufsetzt. Der Hintergrund ist, dass ältere Flash-Dateisysteme wie jffs2 ein mtd-Device benötigen. Um deren Einsatz zu ermöglichen, wurde dieser Zusatz geschaffen. Heute gibt es ubifs, das direkt auf UBI aufsetzt und folglich kein mtd-Device benötigt. Da ubifs ohnehin in allen Bereichen deutliche Vorteile gegenüber jffs2 hat, wird UBIGLUEBI in der Regel nicht mehr benötigt. \includegraphics[width=8cm]{images/ubi-big-picture.png} \subsubsection{UBI-Tools} Da UBI von den MTD-Entwicklern implementiert wurde, sind die UBI-Tools Bestandteil der MTD-Tool-Kollektion. Diese gibt es mittlerweile als Paket in den meisten Distributionen. Unter Debian installiert man das Paket \cmd{mtd-utils}: \begin{lstlisting} aptitude install mtd-utils \end{lstlisting} Hier die wichtigsten UBI-Aktionen in Kurzform: Die Kontrolle über ein mtd-Device an UBI übertragen: \begin{lstlisting} ubiattach /dev/ubi_ctrl -m 2 \end{lstlisting} Dies verbindet \cmd{/dev/mtd2} mit UBI. Ein Volume anlegen: \begin{lstlisting} ubimkvol /dev/ubi0 -s 3MiB -t static -N kernel -n 1 \end{lstlisting} Hier wird ein 3MiB großes statisches Volume mit dem Namen \cmd{kernel} angelegt. Das Volume erhält die Nummer 1. Daten in ein statisches Volume schreiben: \begin{lstlisting} ubiupdatevol /dev/ubi0_1 zImage \end{lstlisting} Die Daten aus der Datei \cmd{zImage} werden in das statische Volume mit der Nummer 1 geschrieben. Natürlich lassen sich komplette Volumes auch wieder entfernen: \begin{lstlisting} ubirmvol/dev/ubi0 -n 1 \end{lstlisting} Das Volume mit der Nummer 1 wird entfernt. Der mit Abstand aufwendigste Befehl ist \cmd{ubinize}. Damit lassen sich vollständige UBI-Images für ein mtd-Device anfertigen. Diese können anschließend mit \cmd{nandwrite} in das mtd-Device geschrieben werden. Alternativ kann das Image natürlich auch mit einem geeigneten JTAGer in das Flash übertragen werden. Da \cmd{ubinize} sehr vielseitig ist und relativ viele Flash- und Layout-Parameter berücksichtigt werden müssen, kann hier nur ein einfaches Beispiel gegeben werden. Zunächst ist eine Konfigurationsdatei erforderlich, in der die einzelnen Volumes sowie die in ihnen unterzubringenden Images beschrieben werden. Diese Datei folgt in ihrer Syntax dem bekannten INI-Format. Ein Volume wird beispielsweise so angegeben: \begin{lstlisting} [rootfs-volume] mode=ubi image=../my-ubifs.img vol_id=1 vol_size=100MiB vol_type=dynamic vol_name=rootfs vol_flags=autoresize vol_alignment=1 \end{lstlisting} Unter der Annahme, dass alle Volumes in der oben angegebenen Weise in der Datei \cmd{ubi-cfg.ini} beschrieben wurden, kann man das UBI-Image mit einem Befehl erzeugen, der etwa so aussieht: \begin{lstlisting} ubinize -o ubi.img -p 128KiB -m 2048 -s 512 ubi-cfg.ini \end{lstlisting} Im Beispiel wird eine Eraseblock-Größe von 128k angegeben, ausserdem eine Pagegröße von 2048 Bytes sowie eine Subpage-Größe von 512 Bytes. Das fertige Image landet in der Datei \cmd{ubi.img}. Weitere Informationen sind unter folgender URL erhältlich: \begin{lstlisting} http://www.linux-mtd.infradead.org/doc/general.html \end{lstlisting} \input{tailhandout}