diff options
author | Mayank Rana <mrana@codeaurora.org> | 2016-01-28 12:02:14 -0800 |
---|---|---|
committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-22 11:10:06 -0700 |
commit | 5e8b41f531999e322d91cd9804691f92c38a0745 (patch) | |
tree | 78c28798f3aaceaa807058b2407304aa7f9d6dbd /drivers | |
parent | 5cd572ca8d3474613d4562e1e9cb533c8ba65842 (diff) |
USB: f_fs: Add memory barrier before atomic operations
In few instances, it is observed that multiple adbd instances are
running on device causing condition BUG_ON(ffs->gadget) to be true.
ffs->opened and ffs->ref atomic variables are used here to make
decision for checking ffs->gadget. These atomic variable operations
requires expilict memory barrier to make sure that update to
ffs->gadget is visible to other CPUs before updated atomic variable
based value is seen. This change also adds explicit memory barriers
before reading or modified any atomic varaiables.
Change-Id: I3c846eb6bbb53663892e05d51ebac8439aac957a
Signed-off-by: Mayank Rana <mrana@codeaurora.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/gadget/function/f_fs.c | 14 |
1 files changed, 12 insertions, 2 deletions
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 4349fe73e23f..4b98e111e09f 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -539,6 +539,7 @@ static int ffs_ep0_open(struct inode *inode, struct file *file) if (unlikely(ffs->state == FFS_CLOSING)) return -EBUSY; + smp_mb__before_atomic(); if (atomic_read(&ffs->opened)) return -EBUSY; @@ -697,6 +698,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) ssize_t ret, data_len = -EINVAL; int halt; + smp_mb__before_atomic(); if (atomic_read(&epfile->error)) return -ENODEV; @@ -718,6 +720,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) * If ep is disabled, this fails all current IOs * and wait for next epfile open to happen. */ + smp_mb__before_atomic(); if (!atomic_read(&epfile->error)) { ret = wait_event_interruptible(epfile->wait, (ep = epfile->ep)); @@ -1443,6 +1446,7 @@ static void ffs_data_get(struct ffs_data *ffs) { ENTER(); + smp_mb__before_atomic(); atomic_inc(&ffs->ref); } @@ -1450,6 +1454,7 @@ static void ffs_data_opened(struct ffs_data *ffs) { ENTER(); + smp_mb__before_atomic(); atomic_inc(&ffs->ref); if (atomic_add_return(1, &ffs->opened) == 1 && ffs->state == FFS_DEACTIVATED) { @@ -1462,6 +1467,7 @@ static void ffs_data_put(struct ffs_data *ffs) { ENTER(); + smp_mb__before_atomic(); if (unlikely(atomic_dec_and_test(&ffs->ref))) { pr_info("%s(): freeing\n", __func__); ffs_data_clear(ffs); @@ -1476,6 +1482,7 @@ static void ffs_data_closed(struct ffs_data *ffs) { ENTER(); + smp_mb__before_atomic(); if (atomic_dec_and_test(&ffs->opened)) { if (ffs->no_disconnect) { ffs->state = FFS_DEACTIVATED; @@ -1491,6 +1498,8 @@ static void ffs_data_closed(struct ffs_data *ffs) ffs_data_reset(ffs); } } + + smp_mb__before_atomic(); if (atomic_read(&ffs->opened) < 0) { ffs->state = FFS_CLOSING; ffs_data_reset(ffs); @@ -1532,8 +1541,8 @@ static void ffs_data_clear(struct ffs_data *ffs) ffs_closed(ffs); if (ffs->gadget) - pr_err("%s: ffs->gadget= %p, ffs->flags= %lu\n", - __func__, ffs->gadget, ffs->flags); + pr_err("%s: ffs:%p ffs->gadget= %p, ffs->flags= %lu\n", + __func__, ffs, ffs->gadget, ffs->flags); BUG_ON(ffs->gadget); if (ffs->epfiles) @@ -3539,6 +3548,7 @@ static void ffs_closed(struct ffs_data *ffs) else goto done; + smp_mb__before_atomic(); if (opts->no_configfs || !opts->func_inst.group.cg_item.ci_parent || !atomic_read(&opts->func_inst.group.cg_item.ci_kref.refcount)) goto done; |