Jak można użyć „dd” do przesunięcia bloków danych w prawo?

10

Rozważ 100-procentowe urządzenie blokowe jako prosty przykład. To jest 204800 bloków po 512 bajtów każdy w sumie 102760448 bajtów.

Wyzwaniem jest przesunięcie pierwszych 98 MB (200704 bloków), aby przed nimi była przerwa 2 MB (4096 bloków). Wykonanie tego w miejscu wymaga, aby nic nie zostało zapisane w sektorze, który nie został odczytany. Jednym ze sposobów osiągnięcia tego jest wprowadzenie bufora:

$ dd if=/dev/sdj2 count=200704 | mbuffer -s 512 -b 4096 -P 100 | dd of=/dev/sdj2 seek=4096

Oczekuje się, że mbufferzapisze 4096 bloków przed przekazaniem czegokolwiek do programu piszącego, zapewniając w ten sposób, że nic nie zostanie zapisane w obszarze, który nie został odczytany, a program piszący opóźnia czytnik o wielkość bufora. Bufor powinien umożliwiać czytelnikowi i pisarzowi działanie tak szybko, jak to możliwe w obrębie tych elementów stałych.

Jednak wydaje się, że nie działa niezawodnie. Próbowałem używać prawdziwych urządzeń, ale to nigdy nie działa na nich, podczas gdy eksperymenty z plikiem działały na moim 64-bitowym pudełku, ale nie na moim 32-bitowym pudełku.

Najpierw trochę przygotowania:

$ dd if=/dev/sdj2 count=200704 | md5sum
0f0727f6644dac7a6ec60ea98ffc6da9
$ dd if=/dev/sdj2 count=200704 of=testfile

To nie działa:

$ 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

Działa to w systemie 64-bitowym, ale nie w systemie 32-bitowym:

$ 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

Jak można to zrobić niezawodnie?


notatki

Czytałem inne pytania dotyczące buforowania i spojrzał pv, buffera mbuffer. Mogłem tylko sprawić, aby ten drugi działał z wymaganym rozmiarem bufora.

Korzystanie z pamięci międzystanowej jest oczywistym rozwiązaniem problemu, który zawsze działa, ale nie jest praktyczne, gdy nie ma wystarczającej wolnej pojemności.

Platformy testowe z systemem Arch Linux w mbufferwersji 20140302.

rozgwiazdy
źródło
Nie sądzę, że rozwiązałoby to problem, ale z ciekawości po mbufferco w ogóle korzystać? Dlaczego zamiast tego nie ddprzeczytać całej zawartości urządzenia blokowego za jednym razem dd bs=102760448? Oczywiście w ten czy inny sposób jest buforowany w pamięci RAM.
Celada,
@Celada - przykład 100 MB był tylko przykładem. Na przykład odczytanie 1 TB na raz nie byłoby dobrym pomysłem.
starfry
2
Ach, rozumiem teraz, dzięki. mbufferPowinny rzeczywiście zmusić drugi ddw tyle za pierwszy i trzeba tylko wystarczającej ilości pamięci RAM do buforowania wielkość przesunięcia. Szkoda, ddże nie obsługuje odczytu i zapisu bloków w kolejności wstecznej, ponieważ wyeliminowałoby to problem!
Celada,
Nie wymieniono sposobu obliczania drugiego md5sum
psusi
@psusi, drugi md5 jest wyprowadzany przez mbuffer (jego -Hargument włącza tę funkcję).
starfry

Odpowiedzi:

2

Bez bufora możesz cofać się o jeden blok na raz.

for i in $(seq 100 -1 0)
do
    dd if=/dev/thing of=/dev/thing \
       bs=1M skip=$i seek=$(($i+2)) count=1
done

Należy pamiętać, że ten przykład jest niebezpieczny z powodu braku sprawdzania błędów.

Jest również powolny ze względu na liczbę ddpołączeń. Jeśli masz wolną pamięć, możesz użyć większego rozmiaru bloku.

Za pomocą bufora strzeż się pułapek . To nie wystarczy, aby zagwarantować 100% Prefill. To, czego potrzebujesz, to minimalne wypełnienie podczas całego procesu. Bufor nigdy nie może spaść poniżej, 2Mponieważ w przeciwnym razie ponownie nadpisane zostaną dane, które należy jeszcze przeczytać.

Tak więc teoretycznie można obejść się bez bufora i łańcucha dd:

dd if=/dev/thing bs=1M | \
dd bs=1M iflag=fullblock | \
dd bs=1M iflag=fullblock | \
dd of=/dev/thing bs=1M seek=2

W praktyce nie działa to niezawodnie, ponieważ nie ma gwarancji, że pierwszemu dduda się nadal odczytywać dane, podczas gdy ostatni dd(z 2M„buforem” pomiędzy nimi) już zapisuje.

Możesz znacznie zwiększyć swoje szanse, znacznie zwiększając odstęp między buforem, ale mimo to nie jest wiarygodny.

Niestety nie znam dobrego programu buforującego z minimalną właściwością wypełnienia. Potrzebujesz takiego, który zatrzymuje wyjście, o ile w buforze jest mniej niż margines bezpieczeństwa.

