1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
|
\input{confighandout}
\subsection{Unsorted Block Images (UBI)}
\subsubsection{Was ist UBI?}
UBI kann am ehesten als Logical Volume Manager (LVM) f\"ur mtd-Devices
bezeichnet werden. Beim Start scanned UBI das mtd-Device und baut eine
Liste der vorhandenen Erasebl\"ocke auf. Dabei werden auch Bad Blocks
richtig behandelt, da das MTD-Subsystem, auf dem UBI aufsetzt, diese
bereits erkennt.
Dieser Gesamtvorrat an physikalischen Erasebl\"ocken wird jetzt im
n\"achsten 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\"angige
Einheiten aufgeteilt. Im Vergleich zu den Partitionen, die das
MTD-Subsystem auf einem Flash anlegen kann, sind UBI-Volumes aber erheblich
leistungsf\"ahiger und flexibler. Aus diesem Grund empfiehlt es sich, so
wenig wie m\"oglich mtd-Partitionen anzulegen, und UBI eine m\"oglichst gro\ss e
Partition zur Verwaltung zu \"ubergeben.
MTD-Partitionen haben eine strikt festgelegte Zuordnung von physikalischen
Erasebl\"ocken zu Partitionen. UBI kann dagegen Erasebl\"ocke bei Bedarf
beliebig zwischen den Volumes umverteilen. Dies geschieht beispielsweise
beim Wear-Leveling, das UBI ebenfalls durchf\"uhrt. Ebenso k\"onnen defekte
Erasebl\"ocke durch andere Bl\"ocke ersetzt werden.
Durch den von UBI verwendeten Algorithmus ist es selbst beim Neuanlegen
eines Volumes kaum vorhersagbar, welche physikalischen Erasebl\"ocke auf
dem Flash es belegt. W\"ahrend eine MTD-Partition immer in denselben
aufeinanderfolgenden Bl\"ocken liegt, \"andert sich die Zuordnung von
physikalischen Erasebl\"ocken des Flash zu logischen Erasebl\"ocken des
Volumes im laufenden Betrieb dynamisch. Ein UBI-Volume mit drei
Erasebl\"ocken kann also durchaus die Bl\"ocke 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\"unscht, da eine
mechanische Platte signifikante Seek-Zeiten aufweist. Man versucht dort,
Daten m\"oglichst in aufeinander folgenden Bl\"ocken 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\"ur Anwendungen gedacht, die kein Dateisystem
ben\"otigen. Ein praktisches Beispiel ist ein kleines Volume, das lediglich einen
Kernel enth\"alt, 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\"ocke zu dem statischen Volume geh\"oren. Ausserdem erf\"ahrt er von UBI,
wie viele Bytes tats\"achlich durch Daten belegt sind. Er l\"adt diese Daten,
im Beispiel einen Kernel, ins RAM und springt sie an. Dies ist mit relativ
wenig Code (einige kB) m\"oglich.
Statische Volumes enthalten also immer nur einen einzigen Datenblock, der
in einem Vorgang geschrieben werden muss.
\paragraph{Dynamische Volumes}
Dynamische Volumes sind daf\"ur gedacht, ein Dateisystem zu enthalten.
Man verwendet sie also beispielsweise f\"ur ein Root-Filesystem oder f\"ur
Volumes, die Nutzerdaten enthalten.
Dynamische Volumes verwendet man am Besten mit dem Dateisystem ubifs.
\paragraph{UBIGLUEBI}
UBIGLUEBI ist ein Aufsatz auf UBI, der f\"ur jedes Volume wieder ein
mtd-Device bereitstellt. Dies klingt zun\"achst \"uberraschend, da UBI ja schon
auf einem mtd-Device aufsetzt. Der Hintergrund ist, dass \"altere
Flash-Dateisysteme wie jffs2 ein mtd-Device ben\"otigen. Um deren Einsatz
zu erm\"oglichen, wurde dieser Zusatz geschaffen.
Heute gibt es ubifs, das direkt auf UBI aufsetzt und folglich kein
mtd-Device ben\"otigt. Da ubifs ohnehin in allen Bereichen deutliche Vorteile
gegen\"uber jffs2 hat, wird UBIGLUEBI in der Regel nicht mehr ben\"otigt.
\includegraphics[width=8cm]{images/ubi-big-picture.png}
\paragraph{Fastmap}
UBI legt in jedem Eraseblock einen Information Header an, der Metadaten wie
z.b. die Zuordnung von physikalischem Eraseblock (PEB) zu logischem Eraseblock
(LEB) beinhaltet. Diese Informationen müssen beim Hinzufügen eines UBI
Devices (ubiattach) eingesammelt werden. Hierzu wird das entsprechende MDT
Volume komplett gelesen und die Metadaten zusammengetragen. Der Aufwand für
diesen Vorgang steigt damit linear zur Größe des Flash-Speichers.
Um den Aufwand für das Zusammentragen der Metadaten beim Hinzufügen eines
UBI Devices zu reduzieren, werden bei UBI Fastmap diese Metadaten persistent
im Flash selbst abgelegt. Während des Vorgangs müssen dann nur noch die
Speicherbereiche gelesen werden, in der die Metadaten abgelegt wurden. Die
Zeitersparnis für ein Attach sinkt damit beträchtlich. Vor allem bei
steigenden Flash Größen macht sich die Ersparnis deutlich bemerkbar.
Hierzu legt UBI in den ersten 64 Eraseblocks einen Superblock an, der eine
Referenz auf den Eraseblock enthält, in welchem die eigentliche Fastmap
hinterlegt ist. Die Fastmap beinhaltet unter anderem statistische Informationen (belegte,
freie und defekte PEBs), sogenannten Pools (Listen von belegten und freien
PEBs), sowie den Metadaten der Volumes. Sowohl die Fastmap selbst, als auch
die Pools können sich ihrerseits wiederum über mehrere verkettete PEBs
erstrecken.
Diese Referenzkette verhindert ein wear-out bestimmter Flash-Bereiche. So
muss der Superblock nur dann schreibend modifiziert werden, wenn die
Fastmap, z.B. Aufgrund eines Bit-Flips, in einem anderen PEB verlegt wird.
Die Fastmap wiederum muss nur dann schreibend modifiziert werden, wenn sich
die Lokation eines oder mehrerer Pools ändert.
UBI Fastmap ist vollständig rückwärts kompatibel, d.h. ein mit UBI Fastmap
generiertes UBI Volume ist auch mit einem älteren Kernel ohne UBI Fastmap
problemlos verwendbar. Natürlich kommt hierbei der Geschwindigkeitszuwachs
beim Attach nicht zum tragen. Ebenso ist es möglich ein bestehendes UBI
Volume ohne Fastmap in ein UBI Volume mit Fastmap umzuwandeln,
vorausgesetzt, es gibt genügend freie PEBs für das Ablegen der Fastmap.
Ebenso ist es möglich, eine beschädigte oder unvollständige Fastmap zu
rekonstruieren. In beiden Fällen muss dazu aber der gesamte Flashbereich des
UBI Volumes gescannt werden. Die Geschwindigkeitsvorteile von Fastmap
greifen dann erst wieder bei einem neuerlichen Attach (z.B. nach einem
Reboot).
UBI Fastmap ist so robust wie UBI selbst. Denn selbst wenn die Fastmap nicht
gelesen werden kann oder wenn nicht genügend Platz auf dem UBI Volume
vorhanden ist um die Fastmap zu speichern, so bleibt das UBI Volume trotzdem
voll funktionsfähig.
\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 \"uber ein mtd-Device an UBI \"ubertragen:
\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\ss es statisches Volume mit dem Namen \cmd{kernel}
angelegt. Das Volume erh\"alt 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\"urlich 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\"andige UBI-Images f\"ur ein mtd-Device anfertigen. Diese k\"onnen
anschlie\ss end mit \cmd{nandwrite} in das mtd-Device geschrieben werden.
Alternativ kann das Image nat\"urlich auch mit einem geeigneten JTAGer
in das Flash \"ubertragen werden. Da \cmd{ubinize} sehr vielseitig ist und
relativ viele Flash- und Layout-Parameter ber\"ucksichtigt werden m\"ussen,
kann hier nur ein einfaches Beispiel gegeben werden.
Zun\"achst 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\"o\ss e von 128k angegeben, ausserdem eine
Pagegr\"o\ss e von 2048 Bytes sowie eine Subpage-Gr\"o\ss e von 512 Bytes. Das
fertige Image landet in der Datei \cmd{ubi.img}.
Weitere Informationen sind unter folgender URL erh\"altlich:
\begin{lstlisting}
http://www.linux-mtd.infradead.org/doc/general.html
\end{lstlisting}
\input{tailhandout}
|