Category Archives: Hardware

Systemdatenträger wechseln ohne “Augen zu und durch”-Mentalität

Einleitung

In diesem Artikel beschreibe ich wie man Windows in wenigen Schritten von einem Speichermedium zum Anderen überträgt — mit professionellen Werkzeugen. Das ist ein kritischer Prozess. Aber ein simpler Prozess, den man verstehen kann und sollte, bevor man ihn einleitet. Wie immer gibt es zahlreiche schändliche Anleitungen da draußen, bei denen dieser Prozess nicht hinreichend erklärt und irgendwelchen bunten Klick-Tools überlassen wird. Das Problem dabei: der Vorgang wird dem Nutzer übersimplifiziert präsentiert. Wichtige Entscheidungen trifft die angepriesene Software selbst, essentielle Details werden vom Nutzer ferngehalten. Aber im Bereich von Datenträgerstrukturen gibt es zu viele potentielle Komplikationen, deren Behandlung man keiner Pseudointelligenz oder auch der “Holzhammermethode” überlassen darf:

Holzhammermethode, zweckentfremdet von http://www.datamartist.com.

Holzhammermethode, zweckentfremdet von datamartist.com.

In professionellen Umgebungen wird ein solcher Migrationsprozess normalerweise akribisch geplant und jeder Schritt mit dem einen dafür etablierten Werkzeug ausgeführt. Ergebnis: die Migration gelingt schnell und zuverlässig.

In privaten Umgebungen herrscht Unsicherheit, man kennt die technischen Details nicht und folgt gerne einer simplen Abstraktion des Problems. Es herrscht Augen zu und durch-Mentalität. Grafisch hübsch aufgemachte Software-Assistenten suggerieren schließlich eine gewisse Sicherheit. Doch Hoffnung ist keine Strategie. Das etwas andere Ergebnis: mit einiger Wahrscheinlichkeit geht etwas schief und man verbringt Stunden oder Tage mit einer chaotischen Phase der Problemlösung, bei der vielleicht Dritte mit einbezogen werden müssen.

Eine grundsätzliche Ursache dieses Gefälles zwischen professioneller und privater Umgebung ist sicherlich der Mangel an Detailwissen in Letzterer. Damit einher geht aber — und das ist das eigentliche Übel — fehlende Anerkennung, dass ein solcher Prozess akribisch geplant werden muss. Ich schreibe das hier auf Deutsch und mit dieser kleinen Einleitung, um in meinem direkten Umfeld ein besseres Bewusstsein für diese Thematik und Problematik zu schaffen.

Es wird unten stehend demonstriert, wie ein solcher Prozess zuverlässig umgesetzt werden kann. Als Beispiel dient ein Spezialfall, den die meisten Windows-Nutzer zu Hause haben. Die Grundidee — Detailplanung und die verwendeten Ansätze und Werkzeuge — sind jedoch auch auf andere Situationen und Betriebssysteme anwendbar. Ihr werdet merken, wenn Eure Situation von der hier beschriebenen abweicht. Dann könnt Ihr mich gerne fragen. Dementsprechend erhebt die folgende Anleitung keinen Anspruch auf Vollständigkeit.

Migrationsprozess

1) Live-Linux präparieren (5 Minuten)

Ihr braucht einen USB-Stick mit einem modernen Live-Linux-System, welches die notwendigen Werkzeuge bereithält, um zuverlässig Daten auf Datenträgern zu analysieren und zu manipulieren. Ich empfehle die Linux-Distribution SystemRescueCD. Gibt es hier zum Herunterladen. Wie bekommt Ihr das auf einen USB-Stick, von dem der Rechner starten kann? Mit dem quelloffenen Rufus. Dort wählt Ihr “create a bootable disk” und bei “select ISO file” wird das SystemRescueCD-Abbild ausgewählt, was gerade heruntergeladen wurde.

2) Transfersystem vorbereiten (5 Minuten)

Der Quell-Datenträger (mit der bisherigen Windows-Installation) wird aus dem Produktivsystem herausgenommen. Der Ziel-Datenträger wird bereitgelegt.

Es wird ein Rechner gebraucht, in dem diese beiden Datenträger gleichzeitig angeschlossen werden. Dieser Rechner wird vom zuvor präparierten USB-Stick gestartet. Beim Start von SystemRescueCD wird der default Start-Modus gewählt, das Tastaturlayout (z. B. DE) definiert und die Desktop-Umgebung mittels startx gestartet.

