이 두 blockdev 선언의 차이점은 무엇입니까?

이 두 blockdev 선언의 차이점은 무엇입니까?

Debian Bullseye에서는 명령줄(예: no virsh또는 기타 도우미/래퍼)을 통해 QEMU/KVM을 사용하여 가상 머신을 시작합니다. 가상 머신 중 하나는 다음과 같이 선언된 블록 장치에서 시작됩니다.

-blockdev driver=file,node-name=q1,filename=/dev/loop0 \

바로 오늘 우연히 이 VM을 시작할 때 QEMU가 다음 경고를 발행하는 것을 발견했습니다.

Opening a block device as a file using the 'file' driver is deprecated

일부 연구에서는 이 경고가 알려져 있으며 @Stephen Kitt가 승인한 것과 같은 해결책이 있다고 제안합니다.여기에 대답하세요다음과 같은 진술을 합니다 blockdev.

-blockdev node-name=q1,driver=raw,file.driver=host_device,file.filename=/dev/loop0 \

이 솔루션은 의심할 여지 없이 유효하지만 이에 대해 아무것도 찾을 수 없습니다 file.driver=host_device. 그래서 다른 옵션을 테스트하고 작동하는 것으로 보이는 다음 솔루션을 생각해 냈습니다.

-blockdev driver=host_device,node-name=q1,filename=/dev/loop0 \

누군가 이 두 진술의 차이점을 간략하게 설명할 수 있습니까? 특히 대기 시간이나 처리량 측면에서 하나가 다른 것보다 낫습니까?

보너스 질문으로, 문서가 어디에 host_device있는지 아는 사람이 있나요? 위에 링크된 다른 질문/답변에는 링크가 있습니다.제출하다이 드라이버가 구현될 수 있습니다. 그러나 해당 링크 뒤에 있는 문서도 찾을 수 없습니다.

답변1

~에 따르면QEMU 변경 로그, QEMU 버전 3.0에서는 file호스트 블록 장치에 액세스할 때 드라이버가 더 이상 사용되지 않고 도입되었습니다.host_device

이것귀하가 언급한 Stephen Kitt의 답변에 대한 PDF 프레젠테이션(20~24페이지 참조) QEMU 스토리지를 정의하는 가장 철저한 방법은 먼저 ( file또는 host_device) 를 사용하여 데이터 위치를 설정한 node_name=다음 데이터 --blockdev형식 예를 들어 ). 이는 사용자에게 탁월한 제어 기능을 제공하지만 대부분의 기본 상황에서는 과잉입니다.file=<previously_defined_node_name>rawqcow2

QEMU 소스 코드 저장소에서qemu-options.hx서류-blockdev지금까지 본 옵션 중 가장 잘 설명된 것 같습니다 .

file.<something>=<something>이 미스터리를 해결하는 데 영감을 줄 수 있는 구절이 있습니다 .

다른 노드(예: )에 대한 참조를 기대하는 file옵션은 두 가지 방법으로 제공될 수 있습니다. 기존 노드의 노드 이름을 지정하거나( ), 점( ) 뒤에 노드를 참조하는 옵션을 추가하여 file=node-name새 노드 인라인을 정의할 수 있습니다 .file.filename=path,file.aio=native

따라서 file.<something>=구문은 본질적으로 -blockdev다른 선언을 지정하는 동시에 node_name네임스페이스를 어지럽히는 "중간 노드" 이름을 피하는 간단한 방법입니다.

따라서 Stephen Jeter의 blockdev진술은 다음과 같습니다.

-blockdev node-name=q1,driver=raw,file.driver=host_device,file.filename=/dev/loop0

확장된 형식과 동일해 보입니다.

-blockdev node_name=<hidden_node>,driver=host_device,filename=/dev/loop0 \
-blockdev node_name=q1,driver=raw,file=<hidden_node>

이 말과 당신의 말의 차이점

-blockdev driver=host_device,node-name=q1,filename=/dev/loop0 

이는 까다로운 질문이며 이를 이해하려면 QEMU 소스 코드에 대한 심층 분석이 필요합니다.

