Richard W.M. Jones
2021-Sep-29 19:22 UTC
[Libguestfs] [virt-v2v PATCH 2/4] test-v2v-cdrom: update the CD-ROM's bus to SATA in the converted domain
On Wed, Sep 29, 2021 at 09:07:57PM +0200, Laszlo Ersek wrote:> On 09/27/21 10:30, Richard W.M. Jones wrote: > > On Mon, Sep 27, 2021 at 08:34:56AM +0200, Laszlo Ersek wrote: > >> Per commit ac39fa292c31 ("v2v: Set machine type explicitly for outputs > >> which support it (RHBZ#1581428).", 2020-12-04), Windows 7 guests (which > >> are "more modern" than Windows XP guests) are converted to Q35, not I440FX > >> boards. > >> > >> Per related commit d0267122e348 ("v2v: -o libvirt: Map IDE disks to > >> bus="sata" on Q35.", 2020-12-04), when a Windows 7 guest with an IDE > >> CD-ROM -- hence, an I440FX board -- is converted, the CD-ROM in the > >> converted domain will be on the SATA bus (Q35 does not have an IDE > >> controller, only a SATA controller). > >> > >> Because the Windows guest used in "test-v2v-cdrom" is "Windows 7 Phony > >> Edition", it triggers the above cascade, and currently fails with: > >> > >>> --- ./test-v2v-cdrom.expected 2021-09-03 22:51:31.026185527 +0200 > >>> +++ test-v2v-cdrom.d/disks 2021-09-19 13:01:47.471745622 +0200 > >>> @@ -4,5 +4,5 @@ > >>> </disk> > >>> <disk device='cdrom' type='file'> > >>> <driver name='qemu' type='raw'/> > >>> - <target dev='hdc' bus='ide'/> > >>> + <target dev='sdc' bus='sata'/> > >>> </disk> > >>> ./test-v2v-cdrom.sh: unexpected disk assignments > >> > >> The conversion seems correct, but the test expectation is stale. Most > >> probably, commit d0267122e348 missed updating the test data. Do it now. > > > > Actually the conversion is wrong - we need to update configuration > > inside the guest. Which is why I didn't fix this test - to remind > > myself that there's still a bug to be fixed. > > Hmm, good point; now I remember that the i440fx->q35 machine type change > is basically a motherboard replacement for Windows. > > So do we have to update some "windows device paths" (leading to the > CD-ROM) in the registry?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. 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*) Rich.> Thanks, > Laszlo > > > > > https://bugzilla.redhat.com/show_bug.cgi?id=1637857 > > > > Rich. > > > >> Fixes: d0267122e348202f6fac4d833f7448409e7129c9 > >> Signed-off-by: Laszlo Ersek <lersek at redhat.com> > >> --- > >> tests/test-v2v-cdrom.expected | 2 +- > >> tests/test-v2v-cdrom.xml.in | 4 +++- > >> 2 files changed, 4 insertions(+), 2 deletions(-) > >> > >> diff --git a/tests/test-v2v-cdrom.expected b/tests/test-v2v-cdrom.expected > >> index 34d2bf5961b0..17bd152d8e64 100644 > >> --- a/tests/test-v2v-cdrom.expected > >> +++ b/tests/test-v2v-cdrom.expected > >> @@ -4,5 +4,5 @@ > >> </disk> > >> <disk device='cdrom' type='file'> > >> <driver name='qemu' type='raw'/> > >> - <target dev='hdc' bus='ide'/> > >> + <target dev='sdc' bus='sata'/> > >> </disk> > >> diff --git a/tests/test-v2v-cdrom.xml.in b/tests/test-v2v-cdrom.xml.in > >> index 6bad5eab1cd4..a6e1e3f514d5 100644 > >> --- a/tests/test-v2v-cdrom.xml.in > >> +++ b/tests/test-v2v-cdrom.xml.in > >> @@ -35,7 +35,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. > >> <disk type='file' device='cdrom'> > >> <driver name='qemu' type='raw'/> > >> <source file='@abs_top_builddir@/test-data/phony-guests/blank-disk.img'/> > >> - <!-- virt-v2v should preserve the device name and bus --> > >> + <!-- virt-v2v should change the bus to sata, due to Windows 7 > >> + triggering a machine type change from i440fx to q35. Beyond that, > >> + virt-v2v should preserve the on-bus index. --> > >> <target dev='hdc' bus='ide'/> > >> </disk> > >> </devices> > >> -- > >> 2.19.1.3.g30247aa5d201 > >> > >> > >> _______________________________________________ > >> Libguestfs mailing list > >> Libguestfs at redhat.com > >> https://listman.redhat.com/mailman/listinfo/libguestfs > >-- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-p2v converts physical machines to virtual machines. Boot with a live CD or over the network (PXE) and turn machines into KVM guests. http://libguestfs.org/virt-v2v
Laszlo Ersek
2021-Sep-30 11:12 UTC
[Libguestfs] translating CD-ROM device paths from i440fx to Q35 in virt-v2v (was: test-v2v-cdrom: update the CD-ROM's bus to SATA in the converted domain)
(+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