Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f50e39e1 authored by Manu Gautam's avatar Manu Gautam
Browse files

usb: gadget: f_mtp: Optimize usage of read_mutex



Driver currently acquires and releases read_mutex multiple
times during single file transfer operation resulting in
throughput degradation. Fix this by holding mutex for
longer times without releasing it as it is perfectly fine
to call usb_ep_queue() while holding a mutex.

Change-Id: Ic235fb92997993bd75ed5e519a5d73e787522810
Signed-off-by: default avatarManu Gautam <mgautam@codeaurora.org>
Signed-off-by: default avatarUdipto Goswami <ugoswami@codeaurora.org>
parent 16232cca
Loading
Loading
Loading
Loading
+8 −31
Original line number Diff line number Diff line
@@ -607,12 +607,11 @@ static ssize_t mtp_read(struct file *fp, char __user *buf,
	mtp_log("(%zu) state:%d\n", count, dev->state);

	/* we will block until we're online */
	mtp_log("waiting for online state\n");
	ret = wait_event_interruptible(dev->read_wq,
		dev->state != STATE_OFFLINE);
	if (ret < 0) {
		r = ret;
		goto done;
		goto wait_err;
	}

	len = ALIGN(count, dev->ep_out->maxpacket);
@@ -650,7 +649,6 @@ static ssize_t mtp_read(struct file *fp, char __user *buf,
	mutex_lock(&dev->read_mutex);
	if (dev->state == STATE_OFFLINE) {
		r = -EIO;
		mutex_unlock(&dev->read_mutex);
		goto done;
	}
requeue_req:
@@ -658,7 +656,6 @@ static ssize_t mtp_read(struct file *fp, char __user *buf,
	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;
@@ -684,7 +681,6 @@ static ssize_t mtp_read(struct file *fp, char __user *buf,
		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)
@@ -698,8 +694,9 @@ static ssize_t mtp_read(struct file *fp, char __user *buf,
	} else
		r = -EIO;

	mutex_unlock(&dev->read_mutex);
done:
	mutex_unlock(&dev->read_mutex);
wait_err:
	spin_lock_irq(&dev->lock);
	if (dev->state == STATE_CANCELED)
		r = -ECANCELED;
@@ -943,15 +940,9 @@ static void receive_file_work(struct work_struct *data)
	if (!IS_ALIGNED(count, dev->ep_out->maxpacket))
		mtp_log("- count(%lld) not multiple of mtu(%d)\n",
						count, dev->ep_out->maxpacket);

	mutex_lock(&dev->read_mutex);
	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;
@@ -960,7 +951,6 @@ 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;
@@ -973,25 +963,17 @@ static void receive_file_work(struct work_struct *data)
		if (write_req) {
			mtp_log("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);
			mtp_log("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;
				if (read_req && !dev->rx_done)
					usb_ep_dequeue(dev->ep_out, read_req);
				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;
@@ -1019,12 +1001,6 @@ 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 ?
@@ -1045,10 +1021,9 @@ static void receive_file_work(struct work_struct *data)

			write_req = read_req;
			read_req = NULL;
			mutex_unlock(&dev->read_mutex);
		}
	}

	mutex_unlock(&dev->read_mutex);
	mtp_log("returning %d\n", r);
	/* write the result */
	dev->xfer_result = r;
@@ -1501,6 +1476,7 @@ mtp_function_unbind(struct usb_configuration *c, struct usb_function *f)
	fi_mtp = container_of(f->fi, struct mtp_instance, func_inst);
	mtp_string_defs[INTERFACE_STRING_INDEX].id = 0;
	mtp_log("dev: %pK\n", dev);

	mutex_lock(&dev->read_mutex);
	while ((req = mtp_req_get(dev, &dev->tx_idle)))
		mtp_request_free(req, dev->ep_in);
@@ -1508,11 +1484,12 @@ mtp_function_unbind(struct usb_configuration *c, struct usb_function *f)
		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);
	spin_lock_irq(&dev->lock);
	dev->state = STATE_OFFLINE;
	dev->cdev = NULL;
	spin_unlock_irq(&dev->lock);
	mutex_unlock(&dev->read_mutex);

	kfree(f->os_desc_table);
	f->os_desc_n = 0;
	fi_mtp->func_inst.f = NULL;