QEMU -blockdev드라이버 file이며 다양한 호스트 아키텍처에 host_device대한 host_cdrom여러 버전이 있습니다. Linux의 경우 해당 항목은 다음 위치에 있습니다.block/file-posix.c. 문자열 인스턴스를 검색하면 BlockDriver bdrv_모든 인스턴스를 찾을 수 있습니다. (또한 host_cdrom어떤 이유로 FreeBSD가 완전히 별개의 정의를 가지고 있다는 것을 알게 될 것입니다 .)

각각은 BlockDriver(주로) 함수 포인터의 구조로 정의되는 것 같습니다. 이러한 포인터는 드라이버별 기능을 가리키거나 다른 드라이버와 공유되는 공통 구현을 참조할 수 있습니다.

드라이버는 file다음과 같이 정의됩니다.

BlockDriver bdrv_file = {
    .format_name = "file",
    .protocol_name = "file",
    .instance_size = sizeof(BDRVRawState),
    .bdrv_needs_filename = true,
    .bdrv_probe = NULL, /* no probe for protocols */
    .bdrv_parse_filename = raw_parse_filename,
    .bdrv_file_open = raw_open,
    .bdrv_reopen_prepare = raw_reopen_prepare,
    .bdrv_reopen_commit = raw_reopen_commit,
    .bdrv_reopen_abort = raw_reopen_abort,
    .bdrv_close = raw_close,
    .bdrv_co_create = raw_co_create,
    .bdrv_co_create_opts = raw_co_create_opts,
    .bdrv_has_zero_init = bdrv_has_zero_init_1,
    .bdrv_co_block_status = raw_co_block_status,
    .bdrv_co_invalidate_cache = raw_co_invalidate_cache,
    .bdrv_co_pwrite_zeroes = raw_co_pwrite_zeroes,
    .bdrv_co_delete_file = raw_co_delete_file,

    .bdrv_co_preadv         = raw_co_preadv,
    .bdrv_co_pwritev        = raw_co_pwritev,
    .bdrv_co_flush_to_disk  = raw_co_flush_to_disk,
    .bdrv_co_pdiscard       = raw_co_pdiscard,
    .bdrv_co_copy_range_from = raw_co_copy_range_from,
    .bdrv_co_copy_range_to  = raw_co_copy_range_to,
    .bdrv_refresh_limits = raw_refresh_limits,
    .bdrv_attach_aio_context = raw_aio_attach_aio_context,

    .bdrv_co_truncate                   = raw_co_truncate,
    .bdrv_co_getlength                  = raw_co_getlength,
    .bdrv_co_get_info                   = raw_co_get_info,
    .bdrv_get_specific_info             = raw_get_specific_info,
    .bdrv_co_get_allocated_file_size    = raw_co_get_allocated_file_size,
    .bdrv_get_specific_stats = raw_get_specific_stats,
    .bdrv_check_perm = raw_check_perm,
    .bdrv_set_perm   = raw_set_perm,
    .bdrv_abort_perm_update = raw_abort_perm_update,
    .create_opts = &raw_create_opts,
    .mutable_opts = mutable_opts,
};

따라서 이는 본질적으로 드라이버의 복제본 raw이며 거의 모든 기능이 이를 참조합니다.

정의는 host_device조금 더 복잡합니다.

