Skip to content

fix(core): add libvirt patch for USB startupPolicy in containers#2432

Open
yaroslavborbat wants to merge 3 commits into
mainfrom
fix/usb/startup-policy-in-containers
Open

fix(core): add libvirt patch for USB startupPolicy in containers#2432
yaroslavborbat wants to merge 3 commits into
mainfrom
fix/usb/startup-policy-in-containers

Conversation

@yaroslavborbat
Copy link
Copy Markdown
Member

@yaroslavborbat yaroslavborbat commented Jun 1, 2026

Description

Add a libvirt patch (005-usb-startup-policy-in-containers.patch) that fixes startupPolicy='optional' for USB hostdev in containerized environments.

The patch adds a virFileExists check on the device node path in virUSBDeviceSearch after sysfs discovery. If the /dev/bus/usb/ node is missing, the device is skipped so that callers see an empty result and handle the absence gracefully.

deckhouse/3p-kubevirt#124
https://github.com/containerd/containerd/blob/c8802b6e7b81b21ffc134a9c1028f472f87dc262/pkg/oci/mounts.go#L58

Why do we need it, and what problem does it solve?

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 libvirt's 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 USB hostdev from the domain XML during incoming migration, and QEMU fails to start with:

Could not open '/dev/bus/usb/005/002': No such file or directory

This breaks VM live migration when USB devices are attached via hotplug and the target node does not yet have the device node mounted into the virt-launcher pod.

What is the expected result?

  1. Start a VM with a hotplugged USB device on node A.
  2. Migrate the VM to node B where the USB device node is not yet in the pod's mount namespace.
  3. The migration succeeds — libvirt skips the missing USB hostdev due to startupPolicy='optional'.
  4. After migration, the USB device is hotplugged into the VM on the target node.

Checklist

  • The code is covered by unit tests.
  • e2e tests passed.
  • Documentation updated according to the changes.
  • Changes were tested in the Kubernetes cluster manually.

Changelog entries

section: core
type: fix
summary: Fix USB startupPolicy='optional' in containers where sysfs exposes host devices but device nodes are absent from the mount namespace.
impact_level: low

@yaroslavborbat yaroslavborbat force-pushed the fix/usb/startup-policy-in-containers branch from 8724900 to bf557f9 Compare June 1, 2026 17:45
@yaroslavborbat yaroslavborbat added this to the v1.9.0 milestone Jun 1, 2026
@yaroslavborbat yaroslavborbat requested a review from Isteb4k as a code owner June 2, 2026 14:44
@yaroslavborbat yaroslavborbat force-pushed the fix/usb/startup-policy-in-containers branch from fd65c11 to 56064f3 Compare June 2, 2026 14:46
Signed-off-by: Yaroslav Borbat <yaroslav.borbat@flant.com>
@yaroslavborbat yaroslavborbat force-pushed the fix/usb/startup-policy-in-containers branch from 95243aa to 66fe545 Compare June 2, 2026 15:50
Signed-off-by: Yaroslav Borbat <yaroslav.borbat@flant.com>
@yaroslavborbat yaroslavborbat force-pushed the fix/usb/startup-policy-in-containers branch from e1b3a01 to c772e3c Compare June 2, 2026 17:27
+ "device node '%s' is not accessible, skipping",
+ found_bus, found_devno,
+ virUSBDeviceGetPath(usb));
+ g_clear_pointer(&usb, virUSBDeviceFree);
Copy link
Copy Markdown
Member

@diafour diafour Jun 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

usb is wrapped with g_autoptr, no need to cleanup explicitly. It will be cleaned automatically when usb goes out of scope, e.g. on return.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

g_autoptr only frees usb when it goes out of scope, i.e. at function exit. Here we need an explicit cleanup because this branch uses continue.

Without g_clear_pointer(&usb, virUSBDeviceFree), the loop would continue and the next assignment to usb would overwrite the current object, leaking it.

Comment on lines +22 to +24
+ if (found)
+ break;
+ continue;
Copy link
Copy Markdown
Member

@diafour diafour Jun 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to continue? We found device in sysfs, but device is not usable. It seems an unrecoverable error, so cleanup is needed:

Suggested change
+ if (found)
+ break;
+ continue;
+ goto cleanup;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

goto cleanup is not appropriate here because a missing device node in /dev/bus/usb is not treated as a fatal search error in this code path. We did find a matching entry in sysfs, but this extra check verifies that the device is actually usable from the current mount namespace. If the node is missing, that means the device must be ignored, not that the search itself failed.

virUSBDeviceSearch() is used in two modes:

  • by vendor/product, where it returns a list and there may be multiple matches;
  • by bus/devno, where at most one match is expected.

That is why the control flow differs:

  • continue is needed for vendor/product search, so we skip the inaccessible device and keep looking for other usable matches;
  • if (found) break; is needed for bus/devno search: once the matching sysfs entry was found but proved unusable, there is nothing else to search for, so we stop and return an empty result.

Using goto cleanup here would turn this case into an error return instead of an empty result. That would break the mandatory = false semantics in the callers: they should observe this case as "device not found/usable", not as an internal error.

Signed-off-by: Yaroslav Borbat <yaroslav.borbat@flant.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants