[qca-nss-drv] Fix memory leak in receiving an SKB chain
Keep the state of an skb chain in case we stop processing in the
middle of receiving one. Otherwise we leak the partially received
skb.
Change-Id: I85760a08ff67a29e45fd45a5193e85232698b27c
Signed-off-by: Selin Dag <sdag@codeaurora.org>
diff --git a/nss_core.c b/nss_core.c
index 399ef25..8f46091 100755
--- a/nss_core.c
+++ b/nss_core.c
@@ -658,10 +658,9 @@
* Free the old head as the frag list is corrupt.
*/
if (unlikely(jumbo_start)) {
- nss_warning("%p: received the second head before a last", jumbo_start);
+ nss_warning("%p: received a full frame before a last", jumbo_start);
dev_kfree_skb_any(jumbo_start);
*jumbo_start_ptr = NULL;
- return false;
}
/*
@@ -697,8 +696,6 @@
if (unlikely(jumbo_start)) {
nss_warning("%p: received the second head before a last", jumbo_start);
dev_kfree_skb_any(jumbo_start);
- *jumbo_start_ptr = NULL;
- return false;
}
/*
@@ -801,10 +798,9 @@
* Free the old head as the frag list is corrupt.
*/
if (unlikely(head)) {
- nss_warning("%p: received the second head before a last", head);
+ nss_warning("%p: received a full frame before a last", head);
dev_kfree_skb_any(head);
*head_ptr = NULL;
- return false;
}
/*
@@ -834,8 +830,6 @@
if (unlikely(head)) {
nss_warning("%p: received the second head before a last", head);
dev_kfree_skb_any(head);
- *head_ptr = NULL;
- return false;
}
/*
@@ -927,7 +921,7 @@
int16_t count, count_temp;
uint16_t size, mask, qid;
uint32_t nss_index, hlos_index;
- struct sk_buff *nbuf, *head, *tail, *jumbo_start;
+ struct sk_buff *nbuf;
struct hlos_n2h_desc_ring *n2h_desc_ring;
struct n2h_desc_if_instance *desc_if;
struct n2h_descriptor *desc_ring;
@@ -965,7 +959,6 @@
count = weight;
}
- head = tail = jumbo_start = NULL;
count_temp = count;
while (count_temp) {
unsigned int buffer_type;
@@ -1043,17 +1036,16 @@
* Check if we received paged skb while constructing
* a linear skb chain. If so we need to free.
*/
- if (unlikely(head)) {
+ if (unlikely(n2h_desc_ring->head)) {
nss_warning("%p: we should not have an incomplete paged skb while"
- " constructing a linear skb %p", nbuf, head);
+ " constructing a linear skb %p", nbuf, n2h_desc_ring->head);
NSS_PKT_STATS_DECREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NSS_SKB_COUNT]);
- dev_kfree_skb_any(head);
- head = NULL;
- goto next;
+ dev_kfree_skb_any(n2h_desc_ring->head);
+ n2h_desc_ring->head = NULL;
}
- if (!nss_core_handle_nr_frag_skb(nss_ctx, &nbuf, &jumbo_start, desc, buffer_type)) {
+ if (!nss_core_handle_nr_frag_skb(nss_ctx, &nbuf, &n2h_desc_ring->jumbo_start, desc, buffer_type)) {
goto next;
}
NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_RX_NR_FRAGS]);
@@ -1064,20 +1056,20 @@
* Check if we received a linear skb while constructing
* a paged skb. If so we need to free the paged_skb and handle the linear skb.
*/
- if (unlikely(jumbo_start)) {
+ if (unlikely(n2h_desc_ring->jumbo_start)) {
nss_warning("%p: we should not have an incomplete linear skb while"
- " constructing a paged skb %p", nbuf, jumbo_start);
+ " constructing a paged skb %p", nbuf, n2h_desc_ring->jumbo_start);
NSS_PKT_STATS_DECREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NSS_SKB_COUNT]);
- dev_kfree_skb_any(jumbo_start);
- jumbo_start = NULL;
+ dev_kfree_skb_any(n2h_desc_ring->jumbo_start);
+ n2h_desc_ring->jumbo_start = NULL;
}
/*
* This is a simple linear skb. Use the the linear skb
* handler to process it.
*/
- if (!nss_core_handle_linear_skb(nss_ctx, &nbuf, &head, &tail, desc)) {
+ if (!nss_core_handle_linear_skb(nss_ctx, &nbuf, &n2h_desc_ring->head, &n2h_desc_ring->tail, desc)) {
goto next;
}
diff --git a/nss_core.h b/nss_core.h
index 65253de..d3aaab3 100755
--- a/nss_core.h
+++ b/nss_core.h
@@ -146,6 +146,11 @@
#define NSS_CTX_MAGIC 0xDEDEDEDE
/*
+ * Number of n2h descriptor rings
+ */
+#define NSS_N2H_DESC_RING_NUM 15
+
+/*
* NSS maximum clients
*/
#define NSS_MAX_CLIENTS 12
@@ -685,6 +690,9 @@
struct n2h_desc_if_instance desc_if;
/* Descriptor ring */
uint32_t hlos_index; /* Current HLOS index for this ring */
+ struct sk_buff *head; /* First segment of an skb fraglist */
+ struct sk_buff *tail; /* Last segment received of an skb fraglist */
+ struct sk_buff *jumbo_start; /* First segment of an skb with frags[] */
};
/*
@@ -730,7 +738,7 @@
/* Interrupt context instances */
struct hlos_h2n_desc_rings h2n_desc_rings[16];
/* Host to NSS descriptor rings */
- struct hlos_n2h_desc_ring n2h_desc_ring[15];
+ struct hlos_n2h_desc_ring n2h_desc_ring[NSS_N2H_DESC_RING_NUM];
/* NSS to Host descriptor rings */
uint16_t n2h_rps_en; /* N2H Enable Multiple queues for Data Packets */
uint16_t n2h_mitigate_en; /* N2H mitigation */
diff --git a/nss_hal/fsm9010/nss_hal_pvt.c b/nss_hal/fsm9010/nss_hal_pvt.c
index 1c3e3b2..dd56706 100644
--- a/nss_hal/fsm9010/nss_hal_pvt.c
+++ b/nss_hal/fsm9010/nss_hal_pvt.c
@@ -561,6 +561,15 @@
nss_ctx->max_buf_size = NSS_NBUF_PAYLOAD_SIZE;
/*
+ * Initialize S/G status pointers to NULL
+ */
+ for (i = 0; i < NSS_N2H_DESC_RING_NUM; i++) {
+ nss_ctx->n2h_desc_ring[i].head = NULL;
+ nss_ctx->n2h_desc_ring[i].tail = NULL;
+ nss_ctx->n2h_desc_ring[i].jumbo_start = NULL;
+ }
+
+ /*
* Increment number of cores
*/
nss_top->num_nss++;
diff --git a/nss_hal/ipq806x/nss_hal_pvt.c b/nss_hal/ipq806x/nss_hal_pvt.c
index 26aa19c..e7b3b5a 100644
--- a/nss_hal/ipq806x/nss_hal_pvt.c
+++ b/nss_hal/ipq806x/nss_hal_pvt.c
@@ -1587,6 +1587,15 @@
*/
nss_ctx->max_buf_size = NSS_NBUF_PAYLOAD_SIZE;
+ /*
+ * Initialize S/G status pointers to NULL
+ */
+ for (i = 0; i < NSS_N2H_DESC_RING_NUM; i++) {
+ nss_ctx->n2h_desc_ring[i].head = NULL;
+ nss_ctx->n2h_desc_ring[i].tail = NULL;
+ nss_ctx->n2h_desc_ring[i].jumbo_start = NULL;
+ }
+
/*
* Increment number of cores
*/