Skip to content

libusb: stop UTM freezing when a USB 3 drive is disconnected - #8131

Merged
osy merged 1 commit into
utmapp:mainfrom
UTMapp-bot:fix/usb-disconnect-freeze
Nov 11, 2026
Merged

osy merged 1 commit into
utmapp:mainfrom
UTMapp-bot:fix/usb-disconnect-freeze

Conversation

@UTMapp-bot

@UTMapp-bot UTMapp-bot commented Nov 11, 2026 •

Copy link
Copy Markdown

Disconnecting a USB drive from a running VM froze UTM when the guest was using the drive through USB Attached SCSI, which most USB 3 drives and SSD enclosures do. The USB menu and the rest of the app stopped answering. After UTM was ended, the drive did not come back to macOS until it was unplugged and plugged in again.

When a device is released, usbredirhost_clear_device() cancels its transfers and waits for them to complete. libusb on macOS refused to cancel bulk stream transfers (darwin_cancel_transfer() returned LIBUSB_ERROR_INVALID_PARAM for LIBUSB_TRANSFER_TYPE_BULK_STREAM), and USB Attached SCSI always has one pending on its status pipe. The wait never ended, and it holds the lock that UTM's main thread takes in spice_usb_device_manager_is_device_connected().

This picks up c1c01e6593 from the UTM libusb fork (utmapp/libusb#1), which sends bulk stream transfers to darwin_abort_transfers(); that function already aborts a stream with AbortStreamsPipe(). The change is by @giovariot, who included it in #7928; this is that change on its own, with them as the patch's author. Upstream libusb's master has the same gap.

Resolves #5851

Related: #7530

Testing

Tested by an AI agent on a MacBook Pro M2 Max, macOS 27.2 (26B123), with a Seagate Backup Plus 500 GB drive (0bc2:ab24) on a USB 3 port (5 Gb/s link). Guest: Ubuntu 26.04 arm64 (Linux 7.0), USB 3.0 controller, the drive attached with the scripting connect command. In the guest the drive is Driver=uas, 5000M. Only reads were done on the drive.

  • Before (the released UTM 5.0.8 (129)): the drive attaches and the guest sees the 500 GB disk. disconnect never returns ("AppleEvent timed out"), and every later scripting command times out too; a click on the USB menu in the VM window freezes the window. A sample of UTM shows a worker thread in spice_usb_backend_channel_detach → usbredirhost_set_device → usbredirhost_clear_device, and the main thread waiting in spice_usb_device_manager_is_device_connected → g_mutex_lock. After ending UTM, diskutil list did not show the drive again until it was replugged.
  • After (a Debug build of main with libusb rebuilt from the patched source in its sysroot):
    • disconnect returns within a second, twice in a row, and the disk is gone from the guest each time. connect brings it back, and 200 MiB reads run at 102 MB/s.
    • disconnect while dd was reading from the drive returns within a second and UTM keeps answering. The drive connects again afterwards.
    • Powering the guest off with the drive attached ends the VM normally, and the drive is back in diskutil list without a replug.
    • The same sequence was repeated on two more builds that also carry a QEMU change for usb-redir (not part of this PR, and not active for a drive attached at SuperSpeed), with a 1000 MiB read at 105 MB/s before the disconnects: no freeze in any of them.

The patch file applies to a fresh extract of libusb-1.0.25.tar.bz2 with no fuzz or rejects. The tests above ran before the change was merged in the fork; the code line is the same.

Not tested: iOS, other drives, a drive using the older bulk-only protocol (its transfers were already cancelled), and a full dependency build (left to CI).

Disconnecting a USB drive that the guest uses through USB Attached SCSI
(most USB 3 drives and SSD enclosures) froze UTM: the USB menu and every
other part of the app stopped answering, and after UTM was ended the
drive did not come back to macOS until it was replugged.

When a device is released, usbredirhost cancels its transfers and waits
for them to complete. libusb on macOS refused to cancel bulk stream
transfers (LIBUSB_ERROR_INVALID_PARAM), and USB Attached SCSI always
has one pending on its status pipe, so the wait never ended while it
held the lock the main thread needs.

Pick up c1c01e6593 from the UTM libusb fork (utmapp/libusb#1), which
cancels bulk stream transfers the way plain bulk transfers are. The
change is by giovariot, who included it in utmapp#7928.

Assisted-by: Claude:claude-fable-5-2
@UTMapp-bot
UTMapp-bot force-pushed the fix/usb-disconnect-freeze branch from 4bc879e to 3353ebf Compare November 11, 2026 06:19
@osy
osy merged commit f1f9c32 into utmapp:main Nov 11, 2026
56 of 62 checks passed
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.

UTM crashes when unplugging SSD when "querying USB devices"

2 participants