btrfs

Natürlich gibt es mehrere Möglichkeiten der Datensicherung für den Raspberry Pi. Ich persönlich nutze rsync und zusätzlich ein selbstentwickeltes Image-Verfahren. Vermisst habe ich allerdings die Möglichkeit, vor Updates und kleinen Änderungen einen Snapshot im Filesystem machen zu können. Daher ist btrfs eine moderne Alternative zum Standard-Filesystem von Raspbian: ext4.

Ein Dateisystem dient der Verwaltung der Dateien auf einem Laufwerk. Das B-Tree Dateisystem (btrfs) weist einige Ähnlichkeiten mit von der Firma Sun Microsystems entwickelten ZFS auf, ist aber noch nicht gleichermaßen ausgereift.

Das B-Tree Filesystem bietet einige Vorteile:

  • Vorhandene extX-Partitionen können offline in btrfs-Partitionen umgewandelt werden.
  • Das Dateisystem umfasst eine optionale Komprimierung.
  • Ein integrierter Volume Manager, der auch RAID beherrscht, macht den Logical Volume Manager (LVM) für btrfs weitgehend überflüssig. Devices lassen sich im laufenden Betrieb hinzufügen und entfernen.
  • Wie ZFS unterstützt btrfs Copy-On-Write (COW). Geänderte Blöcke werden nicht überschrieben, sondern auf bis dahin ungenutztem Platz abgelegt. Anschließend wird der Verweis im Filesystem vom alten Block in den neuen Block geändert.
  • Sehr interessant sind die Filesystem-Snapshots. Sie belegen natürlich etwas Platz, lassen sich aber mit ein wenig Erfahrung als einfache und schnelle Sicherung vor Updates oder Änderungen der  Konfiguration verwenden.
  • Mit Subvolumes unterteilen Sie ein großes Dateisystem und können Snapshots für Teilmengen erstellen oder auch Teile des Dateisystems von einem Snapshot ausnehmen.
  • Ein B-Tree-Filesystem können Sie jederzeit im laufenden Betrieb vergrößern, verkleinern oder defragmentieren.

Backup

Zunächst müssen Sie ein Image-Backup der SD-Karte machen. Danach stecken Sie die SD-Karte mit einem SD-Kartenleser an ein anderes System an. Unter Windows empfehle ich das Programm Win32DiskImager.

Konvertierung

Das Root-Filesystem (in meinem Fall als /dev/sdb2 erkannt) muss für die Konvertierung offline sein. Das ext4-Filesystem wird zunächst gecheckt und danach in ein btrfs-Filesystem konvertiert.

pi@rpi ~ $ sudo fsck.ext4 /dev/sdb2
pi@rpi ~ $ sudo apt-get install btrfs-tools
pi@rpi ~ $ sudo btrfs-convert /dev/sdb2
pi@rpi ~ $ sudo mount -t btrfs /dev/sdb2 /mnt
pi@rpi ~ $ sudo mount -t vfat /dev/sdb1 /mnt/boot
pi@rpi ~ $ sudo chroot /mnt

Mit dem letzten Kommando verlagern Sie den Fokus Ihrer Shell auf das btrfs-Filesystem, das zukünftig als root-Filesystem dienen soll. Diese chroot-Umgebung verlassen Sie nach dem Abschluss der Konfiguration wieder.

Das neue btrfs-Filesystem einbinden

In der Datei /boot/cmdline.txt muss rootfstype=ext4 gegen rootfstype=btrfs ausgetauscht werden.

pi@rpi ~ $ sudo vi /etc/fstab

In der Datei /etc/fstab muss das Filesystem der Rootpartition angepasst werden.

proc            /proc           proc    defaults              0       0
/dev/mmcblk0p1  /boot           vfat    defaults              0       2
/dev/mmcblk0p2  /               btrfs   defaults,noatime      0       1

Die Option ssd wird im Falle von SSDs bei aktuellen Betriebssystemen automatisch hinzugefügt. Die Option noatime verringert die Schreibzugriffe, die ansonsten auf jeden Zugriff auf eine Datei folgen. Weitere Mountoptionen können je nach Bedarf sinnvoll sein:

  • commit=300 setzt den turnusmäßigen Filesystem-sync von 30 Sekunden (Standard) auf 5 Minuten. Das dient dazu, Schreibzugriffe etwas zu reduzieren und die Lebensdauer zu erhöhen.
  • compress=lzo (siehe entsprechender Artikel)
  • autodefrag defragmentiert die Daten on-the-fly. Jedes Copy-on-Write-Dateisystem fragmentiert mit der Zeit. Doch die weit verbreitete Meinung, diese Option könnte für SSDs sinnvoll sein, teile ich so pauschal nicht. Der wahlfreie Zugriff auf die Datenblöcke verhindert geringe Performanceeinbußen zwar nicht vollständig, wirkt sich aber bei fragmentierten Dateisystemen auf SSDs nicht negativ auf deren Lebensdauer aus. Anders ist die Bewertung bei klassischen Spindel-Festplatten. Hier sollte irgendeine Art der Defragmentierung - ob mittels des Kommandos btrfs defragment oder Mountoption sei dahingestellt - vorgenommen werden.

