diff --git a/0027-convert-Model-target-boot-device.patch b/0027-convert-Model-target-boot-device.patch new file mode 100644 index 0000000..aa0c851 --- /dev/null +++ b/0027-convert-Model-target-boot-device.patch @@ -0,0 +1,98 @@ +From c00234c61eb2a49b2961b24672e41f15d8d734b8 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 21 Aug 2025 09:45:44 +0100 +Subject: [PATCH] convert: Model target boot device + +SeaBIOS recently changed how it works so it no longer initializes all +disks at boot. To get around this, for some Linux BIOS guests, we +will have to assign a boot order to the disks, with +for the disk that contains the GRUB bootloader, and higher boot orders +assigned to the other disks. + +As the first step, model the target boot device. + +In the current commit this is always unset (set to 'None'), so this +does nothing. + +(cherry picked from commit e512d84bc8e18734aac7659e839f32c960f6fb0a) +--- + convert/convert.ml | 8 ++++++-- + lib/types.ml | 3 ++- + lib/types.mli | 15 ++++++++++++++- + 3 files changed, 22 insertions(+), 4 deletions(-) + +diff --git a/convert/convert.ml b/convert/convert.ml +index 45d48a95..f8a35506 100644 +--- a/convert/convert.ml ++++ b/convert/convert.ml +@@ -136,7 +136,8 @@ let rec convert input_disks options source = + get_target_firmware i_firmware guestcaps source output in + + (* Create target metadata file. *) +- let target_meta = { guestcaps; target_buses; target_firmware; target_nics } in ++ let target_meta = { guestcaps; target_buses; target_nics; ++ target_firmware; target_boot_device = None } in + + (* This is a good place to dump everything we know about the guest. *) + if verbose () then debug_info source inspect target_meta mpstats; +@@ -366,7 +367,8 @@ and get_target_firmware i_firmware guestcaps source output = + * is enabled. + *) + and debug_info source inspect +- { guestcaps; target_buses; target_firmware; target_nics } ++ { guestcaps; target_buses; target_nics; ++ target_firmware; target_boot_device } + mpstats = + eprintf "info:\n"; + eprintf "%s\n" (string_of_source source); +@@ -374,6 +376,8 @@ and debug_info source inspect + eprintf "%s\n" (string_of_guestcaps guestcaps); + eprintf "%s\n" (string_of_target_buses target_buses); + eprintf "target firmware: %s\n" (string_of_target_firmware target_firmware); ++ eprintf "target boot device: %s\n" ++ (match target_boot_device with None -> "" | Some i -> string_of_int i); + eprintf "target NICs:\n"; + List.iter (fun nic -> eprintf "%s\n" (string_of_source_nic nic)) + target_nics; +diff --git a/lib/types.ml b/lib/types.ml +index 0196a3fd..bd4ab31c 100644 +--- a/lib/types.ml ++++ b/lib/types.ml +@@ -485,8 +485,9 @@ let string_of_target_buses buses = + type target_meta = { + guestcaps : guestcaps; + target_buses : target_buses; ++ target_nics : target_nics; + target_firmware : target_firmware; +- target_nics : target_nics ++ target_boot_device : int option; + } + + type root_choice = AskRoot | SingleRoot | FirstRoot | RootDev of string +diff --git a/lib/types.mli b/lib/types.mli +index b3815c8e..0c43b149 100644 +--- a/lib/types.mli ++++ b/lib/types.mli +@@ -367,8 +367,21 @@ val string_of_target_buses : target_buses -> string + type target_meta = { + guestcaps : guestcaps; + target_buses : target_buses; ++ target_nics : target_nics; ++ + target_firmware : target_firmware; +- target_nics : target_nics ++ ++ target_boot_device : int option; ++ (** The disk index of the device containing the bootloader (index ++ starting from 0). ++ ++ For libvirt guests this should usually be mapped to ++ [] for this disk, and [] ++ where N > 1 for each other disk (order does not matter ++ for the other disks). ++ ++ This is only necessary for SeaBIOS so only collected for ++ a subset of BIOS guests (RHEL-108991). *) + } + + (** {2 Command line parameters} *) diff --git a/0028-output-Add-boot-order-depending-on-target-boot-devic.patch b/0028-output-Add-boot-order-depending-on-target-boot-devic.patch new file mode 100644 index 0000000..074ec39 --- /dev/null +++ b/0028-output-Add-boot-order-depending-on-target-boot-devic.patch @@ -0,0 +1,184 @@ +From e7abf2e39ed17e324b54c00f2386f56152660522 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 21 Aug 2025 09:53:42 +0100 +Subject: [PATCH] output: Add boot order depending on target boot device + +If no target boot device was specified, we number them +through for each disk. + +If a target boot device was specified, then that disk has +, and the remaining disks are numbered sequentially +starting at 2. + +(cherry picked from commit 08e57a392aa5e0720e8787968a562808cb0a31fe) +--- + lib/create_ovf.ml | 19 ++++++++----------- + output/create_libvirt_xml.ml | 16 +++++++++++++++- + output/output_qemu.ml | 16 +++++++++++++--- + tests/test-cdrom.expected | 1 + + tests/test-floppy.expected | 1 + + tests/test-i-ova.xml | 1 + + 6 files changed, 39 insertions(+), 15 deletions(-) + +diff --git a/lib/create_ovf.ml b/lib/create_ovf.ml +index 0af62c88..f74ba3a7 100644 +--- a/lib/create_ovf.ml ++++ b/lib/create_ovf.ml +@@ -544,7 +544,7 @@ let create_meta_files output_alloc output_format sd_uuid image_uuids sizes = + + (* Create the OVF file. *) + let rec create_ovf source inspect +- { guestcaps; target_firmware; target_nics } ++ { guestcaps; target_nics; target_firmware; target_boot_device } + sizes + output_alloc output_format + output_name +@@ -763,7 +763,7 @@ let rec create_ovf source inspect + ] in + + (* Add disks to the OVF XML. *) +- add_disks sizes guestcaps output_alloc output_format ++ add_disks sizes guestcaps target_boot_device output_alloc output_format + sd_uuid image_uuids vol_uuids need_actual_sizes output_disks + ovf_flavour ovf; + +@@ -813,7 +813,7 @@ and get_flavoured_section ovf ovirt_path esd_path esd_path_attr = function + with Not_found -> assert false + + (* This modifies the OVF DOM, adding a section for each disk. *) +-and add_disks sizes guestcaps output_alloc output_format ++and add_disks sizes guestcaps target_boot_device output_alloc output_format + sd_uuid image_uuids vol_uuids need_actual_sizes output_disks + ovf_flavour ovf = + let references = +@@ -838,14 +838,11 @@ and add_disks sizes guestcaps output_alloc output_format + (* Iterate over the disks, adding them to the OVF document. *) + List.iteri ( + fun i (size, image_uuid, vol_uuid, output_uri) -> +- (* This sets the boot order to boot the first disk first. This +- * isn't generally correct. We should copy over the boot order +- * from the source hypervisor. See long discussion in +- * https://bugzilla.redhat.com/show_bug.cgi?id=1308535 for +- * what we should be doing. (XXX) +- *) +- let is_bootable_drive = i == 0 in +- let boot_order = i+1 in ++ let is_bootable_drive, boot_order = ++ match target_boot_device with ++ | None -> i = 0, i+1 ++ | Some disk_index when disk_index = i -> true, 1 ++ | Some _ -> false, i+2 in + + let fileref = + match ovf_flavour with +diff --git a/output/create_libvirt_xml.ml b/output/create_libvirt_xml.ml +index 7ab8d34c..59f2f1f8 100644 +--- a/output/create_libvirt_xml.ml ++++ b/output/create_libvirt_xml.ml +@@ -41,7 +41,8 @@ let get_osinfo_id inspect = + None + + let create_libvirt_xml ?pool source inspect +- { guestcaps; target_buses; target_firmware; target_nics } ++ { guestcaps; target_buses; target_nics; target_firmware; ++ target_boot_device } + target_features outdisk_name output_format output_name = + (* The main body of the libvirt XML document. *) + let body = ref [] in +@@ -206,6 +207,18 @@ let create_libvirt_xml ?pool source inspect + | BusSlotDisk d -> + let outdisk = outdisk_name d.s_disk_id in + ++ let boot_order = ++ match target_boot_device with ++ | None -> ++ (* No known boot device, just number them sequentially. *) ++ i+1 ++ | Some disk_index when disk_index = i -> ++ (* For the boot disk, use order 1. *) ++ 1 ++ | Some _ -> ++ (* For the others number them sequentially starting at 2. *) ++ i+2 in ++ + e "disk" ( + [ + "type", if pool = None then "file" else "volume"; +@@ -231,6 +244,7 @@ let create_libvirt_xml ?pool source inspect + "dev", drive_prefix ^ drive_name i; + "bus", bus_name; + ] []; ++ e "boot" [ "order", string_of_int boot_order ] []; + ] + + | BusSlotRemovable { s_removable_type = CDROM } -> +diff --git a/output/output_qemu.ml b/output/output_qemu.ml +index 37371aad..dff08b66 100644 +--- a/output/output_qemu.ml ++++ b/output/output_qemu.ml +@@ -108,7 +108,8 @@ module QEMU = struct + let _, qemu_boot, output_alloc, output_format, + output_name, output_storage = options in + +- let { guestcaps; target_buses; target_firmware } = target_meta in ++ let { guestcaps; target_buses; ++ target_firmware; target_boot_device } = target_meta in + + (* Start the shell script. Write it to a temporary file + * which we rename at the end. +@@ -282,8 +283,17 @@ module QEMU = struct + * "disk_id". + *) + let outdisk = disk_path output_storage output_name disk_id in +- arg_list "-drive" [ "file=" ^ outdisk; "format=" ^ output_format; +- "if=none"; "id=" ^ backend_name; "media=disk" ] ++ let bootindex = ++ match target_boot_device with ++ | None -> disk_id+1 ++ | Some disk_index when disk_index = disk_id -> 1 ++ | Some _ -> disk_id+2 in ++ arg_list "-drive" [ "file=" ^ outdisk; ++ "format=" ^ output_format; ++ "if=none"; ++ "id=" ^ backend_name; ++ "media=disk"; ++ sprintf "bootindex=%d" bootindex ] + + and add_cdrom_backend backend_name = + (* Add a drive (back-end) for an "ide-cd" or "scsi-cd" device (front-end). +diff --git a/tests/test-cdrom.expected b/tests/test-cdrom.expected +index 17bd152d..806461e7 100644 +--- a/tests/test-cdrom.expected ++++ b/tests/test-cdrom.expected +@@ -1,6 +1,7 @@ + + + ++ + + + +diff --git a/tests/test-floppy.expected b/tests/test-floppy.expected +index a718c21f..c5bd913b 100644 +--- a/tests/test-floppy.expected ++++ b/tests/test-floppy.expected +@@ -1,6 +1,7 @@ + + + ++ + + + +diff --git a/tests/test-i-ova.xml b/tests/test-i-ova.xml +index f1d8f2e3..08b5b9f2 100644 +--- a/tests/test-i-ova.xml ++++ b/tests/test-i-ova.xml +@@ -27,6 +27,7 @@ + + + ++ + + + diff --git a/0029-convert-Detect-target-boot-device-for-Linux-guests.patch b/0029-convert-Detect-target-boot-device-for-Linux-guests.patch new file mode 100644 index 0000000..5905242 --- /dev/null +++ b/0029-convert-Detect-target-boot-device-for-Linux-guests.patch @@ -0,0 +1,78 @@ +From 46af95ecd11c9eda5fd4195b62528b1eea214550 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 21 Aug 2025 10:27:41 +0100 +Subject: [PATCH] convert: Detect target boot device for Linux guests + +If the guest is Linux, try to detect the boot device, so we can set + appropriately. We do this for BIOS or UEFI here, but +this only really matters for SeaBIOS. + +Suggested-by: Gerd Hoffmann +Fixes: https://issues.redhat.com/browse/RHEL-108991 +(cherry picked from commit ca6ec6317e20a633315f783a8ba4ece3c2fc01f2) +--- + convert/convert.ml | 37 ++++++++++++++++++++++++++++++++++++- + 1 file changed, 36 insertions(+), 1 deletion(-) + +diff --git a/convert/convert.ml b/convert/convert.ml +index f8a35506..728ea5a1 100644 +--- a/convert/convert.ml ++++ b/convert/convert.ml +@@ -95,6 +95,10 @@ let rec convert input_disks options source = + let root = Choose_root.choose_root options.root_choice g in + let inspect = Mount_filesystems.mount_filesystems g root in + ++ (* Detect boot device. *) ++ message (f_"Detecting the boot device"); ++ let target_boot_device = get_target_boot_device g inspect in ++ + let mpstats = get_mpstats g in + check_guest_free_space inspect mpstats; + +@@ -137,7 +141,7 @@ let rec convert input_disks options source = + + (* Create target metadata file. *) + let target_meta = { guestcaps; target_buses; target_nics; +- target_firmware; target_boot_device = None } in ++ target_firmware; target_boot_device } in + + (* This is a good place to dump everything we know about the guest. *) + if verbose () then debug_info source inspect target_meta mpstats; +@@ -362,6 +366,37 @@ and get_target_firmware i_firmware guestcaps source output = + + target_firmware + ++and get_target_boot_device g inspect = ++ (* We only do it for Linux, as most likely Windows never(?) boots ++ * from any drive other than C:. We can revisit this decision ++ * if someone reports a bug. ++ *) ++ match inspect.i_type with ++ | "linux" -> ++ (try ++ (* In sane cases, the Grub stage1/boot.img (ie. the boot sector) is ++ * always on the same drive as /boot. So we can just find out ++ * where /boot is mounted and use that. ++ *) ++ let boot_mountpoint = List.assoc "/boot" inspect.i_mountpoints in ++ let boot_device = g#part_to_dev boot_mountpoint in ++ let boot_device = g#device_index boot_device in ++ Some boot_device ++ with ++ | Not_found -> None ++ | G.Error msg ++ (* Returned by part_to_dev if the /boot mountpoint is not ++ * a partition name. ++ *) ++ when String.find msg "device name is not a partition" >= 0 -> None ++ | G.Error msg ++ (* Returned by device_index if the /boot device is not ++ * a normal drive name (eg. /dev/mdX). ++ *) ++ when String.find msg "device not found" >= 0 -> None ++ ) ++ | _ -> None ++ + (* After conversion we dump as much information about the guest + * as we can in one place. Note this is only called when verbose + * is enabled. diff --git a/virt-v2v.spec b/virt-v2v.spec index 2d50d53..8a5ca54 100644 --- a/virt-v2v.spec +++ b/virt-v2v.spec @@ -7,7 +7,7 @@ Name: virt-v2v Epoch: 1 Version: 2.8.1 -Release: 8%{?dist} +Release: 9%{?dist} Summary: Convert a virtual machine to run on KVM License: GPL-2.0-or-later AND LGPL-2.0-or-later @@ -53,6 +53,9 @@ Patch0023: 0023-RHEL-Add-warning-about-virt-v2v-in-place-not-being-s.patch Patch0024: 0024-remove-timeout-before-installing-virtio-win-drivers.patch Patch0025: 0025-v2v-Fix-SELinux-relabelling.patch Patch0026: 0026-RHEL-10-m4-Depend-on-libguestfs-1.56.1-2.el10-for-gu.patch +Patch0027: 0027-convert-Model-target-boot-device.patch +Patch0028: 0028-output-Add-boot-order-depending-on-target-boot-devic.patch +Patch0029: 0029-convert-Detect-target-boot-device-for-Linux-guests.patch %if !0%{?rhel} # libguestfs hasn't been built on i686 for a while since there is no @@ -343,7 +346,7 @@ done %changelog -* Wed Aug 13 2025 Richard W.M. Jones - 1:2.8.1-8 +* Aug 21 2025 Richard W.M. Jones - 1:2.8.1-9 - Rebase to virt-v2v 2.8.1 related: RHEL-81735 - Fix virt-v2v -v --install dnf5 error @@ -386,6 +389,8 @@ done resolves: RHEL-104018 - Fix SELinux relabelling in Linux split-/usr resolves: RHEL-109130 +- Set boot order for Linux guests based on grub location + resolves: RHEL-108991 * Tue Feb 11 2025 Richard W.M. Jones - 1:2.7.1-4 - Rebase to virt-v2v 2.7.1