summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/function/f_fs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/function/f_fs.c')
-rw-r--r--drivers/usb/gadget/function/f_fs.c295
1 files changed, 163 insertions, 132 deletions
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 2dea9e42a0f8..75912ce6ab55 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -59,7 +59,6 @@ static struct ffs_data *__must_check ffs_data_new(const char *dev_name)
__attribute__((malloc));
/* Opened counter handling. */
-static void ffs_data_opened(struct ffs_data *ffs);
static void ffs_data_closed(struct ffs_data *ffs);
/* Called with ffs->mutex held; take over ownership of data. */
@@ -151,6 +150,8 @@ struct ffs_dma_fence {
struct dma_fence base;
struct ffs_dmabuf_priv *priv;
struct work_struct work;
+ struct usb_ep *ep;
+ struct usb_request *req;
};
struct ffs_epfile {
@@ -160,8 +161,6 @@ struct ffs_epfile {
struct ffs_data *ffs;
struct ffs_ep *ep; /* P: ffs->eps_lock */
- struct dentry *dentry;
-
/*
* Buffer for holding data from partial reads which may happen since
* we’re rounding user read requests to a multiple of a max packet size.
@@ -271,11 +270,11 @@ struct ffs_desc_helper {
};
static int __must_check ffs_epfiles_create(struct ffs_data *ffs);
-static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
+static void ffs_epfiles_destroy(struct super_block *sb,
+ struct ffs_epfile *epfiles, unsigned count);
-static struct dentry *
-ffs_sb_create_file(struct super_block *sb, const char *name, void *data,
- const struct file_operations *fops);
+static int ffs_sb_create_file(struct super_block *sb, const char *name,
+ void *data, const struct file_operations *fops);
/* Devices management *******************************************************/
@@ -622,7 +621,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
/* unlocks spinlock */
ret = __ffs_ep0_queue_wait(ffs, data, len);
- if ((ret > 0) && (copy_to_user(buf, data, len)))
+ if ((ret > 0) && (copy_to_user(buf, data, ret)))
ret = -EFAULT;
goto done_mutex;
@@ -638,15 +637,26 @@ done_mutex:
return ret;
}
+
+static void ffs_data_reset(struct ffs_data *ffs);
+
static int ffs_ep0_open(struct inode *inode, struct file *file)
{
- struct ffs_data *ffs = inode->i_private;
+ struct ffs_data *ffs = inode->i_sb->s_fs_info;
- if (ffs->state == FFS_CLOSING)
+ spin_lock_irq(&ffs->eps_lock);
+ if (ffs->state == FFS_CLOSING) {
+ spin_unlock_irq(&ffs->eps_lock);
return -EBUSY;
-
+ }
+ if (!ffs->opened++ && ffs->state == FFS_DEACTIVATED) {
+ ffs->state = FFS_CLOSING;
+ spin_unlock_irq(&ffs->eps_lock);
+ ffs_data_reset(ffs);
+ } else {
+ spin_unlock_irq(&ffs->eps_lock);
+ }
file->private_data = ffs;
- ffs_data_opened(ffs);
return stream_open(inode, file);
}
@@ -806,7 +816,7 @@ static void *ffs_build_sg_list(struct sg_table *sgt, size_t sz)
return NULL;
n_pages = PAGE_ALIGN(sz) >> PAGE_SHIFT;
- pages = kvmalloc_array(n_pages, sizeof(struct page *), GFP_KERNEL);
+ pages = kvmalloc_objs(struct page *, n_pages);
if (!pages) {
vfree(vaddr);
@@ -854,7 +864,6 @@ static void ffs_user_copy_worker(struct work_struct *work)
work);
int ret = io_data->status;
bool kiocb_has_eventfd = io_data->kiocb->ki_flags & IOCB_EVENTFD;
- unsigned long flags;
if (io_data->read && ret > 0) {
kthread_use_mm(io_data->mm);
@@ -867,10 +876,7 @@ static void ffs_user_copy_worker(struct work_struct *work)
if (io_data->ffs->ffs_eventfd && !kiocb_has_eventfd)
eventfd_signal(io_data->ffs->ffs_eventfd);
- spin_lock_irqsave(&io_data->ffs->eps_lock, flags);
usb_ep_free_request(io_data->ep, io_data->req);
- io_data->req = NULL;
- spin_unlock_irqrestore(&io_data->ffs->eps_lock, flags);
if (io_data->read)
kfree(io_data->to_free);
@@ -953,7 +959,7 @@ static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile,
data_len, ret);
data_len -= ret;
- buf = kmalloc(struct_size(buf, storage, data_len), GFP_KERNEL);
+ buf = kmalloc_flex(*buf, storage, data_len);
if (!buf)
return -ENOMEM;
buf->length = data_len;
@@ -1197,33 +1203,41 @@ error:
static int
ffs_epfile_open(struct inode *inode, struct file *file)
{
- struct ffs_epfile *epfile = inode->i_private;
+ struct ffs_data *ffs = inode->i_sb->s_fs_info;
+ struct ffs_epfile *epfile;
- if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
+ spin_lock_irq(&ffs->eps_lock);
+ if (!ffs->opened) {
+ spin_unlock_irq(&ffs->eps_lock);
return -ENODEV;
+ }
+ /*
+ * we want the state to be FFS_ACTIVE; FFS_ACTIVE alone is
+ * not enough, though - we might have been through FFS_CLOSING
+ * and back to FFS_ACTIVE, with our file already removed.
+ */
+ epfile = smp_load_acquire(&inode->i_private);
+ if (unlikely(ffs->state != FFS_ACTIVE || !epfile)) {
+ spin_unlock_irq(&ffs->eps_lock);
+ return -ENODEV;
+ }
+ ffs->opened++;
+ spin_unlock_irq(&ffs->eps_lock);
file->private_data = epfile;
- ffs_data_opened(epfile->ffs);
-
return stream_open(inode, file);
}
static int ffs_aio_cancel(struct kiocb *kiocb)
{
struct ffs_io_data *io_data = kiocb->private;
- struct ffs_epfile *epfile = kiocb->ki_filp->private_data;
- unsigned long flags;
int value;
- spin_lock_irqsave(&epfile->ffs->eps_lock, flags);
-
if (io_data && io_data->ep && io_data->req)
value = usb_ep_dequeue(io_data->ep, io_data->req);
else
value = -EINVAL;
- spin_unlock_irqrestore(&epfile->ffs->eps_lock, flags);
-
return value;
}
@@ -1233,7 +1247,7 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
ssize_t res;
if (!is_sync_kiocb(kiocb)) {
- p = kzalloc(sizeof(io_data), GFP_KERNEL);
+ p = kzalloc_obj(io_data);
if (!p)
return -ENOMEM;
p->aio = true;
@@ -1268,7 +1282,7 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
ssize_t res;
if (!is_sync_kiocb(kiocb)) {
- p = kzalloc(sizeof(io_data), GFP_KERNEL);
+ p = kzalloc_obj(io_data);
if (!p)
return -ENOMEM;
p->aio = true;
@@ -1316,9 +1330,7 @@ static void ffs_dmabuf_release(struct kref *ref)
struct dma_buf *dmabuf = attach->dmabuf;
pr_vdebug("FFS DMABUF release\n");
- dma_resv_lock(dmabuf->resv, NULL);
- dma_buf_unmap_attachment(attach, priv->sgt, priv->dir);
- dma_resv_unlock(dmabuf->resv);
+ dma_buf_unmap_attachment_unlocked(attach, priv->sgt, priv->dir);
dma_buf_detach(attach->dmabuf, attach);
dma_buf_put(dmabuf);
@@ -1342,7 +1354,7 @@ static void ffs_dmabuf_put(struct dma_buf_attachment *attach)
static int
ffs_epfile_release(struct inode *inode, struct file *file)
{
- struct ffs_epfile *epfile = inode->i_private;
+ struct ffs_epfile *epfile = file->private_data;
struct ffs_dmabuf_priv *priv, *tmp;
struct ffs_data *ffs = epfile->ffs;
@@ -1375,6 +1387,21 @@ static void ffs_dmabuf_cleanup(struct work_struct *work)
struct ffs_dmabuf_priv *priv = dma_fence->priv;
struct dma_buf_attachment *attach = priv->attach;
struct dma_fence *fence = &dma_fence->base;
+ struct usb_request *req = dma_fence->req;
+ struct usb_ep *ep = dma_fence->ep;
+
+ /*
+ * eps_lock pairs with the cancel paths so they cannot pass a freed
+ * req to usb_ep_dequeue(). Only clear if priv->req still names ours;
+ * a re-queue on the same attachment may have taken that slot.
+ */
+ spin_lock_irq(&priv->ffs->eps_lock);
+ if (priv->req == req)
+ priv->req = NULL;
+ spin_unlock_irq(&priv->ffs->eps_lock);
+
+ if (ep && req)
+ usb_ep_free_request(ep, req);
ffs_dmabuf_put(attach);
dma_fence_put(fence);
@@ -1404,8 +1431,8 @@ static void ffs_epfile_dmabuf_io_complete(struct usb_ep *ep,
struct usb_request *req)
{
pr_vdebug("FFS: DMABUF transfer complete, status=%d\n", req->status);
+ /* req is freed by ffs_dmabuf_cleanup() under eps_lock. */
ffs_dmabuf_signal_done(req->context, req->status);
- usb_ep_free_request(ep, req);
}
static const char *ffs_dmabuf_get_driver_name(struct dma_fence *fence)
@@ -1493,13 +1520,13 @@ static int ffs_dmabuf_attach(struct file *file, int fd)
goto err_dmabuf_put;
}
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ priv = kzalloc_obj(*priv);
if (!priv) {
err = -ENOMEM;
goto err_dmabuf_detach;
}
- dir = epfile->in ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ dir = epfile->in ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
err = ffs_dma_resv_lock(dmabuf, nonblock);
if (err)
@@ -1629,7 +1656,7 @@ static int ffs_dmabuf_transfer(struct file *file,
/* Make sure we don't have writers */
timeout = nonblock ? 0 : msecs_to_jiffies(DMABUF_ENQUEUE_TIMEOUT_MS);
retl = dma_resv_wait_timeout(dmabuf->resv,
- dma_resv_usage_rw(epfile->in),
+ dma_resv_usage_rw(!epfile->in),
true, timeout);
if (retl == 0)
retl = -EBUSY;
@@ -1642,7 +1669,7 @@ static int ffs_dmabuf_transfer(struct file *file,
if (ret)
goto err_resv_unlock;
- fence = kmalloc(sizeof(*fence), GFP_KERNEL);
+ fence = kmalloc_obj(*fence);
if (!fence) {
ret = -ENOMEM;
goto err_resv_unlock;
@@ -1674,7 +1701,7 @@ static int ffs_dmabuf_transfer(struct file *file,
dma_fence_init(&fence->base, &ffs_dmabuf_fence_ops,
&priv->lock, priv->context, seqno);
- resv_dir = epfile->in ? DMA_RESV_USAGE_WRITE : DMA_RESV_USAGE_READ;
+ resv_dir = epfile->in ? DMA_RESV_USAGE_READ : DMA_RESV_USAGE_WRITE;
dma_resv_add_fence(dmabuf->resv, &fence->base, resv_dir);
dma_resv_unlock(dmabuf->resv);
@@ -1689,6 +1716,10 @@ static int ffs_dmabuf_transfer(struct file *file,
usb_req->context = fence;
usb_req->complete = ffs_epfile_dmabuf_io_complete;
+ /* ffs_dmabuf_cleanup() frees usb_req via these two fields. */
+ fence->req = usb_req;
+ fence->ep = ep->ep;
+
cookie = dma_fence_begin_signalling();
ret = usb_ep_queue(ep->ep, usb_req, GFP_ATOMIC);
dma_fence_end_signalling(cookie);
@@ -1698,7 +1729,6 @@ static int ffs_dmabuf_transfer(struct file *file,
} else {
pr_warn("FFS: Failed to queue DMABUF: %d\n", ret);
ffs_dmabuf_signal_done(fence, ret);
- usb_ep_free_request(ep->ep, usb_req);
}
spin_unlock_irq(&epfile->ffs->eps_lock);
@@ -1734,10 +1764,8 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code,
{
int fd;
- if (copy_from_user(&fd, (void __user *)value, sizeof(fd))) {
- ret = -EFAULT;
- break;
- }
+ if (copy_from_user(&fd, (void __user *)value, sizeof(fd)))
+ return -EFAULT;
return ffs_dmabuf_attach(file, fd);
}
@@ -1745,10 +1773,8 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code,
{
int fd;
- if (copy_from_user(&fd, (void __user *)value, sizeof(fd))) {
- ret = -EFAULT;
- break;
- }
+ if (copy_from_user(&fd, (void __user *)value, sizeof(fd)))
+ return -EFAULT;
return ffs_dmabuf_detach(file, fd);
}
@@ -1756,10 +1782,8 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code,
{
struct usb_ffs_dmabuf_transfer_req req;
- if (copy_from_user(&req, (void __user *)value, sizeof(req))) {
- ret = -EFAULT;
- break;
- }
+ if (copy_from_user(&req, (void __user *)value, sizeof(req)))
+ return -EFAULT;
return ffs_dmabuf_transfer(file, &req);
}
@@ -1876,32 +1900,32 @@ ffs_sb_make_inode(struct super_block *sb, void *data,
}
/* Create "regular" file */
-static struct dentry *ffs_sb_create_file(struct super_block *sb,
- const char *name, void *data,
- const struct file_operations *fops)
+static int ffs_sb_create_file(struct super_block *sb, const char *name,
+ void *data, const struct file_operations *fops)
{
struct ffs_data *ffs = sb->s_fs_info;
struct dentry *dentry;
struct inode *inode;
- dentry = d_alloc_name(sb->s_root, name);
- if (!dentry)
- return NULL;
-
inode = ffs_sb_make_inode(sb, data, fops, NULL, &ffs->file_perms);
- if (!inode) {
- dput(dentry);
- return NULL;
+ if (!inode)
+ return -ENOMEM;
+ dentry = simple_start_creating(sb->s_root, name);
+ if (IS_ERR(dentry)) {
+ iput(inode);
+ return PTR_ERR(dentry);
}
- d_add(dentry, inode);
- return dentry;
+ d_make_persistent(dentry, inode);
+
+ simple_done_creating(dentry);
+ return 0;
}
/* Super block */
static const struct super_operations ffs_sb_operations = {
.statfs = simple_statfs,
- .drop_inode = generic_delete_inode,
+ .drop_inode = inode_just_drop,
};
struct ffs_sb_fill_data {
@@ -1938,10 +1962,7 @@ static int ffs_sb_fill(struct super_block *sb, struct fs_context *fc)
return -ENOMEM;
/* EP0 file */
- if (!ffs_sb_create_file(sb, "ep0", ffs, &ffs_ep0_operations))
- return -ENOMEM;
-
- return 0;
+ return ffs_sb_create_file(sb, "ep0", ffs, &ffs_ep0_operations);
}
enum {
@@ -2066,7 +2087,7 @@ static int ffs_fs_init_fs_context(struct fs_context *fc)
{
struct ffs_sb_fill_data *ctx;
- ctx = kzalloc(sizeof(struct ffs_sb_fill_data), GFP_KERNEL);
+ ctx = kzalloc_obj(struct ffs_sb_fill_data);
if (!ctx)
return -ENOMEM;
@@ -2084,9 +2105,16 @@ static int ffs_fs_init_fs_context(struct fs_context *fc)
static void
ffs_fs_kill_sb(struct super_block *sb)
{
- kill_litter_super(sb);
- if (sb->s_fs_info)
- ffs_data_closed(sb->s_fs_info);
+ kill_anon_super(sb);
+ if (sb->s_fs_info) {
+ struct ffs_data *ffs = sb->s_fs_info;
+ ffs->state = FFS_CLOSING;
+ ffs_data_reset(ffs);
+ // no configfs accesses from that point on,
+ // so no further schedule_work() is possible
+ cancel_work_sync(&ffs->reset_work);
+ ffs_data_put(ffs);
+ }
}
static struct file_system_type ffs_fs_type = {
@@ -2124,23 +2152,12 @@ static void functionfs_cleanup(void)
/* ffs_data and ffs_function construction and destruction code **************/
static void ffs_data_clear(struct ffs_data *ffs);
-static void ffs_data_reset(struct ffs_data *ffs);
static void ffs_data_get(struct ffs_data *ffs)
{
refcount_inc(&ffs->ref);
}
-static void ffs_data_opened(struct ffs_data *ffs)
-{
- refcount_inc(&ffs->ref);
- if (atomic_add_return(1, &ffs->opened) == 1 &&
- ffs->state == FFS_DEACTIVATED) {
- ffs->state = FFS_CLOSING;
- ffs_data_reset(ffs);
- }
-}
-
static void ffs_data_put(struct ffs_data *ffs)
{
if (refcount_dec_and_test(&ffs->ref)) {
@@ -2158,40 +2175,35 @@ static void ffs_data_put(struct ffs_data *ffs)
static void ffs_data_closed(struct ffs_data *ffs)
{
- struct ffs_epfile *epfiles;
- unsigned long flags;
-
- if (atomic_dec_and_test(&ffs->opened)) {
- if (ffs->no_disconnect) {
- ffs->state = FFS_DEACTIVATED;
- spin_lock_irqsave(&ffs->eps_lock, flags);
- epfiles = ffs->epfiles;
- ffs->epfiles = NULL;
- spin_unlock_irqrestore(&ffs->eps_lock,
- flags);
-
- if (epfiles)
- ffs_epfiles_destroy(epfiles,
- ffs->eps_count);
-
- if (ffs->setup_state == FFS_SETUP_PENDING)
- __ffs_ep0_stall(ffs);
- } else {
- ffs->state = FFS_CLOSING;
- ffs_data_reset(ffs);
- }
+ spin_lock_irq(&ffs->eps_lock);
+ if (--ffs->opened) { // not the last opener?
+ spin_unlock_irq(&ffs->eps_lock);
+ return;
}
- if (atomic_read(&ffs->opened) < 0) {
+ if (ffs->no_disconnect) {
+ struct ffs_epfile *epfiles;
+
+ ffs->state = FFS_DEACTIVATED;
+ epfiles = ffs->epfiles;
+ ffs->epfiles = NULL;
+ spin_unlock_irq(&ffs->eps_lock);
+
+ if (epfiles)
+ ffs_epfiles_destroy(ffs->sb, epfiles,
+ ffs->eps_count);
+
+ if (ffs->setup_state == FFS_SETUP_PENDING)
+ __ffs_ep0_stall(ffs);
+ } else {
ffs->state = FFS_CLOSING;
+ spin_unlock_irq(&ffs->eps_lock);
ffs_data_reset(ffs);
}
-
- ffs_data_put(ffs);
}
static struct ffs_data *ffs_data_new(const char *dev_name)
{
- struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL);
+ struct ffs_data *ffs = kzalloc_obj(*ffs);
if (!ffs)
return NULL;
@@ -2202,7 +2214,7 @@ static struct ffs_data *ffs_data_new(const char *dev_name)
}
refcount_set(&ffs->ref, 1);
- atomic_set(&ffs->opened, 0);
+ ffs->opened = 0;
ffs->state = FFS_READ_DESCRIPTORS;
mutex_init(&ffs->mutex);
spin_lock_init(&ffs->eps_lock);
@@ -2236,7 +2248,7 @@ static void ffs_data_clear(struct ffs_data *ffs)
* copy of epfile will save us from use-after-free.
*/
if (epfiles) {
- ffs_epfiles_destroy(epfiles, ffs->eps_count);
+ ffs_epfiles_destroy(ffs->sb, epfiles, ffs->eps_count);
ffs->epfiles = NULL;
}
@@ -2254,6 +2266,7 @@ static void ffs_data_reset(struct ffs_data *ffs)
{
ffs_data_clear(ffs);
+ spin_lock_irq(&ffs->eps_lock);
ffs->raw_descs_data = NULL;
ffs->raw_descs = NULL;
ffs->raw_strings = NULL;
@@ -2277,6 +2290,7 @@ static void ffs_data_reset(struct ffs_data *ffs)
ffs->ms_os_descs_ext_prop_count = 0;
ffs->ms_os_descs_ext_prop_name_len = 0;
ffs->ms_os_descs_ext_prop_data_len = 0;
+ spin_unlock_irq(&ffs->eps_lock);
}
@@ -2333,9 +2347,10 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
{
struct ffs_epfile *epfile, *epfiles;
unsigned i, count;
+ int err;
count = ffs->eps_count;
- epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL);
+ epfiles = kzalloc_objs(*epfiles, count);
if (!epfiles)
return -ENOMEM;
@@ -2349,12 +2364,11 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
sprintf(epfile->name, "ep%02x", ffs->eps_addrmap[i]);
else
sprintf(epfile->name, "ep%u", i);
- epfile->dentry = ffs_sb_create_file(ffs->sb, epfile->name,
- epfile,
- &ffs_epfile_operations);
- if (!epfile->dentry) {
- ffs_epfiles_destroy(epfiles, i - 1);
- return -ENOMEM;
+ err = ffs_sb_create_file(ffs->sb, epfile->name,
+ epfile, &ffs_epfile_operations);
+ if (err) {
+ ffs_epfiles_destroy(ffs->sb, epfiles, i - 1);
+ return err;
}
}
@@ -2362,17 +2376,20 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
return 0;
}
-static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
+static void clear_one(struct dentry *dentry)
+{
+ smp_store_release(&dentry->d_inode->i_private, NULL);
+}
+
+static void ffs_epfiles_destroy(struct super_block *sb,
+ struct ffs_epfile *epfiles, unsigned count)
{
struct ffs_epfile *epfile = epfiles;
+ struct dentry *root = sb->s_root;
for (; count; --count, ++epfile) {
BUG_ON(mutex_is_locked(&epfile->mutex));
- if (epfile->dentry) {
- d_delete(epfile->dentry);
- dput(epfile->dentry);
- epfile->dentry = NULL;
- }
+ simple_remove_by_name(root, epfile->name, clear_one);
}
kfree(epfiles);
@@ -2418,7 +2435,12 @@ static int ffs_func_eps_enable(struct ffs_function *func)
ep = func->eps;
epfile = ffs->epfiles;
count = ffs->eps_count;
- while(count--) {
+ if (!epfile) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ while (count--) {
ep->ep->driver_data = ep;
ret = config_ep_by_speed(func->gadget, &func->function, ep->ep);
@@ -2442,6 +2464,7 @@ static int ffs_func_eps_enable(struct ffs_function *func)
}
wake_up_interruptible(&ffs->wait);
+done:
spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
return ret;
@@ -3295,7 +3318,7 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
if (ffs_ep->descs[ep_desc_id]) {
pr_err("two %sspeed descriptors for EP %d\n",
speed_names[ep_desc_id],
- ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ usb_endpoint_num(ds));
return -EINVAL;
}
ffs_ep->descs[ep_desc_id] = ds;
@@ -3735,6 +3758,7 @@ static int ffs_func_set_alt(struct usb_function *f,
{
struct ffs_function *func = ffs_func_from_usb(f);
struct ffs_data *ffs = func->ffs;
+ unsigned long flags;
int ret = 0, intf;
if (alt > MAX_ALT_SETTINGS)
@@ -3747,12 +3771,15 @@ static int ffs_func_set_alt(struct usb_function *f,
if (ffs->func)
ffs_func_eps_disable(ffs->func);
+ spin_lock_irqsave(&ffs->eps_lock, flags);
if (ffs->state == FFS_DEACTIVATED) {
ffs->state = FFS_CLOSING;
+ spin_unlock_irqrestore(&ffs->eps_lock, flags);
INIT_WORK(&ffs->reset_work, ffs_reset_work);
schedule_work(&ffs->reset_work);
return -ENODEV;
}
+ spin_unlock_irqrestore(&ffs->eps_lock, flags);
if (ffs->state != FFS_ACTIVE)
return -ENODEV;
@@ -3770,16 +3797,20 @@ static void ffs_func_disable(struct usb_function *f)
{
struct ffs_function *func = ffs_func_from_usb(f);
struct ffs_data *ffs = func->ffs;
+ unsigned long flags;
if (ffs->func)
ffs_func_eps_disable(ffs->func);
+ spin_lock_irqsave(&ffs->eps_lock, flags);
if (ffs->state == FFS_DEACTIVATED) {
ffs->state = FFS_CLOSING;
+ spin_unlock_irqrestore(&ffs->eps_lock, flags);
INIT_WORK(&ffs->reset_work, ffs_reset_work);
schedule_work(&ffs->reset_work);
return;
}
+ spin_unlock_irqrestore(&ffs->eps_lock, flags);
if (ffs->state == FFS_ACTIVE) {
ffs->func = NULL;
@@ -3983,7 +4014,7 @@ static void ffs_attr_release(struct config_item *item)
usb_put_function_instance(&opts->func_inst);
}
-static struct configfs_item_operations ffs_item_ops = {
+static const struct configfs_item_operations ffs_item_ops = {
.release = ffs_attr_release,
};
@@ -4020,7 +4051,7 @@ static struct usb_function_instance *ffs_alloc_inst(void)
struct f_fs_opts *opts;
struct ffs_dev *dev;
- opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+ opts = kzalloc_obj(*opts);
if (!opts)
return ERR_PTR(-ENOMEM);
@@ -4096,7 +4127,7 @@ static struct usb_function *ffs_alloc(struct usb_function_instance *fi)
{
struct ffs_function *func;
- func = kzalloc(sizeof(*func), GFP_KERNEL);
+ func = kzalloc_obj(*func);
if (!func)
return ERR_PTR(-ENOMEM);
@@ -4127,7 +4158,7 @@ static struct ffs_dev *_ffs_alloc_dev(void)
if (_ffs_get_single_dev())
return ERR_PTR(-EBUSY);
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ dev = kzalloc_obj(*dev);
if (!dev)
return ERR_PTR(-ENOMEM);