Den btrfs-Treiber in ein initramfs einbinden

Der btrfs-Treiber ist nur als Modul in den Kernel integriert. Deshalb muss dieses Modul für den Bootvorgang in einer Datei abgelegt werden. Die benötigten Module tragen Sie in eine Datei ein.

pi@rpi ~ $ sudo vi /etc/initramfs-tools/modules
btrfs
xor
zlib_deflate
raid6_pq

Danach kann eine initramfs gebaut werden. Standardmäßig baut initramfs eine initrd passend zum laufenden Kernel. Deshalb muss nach einem Update die neue Kernel Version als Argument mitgegeben werden. Achtung: Die initrd muss passend zum Kernel gebaut werden, der von der ARM-Version des Raspberry abhängt. Der Raspberry Pi 2 und der Raspberry Pi 3 laufen mit ARMv7, der Raspberry Pi 1 mit ARMv6.

pi@rpi ~ $ sudo mkinitramfs -o /boot/initramfs-btrfs.gz [Kernel-Version]

Die initramfs beim Systemstart einbinden

Nun muss Raspbian noch beigebracht werden, dass es die initramfs laden soll. Das bewirkt ein Eintrag in der Datei /boot/config.txt:

initramfs initramfs-btrfs.gz

Nacharbeiten

Abschließend die chroot-Umgebung mit exit verlassen und die gemounteten Filesysteme wieder unmounten. Von der Karte booten - fertig!

Wichtig: Die initramfs nach einem rpi-update nicht automatisch neu erstellt; das muss also von Hand gemacht werden. Dabei nicht die Kernel-Version als Argument vergessen!

Irgendwann kann dann die Sicherung des alten Filesystems gelöscht und das Dateisystem neu organisiert werden.

pi@rpi ~ $ sudo btrfs subvolume delete /ext2_saved/
pi@rpi ~ $ sudo btrfs filesystem defrag -r /
pi@rpi ~ $ sudo btrfs balance start /

Regelmäßige Pflege

Die Frage, ob ein btrfs-Filesystem regelmäßig gepalanced werden sollte, wird kontrovers diskutiert. Ausgangspunkt für meine Überlegungen ist der Wunsch, dass mein btrfs-Filesystem niemals zu 100% voll wird.

Dabei können Sie sich keinesfalls auf das Linux-Kommando df verlassen, sondern nur auf das Kommando:

pi@rpi ~ $ btrfs fi df /
Data, single: total=9.00GiB, used=8.63GiB
System, DUP: total=32.00MiB, used=16.00KiB
Metadata, DUP: total=2.50GiB, used=1.61GiB
GlobalReserve, single: total=59.17MiB, used=0.00B

Noch aussagekräftiger ist dieser Befehl:

pi@rpi ~ $ sudo btrfs fi usage /
Overall:
    Device size:                  29.66GiB
    Device allocated:             14.06GiB
    Device unallocated:           15.60GiB
    Device missing:                  0.00B
    Used:                         11.86GiB
    Free (estimated):             15.97GiB      (min: 8.17GiB)
    Data ratio:                       1.00
    Metadata ratio:                   2.00
    Global reserve:               59.17MiB      (used: 0.00B)

Data,single: Size:9.00GiB, Used:8.63GiB
   /dev/mmcblk0p2          9.00GiB

Metadata,DUP: Size:2.50GiB, Used:1.61GiB
   /dev/mmcblk0p2          5.00GiB

System,DUP: Size:32.00MiB, Used:16.00KiB
   /dev/mmcblk0p2         64.00MiB

Unallocated:
   /dev/mmcblk0p2         15.60GiB

Der Status und der Gesundheitszustand der einzelnen Devices in einem btrfs-Volume kann mit diesem Kommando überwacht werden:

