net: qrtr: Move tx_resume handling to work context

There will be non-atomic work associated with receiving the tx resume
packet from the remote. Move the handling to work function context in
preparation for the non-blocking socket blocking improvement.

In system heavy load cases the rx work queued in global worker queue is
getting delayed and causing clients request timeouts.

Create and use separate worker thread to process qrtr rx packets.

Change-Id: I2389bdcffba068258650bfbb579f8cb98a0ac928
Signed-off-by: Chris Lew <quic_clew@quicinc.com>
This commit is contained in:
Chris Lew 2022-10-11 13:33:51 -07:00
parent ed4fba13e9
commit c742a81975

View File

@ -4,6 +4,7 @@
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/netlink.h>
#include <linux/qrtr.h>
@ -136,6 +137,9 @@ static DEFINE_SPINLOCK(qrtr_port_lock);
* @hello_sent: hello packet sent to endpoint
* @rx_queue: receive queue
* @item: list item for broadcast list
* @kworker: worker thread for recv work
* @task: task to run the worker thread
* @read_data: scheduled work for recv work
*/
struct qrtr_node {
struct mutex ep_lock;
@ -149,6 +153,10 @@ struct qrtr_node {
struct sk_buff_head rx_queue;
struct list_head item;
struct kthread_worker kworker;
struct task_struct *task;
struct kthread_work read_data;
};
/**
@ -227,6 +235,8 @@ static void __qrtr_node_release(struct kref *kref)
list_del(&node->item);
up_write(&qrtr_epts_lock);
kthread_flush_worker(&node->kworker);
kthread_stop(node->task);
skb_queue_purge(&node->rx_queue);
/* Free tx flow counters */
@ -235,6 +245,7 @@ static void __qrtr_node_release(struct kref *kref)
radix_tree_iter_delete(&node->qrtr_tx_flow, &iter, slot);
kfree(flow);
}
kfree(node);
}
@ -620,7 +631,8 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len)
}
if (cb->type == QRTR_TYPE_RESUME_TX) {
qrtr_tx_resume(node, skb);
skb_queue_tail(&node->rx_queue, skb);
kthread_queue_work(&node->kworker, &node->read_data);
} else {
ipc = qrtr_port_lookup(cb->dst_port);
if (!ipc) {
@ -671,6 +683,21 @@ static struct sk_buff *qrtr_alloc_ctrl_packet(struct qrtr_ctrl_pkt **pkt,
return skb;
}
/* Handle not atomic operations for a received packet. */
static void qrtr_node_rx_work(struct kthread_work *work)
{
struct qrtr_node *node = container_of(work, struct qrtr_node,
read_data);
struct sk_buff *skb;
while ((skb = skb_dequeue(&node->rx_queue)) != NULL) {
struct qrtr_cb *cb = (struct qrtr_cb *)skb->cb;
if (cb->type == QRTR_TYPE_RESUME_TX)
qrtr_tx_resume(node, skb);
}
}
/**
* qrtr_endpoint_register() - register a new endpoint
* @ep: endpoint to register
@ -697,6 +724,14 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid)
node->ep = ep;
atomic_set(&node->hello_sent, 0);
kthread_init_work(&node->read_data, qrtr_node_rx_work);
kthread_init_worker(&node->kworker);
node->task = kthread_run(kthread_worker_fn, &node->kworker, "qrtr_rx");
if (IS_ERR(node->task)) {
kfree(node);
return -ENOMEM;
}
INIT_RADIX_TREE(&node->qrtr_tx_flow, GFP_KERNEL);
mutex_init(&node->qrtr_tx_lock);