aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2020-05-26 11:57:37 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2020-05-26 11:57:37 -0700
commit6f235135639024d39c837dc17ebc06b7ed8f1f38 (patch)
treeeae6120176a57a056b51ba414a21233a22a11e8b
parent53ee66018b1d8b4d46081405159c3cd33e2ae72c (diff)
parent644e3c853c0ea2e5660cc8da184fc7dace036541 (diff)
Merge "usb: gadget: f_fs: Fail waiting IO after eps disabled"LA.UM.8.13.r1-08500-SAIPAN.0
-rw-r--r--drivers/usb/gadget/function/f_fs.c36
1 files changed, 29 insertions, 7 deletions
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index f916f8753540..ec98f5c0cd39 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -139,6 +139,7 @@ struct ffs_epfile {
struct ffs_data *ffs;
struct ffs_ep *ep; /* P: ffs->eps_lock */
+ atomic_t opened;
struct dentry *dentry;
@@ -205,7 +206,7 @@ struct ffs_epfile {
unsigned char in; /* P: ffs->eps_lock */
unsigned char isoc; /* P: ffs->eps_lock */
- unsigned char _pad;
+ bool invalid;
};
struct ffs_buffer {
@@ -956,6 +957,16 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
+ /*
+ * epfile->invalid is set when EPs are disabled. Userspace
+ * might have stale threads continuing to do I/O and may be
+ * unaware of that especially if we block here. Instead return
+ * an error immediately here and don't allow any more I/O
+ * until the epfile is reopened.
+ */
+ if (epfile->invalid)
+ return -ENODEV;
+
ret = wait_event_interruptible(
epfile->ffs->wait, (ep = epfile->ep));
if (ret)
@@ -1151,15 +1162,16 @@ ffs_epfile_open(struct inode *inode, struct file *file)
ENTER();
- ffs_log("%s: state %d setup_state %d flag %lu", epfile->name,
- epfile->ffs->state, epfile->ffs->setup_state,
- epfile->ffs->flags);
+ ffs_log("%s: state %d setup_state %d flag %lu opened %u",
+ epfile->name, epfile->ffs->state, epfile->ffs->setup_state,
+ epfile->ffs->flags, atomic_read(&epfile->opened));
if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
return -ENODEV;
file->private_data = epfile;
ffs_data_opened(epfile->ffs);
+ atomic_inc(&epfile->opened);
return 0;
}
@@ -1299,9 +1311,12 @@ ffs_epfile_release(struct inode *inode, struct file *file)
ENTER();
__ffs_epfile_read_buffer_free(epfile);
- ffs_log("%s: state %d setup_state %d flag %lu", epfile->name,
- epfile->ffs->state, epfile->ffs->setup_state,
- epfile->ffs->flags);
+ ffs_log("%s: state %d setup_state %d flag %lu opened %u",
+ epfile->name, epfile->ffs->state, epfile->ffs->setup_state,
+ epfile->ffs->flags, atomic_read(&epfile->opened));
+
+ if (atomic_dec_and_test(&epfile->opened))
+ epfile->invalid = false;
ffs_data_closed(epfile->ffs);
@@ -1331,6 +1346,10 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code,
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
+ /* don't allow any I/O until file is reopened */
+ if (epfile->invalid)
+ return -ENODEV;
+
ret = wait_event_interruptible(
epfile->ffs->wait, (ep = epfile->ep));
if (ret)
@@ -1992,6 +2011,8 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
ffs_epfiles_destroy(epfiles, i - 1);
return -ENOMEM;
}
+
+ atomic_set(&epfile->opened, 0);
}
ffs->epfiles = epfiles;
@@ -2039,6 +2060,7 @@ static void ffs_func_eps_disable(struct ffs_function *func)
++ep;
if (epfile) {
+ epfile->invalid = true; /* until file is reopened */
epfile->ep = NULL;
__ffs_epfile_read_buffer_free(epfile);
++epfile;