dd는 언제 데이터 복사에 적합합니까? (또는 read () 및 write () 부분 인 경우)


60

짧은 버전 : 어떤 상황에서 dd데이터를 복사하기에 안전한가, 부분 읽기 또는 쓰기로 인한 손상 위험이 없음을 의미합니까?

긴 버전-프리앰블 : dd 데이터를 특히 장치에서 또는 장치로 복사하는 데 자주 사용됩니다 ( :). 때로는 다른 도구보다 낮은 수준에서 장치에 액세스 할 수 있다는 신비한 특성으로 인해 (실제로 마술을 수행하는 장치 파일 인 경우)- dd if=/dev/sda와 동일합니다 cat /dev/sda. dd때로는 더 빠르다고 생각되지만 실제로 cat는 이길 수 있습니다 . 그럼에도 불구하고 dd때로는 진정으로 유용하게 사용할 수있는 고유 한 속성이 있습니다.

문제 : dd if=foo of=bar 실제로는와 동일하지 않습니다 cat <foo >bar. 대부분의 유니 세 ¹에서을 ( dd를) 한 번 호출합니다 read(). (I 찾을 POSIX 에서 "입력 블록을 읽고"구성 무엇에 퍼지를 dd.) 경우 read()반환 (POSIX 및 기타 참조 문서에 따르면,이 구현 설명서에 별도로 언급되어 있지 않은 한 허용 것) 부분 결과, 일부 블록이 복사됩니다. 에 대해 동일한 문제가 존재합니다 write().

관찰 : 실제로 dd블록 장치 및 일반 파일에 대처할 수는 있지만 실제로는 많이 사용하지 않았을 수 있습니다. 파이프에 관해서 dd는 잘못 을 저지르는 것이 어렵지 않습니다 . 예를 들어이 코드 를 사용해보십시오 :

yes | dd of=out bs=1024k count=10

out파일 크기를 확인 하십시오 (10MB 미만일 수 있음).

질문 : 어떤 상황에서 dd데이터 복사에 안전한가요? 다시 말해, 블록 크기, 구현, 파일 형식 등에서 dd모든 데이터를 복사 할 수있는 조건 은 무엇입니까?

( GNU dd 에는 전체 블록을 전송 fullblock하기 위해 호출 read()또는 write()루프로 지시 하는 플래그가 있습니다. 따라서 dd iflag=fullblock항상 안전합니다. 내 질문은 이러한 플래그 (다른 구현에는 존재하지 않음)가 사용되지 않는 경우에 관한 것입니다 .)

¹ OpenBSD, GNU coreutils 및 BusyBox를 확인했습니다.


한 번의 읽기로 몇 개의 MiB를 읽을 수있는 Unixy 시스템을 본 적이 없습니다.
vonbrand

3
사용시 count상기은 iflag=fullblock(다르게는, 또는 필수 iflag=count_bytes). 없습니다 oflag=fullblock.
frostschutz

답변:


10

로부터 사양 :

  • 경우] bs=expr오퍼랜드를 지정하고 이하 다른 전환되고 sync, noerror또는 notrunc요구되는, 각 입력 블록으로부터 반환 된 데이터는 별도의 출력 블록으로 기록된다; 경우 생성 read()복귀 전체 블록보다 상기 sync변환을 지정하지 않으면, 결과 출력 블록을 상기 입력 블록과 같은 크기로한다.

그래서 이것은 아마도 혼란을 야기 할 것입니다. 예, 때문에이 dd되어 설계 기본적으로 부분 차단 read()부분에 1 : S 1 매핑됩니다 write()의, 또는 다른 사람 sync에 꼬리 패딩 NUL 또는 공간 문자에 나가 거라고 bs=때 크기가 conv=sync지정됩니다.

이것이 뜻 dd이다 (손상의 위험없이 / w 인해 부분 판독 또는 기록하기 위해) 데이터를 복사하는 데 사용할 금고 가 임의로 의해 한정되는 모든 경우이지만 하나 count=, 인수로 인해 그렇지 dd것 게 write()동일 크기의 블록에 출력 입력이 완전히 read()끝날 때까지 read()심지어이주의해야 할 점은 있습니다 만 사실bs=지정 또는 obs=되어 있지 사양 상태에서 바로 다음 문장으로 지정 :

  • 경우] bs=expr오퍼랜드를 지정하거나, 다른보다 전환되지 않고 sync, noerror또는 notrunc요구되는 입력을 처리하여야하며, 최대 크기의 출력 블록으로 수집 입력의 끝에 도달 할 때까지.

없이 ibs=및 / 또는 obs=인수이 문제가되지 수 - 때문에 ibsobs기본적으로 같은 크기의 상표입니다. 그러나 우선 순위를 지정 하므로 지정 하지 않고 다른 크기 를 지정하여 입력 버퍼링에 대해 명시 적으로 얻을있습니다 .bs=

예를 들어, 다음과 같은 경우 :

IN| dd ibs=1| OUT

... 그런 다음 POSIX dd는 모든 단일 바이트를 단일 출력 블록 으로 수집write() 하여 512 바이트 단위로 청크 합니다.read()

그렇지 않으면, 당신이 할 경우 ...

IN| dd obs=1kx1k| OUT

... POSIX dd는 한 read() 번에 최대 512 바이트이지만 입력을 전체 크기의 출력 블록 으로 수집하여 write()모든 메가 바이트 크기의 출력 블록 (최종 EOF이므로 허용하고 제외하는 커널) 을 모두 사용합니다 .

