From 3e4aa12f4aa8154581aa7c399cd46c7f96bc4ddd Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Mon, 16 Dec 2019 17:02:13 -0800 Subject: [PATCH 1/2] 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: Chris Lew --- net/qrtr/qrtr.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c index ae0d0c6d53ad..a7f986ee0c6c 100644 --- a/net/qrtr/qrtr.c +++ b/net/qrtr/qrtr.c @@ -130,6 +130,15 @@ static DECLARE_RWSEM(qrtr_epts_lock); static DEFINE_IDR(qrtr_ports); 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 @@ -716,6 +725,54 @@ 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; + + while (skb_queue_len(&qrtr_backup_lo) < QRTR_BACKUP_LO_NUM) { + skb = alloc_skb(QRTR_BACKUP_LO_SIZE, 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(QRTR_BACKUP_HI_SIZE, 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 @@ -742,8 +799,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; @@ -1937,6 +1999,8 @@ static int __init qrtr_proto_init(void) qrtr_ns_init(); + qrtr_backup_init(); + return rc; } postcore_initcall(qrtr_proto_init); @@ -1946,6 +2010,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); From 8bdd8b34c32cf178c6d928114c3d716a15ba0195 Mon Sep 17 00:00:00 2001 From: Jay Jayanna Date: Wed, 8 Jan 2020 18:04:44 -0800 Subject: [PATCH 2/2] net: qrtr: Use alloc_skb_with_frags for backup memory Use alloc_skb_with_frags for skb allocation to keep it uniform throughout the rx path. Change-Id: Id38eeea0a7d422b50c1ad6a90b9b569f26c45917 Signed-off-by: Jay Jayanna --- net/qrtr/qrtr.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c index a7f986ee0c6c..a5e76ebb730b 100644 --- a/net/qrtr/qrtr.c +++ b/net/qrtr/qrtr.c @@ -728,15 +728,20 @@ 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(QRTR_BACKUP_LO_SIZE, GFP_KERNEL); + 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(QRTR_BACKUP_HI_SIZE, GFP_KERNEL); + 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);