In diesem Zustand ist der Zugriff auf alle Datenträger möglich. SystemRescueCD wagt jedoch keine autonomen Zugriffe. Ohne Anweisung wird kein einziges Dateisystem eingehängt. Insbesondere wird ohne konkreten Befehl auf keinen Datenträger schreibend zugegriffen. Das ist ein konzeptioneller Schutz vor ungeplanten Ereignissen.

3) Quelle und Ziel eindeutig identifizieren (2 Minuten)

Jedes Linux-Betriebssystem nummeriert die Datenträger intern durch. Jeder Datenträger und jede Partition ist per /dev/sd* lesend und schreibend erreichbar. Jetzt muss die Bezeichnung des bisherigen Windows-Datenträgers ausfindig gemacht werden. Es hilft eine Auflistung der verfügbaren Datenträger samt Partitionen. Ein praktischer Befehl ist fsarchiver probe simple, welcher in ein Terminal eingegeben wird. Das ist die Ausgabe in meinem Fall:

[======DISK======] [=============NAME==============] [====SIZE====] [MAJ] [MIN]
[sda             ] [KINGSTON SVP200S               ] [   111.79 GB] [  8] [  0]
[sdb             ] [WDC WD10EAVS-00D               ] [   931.51 GB] [  8] [ 16]
[sdc             ] [Samsung SSD 850                ] [   476.94 GB] [  8] [ 32]
[sdd             ] [RALLY2                         ] [     3.74 GB] [  8] [ 48]
[sde             ] [USB DISK                       ] [     7.55 GB] [  8] [ 64]
 
[=====DEVICE=====] [==FILESYS==] [======LABEL======] [====SIZE====] [MAJ] [MIN] 
[loop0           ] [squashfs   ] [<unknown>        ] [   278.66 MB] [  7] [  0] 
[sda1            ] [ntfs       ] [System Reserved  ] [   100.00 MB] [  8] [  1] 
[sda2            ] [ntfs       ] [<unknown>        ] [   111.69 GB] [  8] [  2] 
[sdb1            ] [ntfs       ] [Software         ] [   196.16 GB] [  8] [ 17] 
[sdb2            ] [ntfs       ] [Daten            ] [   735.35 GB] [  8] [ 18] 
[sdd1            ] [vfat       ] [SYSRCD-4_4_      ] [     3.74 GB] [  8] [ 49] 
[sde1            ] [vfat       ] [<unknown>        ] [     7.55 GB] [  8] [ 65]

Beim Lesen der Ausgabe braucht man ein bisschen Kenntnis über die eigene Hardware: in der oberen Liste sollten Gerätebezeichnung und Datenträgerkapazität genügend Aufschluss geben. Der bisherige Windows-Datenträger von Kingston heißt in diesem Fall sda. Er ist per Dateisystempfad /dev/sda erreichbar.

In der unteren Liste sind die automatisch erkannten Partitionen aufgeführt. Die Partition sda1 ist eine 100 MB große Partition mit dem Namen “System Reserved …”. Diese wird für gewöhnlich von Windows 7 & 8 bei der Installation angelegt und übernimmt essentielle Aufgaben (sie wird im Betrieb von Windows nicht als normaler Datenträger angezeigt aber muss bei der Migration mitgenommen werden). Die Partition sda2 ist das, was man aus Windows-Sicht als Systemlaufwerk bezeichnen würde (meist Laufwerk “C:”). Bei beiden Partitionen hat fsarchiver wie erwartet erkannt, dass sie ein NTFS-Dateisystem enthalten. Es ist keine weitere Partition auf /dev/sda vorhanden. Die Bestandsaufnahme der Quelle ist somit abgeschlossen.

/dev/sdc ist der Datenträger, der zukünftig Windows tragen soll. Bisher ist keine Partition auf diesem Datenträger eingerichtet.

4) Die Transferstrategie festlegen

Die Strategie im Groben: Die Inhalte beider Quell-Partitionen (/dev/sda1 und /dev/sda2) sollen auf Block-Ebene auf den neuen Datenträger kopiert werden. Vorher bekommt der neue Datenträger eine frische Partitionstabelle. Der Bootloader wird vom alten Datenträger auf den Neuen kopiert.