또한 사양에서 :

  • count=n
    • n 개의 입력 블록 만 복사하십시오 .

count=에 매핑 i?bs=블록 등 임의의 한계를 처리하기 위해 count=이식 당신이 개 필요합니다 dd들. 두 개의 dds 로 수행하는 가장 실용적인 방법 은 하나의 출력을 다른 입력으로 파이핑하는 것이므로 원래 입력 유형에 관계없이 특수 파일 을 읽거나 쓰는 영역을 확실히 확보 할 수 있습니다.

IPC 파이프는 [io]bs=인수를 지정할 때 안전하게 지정 하기 위해 이러한 값을 시스템의 정의 된 PIPE_BUF한계 내에 유지해야 함을 의미합니다 . POSIX는 시스템 커널 이 에 정의 된 한계 내 에서만 원자 read()와 원자를 보장해야한다고 명시하고 있습니다. POSIX는이 보장 될 적어도 ...write()PIPE_BUFlimits.hPIPE_BUF

  • {_POSIX_PIPE_BUF}
    • 파이프에 쓸 때 원 자성으로 보장되는 최대 바이트 수입니다.
    • 값 : 512

... (기본 ddI / O 블록 크기 이기도 함 ) 이지만 실제 값은 일반적으로 4k 이상입니다. 최신 Linux 시스템에서는 기본적으로 64k입니다.

따라서 dd프로세스 를 설정할 때 세 가지 값을 기준으로 블록 팩터 에서 프로세스를 수행해야 합니다.

  1. bs = (obs = PIPE_BUF이하)
  2. n = 읽은 총 바이트 수
  3. 카운트 = n / bs

처럼:

yes | dd obs=1k | dd bs=1k count=10k of=/dev/null
10240+0 records in
10240+0 records out
10485760 bytes (10 MB) copied, 0.1143 s, 91.7 MB/s

검색 할 수없는 dd입력을 처리하려면 i / ow /를 동기화해야합니다 . 즉, 파이프 버퍼를 명시 적으로 작성하면 문제가되지 않습니다. 그게 다야 dd. 여기에서 알 수없는 양은 yes버퍼 크기입니다.하지만 다른 것으로 알려진 양으로 차단 dd하면 약간의 정보를 곱하면 dd 데이터를 복사하는 데 안전하게 사용할 수 있습니다 (부분 읽기 또는 쓰기로 인한 손상 위험 없음)count= POSIX 시스템에서 임의의 입력 유형으로 임의의 입력 유형을 임의로 제한 하고 단일 바이트가 누락되지 않은 경우에도 마찬가지 입니다.

다음은 POSIX 사양 의 스 니펫입니다 .

  • ibs=expr
    • 입력 블록 크기를 바이트 단위로 지정하십시오 (기본값은 512) .expr
  • obs=expr
    • 출력 블록 크기를 바이트 단위로 지정하십시오 (기본값은 512) .expr
  • bs=expr
    • 입력 및 출력 블록 크기를 모두 expr바이트, 대체 ibs=및로 설정하십시오 obs=. 이하 전환 다른 경우 sync, noerrornotrunc지정된 각 입력 블록 짧은 블록 응집하지 않고 단일 블록으로 출력으로 복사한다.

또한 여기에 더 잘 설명되어 있습니다 .


5

소켓, 파이프 또는 tty를 사용하면 read () 및 write ()가 요청 된 크기보다 적게 전송할 수 있으므로 dd를 사용할 때 fullblock 플래그가 필요합니다. 그러나 일반 파일 및 블록 장치를 사용하면 짧은 읽기 / 쓰기가 가능한 경우 (OFOF에 도달 한 경우 또는 오류가있는 경우) 두 번만 있습니다. 이것이 fullblock 플래그가없는 dd의 이전 구현이 디스크 복제에 사용하기에 안전한 이유입니다.


그것은 현대의 모든 유니스에도 적용됩니까? (나는 리눅스가 2.0.x 또는 2.2.x까지 가능하지 않다는 것을 알고있다. 나는 2가 아닌 크기 (3kB IIRC)로 호출하고 커널이 둥글 mke2fs었기 때문에 조용히 실패했다 . write()2의 거듭 제곱으로
Gilles

@Gilles는 전혀 다른 문제처럼 들립니다. 블록 장치에는 항상 적절한 블록 크기의 배수를 사용해야합니다. 나는 그것이 모든 unicies에 대해서도 사실이라고 확신하며 Windows에서도 마찬가지입니다.
psusi

테이프와는 별도로, 장치의 블록 크기는 순전히 커널이 신경 쓰는 것입니다. cat </dev/sda >/dev/sdb디스크를 복제하는 데 잘 작동합니다.
Gilles

@Gilles는 OrbWeaver가 그의 답변에서 언급했듯이 고양이가 적절한 블록 크기를 사용하기 때문입니다.
psusi

아니요,“적절한 블록 크기”는 없습니다. cat성능을 위해 버퍼 크기를 선택합니다. 커널에서 장치 관련 정보를 얻지 못합니다. 그렇다 테이프에서 수행 할 수 있습니다 read()write()모든 크기와 블록 장치에 관한 것이다. Linux에서는 최소한 st_blksize기본 장치가 아닌 블록 장치 inode가있는 파일 시스템에만 의존합니다.
Gilles
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.