summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/function
diff options
context:
space:
mode:
authorSujeet Kumar <ksujeet@codeaurora.org>2016-01-28 10:42:06 -0800
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 11:10:01 -0700
commit55a6f12e78ba2ee1eb3be9f12cc840085f1ea9fc (patch)
treedbc646ae27c517a05a07e6e58606fd31ad6e3920 /drivers/usb/gadget/function
parent8b5f119fba94e61fdc271fc555a7357e34192704 (diff)
USB: f_fs: Fail stale read IOs after disconnect
After a USB disconnect, endpoints for adb are disabled. After this no IO is allowed on the endpoints. Since, adbd is not aware of this disconnect, it may still perform read/writes IO. For adb writes, IOs are failed, but for adb reads kernel waits untill endpoints are enabled. When a USB disconnect and adb read still queued a buffer to kernel, ffs_epfile_io simply waits for endpoint to be enabled. A next connect happens and endpoints are enabled after set_alt, the adb read stale buffer from previous session continues and queues to endpoint. All this time, adb did not close the epfile because it did not get return status on the IOs which it queued. This is an issue, because a new session is not established and both userspace and kernel goes out of sync. To fix this issue, when endpoints are disbled set epfile error. This epfile error is only cleared in epfile open. This will ensure that after a USB disconnect and connect, new session is established. Also, return ENODEV if endpoints not enabled rather than EINTR as EINTR case, and simply retries the request. Incase usb_ep_queue failed, return -EIO inspite of depend on return status from usb_ep_queue. Change-Id: I6e677e98ec28e5462b372ed290acdde251286f48 Signed-off-by: Sujeet Kumar <ksujeet@codeaurora.org> Signed-off-by: Mayank Rana <mrana@codeaurora.org>
Diffstat (limited to 'drivers/usb/gadget/function')
-rw-r--r--drivers/usb/gadget/function/f_fs.c22
1 files changed, 18 insertions, 4 deletions
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index c7adc17c1b30..a3862a21db85 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -124,6 +124,7 @@ struct ffs_epfile {
/* Protects ep->ep and ep->req. */
struct mutex mutex;
wait_queue_head_t wait;
+ atomic_t error;
struct ffs_data *ffs;
struct ffs_ep *ep; /* P: ffs->eps_lock */
@@ -703,9 +704,19 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
goto error;
}
- ret = wait_event_interruptible(epfile->wait, (ep = epfile->ep));
- if (ret) {
- ret = -EINTR;
+ /*
+ * If ep is disabled, this fails all current IOs
+ * and wait for next epfile open to happen.
+ */
+ if (!atomic_read(&epfile->error)) {
+ ret = wait_event_interruptible(epfile->wait,
+ (ep = epfile->ep));
+ if (ret < 0)
+ goto error;
+ }
+
+ if (!ep) {
+ ret = -ENODEV;
goto error;
}
}
@@ -830,7 +841,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
spin_unlock_irq(&epfile->ffs->eps_lock);
if (unlikely(ret < 0)) {
- /* nop */
+ ret = -EIO;
} else if (unlikely(
wait_for_completion_interruptible(&done))) {
spin_lock_irq(&epfile->ffs->eps_lock);
@@ -885,6 +896,7 @@ ffs_epfile_open(struct inode *inode, struct file *file)
file->private_data = epfile;
ffs_data_opened(epfile->ffs);
+ atomic_set(&epfile->error, 0);
return 0;
}
@@ -1000,6 +1012,7 @@ ffs_epfile_release(struct inode *inode, struct file *file)
ENTER();
+ atomic_set(&epfile->error, 1);
ffs_data_closed(epfile->ffs);
return 0;
@@ -1633,6 +1646,7 @@ static void ffs_func_eps_disable(struct ffs_function *func)
++ep;
if (epfile) {
+ atomic_set(&epfile->error, 1);
epfile->ep = NULL;
++epfile;
}