From a4c534819e808c5ef6cadc7692976d6417606c3e Mon Sep 17 00:00:00 2001 From: Sujeet Kumar Date: Thu, 10 Nov 2016 18:41:38 -0800 Subject: [PATCH] USB: f_fs: Fix epfile crash during composition switch epfile's ep pointer may be NULL during adb transfer and composition switch happening in parallel. As part of composition switch, first it is set to NONE. Setting sys.usb.config to NONE stops adb and disables the composition. stop adb is not blocking call and adb still might be doing epfile read/write for some time when function unbind is ongoing making the data structures NULL. To fix this crash, call usb_ep_dequeue only if ep->ep is valid. Similarly in success case, return ep->status only if ep->ep is valid otherwise return -ENODEV. Change-Id: Ic152fc1db31cad6f97b8d16d91350dad857a4bf9 Signed-off-by: Sujeet Kumar Signed-off-by: Mayank Rana Signed-off-by: Jack Pham --- drivers/usb/gadget/function/f_fs.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 511125a2d3b3..f69349363912 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1171,21 +1171,32 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) * status. usb_ep_dequeue API should guarantee no race * condition with req->complete callback. */ - usb_ep_dequeue(ep->ep, req); - wait_for_completion(&done); - interrupted = ep->status < 0; + spin_lock_irq(&epfile->ffs->eps_lock); + interrupted = true; + if (ep->ep) { + usb_ep_dequeue(ep->ep, req); + wait_for_completion(&done); + interrupted = ep->status < 0; + } + spin_unlock_irq(&epfile->ffs->eps_lock); } ffs_log("%s:ep status %d for req %pK", epfile->name, ep->status, req); - if (interrupted) + if (interrupted) { ret = -EINTR; - else if (io_data->read && ep->status > 0) + goto error_mutex; + } + + ret = -ENODEV; + spin_lock_irq(&epfile->ffs->eps_lock); + if (ep->ep) + ret = ep->status; + spin_unlock_irq(&epfile->ffs->eps_lock); + if (io_data->read && ret > 0) ret = __ffs_epfile_read_data(epfile, data, ep->status, &io_data->data); - else - ret = ep->status; goto error_mutex; } else if (!(req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC))) { ret = -ENOMEM;