在之前的文章:《QEMU/KVM啟動物理分區的Windows並調優》中筆者使用mdadm創建線性陣列,使VM啟動物理硬碟分區上的Windows系統。這個做法思路清晰且具有實操性,但根據這個issue,Linux內核上游已將CONFIG_MD_LINEAR編譯參數棄置了,這意味著在6.8及以後的內 ...
在之前的文章:《QEMU/KVM啟動物理分區的Windows並調優》中筆者使用mdadm創建線性陣列,使VM啟動物理硬碟分區上的Windows系統。這個做法思路清晰且具有實操性,但根據這個issue,Linux內核上游已將CONFIG_MD_LINEAR編譯參數棄置了,這意味著在6.8及以後的內核中將無法使用mdadm創建線性陣列,相關模塊已不再被內核包含,modprobe linear
命令將失效。
好在創建線性陣列的方法不止這一種,使用device mapper也可以實現同樣的目的。參考這個帖子,這裡提供一個新的libvirt hook腳本,使用device mapper動態創建和銷毀線性陣列:
#!/usr/bin/env bash
#
# Author: yjzzjy4 (https://github.com/yjzzjy4)
#
# This script creates and distroys /dev/mapper/win10-kvm for booting physical windows drive.
#
WIN_PART=/dev/disk/by-uuid/7CEA3A30EA39E6D4
EFI_DIR=/etc/libvirt/hooks/qemu.d/win10/vdisk
VM_ACTION="$2/$3"
if [[ "$VM_ACTION" == "prepare/begin" ]]; then
if [[ -e /dev/mapper/win10-kvm ]]; then
echo "/dev/mapper/win10-kvm already exists" > /dev/kmsg 2>&1
exit 1
fi
if mountpoint -q -- "${WIN_PART}"; then
echo "Unmounting ${WIN_PART}..." > /dev/kmsg 2>&1
umount ${WIN_PART}
fi
modprobe loop
table=""
cur_size=0
LOOP0=$(losetup -f "${EFI_DIR}/win10-vdisk-loop0" --show)
sector_size=$(blockdev --getsz $LOOP0)
table+="$cur_size $sector_size linear $LOOP0 0\n"
cur_size=$((cur_size+sector_size))
sector_size=$(blockdev --getsz $WIN_PART)
table+="$cur_size $sector_size linear $WIN_PART 0\n"
cur_size=$((cur_size+sector_size))
LOOP1=$(losetup -f "${EFI_DIR}/win10-vdisk-loop1" --show)
sector_size=$(blockdev --getsz $LOOP1)
table+="$cur_size $sector_size linear $LOOP1 0"
cur_size=$((cur_size+sector_size))
echo -e "$table" | dmsetup create win10-kvm
elif [[ "$VM_ACTION" == "release/end" ]]; then
dmsetup remove win10-kvm
losetup | grep "win10-vdisk" | awk '{print $1}' | xargs sudo losetup -d
fi
使用這個hook腳本替代原文中manage-vdisk.sh
即可。相較於之前的腳本,做了幾個小優化:
- 使用device mapper創建線性陣列;
- 使用UUID標識分區(筆者遇到過在某次重啟後分區名稱發生改變的情況,使用UUID更準確);
- 規範化腳本中使用的一些目錄和文件命名。
接下來對腳本進行測試,首先是創建線性陣列:
然後是銷毀陣列:
至此,腳本可以作為libvirt hook正常使用,當然,不要忘記修改VM對應的配置,將啟動盤設置為/dev/mapper/win10-kvm
,如下圖所示: