Raspberry Pi SD Karte auf eine kleinere SD Karte klonen

Zuhause laufen hier mittlerweile 3 Raspberry-Pi Computer mit unterschiedlichen Aufgaben. Hin und wieder kommt es vor, dass ich zu Testzwecken die SD Karte von einem dieser Raspberry-Pi kopieren möchte um einige Dinge auszuprobieren ohne das laufende System kaputt zu machen.

Nun habe ich für die laufenden Raspberry-Pi Computer meistens 16 GByte SD Karten. Vor einigen Tagen stand ich nun vor dem Problem etwas ausprobieren zu wollen aber zum Testen nur eine 8 GByte SD Karte zur Verfügung zu haben. Auf dem Dateisystem selbst lagen aber nur rund 5 GByte Daten. Entsprechend ist eine 8 GByte Karte an sich groß genug um das Testsystem aufzunehmen. Ziemlich schnell formierte sich im Kopf die Herausforderung: „Irgendwie muss das doch gehen…!“.

Um die Antwort vorweg zu nehmen: Ja, es geht benötigt aber einige Schritte. Diese Schritte will ich hier für mich (mit zunehmenden Alter wird man ja vergesslicher) und für den einen oder anderen Interessierten dokumentieren.

Es empfiehlt sich auf jeden Fall ein Backup der SD Karte zu erstellen (mit „dd“ oder „Win32DiskImager“). Wie das genau geht soll aber nicht Teil dieser Anleitung sein.

Update 4. Januar 2017: Harald Schmitz hat mich per Mail darauf hingewiesen das einige der Schritte unten für einen Linux Einsteiger nicht ganz 100% nachzuvollziehen sind. Außerdem gibt es einige Abweichungen die davon abhängen welche Linux Distribution man verwendet. Ich habe daher im Vergleich zu der ersten Version des Artikels noch einen „Schritt 0“ und ein paar Ergänzungen bei einigen der anderen Schritten eingefügt. Last but not least scheint es je nach Distribution und Parameter beim erstellen des ursprünglichen Dateisystems unterschiedliche Einstellungen für die Blockgröße des Dateisystems zu geben. Es kann daher sein, dass einige der Ausgaben anders aussehen (z.B. 4k Dateisystem-Blöcke statt wie bei mir 1k-Blöcke).

Schritt 0 – Superuser Rechte erhalten

Ich habe alle Schritte als „root“ durchgeführt. Das kann man mit folgendem Kommando erreichen:

stefan@phex:~$ sudo su
[sudo] Passwort für stefan:
root@phex:/opt/data/home/stefan#

Wem dabei nicht ganz wohl ist alles als root zu machen (man kann dabei mit einem versehentlich falsch geschriebenen Befehl schnell das gesamte Betriebssystem zerstören) kann auch nur die Befehle in den späteren Schritten mit „sudo“ also root ausführen. Je nach Distribution ist es dann aber nötig jedes mal sein Passwort einzugeben.

Schritt 1 – Große SD Karte identifizieren

Als erster Schritt muss klar sein unter welchem Gerät die große SD Karte verfügbar ist. In meinem Fall verwende ich dazu einen USB Kartenleser. So ein Kartenleser taucht im Linux Ringbuffer beim Einstecken auf:

root@phex:/ dmesg

[320755.666886] scsi 6:0:0:0: Direct-Access     Multi    Flash Reader     1.00 PQ: 0 ANSI: 0
[320755.668116] sd 6:0:0:0: Attached scsi generic sg5 type 0
[320756.158677] sd 6:0:0:0: [sdf] 31116288 512-byte logical blocks: (15.9 GB/14.8 GiB)

Je nach Distribution muss die Karte jetzt erst noch aus dem Dateisystem ausgehangen werden. Das kann über die grafische Oberfläche passieren (für gewöhnlich gibt es da ein „Auswerfen“ Symbol im Dateibrowser) oder per Kommandozeile:

root@phex:/# umount /dev/sdf1 && umount /dev/sdf2
root@phex:/# 

Nur um nochmal ganz sicher zu gehen schau ich mir das Partitionslayout der SD Karte nochmal mit fdisk an:

root@phex:/opt/data/home/stefan# fdisk /dev/sdf

Befehl (m für Hilfe): p

Disk /dev/sdf: 15.9 GB, 15931539456 bytes
64 Köpfe, 32 Sektoren/Spur, 15193 Zylinder, zusammen 31116288 Sektoren
Einheiten = Sektoren von 1 × 512 = 512 Bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Festplattenidentifikation: 0x000deb33

   Gerät  boot.     Anfang        Ende     Blöcke   Id  System
