summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMayank Rana <mrana@codeaurora.org>2016-04-11 16:32:48 -0700
committerJeevan Shriram <jshriram@codeaurora.org>2016-04-18 17:06:17 -0700
commit96fc91d1663957226113a0e19187f4fe9099c5d4 (patch)
tree1a8901e99158b79b5db9706811a4d0b5dd755fc9
parent8266c2d117a731a3bb1ecf93b6198d4754e864b0 (diff)
usb: gadget: f_diag: Fix list corruption due to diag_context freed
While performing USB composition switch or adb is being killed, list_add corruption related crash is seen when SLUB_DEBUG is enabled. diag_function_unbind() API decrements kref count and when it becomes zero, it is calling diag_context_release() which frees diag_context. This list corruption is seen from purge_configfs_funcs() API which is trying to move function list as part of func->list. Fix this issue by releasing diag_context with free_func() instead of diag_function_unbind(). CRs-Fixed: 1002041 Change-Id: Ie49e47f2a0f26144e0107759fedc67c3af80032c Signed-off-by: Mayank Rana <mrana@codeaurora.org>
-rw-r--r--drivers/usb/gadget/function/f_diag.c22
1 files changed, 13 insertions, 9 deletions
diff --git a/drivers/usb/gadget/function/f_diag.c b/drivers/usb/gadget/function/f_diag.c
index 7a451b77c4d0..87939140f82e 100644
--- a/drivers/usb/gadget/function/f_diag.c
+++ b/drivers/usb/gadget/function/f_diag.c
@@ -657,7 +657,16 @@ static void diag_function_disable(struct usb_function *f)
static void diag_free_func(struct usb_function *f)
{
- kfree(func_to_diag(f));
+ struct diag_context *ctxt = func_to_diag(f);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctxt->lock, flags);
+ list_del(&ctxt->list_item);
+ if (kref_put(&ctxt->kref, diag_context_release))
+ /* diag_context_release called spin_unlock already */
+ local_irq_restore(flags);
+ else
+ spin_unlock_irqrestore(&ctxt->lock, flags);
}
static int diag_function_set_alt(struct usb_function *f,
@@ -734,16 +743,11 @@ static void diag_function_unbind(struct usb_configuration *c,
*/
if (ctxt->ch && ctxt->ch->priv_usb == ctxt)
ctxt->ch->priv_usb = NULL;
- list_del(&ctxt->list_item);
- /* Free any pending USB requests from last session */
+
spin_lock_irqsave(&ctxt->lock, flags);
+ /* Free any pending USB requests from last session */
free_reqs(ctxt);
-
- if (kref_put(&ctxt->kref, diag_context_release))
- /* diag_context_release called spin_unlock already */
- local_irq_restore(flags);
- else
- spin_unlock_irqrestore(&ctxt->lock, flags);
+ spin_unlock_irqrestore(&ctxt->lock, flags);
}
static int diag_function_bind(struct usb_configuration *c,