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

Commit 3944d87b authored by Chris Lew's avatar Chris Lew
Browse files

net: qrtr: Rearrange tx wait and protect critical section



Check tx wait conditions before entering wait. This helps threads with
pending signals finish their tx's instead of returning ERESTARTSYS.

Make checking the flow count and subsequent waiter operations an atomic
operation. The waiter list and flow count are modified on the tx and rx
threads which opens it to race conditions.

Change-Id: I7cba0e70d8e1760ed2d8cece6404b995721bdcc9
Signed-off-by: default avatarChris Lew <clew@codeaurora.org>
parent f70ca804
Loading
Loading
Loading
Loading
+22 −25
Original line number Diff line number Diff line
@@ -383,10 +383,10 @@ static void qrtr_tx_resume(struct qrtr_node *node, struct sk_buff *skb)
	if (!flow)
		return;

	mutex_lock(&node->qrtr_tx_lock);
	atomic_set(&flow->pending, 0);
	wake_up_interruptible_all(&node->resume_tx);

	mutex_lock(&node->qrtr_tx_lock);
	list_for_each_entry_safe(waiter, temp, &flow->waiters, node) {
		list_del(&waiter->node);
		skbn = alloc_skb(0, GFP_KERNEL);
@@ -446,20 +446,8 @@ static int qrtr_tx_wait(struct qrtr_node *node, struct sockaddr_qrtr *to,
	}
	mutex_unlock(&node->qrtr_tx_lock);

	ret = timeo;
	for (;;) {
		ret = wait_event_interruptible_timeout(
				node->resume_tx,
				!node->ep ||
				atomic_read(&flow->pending) < QRTR_TX_FLOW_HIGH,
				timeo);
		if (ret < 0)
			return ret;
		if (!ret)
			return -EAGAIN;

		if (!node->ep)
			return -EPIPE;

		mutex_lock(&node->qrtr_tx_lock);
		if (atomic_read(&flow->pending) < QRTR_TX_FLOW_HIGH) {
			atomic_inc(&flow->pending);
@@ -468,19 +456,28 @@ static int qrtr_tx_wait(struct qrtr_node *node, struct sockaddr_qrtr *to,
			mutex_unlock(&node->qrtr_tx_lock);
			break;
		}
		mutex_unlock(&node->qrtr_tx_lock);
	}

	if (confirm_rx) {
		if (!ret) {
			waiter = kzalloc(sizeof(*waiter), GFP_KERNEL);
		if (!waiter)
			if (!waiter) {
				mutex_unlock(&node->qrtr_tx_lock);
				return -ENOMEM;
			}
			waiter->sk = sk;
			sock_hold(sk);

		mutex_lock(&node->qrtr_tx_lock);
			list_add_tail(&waiter->node, &flow->waiters);
			mutex_unlock(&node->qrtr_tx_lock);
			return -EAGAIN;
		}
		mutex_unlock(&node->qrtr_tx_lock);

		ret = wait_event_interruptible_timeout(node->resume_tx,
				!node->ep ||
				atomic_read(&flow->pending) < QRTR_TX_FLOW_HIGH,
				timeo);
		if (ret < 0)
			return ret;
		if (!node->ep)
			return -EPIPE;
	}
	return confirm_rx;
}