Festplatte kaputt, RAID degraded, tauschen – FreeBSD, ZFS, gmirror

Homer – ja, Homer – mein Hauptserver zu Hause, hatte auf einer Festplatte immer mal wieder Lesefehler. Das war eine ganze Zeit weg und ich dachte, das Thema wäre gegessen, jetzt tauchten sie aber wieder auf. Also: Neue Festplatte muss rein, bevor die alte stirbt.

Ich schreibe hier einmal die Konstellation und wie ich vorgegangen bin, da das Setup etwas „eigenwillig“ ist.

Homer ist ein HP Microserver der achten Generation, hat 8GB RAM, vier Festplattenplätze, die bei mir komplett mit 2TB-HDDs belegt sind. Installiert ist aktuell FreeBSD 13.1-RELEASE. Ich wollte ein RAID5 haben, aber meine Daten verschlüsselt vom Betriebssystem trennen, ohne eine Festplatte dazu abzustellen oder irgendeine andere Lösung zu nutzen. Auch wollte ich keinen Hardware-RAID-Controller haben. Zum Einen, weil die teuer sind, aber viel wichtiger: weil ich die Vorteile von ZFS wollte.

Also: Betriebssystem unverschlüsselt (kann man drüber streiten, normalerweise solltet ihr aber alles verschlüsseln, auch OS und Logging usw.!), Daten verschlüsselt, alles RAID5 soweit möglich, in meinem Fall also RAID-Z1. Da ich noch einen SWAP-Bereich habe, sollte der auch redundant ausgelegt sein. Dafür nahm ich gmirror (GEOM mirror).

Die Partitionierung aller vier Platten ist identisch:

=>        40  3907029088  adaX  GPT  (1.8T)
          40         944     1  (null)  (472K)
         984    33554432     2  swapX  (16G)
    33555416   125829120     3  zrootX  (60G)
   159384536  3732930560     4  serverX  (1.7T)
  3892315096    14714032        - free -  (7.0G)

Das X steht hier für eine Zahl zwischen 0 und inklusive 3. Alle vier HDDs haben einen Bootsektor und Bootcode für ZFS drauf, so dass tatsächlich jede Platte ausfallen, aber dennoch gebootet werden kann.

Ich hatte hier noch eine Festplatte auf Halde, gleiche Größe, anderes Modell. Aus dem Grund sieht man, dass ich in der Partitionierung noch 7GB freigelassen habe. Freilich ist das ein wenig viel, um Hardwareunterschiede auszugleich, es reicht merklich weniger, aber ich weiß nicht mehr, warum ich diese Entscheidung vor einigen Jahren so traf. Letztlich ist es so, dass die eine 2TB-Platte von Hersteller X doch ein paar weniger oder mehr Bytes als die von Hersteller Y oder von einem anderen Modell haben kann. Ist die Platte kleiner, kann das RAID nicht mehr resilvern, da ja die Kapazität nicht ausreicht. Deshalb lässt man einfach ein paar MB (und nicht wie ich GB) frei, falls das Problem einmal eintreten sollte.

Gut, Platte lag herum, was als nächstes? Natürlich direkt eine neue Platte bestellen, denn sobald ich die auf Halde liegende Platte verbaue, habe ich keinen Ersatz mehr hier für einen meiner Server.

Danach war mein Vorgehen recht einfach. Als erstes sicherte ich mir das Layout der Platte (ada2 war defekt):

gpart backup ada2 > /root/ada2.gpart

Auch, wenn HP angibt, dass ohne RAID-Controller das System nicht „Hotplugable“ sei, ist das doch in den Spezifikationen für SATA drin und ich hätte die Platte auch so ziehen können. Da ich den Rechner aber auch aussagen wollte (und der hatte es nötig!), fuhr ich ihn herunter, saugte aus, tauschte die Platte und fuhr den Rechner wieder hoch (bitte, liebe Hersteller: macht den Tausch von Festplatten doch caddy- und schraubenfrei!).

Natürlich waren die RAIDs jetzt „degraded“. Hier beginnt die kritische Phase. Als erstes sah ich, ob die neue Platte erkannt wurde:

root@homer:~ # camcontrol devlist
<ST2000VX003-1HH164 CV12>          at scbus0 target 0 lun 0 (pass0,ada0)
<ST2000VX003-1HH164 CV12>          at scbus1 target 0 lun 0 (pass1,ada1)
<ST2000DM008-2FR102 0001>          at scbus2 target 0 lun 0 (pass2,ada2)
<ST2000VX003-1HH164 CV12>          at scbus3 target 0 lun 0 (pass3,ada3)
<AHCI SGPIO Enclosure 2.00 0001>   at scbus6 target 0 lun 0 (ses0,pass4)
<asmedia ASM1153E 0>               at scbus7 target 0 lun 0 (da0,pass5)

Und da war sie. Man sieht, dass es ein anderes Modell ist. Mit

root@homer:~ # diskinfo -v ada2
ada2
	512         	# sectorsize
	2000398934016	# mediasize in bytes (1.8T)
	3907029168  	# mediasize in sectors
	4096        	# stripesize
	0           	# stripeoffset
	3876021     	# Cylinders according to firmware.
	16          	# Heads according to firmware.
	63          	# Sectors according to firmware.
	ST2000DM008-2FR102	# Disk descr.
	ZFL5QMHW    	# Disk ident.
	ahcich2     	# Attachment
	id1,enc@n3061686369656d30/type@0/slot@3/elmdesc@Slot_02	# Physical path
	Yes         	# TRIM/UNMAP support
	7200        	# Rotation rate in RPM
	Not_Zoned   	# Zone Mode

