• D
    usb: introduce port status lock · 5c79a1e3
    Dan Williams 提交于
    In general we do not want khubd to act on port status changes that are
    the result of in progress resets or USB runtime PM operations.
    Specifically port power control testing has been able to trigger an
    unintended disconnect in hub_port_connect_change(), paraphrasing:
    
    	if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&
    	    udev->state != USB_STATE_NOTATTACHED) {
    		if (portstatus & USB_PORT_STAT_ENABLE) {
    			/* Nothing to do */
    		} else if (udev->state == USB_STATE_SUSPENDED &&
    				udev->persist_enabled) {
    			...
    		} else {
    			/* Don't resuscitate */;
    		}
    	}
    
    ...by falling to the "Don't resuscitate" path or missing
    USB_PORT_STAT_CONNECTION because usb_port_resume() was in the middle of
    modifying the port status.
    
    So, we want a new lock to hold off khubd for a given port while the
    child device is being suspended, resumed, or reset.  The lock ordering
    rules are now usb_lock_device() => usb_lock_port().  This is mandated by
    the device core which may hold the device_lock on the usb_device before
    invoking usb_port_{suspend|resume} which in turn take the status_lock on
    the usb_port.  We attempt to hold the status_lock for the duration of a
    port_event() run, and drop/re-acquire it when needing to take the
    device_lock.  The lock is also dropped/re-acquired during
    hub_port_reconnect().
    
    This patch also deletes hub->busy_bits as all use cases are now covered
    by port PM runtime synchronization or the port->status_lock and it
    pushes down usb_device_lock() into usb_remote_wakeup().
    Acked-by: NAlan Stern <stern@rowland.harvard.edu>
    Signed-off-by: NDan Williams <dan.j.williams@intel.com>
    Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    5c79a1e3
hub.c 159.1 KB