`dd`를 사용하여 데이터 블록을 오른쪽으로 이동시킬 수 있습니까?


10

간단한 예로 100MB 원시 블록 장치를 고려하십시오. 총 102760448 바이트에 대해 각각 512 바이트의 204800 블록입니다.

문제는 첫 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, buffer및을 보았습니다 mbuffer. 후자는 필요한 버퍼 크기로 작업하게 할 수있었습니다.

종말점 스토리지를 사용하는 것은 항상 작동하는 문제에 대한 확실한 솔루션이지만 충분한 예비 용량을 사용할 수없는 경우에는 실용적이지 않습니다.

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


나는 그것이 문제를 해결할 것이라고 생각하지 않지만 호기심 때문에 왜 mbuffer전혀 사용하지 않습니까? 대신 dd블록 장치의 전체 내용을 한 번에 읽으십시오 dd bs=102760448. 물론 한 가지 방법은 RAM에 버퍼링됩니다.
Celada

@Celada-100MB 예제는 단지 예일뿐입니다. 예를 들어 한 번에 1TB를 읽는 것은 좋은 생각이 아닙니다.
starfry

2
아, 이해합니다, 고마워요 은 mbuffer실제로 초를 강제적으로 dd첫번째에 대한 뒤쳐 당신은 단지 변화의 크기를 버퍼에 충분한 RAM이 필요합니다. 너무 나쁘면 dd문제를 제거하기 때문에 블록을 역순으로 읽고 쓰는 것을 지원하지 않습니다!
Celada

두 번째 md5sum 계산 방법 을 나열하지 않았습니다
psusi

@psusi, 두 번째 md5는 mbuffer에 의해 출력됩니다 ( -H인수는이 기능을 가능하게합니다).
starfry

답변:


2

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

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

실제로 첫 번째 데이터를 계속 읽는다는 보장이없고 마지막 ( 사이에 "버퍼"가 있음)이 이미 쓰고 있다는 보장이 없기 때문에 이것은 실제로 작동 하지 않습니다 .dddd2M

버퍼 간을 상당히 크게 만들어서 기회를 상당히 늘릴 수는 있지만 신뢰할 수는 없습니다.

불행히도 필자는 최소 채우기 속성을 가진 좋은 버퍼 프로그램을 모릅니다. 버퍼 내에 안전 여유가있는 한 출력을 중지하는 것이 필요합니다.


dd사용 방법을 시연하여 원래의 질문에 대답하기 때문에 이것을 받아 들였습니다 . 그러나 실제 솔루션은 사용 dd하지 않고 대신 뒤로 실행되도록 설계된 것을 선택한다고 생각합니다 ddrescue. 나는 그것을 대답하는 방법을 설명했습니다.
starfry

1
@starfry : 물론, 그것을하는 프로그램은 훌륭한 해결책이 될 것입니다. 그러나 나는 ddrescue여기 에 전혀 확신하지 못한다 . 다른 장치에서 작동 할 것으로 예상되는 경우가 아니라면 인수를 수락하도록 속 여야합니다. 내부에 "최소 버퍼 채우기"속성이 없을 수도 있으므로 (다른 장치가 필요하지 않기 때문에) 다시 데이터를 손상시킬 수 있습니다. 소스 코드에서 실제로 사용 사례에 맞게 설계되었는지 확인해야합니다.
frostschutz

1

4096 블록을 읽은 다음 해당 4096 블록을 디스크의 다음 4096 블록에 쓰므로 두 번째 4096 블록을 덮어 쓰기 전에 읽을 수 있습니다. 쓰기를 시작하기 전에 두 번째 4096을 얻으려면 8129 블록을 읽어야합니다. 그런 다음 다음 4096을 읽기 전에 4096 블록 만 쓰면됩니다.

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


그것은 읽을 때 의미가 있으며 나는 그것을 기반으로 다른 모습을 취할 것입니다. 그러나 왜 테스트 파일에서 작동했는지는 설명하지 않습니다.
starfry

파일 시스템을 다시 테스트하십시오. 테스트 파일이 포함 된 파일 시스템을 참조하고 있습니까? 의 그 ext4하지만 블록 장치 사본을, 어떤 파일 시스템은 무관해야한다.
starfry

@starfry, 일반적인 방법 으로이 작업을 수행하는 유일한 방법은 Emmanuel이 제안한 알고리즘 (끝에서 거꾸로 작동)을 사용하는 것입니다.
psusi

블록 크기와 관련하여 더 큰 블록을 시도했습니다 (질문에 작성해야 함). 64K 섹터 버퍼조차도 더 신뢰할 수 없다는 것을 알았습니다. 신뢰할 수있는 솔루션은 거꾸로 실행하는 것입니다 dd.
starfry

1

안정적인 솔루션을 사용하려면 읽지 않았을 수있는 영역에 아무 것도 쓰지 않아야하며이를 달성 할 수있는 유일한 방법은 반대 방향으로 복사를 수행하는 것입니다.

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_copymknod일치하도록 만들었습니다 /dev/sdj11.

매우 빠른 테스트 만 수행했지만 원시 장치를 복사해도 정상적으로 작동하는 것으로 보입니다. 파일에서 작동하지 않습니다 (파일이 동일한 것을 넘어서도록 속일 수는 없었습니다)

이것은 이것을 달성하는 방법을 묻는 원래의 질문에 대한 대답은 dd아니지만 다른 답변을 읽은 후에는 그 대답을 dd할 수 없다고 생각합니다.


ddrescue이 시나리오에서 불량 블록을 발견하면 어떻게됩니까 ? 디스크의 다른 영역으로 이동하여 (불량한 블록을 피하기 위해) 계속 복사하면 데이터의 아직 복사되지 않은 부분을 덮어 씁니다. 동일한 장치에서 작동하지 않을 것으로 예상되는 경우 다양한 가능한 데이터 손상 사례를 방지하기 위해 특별한 조치를 취할 이유가 없습니다.
frostschutz

나는 이것이 잠재적 인 문제라는 데 동의하지만 필요한 것을 수행하는 데 사용할 수 있었기 때문에 가장자리 사례를 보지 못했습니다. 있습니다 ddrescue잘못된 데이터를 복구하는 그 시도를 제한하는 옵션이 있지만, 나는 그들을 사용에보고하지 않았습니다.
starfry

는 입력과 출력이 동일한 경우 작동을 거부한다는 사실은 아마 이 안전하지 않았 음을 표시.
psusi
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.