sah ich mir dann noch die Spezifikationen an und alles war soweit ok. Jetzt spielte ich das Paritionsschema wieder ein, was ich vorher sicherte:

gpart restore ada2 < /root/ada2.gpart

Da ja alle Platten das selbe Partitionsschema haben, hätte ich auch folgendes machen können:

gpart backup ada1 | gpart restore ada2

Dabei werden aber die Labels nicht mitgesichert, so dass ich diese noch setzen musste:

gpart modify -i 2 -l swap2 ada2
gpart modify -i 3 -l zroot2 ada2
gpart modify -i 4 -l server2 ada2

Als nächstes wollte ich mit dem kleinsten Problem beginnen, dem Swap-Mirror, der den Namen „swap“ trägt. Also:

gmirror forget swap
gmirror insert swap /dev/gpt/swap2

Das Resilvering ging dann sehr schnell, weil Swap nicht sonderlich groß war, und schon bald sah es so aus:

root@homer:~ # gmirror status
       Name    Status  Components
mirror/swap  COMPLETE  ada0p2 (ACTIVE)
                       ada1p2 (ACTIVE)
                       ada3p2 (ACTIVE)
                       ada2p2 (ACTIVE)

Dann ging es an den zroot, also den Bereich, auf dem das Betriebssystem liegt. Das war sehr einfach, da nicht verschlüsselt, und somit reichte:

zpool replace zroot gpt/zroot2 gpt/zroot2

Schon begann das Resilvering, was auch nicht lange brauchte. In der Zeit kümmerte ich mich um den „server“-Bereich. Dieser ist mit GELI (GEOM eli) verschlüsselt, also musste ich das zuerst vorbereiten:

geli init -s 4096 -e aes -l 256 /dev/gpt/server2

Dann einhängen:

geli attach /dev/gpt/server2

Hat das funktioniert, dann noch das Device im ZFS-Pool tauschen:

zpool replace server /dev/gpt/server2.eli /dev/gpt/server2.eli

Jetzt noch den Bootcode schreiben, damit man von der Platte auch booten kann:

gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada2

Solange das Resilvering läuft, ist natürlich „kritische Phase“:

root@homer:~ # zpool status
  pool: server
 state: DEGRADED
status: One or more devices is currently being resilvered.  The pool will
	continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.
  scan: resilver in progress since Tue Sep 13 06:32:15 2022
	4.10T scanned at 47.7M/s, 3.34T issued at 38.8M/s, 5.37T total
	856G resilvered, 62.11% done, 15:15:49 to go
config:

	NAME                       STATE     READ WRITE CKSUM
	server                     DEGRADED     0     0     0
	  raidz1-0                 DEGRADED     0     0     0
	    gpt/server0.eli        ONLINE       0     0     0
	    gpt/server1.eli        ONLINE       0     0     0
	    replacing-2            DEGRADED     0     0     0
	      4177616201411802674  UNAVAIL      0     0     0  was /dev/gpt/server2.eli/old
	      gpt/server2.eli      ONLINE       0     0     0  (resilvering)
	    gpt/server3.eli        ONLINE       0     0     0

errors: No known data errors

  pool: zroot
 state: ONLINE
  scan: resilvered 9.88G in 00:06:38 with 0 errors on Tue Sep 13 06:36:11 2022
config:

	NAME            STATE     READ WRITE CKSUM
	zroot           ONLINE       0     0     0
	  raidz1-0      ONLINE       0     0     0
	    gpt/zroot0  ONLINE       0     0     0
	    gpt/zroot1  ONLINE       0     0     0
	    gpt/zroot2  ONLINE       0     0     0
	    gpt/zroot3  ONLINE       0     0     0

errors: No known data errors

Man sieht, dass der Aufwand natürlich durchaus höher ist, als bei einem Hardware-RAID, wo man im Optimalfall nur „Platte raus, Platte rein“ machen muss. Aber sonderlich schwierig und kompliziert ist es auch nicht.

Update

Das Resilvering ist durch, das RAID ist wieder in einem konsistenten Zustand. Es hat fast 43 Stunden gedauert, bis alles durch war.

root@homer:~ # zpool status
  pool: server
 state: ONLINE
  scan: resilvered 1.34T in 1 days 18:41:45 with 0 errors on Thu Sep 15 01:14:00 2022
config:

	NAME                 STATE     READ WRITE CKSUM
	server               ONLINE       0     0     0
	  raidz1-0           ONLINE       0     0     0
	    gpt/server0.eli  ONLINE       0     0     0
	    gpt/server1.eli  ONLINE       0     0     0
	    gpt/server2.eli  ONLINE       0     0     0
	    gpt/server3.eli  ONLINE       0     0     0

errors: No known data errors

  pool: zroot
 state: ONLINE
  scan: resilvered 9.88G in 00:06:38 with 0 errors on Tue Sep 13 06:36:11 2022
config:

	NAME            STATE     READ WRITE CKSUM
	zroot           ONLINE       0     0     0
	  raidz1-0      ONLINE       0     0     0
	    gpt/zroot0  ONLINE       0     0     0
	    gpt/zroot1  ONLINE       0     0     0
	    gpt/zroot2  ONLINE       0     0     0
	    gpt/zroot3  ONLINE       0     0     0

errors: No known data errors