# 실패의 연대기 (Failure Journal) > Windows VM의 디스크 컨트롤러를 **SATA → VirtIO-SCSI**로 마이그레이션하는 과정에서 만난 모든 함정의 기록. > 진짜 원인 — `vioscsi START_TYPE=0 (BOOT_START)` 누락 — 을 찾기까지 수 시간을 소비했다. > 같은 길을 가는 사람이 이 글을 읽고 30분에 끝낼 수 있길. 작성일: 2026-05-19 작업 환경: Proxmox VE 8.1.3 / Windows 10 Pro 19045 / virtio-win-0.1.285 --- ## 출발점 목표: - SMB에 보관된 `vm100.vhd` (120GiB virt, 106GiB sparse) Windows 디스크 이미지를 Proxmox VM에 활용 - 가능하면 SATA 에뮬레이션 대신 **VirtIO-SCSI 컨트롤러**로 운영해서 성능/효율 확보 (멀티큐, iothread, discard/TRIM) 도구: - `qm importdisk` (vhd → raw zvol 변환) - ZFS pool `pve-zfs` (vol storage) - `pnputil` (Windows 드라이버 등록) - `qm sendkey`, QEMU monitor screendump (원격 시각 확인) --- ## Step 1 — vhd → raw zvol 변환 ```bash qm importdisk /mnt/smb/vm100.vhd pve-zfs --format raw ``` 결과: `pve-zfs:vm--disk-1` 생성 (REFER 73.4GB sparse). config에 `unused0:`로 자동 등록. **관찰**: 변환 후 zvol 크기가 120GiB + ~1MB 패딩. fdisk가 `GPT PMBR size mismatch` 경고. 이때는 대수롭지 않게 넘어감. --- ## Step 2 — sata1로 attach + 부팅 시도 ```bash qm set --sata1 pve-zfs:vm--disk-1 qm set --boot 'order=sata1;sata0;ide0' qm start ``` **결과**: Windows 10 데스크톱 정상 진입! 사용자도 다 보임. 데이터 모두 살아있음. **우리가 잘못 알았던 것**: "vhd 변환이 잘 됐구나" — 사실은 **sata0 (기존에 갖고 있던 vm-101-disk-0 zvol)에서 부팅된 것**이었음. `Get-Disk`로 확인 안 했으니 모름. --- ## Step 3 — 안정화: efidisk 추가, VirtIO 드라이버 등록 부팅이 잘 되니 마스터화 준비. 두 가지 작업 진행. ### 3-1. efidisk0 추가 (OVMF NVRAM 영구화) ```bash qm set --efidisk0 pve-zfs:1,efitype=4m,pre-enrolled-keys=0 ``` 이전엔 `WARN: no efidisk configured` 떠서 매 부팅마다 OVMF가 NVRAM 새로 만들고 fallback path로 부팅했음. 영구화하면 부팅 엔트리 저장됨. ### 3-2. VirtIO 드라이버 사전 설치 virtio-win.iso를 attach하고 임시 SCSI 디스크도 같이 띄워 게스트가 새 PCI 디바이스 인식하게 만든 다음: ```cmd pnputil /add-driver F:\vioscsi\w10\amd64\vioscsi.inf /install pnputil /add-driver F:\viostor\w10\amd64\viostor.inf /install pnputil /add-driver F:\NetKVM\w10\amd64\netkvm.inf /install ``` `pnputil`이 INF 파일을 driver store에 등록 + `/install` 옵션이 매칭되는 PnP 디바이스에 즉시 설치. `Get-PnpDevice`에서 "Red Hat VirtIO SCSI pass-through controller" Status=OK 보임. `Get-Service vioscsi` → RUNNING. **우리가 잘못 알았던 것**: "드라이버 등록 완료, 이제 부팅 디스크 인터페이스 바꿔도 BSOD 안 나겠지" — **틀렸다**. --- ## Step 4 — 인터페이스 교체: sata1 → scsi0 깨끗한 마스터를 위해 sata1 detach, scsi0로 같은 zvol attach: ```bash qm set --scsi0 pve-zfs:vm--disk-1,iothread=1,discard=on,ssd=1 qm set --delete sata1 qm set --boot 'order=scsi0' qm start ``` **결과**: **BSOD 0xc0000225** (Recovery / "필요한 장치가 연결되어 있지 않거나 장치에 액세스할 수 없습니다") — `\Windows\system32\config\system` 위치 못 찾음. 이때 처음으로 뭔가 잘못됐다고 느낌. 그러나 원인을 GPT signature 충돌로 오해. --- ## Step 5 — 오해의 시작: "GPT signature 충돌이 원인이다" `Get-Disk`로 보니 두 디스크 GUID 완전 동일: ``` Disk 0: SATA, GUID {4bca652d-2f35-4bd7-8175-8951593eb8c1}, 120GB Disk 1: SAS, GUID {4bca652d-2f35-4bd7-8175-8951593eb8c1}, 120GB (1MB padding 더 큼) ``` 호스트에서 `fdisk -l /dev/zvol/...`로 검증 — 두 zvol의 Disk identifier 동일, 모든 partition UUID 동일. **가설 (틀린 것)**: Windows가 동일 GPT signature 두 디스크 보면 한쪽을 자동 Offline 처리 → sata0 detach 후 scsi0 단독으로는 BCD device path 매칭 실패. 이 가설로 BCD 수정 시도들이 시작됨. --- ## Step 6 — BCD 수정 시도 1: device/osdevice → "boot" 키워드 ```cmd bcdedit /export C:\bcd-backup-20260519.bcd bcdedit /set {bootmgr} device boot # 거부됨 (정상) bcdedit /set {default} device boot # 성공 bcdedit /set {default} osdevice boot # 성공 ``` `boot` 키워드 의미: "이 BCD가 로드된 partition을 동적으로 추적해서 사용". 매혹적이지만 **잘못된 적용**. **검증**: shutdown → sata0 detach → 부팅 → **여전히 BSOD 0xc0000225**. **왜 안 먹혔나**: `osdevice = boot`는 사실 잘못된 의미. winload는 "boot device = system partition (EFI 100MB FAT32)"으로 해석해서 거기서 `\Windows\system32\winload.efi` 찾으려고 함. EFI partition에 \Windows 없으니 fail. --- ## Step 7 — BCD 수정 시도 2: bcdboot으로 새 BCD 생성 scsi0의 EFI partition을 마운트해서 BCD 재구성: ```cmd diskpart 스크립트로 Disk 1 Partition 2에 S: 할당 bcdboot C:\Windows /s S: /f UEFI /v ``` bcdboot이 정상 동작: ``` BFSVC: Creating Recovery directory. BFSVC: Creating OsLoader object. BFSVC: Setting {default} to {bfc003a5-...} 부팅 파일을 만들었습니다. ``` 새 BCD enum: ``` {default}.device = partition=\Device\Harddisk0\Partition4 {default}.osdevice = partition=\Device\Harddisk0\Partition4 ``` **검증**: shutdown → sata0 detach → 부팅 → **다른 BSOD 0xc0000017** (system registry file missing). 이제 한 단계 더 진행됨: OVMF→boot manager→winload까지 OK, OS partition 도달, 거기서 SYSTEM hive 못 읽음. --- ## Step 8 — NTFS 무결성 검사: ntfsfix 호스트에서 NTFS 마운트: ```bash ntfs-3g /dev/zvol/pve-zfs/vm--disk-1-part4 /mnt/winc -o ro ls /mnt/winc/Windows/System32/config/SYSTEM # 24.5MB 존재 hexdump -C -n 16 /mnt/winc/Windows/System32/config/SYSTEM # 00000000 72 65 67 66 ... ← "regf" 시그니처 OK umount /mnt/winc ntfsfix /dev/zvol/pve-zfs/vm--disk-1-part4 # Processing of $MFT and $MFTMirr completed successfully. # Checking the alternate boot sector... OK # NTFS partition was processed successfully. ``` **검증**: 부팅 시도 → **BSOD 0xc0000017 그대로**. SYSTEM hive 파일은 존재 + 헤더 정상 + NTFS metadata clean. 그러나 부팅 실패. --- ## Step 9 — NVRAM 초기화 시도 가설: OVMF NVRAM에 옛 부트 엔트리(detach된 디스크 가리키는 것)가 캐시되어 fallback 실패. ```bash qm set --delete efidisk0 qm set --efidisk0 pve-zfs:1,efitype=4m,pre-enrolled-keys=0 qm start ``` **결과**: 새 NVRAM 만들고 부팅 → **BSOD 0xc0000017 그대로**. --- ## Step 10 — WinRE Startup Repair 시도 BSOD 화면에 "F1 to enter Recovery Environment" 안내가 있음. `qm sendkey f1`로 시도. **결과**: WinRE 진입 안 됨. vhd 백업본에 WinRE WIM이 비활성/누락 상태. 막다른 길. --- ## Step 11 — SSD 마이그레이션식 클론 시도 > 사용자 제안: "보통은 디스크 두 개 만들고 1:1 복사하는 도구로 옮기잖아, SSD 마이그레이션처럼" ZFS send/recv로 vhd 변환본을 새 zvol에 클론: ```bash zfs snapshot pve-zfs/vm--disk-1@clone-master time (zfs send pve-zfs/vm--disk-1@clone-master | zfs recv pve-zfs/vm--disk-4) # real 10m50.003s ``` config 교체: 기존 vhd 변환본 detach + 클론을 scsi0로 attach → boot order=scsi0 단독. **결과**: **BSOD 0xc0000017 — 클론도 동일 증상**. 이로써 가설이 확정적으로 깨짐: GPT 충돌이 단독 원인이라면 단일 디스크 상태에서 해결됐어야 함. 그런데 안 됨. --- ## Step 12 — 결정적 진단: sata0 단독 부팅 검증 ```bash qm set --delete scsi0 qm set --sata0 pve-zfs:vm--disk-0,size=120G qm set --boot 'order=sata0' qm start ``` **결과**: ✅ **정상 부팅** (Windows 10 잠금화면, 0bin 사용자). 이게 결정적. **sata0 단독은 부팅 가능 + vhd 변환본 단독은 부팅 불가**. 두 zvol 데이터가 GPT signature는 같지만 어딘가 다르다 — 또는 컨트롤러 차이 자체가 원인. 게스트 상태 확인: ``` Get-Disk → Disk 0 SATA Online Get-Partition → DiskNumber=0 IsBoot=True Get-Service vioscsi → RUNNING sc qc vioscsi → START_TYPE: 3 DEMAND_START ← 🔥 발견! ``` **진짜 원인 발견**: vioscsi 서비스가 등록은 되어 있지만 **boot critical(=0)이 아니라 수동 시작(=3)**. winload가 부팅 시점에 vioscsi.sys를 로드하지 않음 → VirtIO-SCSI 디스크에서 부팅 시 디스크 접근 못 함 → BSOD. `pnputil /add-driver vioscsi.inf /install`은 드라이버 파일과 PnP 매칭만 등록. **서비스의 Start 값을 자동으로 boot critical로 승격하지 않는다**. --- ## Step 13 — 진짜 해결: vioscsi boot critical 승격 ```cmd sc config vioscsi start= boot ``` 검증: ``` sc qc vioscsi → START_TYPE: 0 BOOT_START reg query HKLM\SYSTEM\CurrentControlSet\Services\vioscsi /v Start → Start REG_DWORD 0x0 ``` --- ## Step 14 — Windows 정상 종료 + ZFS 클론 + 마스터화 ```bash # Windows ACPI shutdown qm shutdown --timeout 180 # 검증된 sata0 디스크를 새 zvol로 클론 zfs snapshot pve-zfs/vm--disk-0@master-final time (zfs send pve-zfs/vm--disk-0@master-final | zfs recv pve-zfs/vm--disk-5) # real 28m43.568s # config 교체 qm set --delete sata0 qm set --scsi0 pve-zfs:vm--disk-5,iothread=1,discard=on,ssd=1 qm set --scsihw virtio-scsi-single qm set --boot 'order=scsi0' qm start ``` --- ## Step 15 — 검증: 진짜 마스터 완성 ``` Get-Disk → Disk 0 QEMU QEMU HARDDISK BusType=SAS 120GB Online Get-Partition → DiskNumber=0 IsBoot=True sc query vioscsi → RUNNING sc qc vioscsi → START_TYPE: 0 BOOT_START ``` **단일 디스크 + virtio-scsi-single + iothread + discard + boot critical** = 마스터 완성. Windows 10 잠금화면 정상 진입. --- ## 교훈 (lessons learned) ### 진짜 원인은 vioscsi의 START_TYPE 다른 모든 가설(GPT signature 충돌, BCD 손상, NVRAM 캐시, vhd 변환 미세 손상)은 부분적으로 그럴듯했지만 **단독 원인이 아니었다**. 진짜 원인은: ``` vioscsi Service Start=3 (DEMAND_START) ↓ winload가 부팅 시점에 vioscsi.sys 안 로드 ↓ virtio-scsi 디스크에서 부팅 시 디스크 IO 핸들러 부재 ↓ INACCESSIBLE_BOOT_DEVICE → BSOD 0xc0000017 또는 0xc0000225 ``` ### pnputil의 한계 - `pnputil /add-driver vioscsi.inf /install` - 드라이버 파일과 PnP 디바이스 매칭은 잘 한다 - 그러나 **서비스의 boot priority는 건드리지 않는다** - 그래서 매뉴얼하게 `sc config vioscsi start= boot` 또는 레지스트리 직접 수정 필요 ### "vhd → raw 변환본"은 부팅 보증 안 된다 - `qm importdisk`로 vhd → raw 변환 시 사이즈에 패딩 추가, GPT backup 위치 미세 차이 - 검증된 sata 원본을 ZFS 클론하는 게 더 안전 - vhd는 "백업본"이지 "라이브 부팅 가능 디스크"가 아닐 수 있음 ### 동일 GPT signature 디스크 두 개를 동시 attach하지 말 것 - Windows가 한쪽을 자동 Offline 처리하지만 NT namespace 매핑/BCD path 종속성으로 detach 시 BSOD - 마이그레이션 작업은 단계별로 단독 attach 검증 권장 ### bcdedit `osdevice = boot`은 함정 - "boot manager가 로드된 partition을 동적 추적"이라는 매혹적인 표현 - 그러나 winload는 그걸 "system partition (EFI)"으로 해석 → \Windows 못 찾음 → BSOD - 잘못된 BCD 수정 패턴. **사용하지 말 것**. ### bcdboot은 깔끔하지만 만능 아님 - BCD store 새로 생성 + 자기 자신 가리키도록 설정 - 그러나 partition UUID는 정확히 같은 zvol이라야 매칭됨 - 동일 GPT signature 디스크가 같이 있을 때는 효과 제한적 --- ## 부록: 알아두면 좋은 진단 명령 ```cmd :: 서비스 시작 유형 sc qc vioscsi | findstr START_TYPE reg query HKLM\SYSTEM\CurrentControlSet\Services\vioscsi /v Start :: VirtIO 디바이스 인식 powershell "Get-PnpDevice | Where Manufacturer -like '*Red Hat*' | Format-Table -AutoSize" :: 부팅 디스크 powershell "Get-Disk | Format-Table -AutoSize Number,FriendlyName,BusType,Size" powershell "Get-Partition | Where IsBoot -eq \$true | Format-List" :: BCD 진단 bcdedit /enum {bootmgr} bcdedit /enum {default} :: driverstore의 OEM INF 등록 상태 pnputil /enum-drivers | findstr /i /c:vioscsi /c:viostor /c:netkvm ``` ```bash # 호스트 (PVE)에서 게스트 디스크 NTFS 검증 mount -t ntfs-3g -o ro /dev/zvol//vm--disk-N-part4 /mnt/winc ls /mnt/winc/Windows/System32/config/SYSTEM hexdump -C -n 16 /mnt/winc/Windows/System32/config/SYSTEM # "regf" 시그니처 umount /mnt/winc ntfsfix /dev/zvol//vm--disk-N-part4 # 두 zvol 비교 fdisk -l /dev/zvol//vm--disk-N ```