Bug 1035863
Summary: | Bulk transfer timeouts cause data corruption | ||||||
---|---|---|---|---|---|---|---|
Product: | [Fedora] Fedora | Reporter: | Tim Waugh <twaugh> | ||||
Component: | libusbx | Assignee: | Hans de Goede <hdegoede> | ||||
Status: | CLOSED NOTABUG | QA Contact: | Fedora Extras Quality Assurance <extras-qa> | ||||
Severity: | unspecified | Docs Contact: | |||||
Priority: | unspecified | ||||||
Version: | 20 | CC: | hdegoede, jv+fedora, lucilanga, novyjindrich, rhbugs | ||||
Target Milestone: | --- | ||||||
Target Release: | --- | ||||||
Hardware: | Unspecified | ||||||
OS: | Unspecified | ||||||
Whiteboard: | |||||||
Fixed In Version: | Doc Type: | Bug Fix | |||||
Doc Text: | Story Points: | --- | |||||
Clone Of: | Environment: | ||||||
Last Closed: | 2013-11-29 10:55:54 UTC | Type: | Bug | ||||
Regression: | --- | Mount Type: | --- | ||||
Documentation: | --- | CRM: | |||||
Verified Versions: | Category: | --- | |||||
oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |||||
Cloudforms Team: | --- | Target Upstream Version: | |||||
Embargoed: | |||||||
Bug Depends On: | |||||||
Bug Blocks: | 1026914 | ||||||
Attachments: |
|
Description
Tim Waugh
2013-11-28 16:40:36 UTC
Created attachment 830317 [details]
usb-libusb.c
The caller code. See print_device(), loop is at lines 364-569.
Hi, What usb-speed is the printer, and what speed port is it plugged into ? Can you do lsusb and lsusb -t on the machine in question, and paste the output of both here? There is no such things as a timeout at the lower usb levels, libusb emulates timeouts by simply setting a timer and async. cancelling pending transfers when the timer expires. In general all layers involved do their best to make sure that the amount of data send before an async cancelled is properly accounted, so that you should be able to re-start the transfer after a cancel as the sane usb backend is trying to do. But this is not guaranteed to work, and there are known cases where it won't work, such as ie an usb-1 device plugged into an usb-2 hub (or an usb-2 port on intel sandy bridge or later hardware, as that has an embedded usb-2 hub. In this case (for example) there are buffers on the hub which may contain data on the async cancel which is not accounted for. Long story short, don't use timeouts the way they are being used in the sane usb backend. Timeouts in libusb are meant for when you expect a transfer to finish within a certain time. If it may take longer and you want to do other stuff in the mean time use threads and/or libusb's async API. Regards, Hans I'm not sure how I can find out about speeds. $ lsusb Bus 002 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 001 Device 005: ID 04f2:b217 Chicony Electronics Co., Ltd Lenovo Integrated Camera (0.3MP) Bus 001 Device 009: ID 045e:00db Microsoft Corp. Natural Ergonomic Keyboard 4000 V1.0 Bus 001 Device 011: ID 046d:c069 Logitech, Inc. M500 Laser Mouse Bus 001 Device 010: ID 0424:2228 Standard Microsystems Corp. 9-in-2 Card Reader Bus 001 Device 008: ID 0424:2602 Standard Microsystems Corp. USB 2.0 Hub Bus 001 Device 007: ID 0424:2512 Standard Microsystems Corp. USB 2.0 Hub Bus 001 Device 006: ID 03f0:3304 Hewlett-Packard DeskJet 990c Bus 001 Device 012: ID 03f0:2911 Hewlett-Packard PSC 2200 Bus 001 Device 004: ID 17ef:100a Lenovo ThinkPad Mini Dock Plus Series 3 Bus 001 Device 003: ID 0a5c:217f Broadcom Corp. BCM2045B (BDC-2.1) Bus 001 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub $ lsusb -t /: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/3p, 480M |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/8p, 480M /: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/3p, 480M |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/6p, 480M |__ Port 4: Dev 3, If 0, Class=Wireless, Driver=btusb, 12M |__ Port 4: Dev 3, If 1, Class=Wireless, Driver=btusb, 12M |__ Port 4: Dev 3, If 2, Class=Vendor Specific Class, Driver=, 12M |__ Port 4: Dev 3, If 3, Class=Application Specific Interface, Driver=, 12M |__ Port 5: Dev 4, If 0, Class=Hub, Driver=hub/6p, 480M |__ Port 1: Dev 12, If 0, Class=Vendor Specific Class, Driver=, 12M |__ Port 1: Dev 12, If 1, Class=Printer, Driver=usblp, 12M |__ Port 1: Dev 12, If 2, Class=Vendor Specific Class, Driver=, 12M |__ Port 1: Dev 12, If 3, Class=Mass Storage, Driver=usb-storage, 12M |__ Port 2: Dev 6, If 0, Class=Printer, Driver=usblp, 12M |__ Port 6: Dev 7, If 0, Class=Hub, Driver=hub/2p, 480M |__ Port 1: Dev 8, If 0, Class=Hub, Driver=hub/4p, 480M |__ Port 1: Dev 10, If 0, Class=Mass Storage, Driver=usb-storage, 480M |__ Port 2: Dev 11, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M |__ Port 2: Dev 9, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M |__ Port 2: Dev 9, If 1, Class=Human Interface Device, Driver=usbhid, 1.5M |__ Port 6: Dev 5, If 0, Class=Video, Driver=uvcvideo, 480M |__ Port 6: Dev 5, If 1, Class=Video, Driver=uvcvideo, 480M Thanks for the information about possible quirks... that reassures me that what I thought was a work-around (increase the timeout a lot) is in fact the correct fix. Hi, (In reply to Tim Waugh from comment #3) > I'm not sure how I can find out about speeds. They are included in the lsusb -t output, I had forgotten about that, so the lsusb output has all I need :) > Bus 001 Device 012: ID 03f0:2911 Hewlett-Packard PSC 2200 This is the device we're talking about, right ? That device is plugged into this hub: > |__ Port 5: Dev 4, If 0, Class=Hub, Driver=hub/6p, 480M And hre is the actual device: > |__ Port 1: Dev 12, If 0, Class=Vendor Specific Class, Driver=, > 12M > |__ Port 1: Dev 12, If 1, Class=Printer, Driver=usblp, 12M > |__ Port 1: Dev 12, If 2, Class=Vendor Specific Class, Driver=, > 12M > |__ Port 1: Dev 12, If 3, Class=Mass Storage, > Driver=usb-storage, 12M Notice how the hub has a speed of 480M, so it us a usb-2 hub, and the device of 12M, so it is a usb-1 device, or iow the known case were cancelling in flight transfers will lead to inaccurate accounting of bytes send before the cancellation I already described (*). So TL;DR: this a known and unfixable problem, and the solution is to simply not cancel transfers (by setting a timeout) and then decide you want to finish the transfer after all. Either decide you want to really cancel the transfer, or just wait for it to finish normally. BTW as documented here: http://libusbx.sourceforge.net/api-1.0/group__syncio.html You can simply specify 0 as timeout to wait indefinitely. Regards, Hans *) To be really precise, you're hitting the code at lines 442 - 446 of: http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/usb/host/ehci-q.c Thanks for the detailed analysis! |