Die Strategie im Detail:

  • Per GNU fdisk wird eine neue Partitionstabelle vom Typ msdos auf /dev/sdc erstellt, sodass die Situation vom alten Datenträger in den wesentlichen Punkten repliziert wird:
    • /dev/sdc1 erhält die selbe Startposition und Größe wie /dev/sda1.
    • In diesem Fall ist der neue Datenträger größer als der alte: /dev/sdc2 soll den Rest des Datenträgers füllen.
    • Beide Partitionen erhalten eine Markierung vom Typ 7 (HPFS/NTFS/exFAT).
    • /dev/sdc1 wird als aktiv markiert.
  • Der Master Boot Record wird per dd nur teilweise vom alten Datenträger auf den neuen kopiert (nur der Bootloader und die Datenträgersignatur, nicht jedoch die Partitionstabelle).
  • /dev/sda1 wird blockweise per dd nach /dev/sdc1 kopiert.
  • /dev/sda2 wird blockweise per dd nach /dev/sdc2 kopiert.
  • Das NTFS-Dateisystem welches auf /dev/sda2 befindet hat nun mehr Platz auf /dev/sdc2. Es wird per ntfsresize entsprechend darauf aufmerksam gemacht, sodass es den verbleibenden Platz innerhalb der Partition nutzen kann. Zur Vereinfachung dieses Schritts wird als Wrapper GParted benutzt. Beide Tools sind quelloffen und Industriestandard.

Alle hier genannten Werkzeuge sind Teil der SystemRescueCD-Distribution.

5) Realisierung (5 Minuten Arbeit, X Minuten Warten)

  • Details der Partitionstabelle vom bisherigen Windows-Datenträger per fdisk -l auslesen:
    Device    Boot     Start       End    Blocks  Id System
    /dev/sda1 *         2048    206847    102400   7 HPFS/NTFS/exFAT
    /dev/sda2         206848 234438655 117115904   7 HPFS/NTFS/exFAT

    Beide Partitionen sind von Typ 7. /dev/sda1 ist Boot-markiert (“active”). Start und Ende sind präzise angegeben. Diese Parameter wollen wir exakt replizieren. Die einzige Änderung der neuen Tabelle gegenüber der Alten wird die Endmarkierung der Partition /dev/sda2 sein, da der neue Datenträger größer ist als der Alte.

  • Neue Partitionstabelle auf neuem Datenträger per fdisk /dev/sdc erstellen. fdisk wird schrittweise per Tastatur bedient:
    • o create a new empty DOS partition table
    • n add a new partition
    • p primary (0 primary, 0 extended, 4 free)
    • Partition number 1, first sector: 2048 (default), last sector: 206847
    • n add a new partition
    • p primary (0 primary, 0 extended, 4 free)
    • Partition number 2, first sector: default, last sector: default (bis zum Ende des Datenträgers)
    • mit Befehl t change a partition type wird Typ 7 für beide Partitionen gewählt.
    • mit Befehl a toggle a bootable flag wird Partition 1 aktiv markiert.
    • mit Befehl w write table to disk and exit werden die Änderungen geschrieben.
  • Bootloader und Datenträgersignatur blockweise kopieren (die ersten 446 Bytes des Datenträgers):
    # dd if=/dev/sda of=/dev/sdc bs=446 count=1
    1+0 records in
    1+0 records out
    446 bytes (446 B) copied, 0.00403888 s, 110 kB/s
  • kleine “System Reserved”-Partition blockweise kopieren:
    # dd if=/dev/sda1 of=/dev/sdc1
    204800+0 records in
    204800+0 records out
    104857600 bytes (105 MB) copied, 2.02602 s, 51.8 MB/s
  • Windows-Partition (“C:”) blockweise kopieren:
    # dd if=/dev/sda2 of=/dev/sdc2
    234231808+0 records in
    234231808+0 records out
    119926685696 bytes (120 GB) copied, 2271.83 s, 52.8 MB/s
  • NTFS-Dateisystem auf /dev/sdc2 vergrößern:
    • GParted starten.
    • /dev/sdc2 rechtsklicken und Check wählen.
    • In der Ausgabe kann man verfolgen, dass ntfsresize --force --force /dev/sdc2 aufgerufen wird. Es wird der Größenunterschied zwischen Dateisystem und Partition aufgeführt: Current volume size: 119926682112 bytes (119927 MB) vs. Current device size: 512004284416 bytes (512005 MB). Am Ende steht ein Successfully resized NTFS on device '/dev/sdc2'. Da keine Daten verschoben werden müssen, dauert dieser Vorgang nur wenige Sekunden.

