net: qrtr: Add backup skb pool

Add a pool of SKBs that can be used when the system is in low memory
conditions. This pool will be shared between all nodes and replenished
by a worker function.

Change-Id: I639a9ac76db726dc8ad46b12d3b3d560c674939c
Signed-off-by: Jay Jayanna <jayanna@codeaurora.org>
Signed-off-by: Chris Lew <quic_clew@quicinc.com>
This commit is contained in:
Chris Lew 2022-10-27 11:07:38 -07:00
parent 08de359d99
commit a34e1c5cea

View File

@ -127,6 +127,15 @@ static DEFINE_XARRAY_ALLOC(qrtr_ports);
u32 qrtr_ports_next = QRTR_MIN_EPH_SOCKET;
static DEFINE_SPINLOCK(qrtr_port_lock);
/* backup buffers */
#define QRTR_BACKUP_HI_NUM 5
#define QRTR_BACKUP_HI_SIZE SZ_16K
#define QRTR_BACKUP_LO_NUM 20
#define QRTR_BACKUP_LO_SIZE SZ_1K
static struct sk_buff_head qrtr_backup_lo;
static struct sk_buff_head qrtr_backup_hi;
static struct work_struct qrtr_backup_work;
/**
* struct qrtr_node - endpoint node
* @ep_lock: lock for endpoint management and callbacks
@ -552,6 +561,59 @@ int qrtr_peek_pkt_size(const void *data)
}
EXPORT_SYMBOL(qrtr_peek_pkt_size);
static void qrtr_alloc_backup(struct work_struct *work)
{
struct sk_buff *skb;
int errcode;
while (skb_queue_len(&qrtr_backup_lo) < QRTR_BACKUP_LO_NUM) {
skb = alloc_skb_with_frags(sizeof(struct qrtr_hdr_v1),
QRTR_BACKUP_LO_SIZE, 0, &errcode,
GFP_KERNEL);
if (!skb)
break;
skb_queue_tail(&qrtr_backup_lo, skb);
}
while (skb_queue_len(&qrtr_backup_hi) < QRTR_BACKUP_HI_NUM) {
skb = alloc_skb_with_frags(sizeof(struct qrtr_hdr_v1),
QRTR_BACKUP_HI_SIZE, 0, &errcode,
GFP_KERNEL);
if (!skb)
break;
skb_queue_tail(&qrtr_backup_hi, skb);
}
}
static struct sk_buff *qrtr_get_backup(size_t len)
{
struct sk_buff *skb = NULL;
if (len < QRTR_BACKUP_LO_SIZE)
skb = skb_dequeue(&qrtr_backup_lo);
else if (len < QRTR_BACKUP_HI_SIZE)
skb = skb_dequeue(&qrtr_backup_hi);
if (skb)
queue_work(system_unbound_wq, &qrtr_backup_work);
return skb;
}
static void qrtr_backup_init(void)
{
skb_queue_head_init(&qrtr_backup_lo);
skb_queue_head_init(&qrtr_backup_hi);
INIT_WORK(&qrtr_backup_work, qrtr_alloc_backup);
queue_work(system_unbound_wq, &qrtr_backup_work);
}
static void qrtr_backup_deinit(void)
{
cancel_work_sync(&qrtr_backup_work);
skb_queue_purge(&qrtr_backup_lo);
skb_queue_purge(&qrtr_backup_hi);
}
/**
* qrtr_endpoint_post() - post incoming data
* @ep: endpoint handle
@ -577,8 +639,13 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len)
return -EINVAL;
skb = alloc_skb_with_frags(sizeof(*v1), len, 0, &errcode, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
if (!skb) {
skb = qrtr_get_backup(len);
if (!skb) {
pr_err("qrtr: Unable to get skb with len:%lu\n", len);
return -ENOMEM;
}
}
skb_reserve(skb, sizeof(*v1));
cb = (struct qrtr_cb *)skb->cb;
@ -1708,6 +1775,8 @@ static int __init qrtr_proto_init(void)
if (rc)
goto err_sock;
qrtr_backup_init();
return 0;
err_sock:
@ -1723,6 +1792,8 @@ static void __exit qrtr_proto_fini(void)
qrtr_ns_remove();
sock_unregister(qrtr_family.family);
proto_unregister(&qrtr_proto);
qrtr_backup_deinit();
}
module_exit(qrtr_proto_fini);