net: qrtr: add resume tx logging

Add xarray database to log both skb allocation failed packets
and skb allocation success packets when cf flag bit is set in
the packet.

Change-Id: Iafc4c781e7fde37b8d19fc050dc9d769b31c306e
Signed-off-by: Sivaji Boddupilli <quic_boddupil@quicinc.com>
This commit is contained in:
Sivaji Boddupilli 2022-04-19 23:14:39 +05:30
parent e22e825e65
commit 4f7bb0f17b
5 changed files with 277 additions and 4 deletions

View File

@ -67,4 +67,12 @@ config QRTR_GUNYAH
Router communication between two virtual machines. The transport
uses dynamically shared memory and gunyah doorbells.
config QRTR_DEBUG
bool "QRTR debug enhancements"
help
Say Y here to enable QRTR debug enhancements support and currently
supporting logging of resume tx failure cases when skb alloc failed
and confirm rx flag is set. Also logging the skb alloc failure
while allocating skb in rx path.
endif # QRTR

View File

@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_QRTR) := qrtr.o ns.o
obj-$(CONFIG_QRTR) += qrtr.o
qrtr-y := af_qrtr.o ns.o
qrtr-$(CONFIG_QRTR_DEBUG) += debug.o
obj-$(CONFIG_QRTR_SMD) += qrtr-smd.o
qrtr-smd-y := smd.o
obj-$(CONFIG_QRTR_TUN) += qrtr-tun.o

View File

@ -2,6 +2,7 @@
/*
* Copyright (c) 2015, Sony Mobile Communications Inc.
* Copyright (c) 2013, 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/kthread.h>
#include <linux/module.h>
@ -20,6 +21,7 @@
#include <uapi/linux/sched/types.h>
#include "qrtr.h"
#include "debug.h"
#define QRTR_LOG_PAGE_CNT 4
#define QRTR_INFO(ctx, x, ...) \
@ -872,6 +874,7 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len)
if (!skb) {
skb = qrtr_get_backup(len);
if (!skb) {
qrtr_log_skb_failure(data, len);
pr_err("qrtr: Unable to get skb with len:%lu\n", len);
return -ENOMEM;
}
@ -944,6 +947,8 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len)
qrtr_node_assign(node, le32_to_cpu(pkt->server.node));
}
if (cb->confirm_rx)
qrtr_log_resume_tx(cb->src_node, cb->src_port, RTX_SKB_ALLOC_SUCC);
qrtr_log_rx_msg(node, skb);
/* All control packets and non-local destined data packets should be
* queued to the worker for forwarding handling.
@ -1329,7 +1334,7 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
/* Wake up any transmitters waiting for resume-tx from the node */
wake_up_interruptible_all(&node->resume_tx);
qrtr_log_resume_tx_node_erase(node->nid);
qrtr_node_release(node);
ep->node = NULL;
}
@ -1383,6 +1388,9 @@ static void qrtr_send_del_client(struct qrtr_sock *ipc)
pkt->client.node = cpu_to_le32(ipc->us.sq_node);
pkt->client.port = cpu_to_le32(ipc->us.sq_port);
qrtr_log_resume_tx(pkt->client.node, pkt->client.port,
RTX_REMOVE_RECORD);
skb_set_owner_w(skb, &ipc->sk);
if (ipc->state == QRTR_STATE_MULTI) {
@ -1788,6 +1796,8 @@ static int qrtr_send_resume_tx(struct qrtr_cb *cb)
skb = qrtr_alloc_ctrl_packet(&pkt);
if (!skb) {
qrtr_log_resume_tx(cb->src_node, cb->src_port,
RTX_CTRL_SKB_ALLOC_FAIL);
qrtr_node_release(node);
return -ENOMEM;
}
@ -1798,7 +1808,7 @@ static int qrtr_send_resume_tx(struct qrtr_cb *cb)
ret = qrtr_node_enqueue(node, skb, QRTR_TYPE_RESUME_TX,
&local, &remote, 0);
qrtr_log_resume_tx(cb->src_node, cb->src_port, RTX_SENT_ACK);
qrtr_node_release(node);
return ret;
@ -2081,6 +2091,7 @@ static int __init qrtr_proto_init(void)
qrtr_ns_init();
qrtr_backup_init();
qrtr_debug_init();
return rc;
}
@ -2093,6 +2104,7 @@ static void __exit qrtr_proto_fini(void)
proto_unregister(&qrtr_proto);
qrtr_backup_deinit();
qrtr_debug_remove();
}
module_exit(qrtr_proto_fini);

200
net/qrtr/debug.c Normal file
View File

