|  | USB device persistence during system suspend | 
|  |  | 
|  | Alan Stern <stern@rowland.harvard.edu> | 
|  |  | 
|  | September 2, 2006 (Updated May 29, 2007) | 
|  |  | 
|  |  | 
|  | What is the problem? | 
|  |  | 
|  | According to the USB specification, when a USB bus is suspended the | 
|  | bus must continue to supply suspend current (around 1-5 mA).  This | 
|  | is so that devices can maintain their internal state and hubs can | 
|  | detect connect-change events (devices being plugged in or unplugged). | 
|  | The technical term is "power session". | 
|  |  | 
|  | If a USB device's power session is interrupted then the system is | 
|  | required to behave as though the device has been unplugged.  It's a | 
|  | conservative approach; in the absence of suspend current the computer | 
|  | has no way to know what has actually happened.  Perhaps the same | 
|  | device is still attached or perhaps it was removed and a different | 
|  | device plugged into the port.  The system must assume the worst. | 
|  |  | 
|  | By default, Linux behaves according to the spec.  If a USB host | 
|  | controller loses power during a system suspend, then when the system | 
|  | wakes up all the devices attached to that controller are treated as | 
|  | though they had disconnected.  This is always safe and it is the | 
|  | "officially correct" thing to do. | 
|  |  | 
|  | For many sorts of devices this behavior doesn't matter in the least. | 
|  | If the kernel wants to believe that your USB keyboard was unplugged | 
|  | while the system was asleep and a new keyboard was plugged in when the | 
|  | system woke up, who cares?  It'll still work the same when you type on | 
|  | it. | 
|  |  | 
|  | Unfortunately problems _can_ arise, particularly with mass-storage | 
|  | devices.  The effect is exactly the same as if the device really had | 
|  | been unplugged while the system was suspended.  If you had a mounted | 
|  | filesystem on the device, you're out of luck -- everything in that | 
|  | filesystem is now inaccessible.  This is especially annoying if your | 
|  | root filesystem was located on the device, since your system will | 
|  | instantly crash. | 
|  |  | 
|  | Loss of power isn't the only mechanism to worry about.  Anything that | 
|  | interrupts a power session will have the same effect.  For example, | 
|  | even though suspend current may have been maintained while the system | 
|  | was asleep, on many systems during the initial stages of wakeup the | 
|  | firmware (i.e., the BIOS) resets the motherboard's USB host | 
|  | controllers.  Result: all the power sessions are destroyed and again | 
|  | it's as though you had unplugged all the USB devices.  Yes, it's | 
|  | entirely the BIOS's fault, but that doesn't do _you_ any good unless | 
|  | you can convince the BIOS supplier to fix the problem (lots of luck!). | 
|  |  | 
|  | On many systems the USB host controllers will get reset after a | 
|  | suspend-to-RAM.  On almost all systems, no suspend current is | 
|  | available during hibernation (also known as swsusp or suspend-to-disk). | 
|  | You can check the kernel log after resuming to see if either of these | 
|  | has happened; look for lines saying "root hub lost power or was reset". | 
|  |  | 
|  | In practice, people are forced to unmount any filesystems on a USB | 
|  | device before suspending.  If the root filesystem is on a USB device, | 
|  | the system can't be suspended at all.  (All right, it _can_ be | 
|  | suspended -- but it will crash as soon as it wakes up, which isn't | 
|  | much better.) | 
|  |  | 
|  |  | 
|  | What is the solution? | 
|  |  | 
|  | Setting CONFIG_USB_PERSIST will cause the kernel to work around these | 
|  | issues.  It enables a mode in which the core USB device data | 
|  | structures are allowed to persist across a power-session disruption. | 
|  | It works like this.  If the kernel sees that a USB host controller is | 
|  | not in the expected state during resume (i.e., if the controller was | 
|  | reset or otherwise had lost power) then it applies a persistence check | 
|  | to each of the USB devices below that controller for which the | 
|  | "persist" attribute is set.  It doesn't try to resume the device; that | 
|  | can't work once the power session is gone.  Instead it issues a USB | 
|  | port reset and then re-enumerates the device.  (This is exactly the | 
|  | same thing that happens whenever a USB device is reset.)  If the | 
|  | re-enumeration shows that the device now attached to that port has the | 
|  | same descriptors as before, including the Vendor and Product IDs, then | 
|  | the kernel continues to use the same device structure.  In effect, the | 
|  | kernel treats the device as though it had merely been reset instead of | 
|  | unplugged. | 
|  |  | 
|  | If no device is now attached to the port, or if the descriptors are | 
|  | different from what the kernel remembers, then the treatment is what | 
|  | you would expect.  The kernel destroys the old device structure and | 
|  | behaves as though the old device had been unplugged and a new device | 
|  | plugged in, just as it would without the CONFIG_USB_PERSIST option. | 
|  |  | 
|  | The end result is that the USB device remains available and usable. | 
|  | Filesystem mounts and memory mappings are unaffected, and the world is | 
|  | now a good and happy place. | 
|  |  | 
|  | Note that even when CONFIG_USB_PERSIST is set, the "persist" feature | 
|  | will be applied only to those devices for which it is enabled.  You | 
|  | can enable the feature by doing (as root): | 
|  |  | 
|  | echo 1 >/sys/bus/usb/devices/.../power/persist | 
|  |  | 
|  | where the "..." should be filled in the with the device's ID.  Disable | 
|  | the feature by writing 0 instead of 1.  For hubs the feature is | 
|  | automatically and permanently enabled, so you only have to worry about | 
|  | setting it for devices where it really matters. | 
|  |  | 
|  |  | 
|  | Is this the best solution? | 
|  |  | 
|  | Perhaps not.  Arguably, keeping track of mounted filesystems and | 
|  | memory mappings across device disconnects should be handled by a | 
|  | centralized Logical Volume Manager.  Such a solution would allow you | 
|  | to plug in a USB flash device, create a persistent volume associated | 
|  | with it, unplug the flash device, plug it back in later, and still | 
|  | have the same persistent volume associated with the device.  As such | 
|  | it would be more far-reaching than CONFIG_USB_PERSIST. | 
|  |  | 
|  | On the other hand, writing a persistent volume manager would be a big | 
|  | job and using it would require significant input from the user.  This | 
|  | solution is much quicker and easier -- and it exists now, a giant | 
|  | point in its favor! | 
|  |  | 
|  | Furthermore, the USB_PERSIST option applies to _all_ USB devices, not | 
|  | just mass-storage devices.  It might turn out to be equally useful for | 
|  | other device types, such as network interfaces. | 
|  |  | 
|  |  | 
|  | WARNING: Using CONFIG_USB_PERSIST can be dangerous!! | 
|  |  | 
|  | When recovering an interrupted power session the kernel does its best | 
|  | to make sure the USB device hasn't been changed; that is, the same | 
|  | device is still plugged into the port as before.  But the checks | 
|  | aren't guaranteed to be 100% accurate. | 
|  |  | 
|  | If you replace one USB device with another of the same type (same | 
|  | manufacturer, same IDs, and so on) there's an excellent chance the | 
|  | kernel won't detect the change.  Serial numbers and other strings are | 
|  | not compared.  In many cases it wouldn't help if they were, because | 
|  | manufacturers frequently omit serial numbers entirely in their | 
|  | devices. | 
|  |  | 
|  | Furthermore it's quite possible to leave a USB device exactly the same | 
|  | while changing its media.  If you replace the flash memory card in a | 
|  | USB card reader while the system is asleep, the kernel will have no | 
|  | way to know you did it.  The kernel will assume that nothing has | 
|  | happened and will continue to use the partition tables, inodes, and | 
|  | memory mappings for the old card. | 
|  |  | 
|  | If the kernel gets fooled in this way, it's almost certain to cause | 
|  | data corruption and to crash your system.  You'll have no one to blame | 
|  | but yourself. | 
|  |  | 
|  | YOU HAVE BEEN WARNED!  USE AT YOUR OWN RISK! | 
|  |  | 
|  | That having been said, most of the time there shouldn't be any trouble | 
|  | at all.  The "persist" feature can be extremely useful.  Make the most | 
|  | of it. |