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

Commit d6a847bc authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "USB: f_mtp: Perform vfs_write under mutex protection"

parents 824c0c41 b28d3e89
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
@@ -137,6 +137,7 @@ struct mtp_dev {
	} perf[MAX_ITERATION];
	unsigned int dbg_read_index;
	unsigned int dbg_write_index;
	struct mutex  read_mutex;
};

static struct usb_interface_descriptor mtp_interface_desc = {
@@ -626,11 +627,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;
@@ -656,6 +664,7 @@ 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)
@@ -669,6 +678,7 @@ static ssize_t mtp_read(struct file *fp, char __user *buf,
	} else
		r = -EIO;

	mutex_unlock(&dev->read_mutex);
done:
	spin_lock_irq(&dev->lock);
	if (dev->state == STATE_CANCELED)
@@ -920,6 +930,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;
@@ -928,6 +944,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;
@@ -940,15 +957,23 @@ static void receive_file_work(struct work_struct *data)
		if (write_req) {
			DBG(cdev, "rx %p %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;
@@ -976,6 +1001,13 @@ static void receive_file_work(struct work_struct *data)
				r = read_req->status;
				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 ?
@@ -996,6 +1028,7 @@ static void receive_file_work(struct work_struct *data)

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

@@ -1446,12 +1479,14 @@ mtp_function_unbind(struct usb_configuration *c, struct usb_function *f)
	int i;

	mtp_string_defs[INTERFACE_STRING_INDEX].id = 0;
	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;
	kfree(f->os_desc_table);
	f->os_desc_n = 0;
@@ -1852,6 +1887,7 @@ struct usb_function *function_alloc_mtp_ptp(struct usb_function_instance *fi,
	dev->function.free_func = mtp_free;
	fi->f = &dev->function;

	mutex_init(&dev->read_mutex);
	return &dev->function;
}
EXPORT_SYMBOL_GPL(function_alloc_mtp_ptp);