frostschutz
źródło
Zaakceptowałem to, ponieważ odpowiada na pierwotne pytanie, pokazując, jak ddmożna go użyć. Myślę jednak, że prawdziwym rozwiązaniem nie jest użycie, ddale wybór czegoś, co jest zaprojektowane tak, aby działało wstecz ddrescue. Opisałem sposób na to w odpowiedzi.
starfry
1
@starfry: na pewno program, który to zrobi, będzie dobrym rozwiązaniem. Jednak nie jestem wcale tego pewien ddrescue. Nie, jeśli spodziewa się, że będzie działać na różnych urządzeniach, a ty musisz oszukać go, aby zaakceptował twoje argumenty. Może również nie mieć wewnętrznej właściwości „minimalnego zapełnienia bufora” (ponieważ w przypadku różnych urządzeń nie jest to konieczne), więc ponownie może uszkodzić dane. Będziesz musiał sprawdzić w kodzie źródłowym, czy rzeczywiście jest on zaprojektowany dla twojego przypadku użycia.
frostschutz
1

Czytasz 4096 bloków, a następnie zapisujesz te 4096 bloków do następnych 4096 bloków dysku, zastępując w ten sposób drugie 4096 bloków, zanim będą mogły zostać odczytane. Musisz przeczytać 8129 bloków, aby uzyskać drugie 4096 przed rozpoczęciem pisania, a następnie musisz tylko napisać 4096 bloków przed odczytaniem następnego 4096.

Nie wspomniałeś, jaki to system plików. Jeśli jest to ext [234] i masz najnowszą wersję e2fsprogs, możesz użyć e2image -ra -O 512 /dev/sdj2. Ma to również tę dodatkową zaletę, że jest wystarczająco inteligentny, aby pominąć wolne miejsce w woluminie.

psusi
źródło
Ma to sens podczas czytania i na tej podstawie przyjrzę się jeszcze raz. Ale to nie wyjaśnia, dlaczego działało na pliku testowym.
starfry
Jeśli chodzi o system plików, czy masz na myśli system plików zawierający mój plik testowy? To ext4samo dotyczy kopii urządzenia blokowego, każdy system plików powinien być nieistotny.
starfry
@starfry, jedynym znanym mi sposobem na zrobienie tego w ogólny sposób jest użycie algorytmu zaproponowanego przez Emmanuela (praca wstecz od końca), co robi gparted.
psusi
jeśli chodzi o rozmiar bloku, próbowałem większych bloków (powinienem był to napisać w pytaniu). Odkryłem, że nie stał się bardziej niezawodny nawet bufor sektorowy 64K. Niezawodnym rozwiązaniem jest bieganie wstecz, co ddnie działa.
starfry
1

Niezawodne rozwiązanie wymaga upewnienia się, że nic nie zapisuje w obszarze, który mógł nie zostać odczytany, a jedynym prawdziwym sposobem na osiągnięcie tego jest wykonanie kopii w odwrotnym kierunku.

ddrescueNarzędzie może pracować w odwrotnym kierunku, ale odmawia pracy z wejścia i wyjścia są takie same. Można go jednak oszukać, duplikując węzeł urządzenia.

Przeprowadziłem kilka szybkich eksperymentów i wydaje się, że działają. Wiersz polecenia to:

$ ddrescue -f -R -s 200704s -o 4096s /dev/sdj11 /dev/sdj11_copy

Argumenty są

  • -f jest wymagane, aby wymusić zapis na istniejącym urządzeniu wyjściowym
  • -R każe mu działać w odwrotnym kierunku
  • -sinformuje, ile danych wejściowych należy skopiować (użyłem ssufiksu, aby określić liczbę sektorów)
  • -okaże szukać dalej w urządzeniu wyjściowym przed zapisem (ponownie w sektorach z ssufiksem)
  • /dev/sdj11 to urządzenie blokowe do odczytu
  • /dev/sdj11_copy jest urządzeniem blokowym do pisania

Utworzyłem za /dev/sdj11_copypomocą, mknodaby dopasować parametry /dev/sdj11.

Zrobiłem tylko kilka bardzo szybkich testów, ale wydaje się, że to działa dobrze, aby skopiować surowe urządzenie. Nie działa na pliku (nie mogłem go oszukać, aby wyjść poza pliki, które są takie same)

To nie odpowiada na moje pierwotne pytanie dd, które brzmiało, jak to osiągnąć, ale myślę, że po przeczytaniu innych odpowiedzi odpowiedź na to jest ddniemożliwa.

rozgwiazdy
źródło
Co się stanie, jeśli ddrescueodkryje zły blok w tym scenariuszu? Jeśli przeskoczy na inny obszar dysku (aby uniknąć złych bloków) i kontynuuje kopiowanie z tego miejsca, ponownie zastąpi jeszcze nie skopiowane części danych. Jeśli nie spodziewa się, że będzie działać z tym samym urządzeniem, nie ma powodu, aby podejmować specjalne środki, aby zapobiec różnym możliwym przypadkom uszkodzenia danych.
frostschutz
Zgadzam się, że jest to potencjalny problem, ale nie przyjrzałem się przypadkowym przypadkom, ponieważ mogłem go wykorzystać do robienia tego, czego potrzebowałem. Istnieją ddrescueopcje ograniczenia prób odzyskania złych danych, ale nie zastanawiałem się nad ich wykorzystaniem.
starfry
Fakt, że odmawia działania, jeśli dane wejściowe i wyjściowe są takie same, jest prawdopodobnie dobrym wskaźnikiem, że nie jest bezpieczny.
psusi