diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2017-03-03 17:39:17 -0800 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2017-03-03 17:39:16 -0800 |
commit | 9b591f82cc92de67c57d0c30ae38def284572611 (patch) | |
tree | bdffb367ca0761c722629ed56eec5570d9624bed /drivers/usb | |
parent | 9067d4454d1c6fc6130d41df3d48c2191061faa3 (diff) | |
parent | 25ddcc7b1e2ef719eb23717e72eaedc630841c9c (diff) |
Merge "USB: f_mtp: Perform vfs_write under mutex protection"
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/gadget/function/f_mtp.c | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c index 972ea68b16e4..de648b0ae2b8 100644 --- a/drivers/usb/gadget/function/f_mtp.c +++ b/drivers/usb/gadget/function/f_mtp.c @@ -137,6 +137,7 @@ struct mtp_dev { unsigned dbg_read_index; unsigned dbg_write_index; bool is_ptp; + struct mutex read_mutex; }; static struct usb_interface_descriptor mtp_interface_desc = { @@ -640,11 +641,18 @@ static ssize_t mtp_read(struct file *fp, char __user *buf, dev->state = STATE_BUSY; spin_unlock_irq(&dev->lock); + mutex_lock(&dev->read_mutex); + if (dev->state == STATE_OFFLINE) { + r = -EIO; + mutex_unlock(&dev->read_mutex); + goto done; + } requeue_req: /* queue a request */ req = dev->rx_req[0]; req->length = len; dev->rx_done = 0; + mutex_unlock(&dev->read_mutex); ret = usb_ep_queue(dev->ep_out, req, GFP_KERNEL); if (ret < 0) { r = -EIO; @@ -670,6 +678,7 @@ requeue_req: usb_ep_dequeue(dev->ep_out, req); goto done; } + mutex_lock(&dev->read_mutex); if (dev->state == STATE_BUSY) { /* If we got a 0-len packet, throw it back and try again. */ if (req->actual == 0) @@ -683,6 +692,7 @@ requeue_req: } else r = -EIO; + mutex_unlock(&dev->read_mutex); done: spin_lock_irq(&dev->lock); if (dev->state == STATE_CANCELED) @@ -937,6 +947,12 @@ static void receive_file_work(struct work_struct *data) while (count > 0 || write_req) { if (count > 0) { + mutex_lock(&dev->read_mutex); + if (dev->state == STATE_OFFLINE) { + r = -EIO; + mutex_unlock(&dev->read_mutex); + break; + } /* queue a request */ read_req = dev->rx_req[cur_buf]; cur_buf = (cur_buf + 1) % RX_REQ_MAX; @@ -945,6 +961,7 @@ static void receive_file_work(struct work_struct *data) read_req->length = mtp_rx_req_len; dev->rx_done = 0; + mutex_unlock(&dev->read_mutex); ret = usb_ep_queue(dev->ep_out, read_req, GFP_KERNEL); if (ret < 0) { r = -EIO; @@ -957,15 +974,23 @@ static void receive_file_work(struct work_struct *data) if (write_req) { DBG(cdev, "rx %pK %d\n", write_req, write_req->actual); start_time = ktime_get(); + mutex_lock(&dev->read_mutex); + if (dev->state == STATE_OFFLINE) { + r = -EIO; + mutex_unlock(&dev->read_mutex); + break; + } ret = vfs_write(filp, write_req->buf, write_req->actual, &offset); DBG(cdev, "vfs_write %d\n", ret); if (ret != write_req->actual) { r = -EIO; + mutex_unlock(&dev->read_mutex); if (dev->state != STATE_OFFLINE) dev->state = STATE_ERROR; break; } + mutex_unlock(&dev->read_mutex); dev->perf[dev->dbg_write_index].vfs_wtime = ktime_to_us(ktime_sub(ktime_get(), start_time)); dev->perf[dev->dbg_write_index].vfs_wbytes = ret; @@ -989,6 +1014,12 @@ static void receive_file_work(struct work_struct *data) break; } + mutex_lock(&dev->read_mutex); + if (dev->state == STATE_OFFLINE) { + r = -EIO; + mutex_unlock(&dev->read_mutex); + break; + } /* Check if we aligned the size due to MTU constraint */ if (count < read_req->length) read_req->actual = (read_req->actual > count ? @@ -1009,6 +1040,7 @@ static void receive_file_work(struct work_struct *data) write_req = read_req; read_req = NULL; + mutex_unlock(&dev->read_mutex); } } @@ -1469,12 +1501,14 @@ mtp_function_unbind(struct usb_configuration *c, struct usb_function *f) struct usb_request *req; int i; + mutex_lock(&dev->read_mutex); while ((req = mtp_req_get(dev, &dev->tx_idle))) mtp_request_free(req, dev->ep_in); for (i = 0; i < RX_REQ_MAX; i++) mtp_request_free(dev->rx_req[i], dev->ep_out); while ((req = mtp_req_get(dev, &dev->intr_idle))) mtp_request_free(req, dev->ep_intr); + mutex_unlock(&dev->read_mutex); dev->state = STATE_OFFLINE; dev->is_ptp = false; kfree(f->os_desc_table); @@ -1877,6 +1911,7 @@ struct usb_function *function_alloc_mtp_ptp(struct usb_function_instance *fi, dev->is_ptp = !mtp_config; fi->f = &dev->function; + mutex_init(&dev->read_mutex); return &dev->function; } EXPORT_SYMBOL_GPL(function_alloc_mtp_ptp); |