pi@rpi ~ $ sudo btrfs device stats /
[/dev/mmcblk0p2].write_io_errs   0
[/dev/mmcblk0p2].read_io_errs    0
[/dev/mmcblk0p2].flush_io_errs   0
[/dev/mmcblk0p2].corruption_errs 0
[/dev/mmcblk0p2].generation_errs 0

Eigentlich dient der balance der gleichmäßigen Verteilung bei Nutzung mehrerer Volumes. Damit lässt sich das Dateisystem allerdings auch reorganisieren und nicht genutzter Platz freigeben. Es hängt immer vom Einzelfall ab und es lässt sich kein pauschaler Rat geben, aber ich selber nutze einen cron-job, der im Verzeichnis /etc/cron.weekly liegt und damit wöchentlich ausgeführt wird:

#!/bin/bash

#
# paranoia settings
#
umask 022
PATH=/sbin:/bin:/usr/sbin:/usr/bin
export PATH

btrfs scrub start -B / | tee /var/log/btrfs-scrub.log

(( m = 0 ))

while btrfs balance start -musage=$m /
do
        (( m = m + 5 ))
done

(( d = 0 ))

while btrfs balance start -dusage=$d /
do
        (( d = d + 5 ))
done

btrfs balance start /

btrfs scrub start -Bd /

exit 0

Der Output des Scriptes wäre wie folgt:

pi@rpi ~ $ sudo bash /etc/cron.weekly/btrfs-balance
scrub done for 0e60be25-ecbf-4ac7-a45a-9e29cfd47e66
        scrub started at Fri Apr 12 21:04:01 2019 and finished after 00:09:14
        total bytes scrubbed: 11.82GiB with 0 errors
Done, had to relocate 0 out of 21 chunks
Done, had to relocate 1 out of 21 chunks
Done, had to relocate 1 out of 21 chunks
Done, had to relocate 1 out of 21 chunks
Done, had to relocate 1 out of 21 chunks
Done, had to relocate 1 out of 21 chunks
Done, had to relocate 1 out of 21 chunks
Done, had to relocate 1 out of 21 chunks
Done, had to relocate 1 out of 21 chunks
Done, had to relocate 3 out of 21 chunks
Done, had to relocate 2 out of 19 chunks
Done, had to relocate 1 out of 18 chunks
Done, had to relocate 1 out of 18 chunks
Done, had to relocate 1 out of 18 chunks
Done, had to relocate 1 out of 18 chunks
Done, had to relocate 1 out of 18 chunks
Done, had to relocate 1 out of 18 chunks
Done, had to relocate 3 out of 18 chunks
Done, had to relocate 4 out of 19 chunks
Done, had to relocate 4 out of 19 chunks
Done, had to relocate 9 out of 19 chunks
ERROR: invalid usage argument: 105
Done, had to relocate 0 out of 19 chunks
Done, had to relocate 1 out of 19 chunks
Done, had to relocate 0 out of 18 chunks
Done, had to relocate 0 out of 18 chunks
Done, had to relocate 0 out of 18 chunks
Done, had to relocate 0 out of 18 chunks
Done, had to relocate 0 out of 18 chunks
Done, had to relocate 0 out of 18 chunks
Done, had to relocate 0 out of 18 chunks
Done, had to relocate 0 out of 18 chunks
Done, had to relocate 0 out of 18 chunks
Done, had to relocate 0 out of 18 chunks
Done, had to relocate 0 out of 18 chunks
Done, had to relocate 1 out of 18 chunks
Done, had to relocate 1 out of 19 chunks
Done, had to relocate 1 out of 19 chunks
Done, had to relocate 1 out of 19 chunks
Done, had to relocate 1 out of 19 chunks
Done, had to relocate 1 out of 19 chunks
Done, had to relocate 1 out of 19 chunks
Done, had to relocate 2 out of 19 chunks
ERROR: invalid usage argument: 105
WARNING:

        Full balance without filters requested. This operation is very
        intense and takes potentially very long. It is recommended to
        use the balance filters to narrow down the balanced data.
        Use 'btrfs balance start --full-balance' option to skip this
        warning. The operation will start in 10 seconds.
        Use Ctrl-C to stop it.
10 9 8 7 6 5 4 3 2 1
Starting balance without any filters.
Done, had to relocate 19 out of 19 chunks
scrub device /dev/mmcblk0p2 (id 1) done
        scrub started at Sat Apr 13 00:11:28 2019 and finished after 00:09:21
        total bytes scrubbed: 11.87GiB with 0 errors

Auf ein defragmentieren des Filesystemes verzichte ich im Falle von SD-Karten und SSDs.

Previous page: watchdog Next page: btrfs Filesystem vergrößern