Commit 687fcad8 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull rpmsg updates from Bjorn Andersson:
 "This contains a number of bug fixes to the GLINK transport driver, an
  off-by-one in the GLINK smem driver and a memory leak fix in the rpmsg
  char driver"

* tag 'rpmsg-v5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc:
  rpmsg: Fix Kconfig indentation
  rpmsg: char: Simplify 'rpmsg_eptdev_release()'
  rpmsg: glink: Free pending deferred work on remove
  rpmsg: glink: Don't send pending rx_done during remove
  rpmsg: glink: Fix rpmsg_register_device err handling
  rpmsg: glink: Put an extra reference during cleanup
  rpmsg: glink: Fix use after free in open_ack TIMEOUT case
  rpmsg: glink: Fix reuse intents memory leak issue
  rpmsg: glink: Set tail pointer to 0 at end of FIFO
  rpmsg: char: release allocated memory
parents 5e3b06d3 8cf9b615
Loading
Loading
Loading
Loading
+42 −11
Original line number Diff line number Diff line
@@ -241,10 +241,31 @@ static void qcom_glink_channel_release(struct kref *ref)
{
	struct glink_channel *channel = container_of(ref, struct glink_channel,
						     refcount);
	struct glink_core_rx_intent *intent;
	struct glink_core_rx_intent *tmp;
	unsigned long flags;
	int iid;

	/* cancel pending rx_done work */
	cancel_work_sync(&channel->intent_work);

	spin_lock_irqsave(&channel->intent_lock, flags);
	/* Free all non-reuse intents pending rx_done work */
	list_for_each_entry_safe(intent, tmp, &channel->done_intents, node) {
		if (!intent->reuse) {
			kfree(intent->data);
			kfree(intent);
		}
	}

	idr_for_each_entry(&channel->liids, tmp, iid) {
		kfree(tmp->data);
		kfree(tmp);
	}
	idr_destroy(&channel->liids);

	idr_for_each_entry(&channel->riids, tmp, iid)
		kfree(tmp);
	idr_destroy(&channel->riids);
	spin_unlock_irqrestore(&channel->intent_lock, flags);

@@ -1094,13 +1115,12 @@ static int qcom_glink_create_remote(struct qcom_glink *glink,
close_link:
	/*
	 * Send a close request to "undo" our open-ack. The close-ack will
	 * release the last reference.
	 * release qcom_glink_send_open_req() reference and the last reference
	 * will be relesed after receiving remote_close or transport unregister
	 * by calling qcom_glink_native_remove().
	 */
	qcom_glink_send_close_req(glink, channel);

	/* Release qcom_glink_send_open_req() reference */
	kref_put(&channel->refcount, qcom_glink_channel_release);

	return ret;
}

@@ -1415,15 +1435,13 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,

		ret = rpmsg_register_device(rpdev);
		if (ret)
			goto free_rpdev;
			goto rcid_remove;

		channel->rpdev = rpdev;
	}

	return 0;

free_rpdev:
	kfree(rpdev);
rcid_remove:
	spin_lock_irqsave(&glink->idr_lock, flags);
	idr_remove(&glink->rcids, channel->rcid);
@@ -1544,6 +1562,18 @@ static void qcom_glink_work(struct work_struct *work)
	}
}

static void qcom_glink_cancel_rx_work(struct qcom_glink *glink)
{
	struct glink_defer_cmd *dcmd;
	struct glink_defer_cmd *tmp;

	/* cancel any pending deferred rx_work */
	cancel_work_sync(&glink->rx_work);

	list_for_each_entry_safe(dcmd, tmp, &glink->rx_queue, node)
		kfree(dcmd);
}

struct qcom_glink *qcom_glink_native_probe(struct device *dev,
					   unsigned long features,
					   struct qcom_glink_pipe *rx,
@@ -1619,23 +1649,24 @@ void qcom_glink_native_remove(struct qcom_glink *glink)
	struct glink_channel *channel;
	int cid;
	int ret;
	unsigned long flags;

	disable_irq(glink->irq);
	cancel_work_sync(&glink->rx_work);
	qcom_glink_cancel_rx_work(glink);

	ret = device_for_each_child(glink->dev, NULL, qcom_glink_remove_device);
	if (ret)
		dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret);

	spin_lock_irqsave(&glink->idr_lock, flags);
	/* Release any defunct local channels, waiting for close-ack */
	idr_for_each_entry(&glink->lcids, channel, cid)
		kref_put(&channel->refcount, qcom_glink_channel_release);

	/* Release any defunct local channels, waiting for close-req */
	idr_for_each_entry(&glink->rcids, channel, cid)
		kref_put(&channel->refcount, qcom_glink_channel_release);

	idr_destroy(&glink->lcids);
	idr_destroy(&glink->rcids);
	spin_unlock_irqrestore(&glink->idr_lock, flags);
	mbox_free_channel(glink->mbox_chan);
}
EXPORT_SYMBOL_GPL(qcom_glink_native_remove);
+1 −1
Original line number Diff line number Diff line
@@ -105,7 +105,7 @@ static void glink_smem_rx_advance(struct qcom_glink_pipe *np,
	tail = le32_to_cpu(*pipe->tail);

	tail += count;
	if (tail > pipe->native.length)
	if (tail >= pipe->native.length)
		tail -= pipe->native.length;

	*pipe->tail = cpu_to_le32(tail);
+5 −7
Original line number Diff line number Diff line
@@ -146,7 +146,6 @@ static int rpmsg_eptdev_release(struct inode *inode, struct file *filp)
{
	struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev);
	struct device *dev = &eptdev->dev;
	struct sk_buff *skb;

	/* Close the endpoint, if it's not already destroyed by the parent */
	mutex_lock(&eptdev->ept_lock);
@@ -157,10 +156,7 @@ static int rpmsg_eptdev_release(struct inode *inode, struct file *filp)
	mutex_unlock(&eptdev->ept_lock);

	/* Discard all SKBs */
	while (!skb_queue_empty(&eptdev->queue)) {
		skb = skb_dequeue(&eptdev->queue);
		kfree_skb(skb);
	}
	skb_queue_purge(&eptdev->queue);

	put_device(dev);

@@ -227,8 +223,10 @@ static ssize_t rpmsg_eptdev_write_iter(struct kiocb *iocb,
	if (!kbuf)
		return -ENOMEM;

	if (!copy_from_iter_full(kbuf, len, from))
		return -EFAULT;
	if (!copy_from_iter_full(kbuf, len, from)) {
		ret = -EFAULT;
		goto free_kbuf;
	}

	if (mutex_lock_interruptible(&eptdev->ept_lock)) {
		ret = -ERESTARTSYS;
+1 −1

File changed.

Contains only whitespace changes.