@ -0,0 +1,200 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/xarray.h>
#include <linux/list.h>
#include "debug.h"
static LIST_HEAD(rtx_pkt_list);
static DEFINE_SPINLOCK(rtx_pkt_list_lock);
static DEFINE_XARRAY(rtx_records);
static DEFINE_MUTEX(rtx_records_lock);
static struct work_struct rtx_work;
#define QRTR_FLAGS_CONFIRM_RX BIT(0)
#define QRTR_PROTO_VER_1 1
#define QRTR_PROTO_VER_2 3
struct qrtr_hdr_v1 {
__le32 version;
__le32 type;
__le32 src_node_id;
__le32 src_port_id;
__le32 confirm_rx;
__le32 size;
__le32 dst_node_id;
__le32 dst_port_id;
} __packed;
struct qrtr_hdr_v2 {
u8 version;
u8 type;
u8 flags;
u8 optlen;
__le32 size;
__le16 src_node_id;
__le16 src_port_id;
__le16 dst_node_id;
__le16 dst_port_id;
};
struct qrtr_rtx_record {
u8 state;
unsigned long key;
struct timespec64 time;
};
struct qrtr_rtx_pkt {
u8 state;
unsigned long key;
struct list_head item;
};
void qrtr_log_resume_tx_node_erase(unsigned int node_id)
{
unsigned long index;
struct qrtr_rtx_record *record;
mutex_lock(&rtx_records_lock);
xa_for_each(&rtx_records, index, record) {
if ((record->key >> 32) == node_id &&
record->state != RTX_UNREG_NODE) {
xa_erase(&rtx_records, record->key);
kfree(record);
}
}
mutex_unlock(&rtx_records_lock);
qrtr_log_resume_tx(node_id, 0, RTX_UNREG_NODE);
}
EXPORT_SYMBOL(qrtr_log_resume_tx_node_erase);
static void qrtr_update_record(unsigned long key, u8 state)
{
struct qrtr_rtx_record *record;
mutex_lock(&rtx_records_lock);
record = xa_load(&rtx_records, key);
if (!record) {
record = kzalloc(sizeof(*record), GFP_KERNEL);
if (!record) {
mutex_unlock(&rtx_records_lock);
return;
}
record->key = key;
record->state = state;
ktime_get_ts64(&record->time);
xa_store(&rtx_records, record->key, record, GFP_KERNEL);
mutex_unlock(&rtx_records_lock);
return;
}
if (record->state == RTX_REMOVE_RECORD) {
xa_erase(&rtx_records, record->key);
mutex_unlock(&rtx_records_lock);
kfree(record);
return;
}
record->state = state;
ktime_get_ts64(&record->time);
mutex_unlock(&rtx_records_lock);
}
static void qrtr_rtx_work(struct work_struct *work)
{
struct qrtr_rtx_pkt *pkt, *tmp;
unsigned long flags;
spin_lock_irqsave(&rtx_pkt_list_lock, flags);
list_for_each_entry_safe(pkt, tmp, &rtx_pkt_list, item) {
list_del(&pkt->item);
spin_unlock_irqrestore(&rtx_pkt_list_lock, flags);
qrtr_update_record(pkt->key, pkt->state);
kfree(pkt);
spin_lock_irqsave(&rtx_pkt_list_lock, flags);
}
spin_unlock_irqrestore(&rtx_pkt_list_lock, flags);
}
int qrtr_log_resume_tx(unsigned int node_id,
unsigned int port_id, u8 state)
{
struct qrtr_rtx_pkt *pkt;
unsigned long flags;
pkt = kzalloc(sizeof(*pkt), GFP_ATOMIC);
if (!pkt)
return -ENOMEM;
pkt->state = state;
pkt->key = ((u64)node_id << 32 | port_id);
spin_lock_irqsave(&rtx_pkt_list_lock, flags);
list_add(&pkt->item, &rtx_pkt_list);
spin_unlock_irqrestore(&rtx_pkt_list_lock, flags);
schedule_work(&rtx_work);
return 0;
}
EXPORT_SYMBOL(qrtr_log_resume_tx);
void qrtr_log_skb_failure(const void *data, size_t len)
{
const struct qrtr_hdr_v1 *v1;
const struct qrtr_hdr_v2 *v2;
bool confirm_rx = false;
unsigned int node_id;
unsigned int port_id;
unsigned int ver;
ver = *(u8 *)data;
if (ver == QRTR_PROTO_VER_1 && len > sizeof(*v1)) {
v1 = data;
if (v1->confirm_rx) {
node_id = v1->src_port_id;
port_id = v1->src_port_id;
confirm_rx = true;
}
} else if (ver == QRTR_PROTO_VER_2 && len > sizeof(*v2)) {
v2 = data;
if (v2->flags & QRTR_FLAGS_CONFIRM_RX) {
node_id = v2->src_node_id;
port_id = v2->src_port_id;
confirm_rx = true;
}
} else {
pr_err("%s: Invalid version %d\n", __func__, ver);
}
if (confirm_rx)
qrtr_log_resume_tx(node_id, port_id,
RTX_SKB_ALLOC_FAIL);
}
EXPORT_SYMBOL(qrtr_log_skb_failure);
void qrtr_debug_init(void)
{
INIT_WORK(&rtx_work, qrtr_rtx_work);
}
EXPORT_SYMBOL(qrtr_debug_init);
void qrtr_debug_remove(void)
{
cancel_work_sync(&rtx_work);
}
EXPORT_SYMBOL(qrtr_debug_remove);
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. QRTR debug");
MODULE_LICENSE("GPL v2");

52
net/qrtr/debug.h Normal file
View File

@ -0,0 +1,52 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef __QRTR_DEBUG_H_
#define __QRTR_DEBUG_H_
#include <linux/types.h>
enum {
RTX_REMOVE_RECORD = 0xFF,
RTX_SKB_ALLOC_FAIL = 0xAA,
RTX_SKB_ALLOC_SUCC = 0xBB,
RTX_SENT_ACK = 0xCC,
RTX_CTRL_SKB_ALLOC_FAIL = 0xDD,
RTX_UNREG_NODE = 0xEE,
};
#if IS_ENABLED(CONFIG_QRTR_DEBUG)
void qrtr_debug_init(void);
void qrtr_debug_remove(void);
void qrtr_log_resume_tx_node_erase(unsigned int node_id);
int qrtr_log_resume_tx(unsigned int node_id,
unsigned int port_id, u8 state);
void qrtr_log_skb_failure(const void *data, size_t len);
#else
static inline void qrtr_debug_init(void) { }
static inline void qrtr_debug_remove(void) { }
static inline void qrtr_log_resume_tx_node_erase(unsigned int node_id) { }
static inline int qrtr_log_resume_tx(unsigned int node_id,
unsigned int port_id, u8 state)
{
return 0;
}
static inline void qrtr_log_skb_failure(const void *data, size_t len) { }
#endif
#endif