Balancierung eines "vollen" btrfs-Dateisystems
Balancierung eines "vollen" btrfs-Dateisystems
Mitunter kommt es bei Verwendung des btrfs-Dateisystems zu Fehlermeldungen, die Festplatte sei voll, obwohl (sub-)volumes bzw. darin enthaltene Dateien kaum Platz auf der Festplatte belegen.
Es entstehen Fehlermeldungen der Art
No space left on device
can't access tty
Beispielsweise meldet df
, dass nur 19% der Festplatte belegt sind:
df -h
Dateisystem Größe Benutzt Verf. Verw% Eingehängt auf
/dev/sda2 101G 19G 82G 19% /
Jedoch meldet btrfs selbst eine volle Festplatte:
btrfs filesystem show
[...]
devid 1 size 100.61GiB used 100.61GiB path /dev/sda2
Das heißt, für btrfs ist die Festplatte scheinbar "voll". Der Grund hierfür ist, dass btrfs Daten fortlaufend wegschreibt, bis die Festplatte voll ist. Bereits benutzte Bereiche werden nicht zwingend in einer Form freigegeben, die weiteres Beschreiben der Festplatte sicherstellt. Insbesondere unterscheidet btrfs zwischen Bereichen für Daten und Metadaten und teilt entsprechende Speicherbereiche zu. Überschreiten zu schreibende Metadaten den hierfür verfügbaren Speicherbereich, dann führt dies zu einem entsprechenden Fehler, in diesem Fall zur Fehlermeldung, dass die Festplatte "voll" sei.
Nun muss (bislang noch) der Benutzer eingreifen, damit der für btrfs nicht nutzbare Speicher wieder zur Benutzung freigegeben wird. Dies wird im Folgenden beschrieben. /dev/sda2
sei im Folgenden die "volle" btrfs-Partition. Befehle sind als root
durchzuführen oder jeweils sudo
voranzustellen. Die Balancierung kann gestartet werden mit:
cd /mnt
mkdir fulldisk
mount /dev/sda2 fulldisk
btrfs balance start /mnt/fulldisk
Jedoch können folgende Probleme in diesem Szenario bei btrfs entstehen, da btrfs für folgende Operationen freien Speicherplatz benötigt:
- Löschen: Dateien, Verzeichnisse und Subvolumes lassen sich nicht löschen
- Balancierung: Balancierung lässt sich nicht durchführen
Wurde eine Balancierung gestartet und es steht nicht genügend Speicherplatz für eine Balancierung zur Verfügung, dann äußert sich dies meist wie folgt:
dmesg|tail
liefertbtrfs: 1 enospc errors during balance
undbtrfs balance
terminiert unverrichteter Dingedmesg|tail
liefertNMI watchdog: BUG: soft lockup
, das Dateisystem wird read-only gemounted, es entstehen Input/Output-Fehler, Verzeichnisse sind nicht lesbar und das System reagiert mit unerwartetem Verhalten.
Vermeintlich hat man nun das Problem, dass man auf dem vollen Dateisystem nichts löschen und auch keine Balancierung durchführen kann, um Speicher wieder freizugeben. Im Folgenden wird daher ein Weg beschrieben, eine Balancierung auch bei einem "vollen" btrfs-Dateisystem durchzuführen, indem ein "volles" btrfs-Dateisystem mit einem zusätzlichen Datenträger erweitert wird. Die Speicherkapazität dieses Datenträgers kann von btrfs zur Durchführung einer Balancierung benutzt werden. Der zusätzliche Datenträger muss im Anschluss wieder aus dem btrfs-Dateisystem entfernt werden (sofern eine dauerhafte Nutzung nicht vorgesehen ist).
Alle Schritte lassen sich theoretisch auf einem laufenden System ausführen, d. h. es ist kein unmount der entsprechenden Dateisysteme nötig - btrfs erlaubt, ein Dateisystem mehrfach zu mounten. Wenn man vorsichtig sein möchte, kann man das System jedoch auch mit einer Live-CD booten. Der Kernel der Live-CD sollte für btrfs idealerweise ungefähr gleich alt sein wie der des Systems. Ein zu alter Kernel könnte fehlerbehaftet sein. Ein zu neuer Kernel könnte Änderungen auf dem Filesystem durchführen, mit denen das System dann später nicht zurecht kommt. Im Zweifel sollte man bei btrfs lieber zu einem zu neuen Kernel greifen statt zu einem zu alten. Vergleichbar verhält es sich mit den btrfs-tools, welche nicht Teil des Kernels sind.
Der beschriebene Rettungsversuch sollte nur unternommen werden, wenn eine Datensicherung vorliegt. Die zu rettende Partition kann beispielsweise mit dd
physisch auf einen weiteren Datenträger gesichert werden. So lässt sich bei einem fehlgeschlagenen Rettungsversuch wenigstens der Originalzustand wieder herstellen.
Getestet mit Ubuntu 14.04.2, Kernel 3.16.0.
Balancierung eines "vollen" btrfs-Dateisystems mit USB-Stick oder Festplatte (extern oder intern)
ACHTUNG: Die Daten auf dem Datenträger (USB-Stick oder Festplatte) werden hierbei unbrauchbar! Wenn man dies nicht möchte, sollte man die Variante mittels Image-Datei (weiter unten beschrieben) verwenden.
Im vorliegenden Fall eines "vollen" 128GB-btrfs-Dateisystems waren 2 GB Speicherkapazität ausreichend.
/dev/sda2
sei das volle btrfs-Dateisystem, /dev/sdb
sei ein leerer USB-Stick bzw. eine leere Festplatte
cd /mnt
mkdir fulldisk
#hier: die "volle" btrfs-Partition ist /dev/sda2
mount /dev/sda2 fulldisk
#Hinzufügen des USB-Sticks zum "vollen" btrfs-Dateisystem
btrfs device add /dev/sdb fulldisk
#Balancierung sollte jetzt klappen. Dauert einige Zeit
btrfs balance start fulldisk
#USB-Stick vom btrfs-Dateisystem wieder entfernen
btrfs device delete /dev/sdb fulldisk
Balancierung eines "vollen" btrfs-Dateisystems mittels Image-Datei
Wenn man keinen leeren bzw. zu überschreibenden Datenträger hat, kann man auch einen Datenträger bzw. Partition mit einem bestehenden Dateisystem verwenden. Im vorliegenden Fall ist es ausreichend, wenn dieser Datenträger noch ca. 2 GB freien Speicherplatz hat.
Folgende Schritte werden im Folgenden durchgeführt:
- Mounten des zusätzlichen Dateisystems (sofern nicht schon geschehen)
- Anlegen einer Image-Datei mit Größe 2GB auf dem zusätzlichen Dateisystem
- Erstellung eines Loop-Devices über die Image-Datei
- Hinzufügen des Loop-Devices zum "vollen" btrfs-Dateisystem
- Balancierung des btrfs-Dateisystems
- Entfernen des Loop-Devices vom btrfs-Dateisystem
/dev/sda2
sei das volle btrfs-Dateisystem, /dev/sdb1
sei die Partition mit dem zusätzlichen Dateisystem
#Anlegen eines Mountpoints
cd /mntmkdir fulldisk
#mounten des "vollen" btrfs-Dateisystems
mount /dev/sda2 fulldisk
#Anlegen eines Mountpoints
mkdir externalfs
#mounten des zusätzlichen Dateisystems
mount /dev/sdb1 externalfs
#2GB-Image-Datei erstellen
dd if=/dev/zero of=externalfs/extend.img bs=1M count=2048
#Loop-Device loop0 über die Image-Datei erstellen
losetup /dev/loop0 externalfs/extend.img
#Hinzufügen der Image-Datei zum "vollen" btrfs-Dateisystem
btrfs device add /dev/loop0 fulldisk
#Balancierung sollte jetzt klappen. Warten.
btrfs balance start fulldisk
#Image-Datei vom btrfs-Dateisystem wieder entfernen
btrfs device delete /dev/loop0 fulldisk
Vor dem Entfernen der Image-Datei aus dem btrfs-Dateisystem werden hierbei die Daten der Image-Datei in die Speicherbereiche verschoben, welche im btrfs-Dateisystem (ohne die Image-Datei) verbleiben. Wenn btrfs device delete keinen Fehler liefert, hat das Verschieben der Daten geklappt und Loop-Device sowie Image-Datei können gefahrlos entfernt werden (andernfalls: Gefahr von Datenverlust!):
#Loop-Device entfernen.
losetup -d /dev/loop0
#Image-Datei löschen
rm externalfs/extend.img
Hinweis: Die Datei extend.img kann an einem beliebigen Ort liegen, z. B. in einem bereits gemounteten Filesystem. Pfade wären dann entsprechend anzupassen. Mutige können die Datei auch in einem tmpfs anlegen, was zusätzliche Datenträger bzw. Partitionen erübrigen würde (birgt jedoch die Gefahr von Datenverlust, z. B. bei Stromausfall).
Troubleshooting: Raid1 statt Raid0
Beim btrfs device delete
erhält man mitunter folgende Meldung:
error removing the device '/dev/sdb' - unable to go below two devices on raid1
Diese Meldung bedeutet, das btrfs für Daten und/oder Metadaten eine Datenspiegelung über mehrere Geräte auf Ebene des Dateisystems sicherstellen möchte. Ist die zu entfernende Festplatte das vorletzte Gerät, dann wäre diese Zusicherung nicht mehr gegeben und daher lässt sich dieser Schritt nicht durchführen.
Bemerkenswert ist allerdings, dass btrfs im Labor ein raid1 sicherstellen möchte, obwohl dies nie festgelegt wurde und eigentlich nur von dem btrfs device add
herrühren kann. Wie auch immer: Wenn man vorher keine Spiegelung hatte und auch beim Entfernen des Gerätes im Anschluss keine Spiegelung auf Ebene von btrfs möchte, dann kann man btrfs die Datenspiegelung austreiben mit
btrfs balance start -f -dconvert=single -mconvert=single /path/to/mountpoint
Mittels single
wird für Daten und Metadaten nur eine Kopie sichergestellt. Außerdem versucht die Balancierung nicht, die Daten gleichmäßig auf mehrere Festplatten zu fragmentieren, wie es bei raid0
der Fall wäre.
Hinweis: Die oben beschriebene Situation entstand (unter Ubuntu 14.04.4, HES-Kernel 4.2.0-30, btrfs-tools 3.12) nach Abbruch der Balancierung mittels
btrfs balance cancel /path/to/mountpoint
Erfolgskontrolle
btrfs filesystem show
liefert jetzt:
Label: none uuid: xxxxxxxx-...
Total devices 1 FS bytes used 18.13GiB
devid 1 size 100.61GiB used 21.03GiB path /dev/sdb2
Vor der Balancierung waren 100,61GB benutzt (s.o.), jetzt sind es nur noch 21,03GB. Das bedeutet, 79GB sind für btrfs jetzt wieder nutzbar gemacht worden.
Testweise kann man einen Schreibversuch wagen, z. B.:
cd /mnt/fulldisk
#leere Datei anlegen
touch x
#leere Datei löschen
rm x
Problemvermeidung
Es sollte vermieden werden, dass ein btrfs-Dateisystem jemals "voll" wird. Entsprechend sollte die Balancierung regelmäßig durchgeführt werden, spätestens jedoch wenn btrfs filesystem show
vermeldet, dass der Benutzungsgrad gegen 100% geht.
Auf den Unix-Befehl df
sollte man sich bei btrfs keinesfalls verlassen.
Ausblick
Btrfs unterliegt derzeit noch umfangreichen Entwicklungsschritten und wurde von den Entwicklern bislang nicht als "stabil" gekennzeichnet. Es bleibt zu hoffen, dass die Balancierung irgendwann ohne Benutzereingriff automatisch bzw. "on-the-fly" erfolgt. Insbesondere wäre zu vermeiden, dass das btrfs-Dateisystem die Benutzer mangels rechtzeitiger Balancierung vor absehbare, aber unzumutbare Probleme stellt. Eine automatische Balancierung mittels cron-jobs erscheint wiederum gefährlich, denn bei voller Festplatte kann die Balancierung einen manuellen Benutzereingriff nötig machen.