Repository navigation
Description
What happened
A custom-device plug with subsystem: usb connects without error, but the container gets no USB device node. Flashing tools that use libusb cannot see the probe.
How to reproduce
I reproduced this with a real SEGGER J-Link (1366:1065) in a Workshop 26.04 container (base [email protected]).
Declare an in-project SDK with a USB-subsystem plug for the probe:
name: jlink-usb
plugs:
jlink:
interface: custom-device
subsystem: usb
vendorid: "1366"
productid: "1065"Add it to the workshop definition, refresh, then connect the plug to the system slot:
$ workshop connect my-workshop/jlink-usb:jlink :custom-deviceThe connection lists normally, the same as a working tty plug:
$ workshop connections my-workshop
custom-device my-workshop/jlink-usb:jlink my-workshop/system:custom-device manualNow look inside the container:
$ workshop exec my-workshop -- ls /dev/bus/usb/003/
ls: cannot access '/dev/bus/usb/003/': No such file or directory
$ workshop exec my-workshop -- find /dev/bus
find: '/dev/bus': No such file or directoryNothing under /dev/bus exists in the container. The host side looks fine: udevadm reports the probe at /dev/bus/usb/003/013 with SUBSYSTEM=usb, ID_VENDOR_ID=1366, ID_MODEL_ID=1065. The only mount the plug produces inside the container is the SDK tree itself.
A tty plug for the same physical board works in the same setup. The raw USB node is the difference.
Why it matters
Debug probes register as raw USB devices. openocd and other flash tools reach them through libusb, which needs the /dev/bus/usb/<bus>/<dev> node. Without it, west flash fails:
Warn : Failed to open device: LIBUSB_ERROR_NO_DEVICE
Error: No J-Link device found
FATAL ERROR: command exited with status 1
A tty plug is no substitute here, because probe flashing is not serial traffic.
What I expected
- The container receives the
/dev/bus/usb/<bus>/<dev>node for the matched device. - Hotplug updates the mapping as the device is added or removed.
- Stop and start, disconnect and reconnect, and replugging keep working.
The interface docs list usb as a supported subsystem value, so I read this plug shape as supported. Am I missing something about how the USB subsystem is meant to be wired, or is the container-side bind for subsystem: usb devices not implemented yet?
Environment
- Workshop 0.9.7-d1613f5 (snap, classic)
- LXD 6.9
- Ubuntu host
- Workshop base:
[email protected] - Device: SEGGER J-Link (
1366:1065)
Disclosure: Qwen 3.8 Flash Next drafted this report. A human reviewed it before posting.
Activity
jonathan-conder commentedon Sep 20, 2026
I can reproduce this with a different USB device. It looks like LXD carves out an exception for the
usbsubsystem here: https://github.com/canonical/lxd/blob/lxd-6.9/lxd/device/unix_hotplug.go#L25, even if you explicitly specifysubsystem: usb. Will see what we can do about that.In the meantime, a workaround would be to manually add a
unix-charorusbdevice, e.g.:$ lxc config device add --project "workshop.$(id -u)" "my-workshop-$(< .workshop.lock)" jlink-usb usb vendorid=1366 productid=1065jonathan-conder commentedon Oct 29, 2026
@MirkoCovizzi I talked to @locnnil about this today, it would be good if you could confirm that the workaround I mentioned works properly; if so we can make it part of the fix.
MirkoCovizzi commentedon Nov 5, 2026
@jonathan-conder I tried the workaround with the real J-Link (
1366:1065) on Workshop 0.9.9 and LXD 6.10.1. It creates the node, but needs two corrections, and it doesn't survive a replug.Works
/dev/bus/usb/003/<dev>appears in the running container straight away.workshop stop/startandworkshop refresh.lsusb -vand SEGGER'sJLinkExework through the node.Corrections
workshop.$(id -un)for the project, notworkshop.$(id -u). Workshop names its LXD project after the user name, not the numeric uid. Withid -uthe command fails withProject not found.uid,gidandmode. Without them the node is createdroot:rootwith mode0664. The container user isworkshop(uid 1000), so it can't open the node read-write, and libusb needs read-write.open(O_RDWR)fails withPermission denieduntil the node is owned by that user.Doesn't work: hotplug
uid/gid/mode.So the hotplug expectation isn't met by the manual
usbdevice.Disclosure:
Claude Sonnet 5.5drafted this comment. A human reviewed it before posting.jonathan-conder commentedon Nov 5, 2026
@MirkoCovizzi Thanks! That's really useful.
For the UID/GID and mode it looks like we'll need the
usbdevices to supportownership.inherit; I filed a feature request at canonical/lxd#19448. In the meantime we could potentially supply the UID and GID manually like you suggest.I noticed, at least on my machine, I can't open the devices in
/dev/bus/usb/*/*for writing as a normal user; do you expect to be able to do that? Maybe you can just usesudoinside the workshop?I can confirm the hotplugging doesn't work. The LXD docs say it should though!
jonathan-conder commentedon Nov 6, 2026
I pushed a fix for the hotplugging issue: canonical/lxd#19450. Hopefully that will get the ball rolling a bit.
Also one for inheriting ownership: canonical/lxd#19451; I don't think it's super relevant for this use case though.
Once hotplugging is working, it should be possible to add a udev rule inside the workshop that changes the permissions, if that's what you want. It will only work when hotplugging the device though. I have another feature request to fix that here: canonical/lxd#18430.
jonathan-conder commentedon Nov 12, 2026
A fix is available in the
edge/1151channel, I'll test it tomorrow if I get the chance (CC @locnnil)jonathan-conder commentedon Nov 12, 2026
It seems to basically work; no hotplugging or ownership inheritance yet though since we'll have to wait for a LXD fix