-stable review patch. If anyone has any objections, please let us know. --------------------- From: Simon Arlott As part of the device initialisation cxacru_atm_start starts a rearming status polling task, which is cancelled in cxacru_unbind. Failure to ever start the task means an infinite loop occurs trying to cancel it. Possible reasons for not starting the polling task: * Firmware files missing * Device initialisation fails * User unplugs device or unloads module Effect: * Infinite loop in khubd trying to add/remove the device (or rmmod if timed right) Signed-off-by: Simon Arlott Signed-off-by: Chris Wright --- Fixed for 2.6.22 by 6a02c996bce297a782432e29c69268356e97fadd. drivers/usb/atm/cxacru.c | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) --- linux-2.6.21.1.orig/drivers/usb/atm/cxacru.c +++ linux-2.6.21.1/drivers/usb/atm/cxacru.c @@ -146,6 +146,12 @@ enum cxacru_info_idx { CXINF_MAX = 0x1c, }; +enum poll_state { + CX_INIT, + CX_POLLING, + CX_ABORT +}; + struct cxacru_modem_type { u32 pll_f_clk; u32 pll_b_clk; @@ -159,6 +165,8 @@ struct cxacru_data { int line_status; struct delayed_work poll_work; + struct mutex poll_state_serialize; + enum poll_state poll_state; /* contol handles */ struct mutex cm_serialize; @@ -356,7 +364,7 @@ static int cxacru_atm_start(struct usbat /* struct atm_dev *atm_dev = usbatm_instance->atm_dev; */ - int ret; + int ret, start_polling = 1; dbg("cxacru_atm_start"); @@ -376,7 +384,15 @@ static int cxacru_atm_start(struct usbat } /* Start status polling */ - cxacru_poll_status(&instance->poll_work.work); + mutex_lock(&instance->poll_state_serialize); + if (instance->poll_state == CX_INIT) + instance->poll_state = CX_POLLING; + else /* poll_state == CX_ABORT */ + start_polling = 0; + mutex_unlock(&instance->poll_state_serialize); + + if (start_polling) + cxacru_poll_status(&instance->poll_work.work); return 0; } @@ -685,6 +701,9 @@ static int cxacru_bind(struct usbatm_dat instance->usbatm = usbatm_instance; instance->modem_type = (struct cxacru_modem_type *) id->driver_info; + mutex_init(&instance->poll_state_serialize); + instance->poll_state = CX_INIT; + instance->rcv_buf = (u8 *) __get_free_page(GFP_KERNEL); if (!instance->rcv_buf) { dbg("cxacru_bind: no memory for rcv_buf"); @@ -744,6 +763,7 @@ static void cxacru_unbind(struct usbatm_ struct usb_interface *intf) { struct cxacru_data *instance = usbatm_instance->driver_data; + int stop_polling = 1; dbg("cxacru_unbind entered"); @@ -752,8 +772,20 @@ static void cxacru_unbind(struct usbatm_ return; } - while (!cancel_delayed_work(&instance->poll_work)) - flush_scheduled_work(); + mutex_lock(&instance->poll_state_serialize); + if (instance->poll_state != CX_POLLING) { + /* Polling hasn't started yet and with + * the mutex locked it can be prevented + * from starting. + */ + instance->poll_state = CX_ABORT; + stop_polling = 0; + } + mutex_unlock(&instance->poll_state_serialize); + + if (stop_polling) + while (!cancel_delayed_work(&instance->poll_work)) + flush_scheduled_work(); usb_kill_urb(instance->snd_urb); usb_kill_urb(instance->rcv_urb); -- - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/