diff --git a/build/components/versions.yml b/build/components/versions.yml index e78f3a440a..fa5a5e00e8 100644 --- a/build/components/versions.yml +++ b/build/components/versions.yml @@ -3,7 +3,7 @@ firmware: libvirt: v10.9.0 edk2: stable202411 core: - 3p-kubevirt: v1.6.2-v12n.41 + 3p-kubevirt: v1.6.2-v12n.42 3p-containerized-data-importer: v1.60.3-v12n.19 distribution: 2.8.3 package: diff --git a/images/packages/libvirt/patches/005-usb-startup-policy-in-containers.patch b/images/packages/libvirt/patches/005-usb-startup-policy-in-containers.patch new file mode 100644 index 0000000000..51ddec4d5b --- /dev/null +++ b/images/packages/libvirt/patches/005-usb-startup-policy-in-containers.patch @@ -0,0 +1,29 @@ +diff --git a/src/util/virusb.c b/src/util/virusb.c +index cf3461f80a..5a92098452 100644 +--- a/src/util/virusb.c ++++ b/src/util/virusb.c +@@ -169,6 +169,24 @@ virUSBDeviceSearch(unsigned int vendor, + if (!usb) + goto cleanup; + ++ /* In containerized environments sysfs may expose USB devices ++ * from the host kernel while the corresponding device node ++ * under /dev/bus/usb/ is not present in the container's mount ++ * namespace. Skip such devices so that callers relying on ++ * startupPolicy='optional' see an empty result and can handle ++ * the missing device gracefully. */ ++ if (virUSBDeviceGetPath(usb) && ++ !virFileExists(virUSBDeviceGetPath(usb))) { ++ VIR_DEBUG("USB device %03u:%03u found in sysfs but " ++ "device node '%s' is not accessible, skipping", ++ found_bus, found_devno, ++ virUSBDeviceGetPath(usb)); ++ g_clear_pointer(&usb, virUSBDeviceFree); ++ if (found) ++ break; ++ continue; ++ } ++ + if (virUSBDeviceListAdd(list, &usb) < 0) + goto cleanup; + diff --git a/images/packages/libvirt/patches/README.md b/images/packages/libvirt/patches/README.md index 06b03748b1..59f147d38f 100644 --- a/images/packages/libvirt/patches/README.md +++ b/images/packages/libvirt/patches/README.md @@ -41,3 +41,11 @@ This feature enhances security by preventing unauthorized access to the socket a Fixes a non-shared storage migration cancel race in libvirt/QEMU. After `AbortJob`, mirror block jobs may become `concluded` in QEMU while libvirt still polls synchronous migration mirrors. The patch refreshes monitor job status and drives pending terminal transitions so concluded jobs are dismissed/unregistered and do not block subsequent migrations. + +## 005-usb-startup-policy-in-containers.patch + +Fixes `startupPolicy='optional'` for USB hostdev in containerized environments. + +In containers, sysfs (`/sys/bus/usb/devices/`) is mounted from the host kernel and exposes all USB devices regardless of mount namespace isolation. This causes `virUSBDeviceSearch` to report a device as available even when the corresponding `/dev/bus/usb/` node is not present in the container's mount namespace. As a result, `startupPolicy='optional'` does not remove the missing hostdev from the domain XML, and QEMU fails to start. + +The patch adds a `virFileExists` check on the device node path after sysfs discovery. If the node is missing, the device is skipped so that callers see an empty result and handle the absence gracefully. diff --git a/test/e2e/vm/usb.go b/test/e2e/vm/usb.go index e7cfeca6bd..99858b96af 100644 --- a/test/e2e/vm/usb.go +++ b/test/e2e/vm/usb.go @@ -19,6 +19,7 @@ package vm import ( "context" "fmt" + "math/rand" "strings" "time" @@ -188,14 +189,15 @@ func (t *VMUSBTest) GenerateEnvironmentResources(ctx context.Context) { nodeUSBList, err := virtClient.NodeUSBDevices().List(ctx, metav1.ListOptions{}) Expect(err).NotTo(HaveOccurred()) - var freeUSB *v1alpha2.NodeUSBDevice + var freeUSBs []*v1alpha2.NodeUSBDevice for i := range nodeUSBList.Items { if nodeUSBList.Items[i].Status.Attributes.VendorID == "1d6b" && nodeUSBList.Items[i].Status.Attributes.ProductID == "0104" && nodeUSBList.Items[i].Spec.AssignedNamespace == "" { - freeUSB = &nodeUSBList.Items[i] - break + freeUSBs = append(freeUSBs, &nodeUSBList.Items[i]) } } - Expect(freeUSB).NotTo(BeNil(), "no free USB devices available") + Expect(freeUSBs).NotTo(BeEmpty(), "no free USB devices available") + + freeUSB := freeUSBs[rand.New(rand.NewSource(time.Now().UnixNano())).Intn(len(freeUSBs))] GinkgoWriter.Println("Found free USB device:", freeUSB.Name)