Betrachten Sie ein 100-MB-Raw-Block-Gerät als einfaches Beispiel. Das sind 204800 Blöcke mit jeweils 512 Bytes für insgesamt 102760448 Bytes.
Die Herausforderung besteht darin, die ersten 98 MB (200704 Blöcke) so zu verschieben, dass eine Lücke von 2 MB (4096 Blöcke) davor liegt. Um dies direkt zu tun, muss nichts in einen Sektor geschrieben werden, der nicht gelesen wurde. Eine Möglichkeit, dies zu erreichen, besteht darin, einen Puffer einzuführen:
$ dd if=/dev/sdj2 count=200704 | mbuffer -s 512 -b 4096 -P 100 | dd of=/dev/sdj2 seek=4096
Die Erwartung ist, dass mbuffer
4096 Blöcke gespeichert werden, bevor etwas an den Schreiber übergeben wird, wodurch sichergestellt wird, dass nichts in einen Bereich geschrieben wird, der nicht gelesen wurde, und dass der Schreiber dem Leser um die Größe des Puffers hinterherhinkt. Der Puffer sollte es dem Leser und dem Schreiber ermöglichen, innerhalb dieser Konstrianten so schnell wie möglich zu arbeiten.
Es scheint jedoch nicht zuverlässig zu funktionieren. Ich habe versucht, echte Geräte zu verwenden, aber es funktioniert nie auf ihnen, während Experimente mit einer Datei auf meiner 64-Bit-Box, aber nicht auf meiner 32-Bit-Box funktionierten.
Zunächst einige Vorbereitungen:
$ dd if=/dev/sdj2 count=200704 | md5sum
0f0727f6644dac7a6ec60ea98ffc6da9
$ dd if=/dev/sdj2 count=200704 of=testfile
Das funktioniert nicht:
$ dd if=/dev/sdj2 count=200704 | mbuffer -s 512 -b 4096 -P 100 -H | dd of=/dev/sdj2 seek=4096
summary: 98.0 MiByte in 4.4sec - average of 22.0 MiB/s
md5 hash: 3cbf1ca59a250d19573285458e320ade
Dies funktioniert auf einem 64-Bit-System, jedoch nicht auf einem 32-Bit-System:
$ dd if=testfile count=200704 | mbuffer -s 512 -b 4096 -P 100 -H | dd of=testfile seek=4096 conv=notrunc
summary: 98.0 MiByte in 0.9sec - average of 111 MiB/s
md5 hash: 0f0727f6644dac7a6ec60ea98ffc6da9
Wie geht das zuverlässig?
Anmerkungen
Ich habe andere Fragen zum Puffern gelesen und angeschaut pv
, buffer
und mbuffer
. Letzteres konnte ich nur mit der erforderlichen Puffergröße zum Laufen bringen.
Die Verwendung von Intermetiate-Speicher ist eine offensichtliche Lösung für das Problem, das immer funktioniert, aber nicht praktikabel ist, wenn nicht genügend freie Kapazität verfügbar ist.
Testplattformen unter Arch Linux mit mbuffer
Version 20140302.
quelle
mbuffer
überhaupt verwenden? Warum nicht stattdessendd
den gesamten Inhalt des Blockgeräts auf einmal lesen lassendd bs=102760448
? Natürlich ist es auf die eine oder andere Weise im RAM gepuffert.mbuffer
sollte tatsächlich den zweiten zwingendd
, für den ersten zurückzubleiben, und Sie benötigen nur genügend RAM, um die Größe der Verschiebung zu puffern. Schade, dassdd
das Lesen und Schreiben von Blöcken in umgekehrter Reihenfolge nicht unterstützt wird, da dies das Problem beseitigen würde!-H
Argument aktiviert diese Funktion).Antworten:
Ohne Puffer können Sie Block für Block rückwärts gehen.
Bitte beachten Sie, dass dieses Beispiel aufgrund fehlender Fehlerprüfung gefährlich ist.
Es ist auch langsam aufgrund der Anzahl der
dd
Anrufe. Wenn Sie Speicherplatz zur Verfügung haben, können Sie eine größere Blockgröße verwenden.Achten Sie mit einem Puffer auf Fallstricke . Es reicht nicht aus, eine 100% ige Vorfüllung zu gewährleisten. Was Sie brauchen, ist eine minimale Füllung während des gesamten Prozesses. Der Puffer darf niemals unterschreiten,
2M
da Sie sonst Ihre noch zu lesenden Daten erneut überschrieben haben.Theoretisch könnte man also auf jede Art von Puffer verzichten und nur verketten
dd
:In der Praxis funktioniert dies nicht zuverlässig, da es keine Garantie gibt, dass der erste
dd
Daten weiter liest, während der letztedd
(mit2M
"Puffer" dazwischen) bereits schreibt.Sie können Ihre Chancen erheblich erhöhen, indem Sie den Zwischenpuffer erheblich vergrößern. Trotzdem ist er nicht zuverlässig.
Leider kenne ich kein gutes Pufferprogramm mit minimaler Fülleigenschaft. Sie benötigen eine, die die Ausgabe stoppt, solange sich weniger als Ihr Sicherheitsspielraum im Puffer befindet.
quelle
dd
es verwendet werden kann. Ich denke jedoch, dass die wirkliche Lösung nicht darin bestehtdd
, etwas zu verwenden, sondern sich für etwas zu entscheiden, das so konzipiert ist, dass es rückwärts läuftddrescue
. Ich habe in einer Antwort einen Weg beschrieben, dies zu tun.ddrescue
. Nicht, wenn erwartet wird, dass es auf verschiedenen Geräten funktioniert, und Sie es dazu bringen müssen, Ihre Argumente zu akzeptieren. Möglicherweise verfügt es auch intern nicht über die Eigenschaft "Minimum Buffer Fill" (da dies bei verschiedenen Geräten nicht erforderlich ist), sodass Ihre Daten erneut beschädigt werden können. Sie müssten den Quellcode einchecken, ob er tatsächlich für Ihren Anwendungsfall entwickelt wurde.Sie lesen 4096 Blöcke und schreiben diese 4096 Blöcke dann in die nächsten 4096 Blöcke der Festplatte, wodurch die zweiten 4096 Blöcke überschrieben werden, bevor sie gelesen werden können. Sie müssen 8129 Blöcke lesen, um diese zweiten 4096 zu erhalten, bevor Sie mit dem Schreiben beginnen, und dann müssen Sie nur 4096 Blöcke schreiben, bevor Sie die nächsten 4096 lesen.
Sie haben nicht erwähnt, um welche Art von Dateisystem es sich handelt. Wenn es ext [234] ist und Sie eine aktuelle Version von e2fsprogs haben, können Sie verwenden
e2image -ra -O 512 /dev/sdj2
. Dies hat auch den zusätzlichen Vorteil, dass es intelligent genug ist, um den freien Speicherplatz im Volume zu überspringen.quelle
ext4
, für die Blockgerätekopie sollte jedes Dateisystem irrelevant sein.dd
nicht funktioniert.Für eine zuverlässige Lösung müssen Sie sicherstellen, dass nichts in einen Bereich geschrieben wird, der möglicherweise nicht gelesen wurde. Der einzige wirkliche Weg, dies zu erreichen, besteht darin, die Kopie in umgekehrter Richtung auszuführen.
Das
ddrescue
Tool kann in umgekehrter Richtung arbeiten, weigert sich jedoch, mit gleicher Eingabe und Ausgabe zu arbeiten. Es ist jedoch möglich, es durch Duplizieren des Geräteknotens auszutricksen.Ich habe einige schnelle Experimente durchgeführt und es scheint zu funktionieren. Die Befehlszeile lautet:
Die Argumente sind
-f
ist erforderlich, um das Schreiben auf ein vorhandenes Ausgabegerät zu erzwingen-R
sagt ihm, er solle in umgekehrter Richtung arbeiten-s
gibt an, wie viel von der Eingabe kopiert werden soll (ich habe dass
Suffix verwendet, um die Anzahl der Sektoren anzugeben)-o
weist es an, vor dem Schreiben im Ausgabegerät nach vorne zu suchen (erneut in Sektoren mit dems
Suffix angegeben)/dev/sdj11
ist das zu lesende Blockgerät/dev/sdj11_copy
ist das zu schreibende BlockgerätIch habe
/dev/sdj11_copy
mitmknod
den Parameter übereinstimmen/dev/sdj11
.Ich habe nur einige sehr schnelle Tests durchgeführt, aber dies scheint in Ordnung zu sein, um ein unformatiertes Gerät zu kopieren. Es funktioniert nicht mit einer Datei (ich konnte es nicht dazu bringen, über die gleichen Dateien hinauszugehen)
Dies beantwortet nicht meine ursprüngliche Frage, mit der gefragt wurde, wie dies erreicht werden soll,
dd
aber ich denke, nachdem ich die anderen Antworten gelesen habe, ist die Antwort darauf, dassdd
dies nicht möglich ist.quelle
ddrescue
in diesem Szenario ein fehlerhafter Block entdeckt wird? Wenn es in einen anderen Bereich der Festplatte springt (um fehlerhafte Blöcke zu vermeiden) und von dort aus weiter kopiert, werden noch nicht kopierte Teile Ihrer Daten erneut überschrieben. Wenn nicht erwartet wird, dass es mit demselben Gerät funktioniert, gibt es keinen Grund, besondere Maßnahmen zu ergreifen, um verschiedene mögliche Fälle von Datenkorruption zu verhindern.ddrescue
Optionen, um die Versuche, fehlerhafte Daten wiederherzustellen, einzuschränken, aber ich habe nicht versucht, sie zu verwenden.