static BlockDriver bdrv_host_device = {
    .format_name        = "host_device",
    .protocol_name        = "host_device",
    .instance_size      = sizeof(BDRVRawState),
    .bdrv_needs_filename = true,
    .bdrv_probe_device  = hdev_probe_device,
    .bdrv_parse_filename = hdev_parse_filename,
    .bdrv_file_open     = hdev_open,
    .bdrv_close         = raw_close,
    .bdrv_reopen_prepare = raw_reopen_prepare,
    .bdrv_reopen_commit  = raw_reopen_commit,
    .bdrv_reopen_abort   = raw_reopen_abort,
    .bdrv_co_create_opts = bdrv_co_create_opts_simple,
    .create_opts         = &bdrv_create_opts_simple,
    .mutable_opts        = mutable_opts,
    .bdrv_co_invalidate_cache = raw_co_invalidate_cache,
    .bdrv_co_pwrite_zeroes = hdev_co_pwrite_zeroes,

    .bdrv_co_preadv         = raw_co_preadv,
    .bdrv_co_pwritev        = raw_co_pwritev,
    .bdrv_co_flush_to_disk  = raw_co_flush_to_disk,
    .bdrv_co_pdiscard       = hdev_co_pdiscard,
    .bdrv_co_copy_range_from = raw_co_copy_range_from,
    .bdrv_co_copy_range_to  = raw_co_copy_range_to,
    .bdrv_refresh_limits = raw_refresh_limits,
    .bdrv_attach_aio_context = raw_aio_attach_aio_context,

    .bdrv_co_truncate                   = raw_co_truncate,
    .bdrv_co_getlength                  = raw_co_getlength,
    .bdrv_co_get_info                   = raw_co_get_info,
    .bdrv_get_specific_info             = raw_get_specific_info,
    .bdrv_co_get_allocated_file_size    = raw_co_get_allocated_file_size,
    .bdrv_get_specific_stats = hdev_get_specific_stats,
    .bdrv_check_perm = raw_check_perm,
    .bdrv_set_perm   = raw_set_perm,
    .bdrv_abort_perm_update = raw_abort_perm_update,
    .bdrv_probe_blocksizes = hdev_probe_blocksizes,
    .bdrv_probe_geometry = hdev_probe_geometry,

    /* generic scsi device */
#ifdef __linux__
    .bdrv_co_ioctl          = hdev_co_ioctl,
#endif

    /* zoned device */
#if defined(CONFIG_BLKZONED)
    /* zone management operations */
    .bdrv_co_zone_report = raw_co_zone_report,
    .bdrv_co_zone_mgmt = raw_co_zone_mgmt,
    .bdrv_co_zone_append = raw_co_zone_append,
#endif
};

raw또한 대부분의 드라이버 기능을 참조 하지만 다음과 같은 전용 기능도 있습니다.

  • 탐지장비
  • 파일 이름을 구문 분석합니다(아마도 유효한 호스트 장치를 확인하기 위해).
  • 장치를 엽니다(자세히 살펴보면 MacOS에서 사용자로 블록 장치에 액세스하려면 상당한 추가 코드가 필요하므로 이는 OS별로 필요할 가능성이 높습니다)
  • 큰 0 덩어리를 빠르게 작성
  • 데이터 삭제
  • 장치 권한 확인 및 설정
  • 장치 통계 가져오기
  • 장치 블록 크기 및 드라이브 구조 감지
  • 일반적인 SCSI 명령 전달

이러한 host_device특정 기능 중 일부는 단순히 추가 오류 검사를 수행한 다음 raw드라이버의 해당 기능을 호출합니다. 그러나 이는 아마도 host_device대부분의 드라이버 가치를 제공하는 마지막 것일 것입니다 . 이를 통해 가상 머신은 호스트 장치의 실제 블록 크기와 기하학적 구조(해당되는 경우)를 명시적으로 볼 수 있습니다. 일반 SCSI 명령을 통해 VM은 테이프 라이브러리 로봇, 대용량 테이프 드라이브, DVD 버너 등 다양한 항목에 대한 액세스 권한을 부여받을 수 있습니다.

대부분의 경우 host_device선언은 본질적으로 드라이버의 기능으로 대체되므로 더 짧은 선언이 작동합니다.raw

위 내용은 POSIX 스타일 운영 체제에만 적용됩니다. Windows에서 QEMU를 실행하는 경우 장치 액세스는 일반 파일 액세스와 완전히 달라야 할 수 있으며 더 짧은 명령문은 전혀 작동하지 않을 수 있습니다. file와 사이의 차이점은 host_device주로 QEMU를 장치 액세스가 일반 파일과 크게 다른 다른 시스템 아키텍처로 포팅하기 위한 것입니다.

성능에 대해 걱정하시겠지만 성능은 기본적으로 동일할 것으로 예상하고,세 가지 드라이버 모두 핵심 기능을 구현하기 위해 정확히 동일한 코드를 호출하게 되기 때문입니다., bdrv_co_preadvbdrv_co_pwritev기능.

드라이버를 서로 계층화할 때 특정 드라이버가 그 위에 계층화될 드라이버와 정확히 동일한 기능을 사용하는지 여부를 감지하고 중복을 제거하도록 최적화하는 것은 매우 간단합니다. 내 첫 번째 추측은 모든 종류의 어리석은 행동을 피하기 위해 그러한 최적화가 실제로 매우 필요하다는 것입니다. 따라서 구성이 정확히 동일한 작업을 수행하게 되면 선언 방법에 관계없이 동일한 작업을 수행하기를 원합니다.

관련 정보