(+libvirt-devel)
On 09/29/21 21:22, Richard W.M. Jones wrote:
We currently partially install the virtio block drivers in the
Windows
guest (just enough to get the guest to boot on the target), and
Windows itself re-installs the virtio block driver and other drivers
it needs, and that's enough to get it to see C:
As for other hard disk partitions, Windows does indeed contain a
mapping to other drives in the Registry but IIRC it's not sensitive to
the device driver (unlike Linux /dev/vdX vs /dev/sdX). If you're
interested in that, see libguestfs.git/daemon/inspect_fs_windows.ml:
get_drive_mappings. We never bothered with attempting to handle
conversion of floppy drives or CD-ROMs for Windows.
OK. So AIUI, that means no work is needed here for Windows.
On Linux we do better: We iterate over all the configuration files
in
/etc and change device paths. The significance of this bug is we need
to change (eg) /dev/hdc to /dev/<something>. The difficulty is
working out where the device will appear on the target and not having
it conflict with any hard disk, something we partly control (see
virt-v2v.git/convert/target_bus_assignment.ml*)
AIUI the conflict avoidance logic ("no overlapping disks") is already in
place. The question is how to translate device paths in /etc/fstab and
similar.
Please correct me if I'm wrong: at the moment, I believe virt-v2v parses
and manipulates the following elements and attributes in the domain XML:
<target dev='hda' bus='ide'/>
<target dev='hdb' bus='ide'/>
<target dev='hdc' bus='ide'/>
<target dev='hdd' bus='ide'/>
^^^ ^^^
My understanding is however that the target/@dev attribute is mostly
irrelevant:
https://libvirt.org/formatdomain.html#hard-drives-floppy-disks-cdroms
The dev attribute indicates the "logical" device name. The actual
device name specified is not guaranteed to map to the device name in
the guest OS. Treat it as a device ordering hint. [...]
What actually matters is the target/@bus attribute, in combination with
the sibling element <address>. Such as:
<target dev='hda' bus='ide'/>
^^^
<address type='drive' controller='0' bus='0'
target='0' unit='0'/>
^ ^ ^
<target dev='hdb' bus='ide'/>
^^^
<address type='drive' controller='0' bus='0'
target='0' unit='1'/>
^ ^ ^
<target dev='hdc' bus='ide'/>
^^^
<address type='drive' controller='0' bus='1'
target='0' unit='0'/>
^ ^ ^
<target dev='hdd' bus='ide'/>
^^^
<address type='drive' controller='0' bus='1'
target='0' unit='1'/>
^ ^ ^
So, target/@dev should be mostly ignored; what matters is the following
tuple:
(target/@bus, address/@controller, address/@bus, address/@unit)
Extracting just the tuples:
(ide, 0, 0, 0)
(ide, 0, 0, 1)
(ide, 0, 1, 0)
(ide, 0, 1, 1)
The first two components of each tuple -- i.e., (ide, 0) -- refer to the
following IDE controller:
<controller type='ide' index='0'>
^^^^^^^^^^ ^^^^^^^^^
<address type='pci' domain='0x0000' bus='0x00'
slot='0x01' function='0x1'/>
</controller>
and then the rest of the components, such as (0, 0), (0, 1), (1, 0), (1,
1), identify the disk on that IDE controller.
(Side comment: the PCI location of the (first) IDE controller is fixed
in QEMU; if one tries to change it, libvirt complains: "Primary IDE
controller must have PCI address 0:0:1.1".)
(Side comment: on the QEMU command line, this maps to
-device ide-cd,bus=ide.0,unit=0,... \
-device ide-cd,bus=ide.0,unit=1,... \
-device ide-cd,bus=ide.1,unit=0,... \
-device ide-cd,bus=ide.1,unit=1,... \
)
Inside the guest, /dev/hd* nodes don't even exist, so it's unlikely that
/etc/fstab would refer to them. /etc/fstab can however refer to symlinks
under "/dev/disk/by-id" (for example):
lrwxrwxrwx. 1 root root 9 Sep 30 11:54 ata-QEMU_DVD-ROM_QM00001 -> ../../sr0
lrwxrwxrwx. 1 root root 9 Sep 30 11:54 ata-QEMU_DVD-ROM_QM00002 -> ../../sr1
lrwxrwxrwx. 1 root root 9 Sep 30 11:54 ata-QEMU_DVD-ROM_QM00003 -> ../../sr2
lrwxrwxrwx. 1 root root 9 Sep 30 11:54 ata-QEMU_DVD-ROM_QM00004 -> ../../sr3
Furthermore, we have pseudo-files (directories) such as:
/sys/devices/pci0000:00/0000:00:01.1/ata1/host0/target0:0:0/0:0:0:0/block/sr0
/sys/devices/pci0000:00/0000:00:01.1/ata1/host0/target0:0:1/0:0:1:0/block/sr1
/sys/devices/pci0000:00/0000:00:01.1/ata2/host1/target1:0:0/1:0:0:0/block/sr2
/sys/devices/pci0000:00/0000:00:01.1/ata2/host1/target1:0:1/1:0:1:0/block/sr3
^ ^
So in order to map a device path from the original guest's "/etc/fstab",
such as "/dev/disk/by-id/ata-QEMU_DVD-ROM_QM00003", to the original
domain XML's <disk> element, we have to do the following in the
"source"
appliance:
NODE=$(realpath /dev/disk/by-id/ata-QEMU_DVD-ROM_QM00003)
# -> /dev/sr2
NODE=${NODE#/dev/}
# -> sr2
DEVPATH=$(ls -d
/sys/devices/pci0000:00/0000:00:01.1/ata?/host?/target?:0:?/?:0:?:0/block/$NODE)
# -> /sys/devices/pci0000:00/0000:00:01.1/ata2/host1/target1:0:0/1:0:0:0/block/sr2
And then map the "1:0:0:0" pathname component from $DEVPATH to:
<target dev='hdc' bus='ide'/>
<address type='drive' controller='0' bus='1'
target='0' unit='0'/>
^^^^^^^ ^^^^^^^^
[1]:0:0:0 1:0:[0]:0
in the original domain XML. This tells us under what device node the
original guest sees the host-side file (<source> element).
After conversion, on the Q35 board, the inverse mapping is needed. We
start from the domain XML,
<target dev='sd*' bus='sata'/>
<address type='drive' controller='0' bus='0'
target='0' unit='0'/>
<target dev='sd*' bus='sata'/>
<address type='drive' controller='0' bus='0'
target='0' unit='1'/>
<target dev='sd*' bus='sata'/>
<address type='drive' controller='0' bus='0'
target='0' unit='2'/>
<target dev='sd*' bus='sata'/>
<address type='drive' controller='0' bus='0'
target='0' unit='3'/>
<target dev='sd*' bus='sata'/>
<address type='drive' controller='0' bus='0'
target='0' unit='4'/>
<target dev='sd*' bus='sata'/>
<address type='drive' controller='0' bus='0'
target='0' unit='5'/>
<controller type='sata' index='0'>
<address type='pci' domain='0x0000' bus='0x00'
slot='0x1f' function='0x2'/>
</controller>
(Side comment: the PCI B/D/F of the SATA controller is also fixed in
QEMU; otherwise libvirt complains: "Primary SATA controller must have
PCI address 0:0:1f.2".)
(Side comment: the QEMU command line is
-device ide-cd,bus=ide.0,... \
-device ide-cd,bus=ide.1,... \
-device ide-cd,bus=ide.2,... \
-device ide-cd,bus=ide.3,... \
-device ide-cd,bus=ide.4,... \
-device ide-cd,bus=ide.5,... \
)
In the guest we have:
/sys/devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/block/sr0
/sys/devices/pci0000:00/0000:00:1f.2/ata2/host1/target1:0:0/1:0:0:0/block/sr1
/sys/devices/pci0000:00/0000:00:1f.2/ata3/host2/target2:0:0/2:0:0:0/block/sr2
/sys/devices/pci0000:00/0000:00:1f.2/ata4/host3/target3:0:0/3:0:0:0/block/sr3
/sys/devices/pci0000:00/0000:00:1f.2/ata5/host4/target4:0:0/4:0:0:0/block/sr4
/sys/devices/pci0000:00/0000:00:1f.2/ata6/host5/target5:0:0/5:0:0:0/block/sr5
So, assuming we mapped the original (i440fx)
"/dev/disk/by-id/ata-QEMU_DVD-ROM_QM00003" guest device path to some
<source> element (= host-side file) in the original domain XML, and
assuming virt-v2v assigned the same <source> element to the following
element on the Q35 board:
<target dev='sd*' bus='sata'/>
<address type='drive' controller='0' bus='0'
target='0' unit='4'/>
^^^^^^^^
we find the device node in the destination appliance as follows:
NODE=$(basename
/sys/devices/pci0000:00/0000:00:1f.2/ata?/host?/target?:0:0/4:0:0:0/block/*)
^
unit='4'
# -> sr4
and then replace "/dev/disk/by-id/ata-QEMU_DVD-ROM_QM00003" with
"/dev/sr4" in "/etc/fstab".
All this requires virt-v2v to parse complete <address> elements from the
original domain XML, and to generate complete <address> elements in the
destination domain XML. Is that feasible?
The @wwn and @serial attributes don't look safe to me, because the guest
could refer to them even when the original domain XML does not spell
them out (eg. "QM00003" is such a @serial). So neither can we trust that
a @serial is present in the original XML, nor can we just go ahead and
generate a @serial if it is absent. (The generation step could
immediately break references such as "QM00003" in the guest.)
/dev/disk/by-label and /dev/disk/by-uuid are based on media contents,
and multiple CD-ROMs may (read-only) map the same host-side file, so
those are not good for mapping either, I think. Also does not cover
CD-ROM devices that are empty (have no medium) at the time of
conversion, but "/etc/fstab" still refers to them (potentially with
"noauto"). So I think the only reliable ID is the hardware device path.
... Now if *that* needs to work when the original guest comes from a
different management application than libvirt, then I have no idea. The
original address (PCI B/D/F of the IDE controller, and IDE bus and unit
of the drive) need to be known somehow; otherwise we cannot associate
the guest-side "/dev/..." reference with the host-side file underlying
that CD-ROM.
Thanks,
Laszlo