Bei den obig angegebenen Schritten ist zu beachten, dass ein Vertauschen/Verschreiben bei den Gerätepfaden (/dev/sd*) unverzeihlich ist. Bitte drei mal denken und kontrollieren, bevor Ihr auf Enter drückt. Ansonsten habt Ihr ja sicherlich eine Sicherung Eurer persönlichen Daten.

6) Rückbau des Datenträgers in das Produktivsystem (5 Minuten)

Der neue Datenträger mit der Windows-Installation wird in das Produktivsystem zurückgebaut. Per BIOS-Einstellung wird das Produktivsystem vom neuen Datenträger gestartet. Es sind keine weiteren Schritte erforderlich.

Fazit

Etwa 25 Minuten Arbeit für eine Betriebssystemmigration (+ Zeit für Datentransfer). Das ist schnell. Warum gewährleistet obige Strategie Zuverlässigkeit? Der durchgeführte Prozess stellt sicher, dass sich zwischen der alten und der neuen Situation nur zwei Kleinigkeiten geändert haben: die Bezeichnung des Datenträgers und die Größe des NTFS-Dateisystems in dem Windows (mehrheitlich) installiert ist. Aus Sicht des BIOS und aus Sicht des Betriebssystems ist der Rest des Gesamtsystems äquivalent zum vorherigen Zustand. Mit dieser Betrachtungsweise ist es leicht zu verstehen, dass die Migration mit hoher Wahrscheinlichkeit gelingt. Die präzise Kontrolle der Geschehnisse erleichtert auch eine etwaige Fehlersuche: gibt es nach Schritt 6 ein Problem, so muss es an einem der beiden geänderten Parameter liegen (in der Tat: UEFI Systeme mögen bedingt durch den Wechsel des Geräte-Namens bzw. der Geräte-ID einen weiteren kleinen Schritt erfordern).

Bei Eurem nächsten Wechsel des Systemdatenträgers solltet Ihr die Migration systematisch durchführen. Wenn Ihr den Prozess unter Kontrolle habt, dann gelingt er mit hoher Wahrscheinlichkeit. Traut lieber den quelloffenen Standard-Werkzeugen welche in professionellen Umgebungen eingesetzt werden als den großen Versprechungen von (kommerziell erhältlichen) Software-Assistenten für Privantanwender.

Consumer hard disks: a large-scale reliability study

Backblaze, an online backup service, have published statistics about the reliability of consumer hard disk drives (HDDs) in their enterprise environment: http://blog.backblaze.com/2014/01/21/what-hard-drive-should-i-buy/

Throughout the last couple of years, they have applied different models of Seagate, Western Digital, and Hitachi drives in large scale (thousands of individual disks) in their storage pools, enabling them to collect conclusive statistical data, such as the “annual failure rate” (cumulative drive years of service / number of failures). An impressive visualization is the 3 year survival rate:

Backblaze blog: disk survival rate by vendor

Backblaze data: disk survival rate by vendor

Note: for a normal consumer type, a Seagate drive should (on average) last longer than indicated by the graph above, since Backblaze is putting their drives under heavier load than normal users do (Backblaze for sure performs significantly more write operations on the disks, also the normal user does not spin the drive 24/7). While there is no doubt that Seagate drives were identified to be significantly less reliable in this study (compared to WD and Hitachi), Backblaze still likes Seagate drives, because they usually are quite cheap.

You might be wondering why exactly Backblaze is using consumer hard disk drives for running their service instead of enterprise class disks. It’s all about money — especially the value-for-money ratio. Backblaze realized that the relative enhancement in reliability and warranty of enterprise class disks compared to consumer HDDs is not as high as the relative prize increment. On a small scale, it might be worth having enterprise disks, because one has less trouble with failing hardware. When operating on the large scale, however, Backblaze concluded that it is cheaper to operate with consumer HDDs. Obviously, Backblaze has to make sure (and they do, I guess), that data is stored with sufficient redundancy, so that the overall likelihood of data loss is on the same level (almost zero) as with enterprise disks. Also, Backblaze has to properly adjust their infrastructure and internal processes/guidelines according to the “high” rate of disk failures. Considering 30,000 disks being operated simultaneously, and an annual failure rate of 5 % (which is realistic, according to their data), about 4 disks have to be exchanged per day (30000*0.05/365).

For my NAS, I have recently bought Western Digital’s 3 TB disks from the Red line, which are energy-saving consumer disks ‘certified’ for 24/7 operation — a very good choice, according to technical reviews and Backblaze’s data. You might want to look into these Red line models yourself, they come at a very good price. So far, I was assuming that the differences in HDD quality on the consumer market are small. Backblaze’s data disproves this assumption and although Seagate models surely are fine for many types of applications, I won’t blindly buy Seagate anymore. It is impressive to see certain models being much more reliable than others (on average) under heavy load conditions.

I am looking forward to seeing more conclusive data provided by Backblaze in the next couple of years. This kind of data is something that usually is kept secret within the manufacturer companies, and normal tech reviews simply cannot provide these data as of missing statistics.

Bitwise identity of NetCDF data — hashing numpy arrays

In a molecular dynamics (MD) simulation, a molecular system is evolved over time, i.e. the movement of single atoms at a given temperature is simulated over time. The output of such a simulation is a so-called MD trajectory. It becomes written to disk while the simulation is running and contains snapshots of the molecular system for certain points in time. These snapshots are called frames. Each frame contains the coordinates of all atoms in the molecular system for one single point in time. Considering N atoms, three spatial dimensions and F frames, 3 x N x F floating point numbers are stored within a trajectory file. Amber, a well-established molecular dynamics software, can store this data in binary form in a NetCDF file.

Given two trajectory files in NetCDF format, I wanted to find out if the coordinates of both trajectories are equal up to a certain frame number. The issue here was that these two trajectory files were created by independent simulations starting from the same input data on the same hardware (an Nvidia GTX 580), while one of the simulations unexpectedly crashed in the middle of the run. In case both simulations produced bitwise identical output up to the point where the one simulation crashed, most likely external factors such as temperature or voltage were the reason for the crash. In case the simulations diverged before the crash appeared, an error in the Amber code or a general hardware problem with the GTX 580 is more likely.

So, how can we find out if both simulations produced bitwise identical output up to the point where one crashed? We have two NetCDF files and want to see if one contains an exact subset of numerical data of the other. If we expected the entire files to be identical then we could just apply a hash function to the entire files. We already know that the files are not identical, just a certain part of the data contained in both files should be checked for equality. So, a good idea might be to apply a hash function to the raw data representing these parts.

Luckily, NetCDF is a well-structured file format with strong language support. I love Python and used its netCDF4 module. Its usage is pretty straight-forward:

In [1]: from netCDF4 import Dataset

Load the trajectory file that is incomplete and have a look into the file structure, especially at the shape of the coordinates data:

In [2]: old = Dataset('production_NVT.mdcrd.OLD')
In [3]: print old.variables['coordinates']
<type 'netCDF4.Variable'>
float32 coordinates(frame, atom, spatial)
    units: angstrom
unlimited dimensions: frame
current shape = (1768, 46010, 3)

From the shape we can infer that this trajectory file contains 1768 frames made of 46010 atoms each and that we have — suprise, surprise — three spatial dimensions.

Load the trajectory file that is complete:

In [4]: new = Dataset('production_NVT.mdcrd')
In [5]: print new.variables['coordinates']
<type 'netCDF4.Variable'>
float32 coordinates(frame, atom, spatial)
    units: angstrom
unlimited dimensions: frame
current shape = (2500, 46010, 3)

It contains 2500 frames, which was the final goal of the simulation.

Upon access, the coordinates are returned within numpy arrays containing numpy data types. In this case, coordinate values are stored in single precision (32 bit) floating point numbers, as you can see for the set of coordinates belonging to the first frame of the damaged trajectory:

In [6]: old.variables['coordinates'][1,:,:].dtype
Out[6]: dtype('float32')

Now, we can just go ahead and build a check sum of the coordinates belonging to the first 1768 frames of both trajectories:

