"dd"를 사용하여 데이터 블록을 오른쪽으로 이동하는 방법은 무엇입니까?

"dd"를 사용하여 데이터 블록을 오른쪽으로 이동하는 방법은 무엇입니까?

100MB 원시 블록 장치를 예로 들어 보겠습니다. 이는 각각 512바이트의 블록 204,800개로 총 102,760,448바이트입니다.

문제는 첫 번째 98MB(200704블록)를 이동하여 그 앞에 2MB(4096블록)의 간격이 있도록 하는 것입니다. 이 작업을 수행하려면 아직 읽지 않은 섹터에 아무 것도 쓰지 않아야 합니다. 이를 달성하는 한 가지 방법은 버퍼를 도입하는 것입니다.

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

mbuffer기록기에 무엇인가 전달되기 전에 4096개의 블록이 저장되어 아직 읽히지 않은 영역에 아무 것도 기록되지 않고 기록기가 판독기 버퍼의 크기보다 뒤떨어지는 것을 보장할 것으로 예상됩니다 . 버퍼는 판독기와 기록기가 이러한 제약 조건 내에서 최대한 빠르게 작동할 수 있도록 해야 합니다.

그러나 안정적으로 작동하지 않는 것 같습니다. 실제 장치를 사용해 보았으나 전혀 작동하지 않았습니다. 파일을 사용한 실험은 64비트 컴퓨터에서는 작동하지만 32비트 컴퓨터에서는 작동하지 않습니다.

먼저, 몇 가지 준비사항:

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

이것은 작동하지 않습니다:

$ 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

이는 64비트 시스템에서는 작동하지만 32비트 시스템에서는 작동하지 않습니다.

$ 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

이 작업을 어떻게 안정적으로 수행할 수 있습니까?


노트

버퍼링 및 에 대한 다른 질문을 읽고 살펴보았습니다 pv. 필요한 버퍼 크기를 사용하도록 후자만 얻을 수 있습니다.buffermbuffer

중간 저장소를 사용하는 것은 이 문제에 대한 확실한 해결책이며 항상 작동하지만 여유 용량이 충분하지 않은 경우에는 실용적이지 않습니다.

Arch Linux 버전 20140302를 실행하는 테스트 플랫폼 mbuffer.

답변1

버퍼가 없으면 한 번에 한 블록씩 뒤로 이동할 수 있습니다.

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

이 예제는 오류 검사가 부족하여 위험합니다.

통화량이 많아서 속도도 느렸습니다 dd. 여유 메모리가 있으면 더 큰 블록 크기를 사용할 수 있습니다.

버퍼로,함정을 조심하세요. 이것은아니요100% 사전 충전을 보장할 만큼 충분합니다. 당신이 원하는 것은 전체적으로 최소한의 패딩입니다. 버퍼는 절대 아래로 내려가서는 안 됩니다. 2M그렇지 않으면 아직 읽지 않은 데이터를 덮어쓰게 됩니다.

따라서 이론적으로는 어떤 종류의 버퍼도 사용할 수 없으며 체인만 사용할 수 있습니다 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

실제로는 이렇게 합니다.아니요마지막 항목 ( 사이에 "버퍼" 포함)이 이미 쓰고 있는 dd동안 첫 번째 항목이 계속해서 데이터를 읽는다는 보장이 없기 때문에 안정적으로 작동합니다 .dd2M

중간 버퍼를 상당히 크게 만들면 가능성을 크게 높일 수 있지만 그래도 여전히 신뢰할 수 없습니다.

불행하게도 저는 최소한의 패딩 속성을 갖춘 좋은 버퍼 프로그램을 모릅니다. 버퍼 내의 안전 여유가 안전 여유보다 작을 때마다 출력을 중지할 수 있는 장치가 필요합니다.

답변2

4096개 블록을 읽은 후 다음 4096개 블록을 디스크에 쓰고 있으므로 읽기 전에 두 번째 4096개 블록을 덮어씁니다. 쓰기를 시작하기 전에 두 번째 4096 블록을 얻으려면 8129 블록을 읽어야 하며, 다음 4096 블록을 읽기 전에 4096 블록만 쓰면 됩니다.

이것이 어떤 유형의 파일 시스템인지 언급하지 않았습니다. ext[234]이고 최신 버전의 e2fsprogs가 있는 경우 을 사용할 수 있습니다 e2image -ra -O 512 /dev/sdj2. 이는 볼륨의 여유 공간을 건너뛸 수 있을 만큼 똑똑하다는 추가 이점이 있습니다.

답변3

신뢰할 수 있는 솔루션을 위해서는 읽혀지지 않은 영역에 아무것도 기록되지 않도록 해야 하며, 이를 달성하는 유일한 실제 방법은 반대 방향으로 복사를 수행하는 것입니다.

ddrescue도구는 반대로 작동하지만 동일한 입력 및 출력으로 실행되는 것을 거부합니다. 그러나 장치 노드를 복제하여 스푸핑하는 것이 가능합니다.

몇 가지 간단한 실험을 해봤는데 효과가 있는 것 같습니다. 명령줄은 다음과 같습니다.

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

주장은

  • -f기존 출력 장치에 강제로 쓰도록 해야 합니다.
  • -R반대 방향으로 작동하도록 지시
  • -s복사할 입력의 양을 알려줍니다. ( s섹터 수를 지정하기 위해 접미사를 사용합니다.)
  • -o쓰기 전에 출력 장치에서 앞으로 기다리도록 지시합니다(접미사를 사용하여 섹터에 다시 지정됨 s).
  • /dev/sdj11읽을 블록 장치입니다.
  • /dev/sdj11_copy기록할 블록 장치입니다.

일치 /dev/sdj11_copy하는 매개변수를 만들었습니다 .mknod/dev/sdj11

아주 간단한 몇 가지 테스트만 수행했지만 이는 원래 장치를 잘 복제한 것 같습니다. 파일에서는 작동하지 않습니다(파일과 동일한 범위를 넘어서도록 속일 수는 없습니다).

이것은 이것을 달성하는 방법에 대한 원래 질문에 대답하지 않지만 dd다른 답변을 읽은 후에는 대답이 dd불가능하다는 것입니다.

관련 정보