diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index 2dae474dc..5b30303ad 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -2382,10 +2382,25 @@ static void vub300_disconnect(struct usb_interface *interface) } else { int ifnum = interface_to_InterfaceNumber(interface); usb_set_intfdata(interface, NULL); + /* + * The inactivity timer holds a reference to the host + * and can be rearmed by work items. Shut it down + * before clearing interface, otherwise its callback + * can drop the timer reference while a concurrent + * work item is rearming the timer, leaving the host + * to be freed while the timer is still active. + */ + timer_shutdown_sync(&vub300->inactivity_timer); /* prevent more I/O from starting */ vub300->interface = NULL; mmc_remove_host(mmc); kref_put(&vub300->kref, vub300_delete); + /* + * The timer is shut down, so it will no longer drop + * the reference that was acquired for it in + * vub300_probe(). Drop it here. + */ + kref_put(&vub300->kref, vub300_delete); pr_info("USB vub300 remote SDIO host controller[%d]" " now disconnected", ifnum); return;