From a34e1c5cea368289b2a452f0ccba6004d4b42f68 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Thu, 27 Oct 2022 11:07:38 -0700 Subject: [PATCH] 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 Signed-off-by: Chris Lew --- net/qrtr/af_qrtr.c | 75 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c index bfa7a1618180..3124c5115e49 100644 --- a/net/qrtr/af_qrtr.c +++ b/net/qrtr/af_qrtr.c @@ -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);