/dev/sdf1   *        2048      264192      131072+   c  W95 FAT32 (LBA)
/dev/sdf2          266240    31115263    15424512   83  Linux

Passt. Die Partition sdf1 ist die Boot-Partition mit dem Raspberry Pi Bootloader. Die zweite Partition sdf2 ist die zu schrumpfende und zu kopierende Partition.

Optional kann man jetzt auch das Linux Dateisystem nochmal überprüfen:

root@phex:/opt/data/home/stefan# fsck.ext4 -f /dev/sdf2
e2fsck 1.42.9 (4-Feb-2014)
Durchgang 1: Prüfe Inodes, Blocks und Größen
Durchgang 2: Prüfe die Verzeichnisstruktur
Durchgang 3: Prüfe Verzeichnis-Verknüpfungen
Durchgang 4: Überprüfe die Referenzzähler
Durchgang 5: Überprüfe die zusammengefasste Gruppeninformation

/dev/sdf2: 5820/1859584 Dateien (0.8% nicht zusammenhängend), 4507911/15424512 Blöcke

Keine Probleme. Also kann es weitergehen.

Schritt 2 – Partition verkleinern

Ich verwende ausschließlich Raspbian auf meinen Raspberry Pi Computern. Die fertigen Raspbian-Images verwenden ext4 als Dateisystem (zumindest beim schreiben dieses Artikels). Um ein ext4 Dateisystem zu verkleinern gibt es das Tool „resize2fs“. Mit dem Parameter „-P“ kann man anzeigen lassen wie weit sich das Dateisystem maximal verkleinern lässt:

root@phex:/opt/data/home/stefan# resize2fs -P /dev/sdf2
resize2fs 1.42.9 (4-Feb-2014)
Geschätzte minimale Grösse des Dateisystems: 4440858

In diesem Fall sind also etwa 4,3 GByte das Minimum. Da wir auf der zweiten SD Karte haben passt das also alles zusammen. Beim Verkleinern muss aber bedacht werden, dass es vor der eigentlichen ext4 Partition noch die Boot Partition gibt. In der obigen fdisk Ausgabe steht die Bootpartition mit (264192-2048)*512 Byte = 134217728 Byte = 128 Mbyte.

Ich rechne großzügig und bequem und lasse das Dateisystem auf 7 GByte verkleinern. Damit bin ich auf der sicheren Seite und muss wenig rechnen. Das schrumpfen wird wie folgt gestartet:

root@phex:/opt/data/home/stefan# resize2fs -p /dev/sdf2 7G
resize2fs 1.42.9 (4-Feb-2014)
Die Grösse des Dateisystems auf /dev/sdf2 wird auf 7340032 (1k) Blöcke geändert.

Start von Durchgang 2 (max = 4771)
Verteile die Blöcke neu      XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Start von Durchgang 3 (max = 1883)
Prüfe die Inode-Tabelle      XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Start von Durchgang 4 (max = 665)
Aktualisiere die Inode-Referenzen  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Das Dateisystem auf /dev/sdf2 ist nun 7340032 Blöcke groß.

Nach dem schrumpfen können wir nun sicher sein, dass nach der Boot-Partition und dem geschrumpften Linux-Dateisystem nur noch Datenmüll liegt.

Schritt 3 – Daten auslesen

Als nächstes lesen wir die SD Karte aus. Der Einfachheit halber hab ich die komplette SD-Karte ausgelesen:

root@phex:/opt/data/home/stefan# dd if=/dev/sdf of=/home/stefan/16gb.img bs=4k
3889536+0 Datensätze ein
3889536+0 Datensätze aus
15931539456 Bytes (16 GB) kopiert, 1146,87 s, 13,9 MB/s

Im Anschluss kann das Image auf die kleinere SD-Karte geschrieben werden:

root@phex:/opt/data/home/stefan# dd if=/home/stefan/16gb.img of=/dev/sdf bs=4k
dd: Fehler beim Schreiben von »/dev/sdf“: Auf dem Gerät ist kein Speicherplatz mehr verfügbar
1891329+0 Datensätze ein
1891328+0 Datensätze aus
7746879488 Bytes (7,7 GB) kopiert, 1592,02 s, 4,9 MB/s

Die Fehlermeldung „Auf dem Gerät ist kein Speicherplatz mehr verfügbar“ ist in Ordnung. Durch das vorherige schrumpfen des Dateisystems gehen dabei keine Daten verloren. Nur sowieso ungenutzter Speicherplatz wird nicht auf die kleinere SD-Karte geschrieben.