In [7]: import hashlib
In [8]: hashlib.sha1(new.variables['coordinates'][:1768,:,:]).hexdigest()
Out[8]: 'b8bd51001aedbdc52de0d9e39ceb5284e9641a8a'
In [9]: hashlib.sha1(old.variables['coordinates'][:1768,:,:]).hexdigest()
Out[9]: 'b8bd51001aedbdc52de0d9e39ceb5284e9641a8a'

They are identical. But which data is actually used for building the hash? The goal is to make sure that the compared data is bitwise identical, because this is what we expect from working Amber code and from a valid CUDA device. Of course, we can make a step back and just compare the numerical values first:

In [10]: (old.variables['coordinates'][:1768,:,:] == new.variables['coordinates'][:1768,:,:]).all()
Out[10]: True

Okay, numpy considers all coordinate values in the first 1768 frames to be equal. What does this mean? All numerics frameworks use some kind of epsilon value for comparison of floating point numbers. In this case this is:

In [11]: np.finfo(np.single).eps
Out[11]: 1.1920929e-07

Quite a large value. The comparison above proves strong similarity, but not bitwise identity of data. We can go ahead and decrease the epsilon value for the numeric comparison:

In [12]: np.allclose(old.variables['coordinates'][:1768,:,:], new.variables['coordinates'][:1768,:,:], rtol=1e-10, atol=1e-12)
Out[12]: True

Now we have proven that the two data sets are extremely similar. But how can we actually prove bitwise identity? The easiest is hashing, but we have to kind of validate that the hash function actually considers all the bits of the data. Let’s make up a small example for this:

>>> import numpy as np
>>> from hashlib import sha1
>>> a = np.random.rand(5)
>>> a
array([ 0.1841292 ,  0.25379848,  0.27524327,  0.15762775,  0.88225297])
>>> a.dtype
dtype('float64')
>>> sha1(a).hexdigest()
'59db294ed35dc9137394198413ca7fca592a7ac2'

So far, we have created an array a containing 5 randomly created double precision (64 bit) floating point numbers. We have built a corresponding hash value from this array, as done above in case of the trajectory data. Now, numpy provides a convenient function to re-interpret the raw array data. In this process, the array data is considered as a large set of single bits which becomes masked by a new data type. Above, a contains 5 * 64 bit = 320 bit of raw data. Interpreted with an 8 bit integer data type, a looks like this:

>>> a.view(dtype=np.uint8)
array([ 24,  30,  26, 171, 139, 145, 199,  63, 188,  18,  20, 248,  59,
        62, 208,  63,   0, 236,  40, 243, 149, 157, 209,  63, 104,  99,
       220,  99,  37,  45, 196,  63, 204,  14, 233, 147, 106,  59, 236,  63], dtype=uint8)
>>> len(a.view(dtype=np.uint8))
40

Obviously, 320 bit of raw data result in exactly 40 of 8 bit integer values. This view creates a different representation of the same raw data. What happens when we hash this representation?

>>> sha1(a.view(dtype=np.uint8)).hexdigest()
'59db294ed35dc9137394198413ca7fca592a7ac2'

The same as above. This proves that changing the representation does not change the check sum. But does it prove that the check sum is built from the raw data? Simple check:

>>> a[1]
0.2537984774246913
>>> a[1] = 0.2537984774246912
>>> sha1(a.view(dtype=np.uint8)).hexdigest()
'7ffdda4de9654c11f0c8387b82d83b577cdc64cc'
>>> sha1(a).hexdigest()
'7ffdda4de9654c11f0c8387b82d83b577cdc64cc'

Above, one numerical value in a was changed. As a consequence, the direct check sum of a as well as the check sum of a in uint8 representation also changed. So, yes, the raw numerical data is used for building the check sum.

Hence,

sha1(new.variables['coordinates'][:1768,:,:]).hexdigest()

builds a check sum from all bits of the numerical raw data of the first 1768 frames in the given trajectory. The equality of both check sums for the first 1768 frames in both trajectories means that in both trajectories the coordinates in the the first 1768 frames are bitwise identical.

This probably means that the hardware as well as the software was working just fine until at some point between writing frame 1768 and 1769 something happened that made the simulation crash.

By the way, this was done with Python 2.7.3 and numpy 1.6.2.