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.