Schritt 4 – Partitionen korrigieren

Nach dem Schreiben des Images könnte man mit der SD Karte schon booten. Allerdings stehen in der Partitionstabelle dann auch die Daten für die große SD Karte. Da das evtl. zu problemen führen kann muss die Partitionstabelle noch korrigiert werden. Das machen wir indem wir fdisk aufrufen und im Anschluss die zu große Partition löschen und mit korrektem Ende anlegen.

Ganz, ganz wichtig: Vor dem löschen der Partition den Anfangssektor notieren. Ist der Anfangssektor unbekannt wird es schwierig bis unmöglich die Partition neu anzulegen! Nochmal glasklar: Wer den Anfangssektor nicht aufschreibt der wird Daten verlieren!

root@phex:/opt/data/home/stefan# fdisk /dev/sdf

Befehl (m für Hilfe): p

Platte /dev/sdf: 7746 MByte, 7746879488 Byte
239 Köpfe, 62 Sektoren/Spur, 1021 Zylinder, zusammen 15130624 Sektoren
Einheiten = Sektoren von 1 × 512 = 512 Bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Festplattenidentifikation: 0x000deb33

   Gerät  boot.     Anfang        Ende     Blöcke   Id  System
/dev/sdf1   *        2048      264192      131072+   c  W95 FAT32 (LBA)
/dev/sdf2          266240    31115263    15424512   83  Linux # Anfang notieren!!

Befehl (m für Hilfe): d
Partitionsnummer (1-4): 2

Befehl (m für Hilfe): n
Partition type:
   p   primary (1 primary, 0 extended, 3 free)
   e   extended
Select (default p): p
Partitionsnummer (1-4, Vorgabe: 2): 2                        # Den oben notierten Anfang als
Erster Sektor (264193-15130623, Vorgabe: 264193): 266240     # Startsektor eingeben.
                                                             # Endsektor mit Vorgabewert.
Last Sektor, +Sektoren or +size{K,M,G} (266240-15130623, Vorgabe: 15130623): 15130623    

Befehl (m für Hilfe): w
Die Partitionstabelle wurde verändert!

Rufe ioctl() um Partitionstabelle neu einzulesen.
Synchronisiere Platten.

Damit ist nun die Partitionstabelle auch korrekt. Nun bleibt nicht mehr viel zu tun. Außer…:

Schritt 5 – aufräumen

root@phex:/opt/data/home/stefan# resize2fs /dev/sdf2
resize2fs 1.42.9 (4-Feb-2014)
Die Grösse des Dateisystems auf /dev/sdf2 wird auf 7432192 (1k) Blöcke geändert.

Das Dateisystem auf /dev/sdf2 ist nun 7432192 Blöcke groß.

Schritt 6 – Überprüfen

Zu guter letzt kann es nicht schaden das fertige Dateisystem einmal überprüfen zu lassen. Da es nicht als unsauber ausgehangen markiert ist muss der check erzwungen werden. Dazu dient der Parameter „-f“. Ganz konkret also:

root@phex:/opt/data/home/stefan# fsck.ext4 -f /dev/sdf2
e2fsck 1.42.9 (4-Feb-2014)
Durchgang 1: Prüfe Inodes, Blocks und Größen
Durchgang 2: Prüfe die Verzeichnisstruktur
Durchgang 3: Prüfe Verzeichnis-Verknüpfungen
Durchgang 4: Überprüfe die Referenzzähler
Durchgang 5: Überprüfe die zusammengefasste Gruppeninformation

/dev/sdf2: 5820/1859584 Dateien (0.8% nicht zusammenhängend), 4507911/7432192 Blöcke

Keine Meldungen. Alles gut und wir sind fertig. 🙂

Abschließende Gedanken

Nachdem wir nun fertig sind sollte man mit resize2fs auf der großen SD Karte das Dateisystem wieder auf die volle Kapazität erweitern. Rückblickend wäre es vermutlich besser zuerst mit dd ein Image zu generieren und anschließend resize2fs nur auf dem Image zu nutzen. Dann spart man sich das nachträgliche vergrößern des ursprünglichen Dateisystems und ganz generell werden keine Änderungen an der großen SD Karte selbst vorgenommen. Es kann ja immer mal der Strom ausfallen während das Dateisystem verändert wird. In so einem Fall wären Datenverluste auf der großen SD Karte denkbar.

Wenn ich demnächst irgendwann nochmal in die Situation komme eine SD Karte zu klonen, dann werde ich das obige Verfahren hier dokumentieren.