diff options
-rw-r--r-- | drivers/usb/gadget/function/f_fs.c | 12 |
1 files changed, 9 insertions, 3 deletions
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index c39e92d3b422..a1a4360139c3 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -793,6 +793,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) ret = -EINVAL; } else if (!io_data->aio) { DECLARE_COMPLETION_ONSTACK(done); + bool interrupted = false; req = ep->req; req->buf = data; @@ -808,9 +809,14 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) spin_unlock_irq(&epfile->ffs->eps_lock); if (unlikely(wait_for_completion_interruptible(&done))) { - ret = -EINTR; + /* + * To avoid race condition with ffs_epfile_io_complete, + * dequeue the request first then check + * status. usb_ep_dequeue API should guarantee no race + * condition with req->complete callback. + */ usb_ep_dequeue(ep->ep, req); - goto error_mutex; + interrupted = ep->status < 0; } /* @@ -820,7 +826,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) * to maxpacketsize), we may end up with more * data then user space has space for. */ - ret = ep->status; + ret = interrupted ? -EINTR : ep->status; if (io_data->read && ret > 0) { ret = copy_to_iter(data, ret, &io_data->data); if (!ret) |