Merge "[qca-nss-drv] kmemleak-Fix false positives by adding references"
diff --git a/Makefile b/Makefile
index 9f0f072..08ce191 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
 ##########################################################################
-# Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+# Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
 # Permission to use, copy, modify, and/or distribute this software for
 # any purpose with or without fee is hereby granted, provided that the
 # above copyright notice and this permission notice appear in all copies.
@@ -58,7 +58,7 @@
 
 PM_SUPPORT := 0
 
-ccflags-y += -I$(obj)/nss_hal/include -I$(obj)/exports -DNSS_DEBUG_LEVEL=0 -DNSS_EMPTY_BUFFER_SIZE=1792 -DNSS_PKT_STATS_ENABLED=0
+ccflags-y += -I$(obj)/nss_hal/include -I$(obj)/exports -DNSS_DEBUG_LEVEL=0 -DNSS_EMPTY_BUFFER_SIZE=1792 -DNSS_PKT_STATS_ENABLED=1
 ccflags-y += -DNSS_PM_DEBUG_LEVEL=0
 
 ifneq ($(findstring 3.4, $(KERNELVERSION)),)
diff --git a/nss_core.c b/nss_core.c
index 44ff83b..b0cb03d 100755
--- a/nss_core.c
+++ b/nss_core.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
  * above copyright notice and this permission notice appear in all copies.
@@ -49,6 +49,11 @@
 
 static struct nss_rx_cb_list nss_rx_interface_handlers[NSS_MAX_NET_INTERFACES];
 
+#ifdef CONFIG_DEBUG_KMEMLEAK
+struct sk_buff_head nss_skb_list;
+#endif
+
+
 /*
  * nss_core_set_jumbo_mru()
  *	Set the jumbo_mru to the specified value
@@ -301,6 +306,18 @@
 	nss_phys_if_rx_callback_t cb;
 	struct nss_subsystem_dataplane_register *subsys_dp_reg = &nss_top->subsys_dp_register[interface_num];
 
+
+#ifdef CONFIG_DEBUG_KMEMLEAK
+	/*
+	 * Tracking for kmemleak: Remove the skb from the nss_skb_list
+	 */
+	spin_lock_bh(&nss_skb_list.lock);
+	__skb_unlink(nbuf, &nss_skb_list);
+	spin_unlock_bh(&nss_skb_list.lock);
+#endif
+
+	NSS_PKT_STATS_DECREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NSS_SKB_COUNT]);
+
 	switch (buffer_type) {
 	case N2H_BUFFER_SHAPER_BOUNCED_INTERFACE:
 		{
@@ -879,7 +896,7 @@
 		opaque = desc->opaque;
 		bit_flags = desc->bit_flags;
 		if (unlikely((buffer_type == N2H_BUFFER_CRYPTO_RESP))) {
-			NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_top->stats_drv[NSS_STATS_DRV_RX_CRYPTO_RESP]);
+			NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_RX_CRYPTO_RESP]);
 			/*
 			 * This is a crypto buffer hence send it to crypto driver
 			 *
@@ -900,7 +917,7 @@
 			 * Invalid opaque pointer
 			 */
 			nss_dump_desc(nss_ctx, desc);
-			NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_top->stats_drv[NSS_STATS_DRV_RX_BAD_DESCRIPTOR]);
+			NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_RX_BAD_DESCRIPTOR]);
 			goto next;
 		}
 
@@ -949,6 +966,17 @@
 			if (unlikely(head)) {
 				nss_warning("%p: we should not have an incomplete paged skb while"
 								" constructing a linear skb %p", nbuf, head);
+
+#ifdef CONFIG_DEBUG_KMEMLEAK
+				/*
+				 * Tracking for kmemleak: Remove the skb from the nss_skb_list
+				 */
+				spin_lock_bh(&nss_skb_list.lock);
+				__skb_unlink(head, &nss_skb_list);
+				spin_unlock_bh(&nss_skb_list.lock);
+#endif
+
+				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;
@@ -968,6 +996,17 @@
 		if (unlikely(jumbo_start)) {
 			nss_warning("%p: we should not have an incomplete linear skb while"
 							" constructing a paged skb %p", nbuf, jumbo_start);
+
+#ifdef CONFIG_DEBUG_KMEMLEAK
+			/*
+			 * Tracking for kmemleak: Remove the skb from the nss_skb_list
+			 */
+			spin_lock_bh(&nss_skb_list.lock);
+			__skb_unlink(jumbo_start, &nss_skb_list);
+			spin_unlock_bh(&nss_skb_list.lock);
+#endif
+
+			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;
 			goto next;
@@ -1241,6 +1280,16 @@
 				break;
 			}
 
+#ifdef CONFIG_DEBUG_KMEMLEAK
+			/*
+			 * Tracking for kmemleak because skbs dont have references.
+			 */
+			spin_lock_bh(&nss_skb_list.lock);
+			__skb_queue_head(&nss_skb_list, nbuf);
+			spin_unlock_bh(&nss_skb_list.lock);
+#endif
+
+			NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NSS_SKB_COUNT]);
 			desc->opaque = (uint32_t)nbuf;
 			desc->buffer = buffer;
 			desc->buffer_type = H2N_BUFFER_EMPTY;
@@ -1899,6 +1948,16 @@
 	h2n_desc_ring->hlos_index = hlos_index;
 	if_map->h2n_hlos_index[qid] = hlos_index;
 
+#ifdef CONFIG_DEBUG_KMEMLEAK
+	/*
+	 * Tracking for kmemleak because skbs dont have references.
+	 */
+	spin_lock_bh(&nss_skb_list.lock);
+	__skb_queue_head(&nss_skb_list, nbuf);
+	spin_unlock_bh(&nss_skb_list.lock);
+#endif
+
+	NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NSS_SKB_COUNT]);
 	spin_unlock_bh(&h2n_desc_ring->lock);
 	return NSS_CORE_STATUS_SUCCESS;
 }
diff --git a/nss_core.h b/nss_core.h
index 20f3628..d088084 100755
--- a/nss_core.h
+++ b/nss_core.h
@@ -88,6 +88,7 @@
 
 #if (NSS_PKT_STATS_ENABLED == 1)
 #define NSS_PKT_STATS_INCREMENT(nss_ctx, x) nss_pkt_stats_increment((nss_ctx), (x))
+#define NSS_PKT_STATS_DECREMENT(nss_ctx, x) nss_pkt_stats_decrement((nss_ctx), (x))
 #else
 #define NSS_PKT_STATS_INCREMENT(nss_ctx, x)
 #endif
@@ -314,6 +315,7 @@
 	NSS_STATS_DRV_RX_NR_FRAGS,		/* N2H NR Frags SKB Packets */
 	NSS_STATS_DRV_RX_SKB_FRAGLIST,		/* N2H Fraglist SKB Packets */
 	NSS_STATS_DRV_RX_BAD_DESCRIPTOR,	/* N2H Bad descriptor reads */
+	NSS_STATS_DRV_NSS_SKB_COUNT,
 	NSS_STATS_DRV_MAX,
 };
 
@@ -702,6 +704,17 @@
 	*stat = *stat + 1;
 	spin_unlock_bh(&nss_ctx->nss_top->stats_lock);
 }
+
+/*
+ * nss_pkt_stats_increment()
+ */
+static inline void nss_pkt_stats_decrement(struct nss_ctx_instance *nss_ctx, uint64_t *stat)
+{
+	spin_lock_bh(&nss_ctx->nss_top->stats_lock);
+	*stat = *stat - 1;
+	spin_unlock_bh(&nss_ctx->nss_top->stats_lock);
+}
+
 #endif
 
 /*
diff --git a/nss_init.c b/nss_init.c
index 29203b2..f9ca687 100755
--- a/nss_init.c
+++ b/nss_init.c
@@ -68,6 +68,10 @@
 int nss_jumbo_mru  __read_mostly = 0;
 int nss_paged_mode __read_mostly = 0;
 
+#ifdef CONFIG_DEBUG_KMEMLEAK
+extern struct sk_buff_head nss_skb_list;
+#endif
+
 /*
  * PM client handle
  */
@@ -1376,6 +1380,15 @@
 	nss_ipv4_register_sysctl();
 	nss_ipv6_register_sysctl();
 
+#ifdef CONFIG_DEBUG_KMEMLEAK
+	/*
+	 * If the system is under kmemleak debugging, track our
+	 * skbs by putting them in a list.
+	 */
+
+	skb_queue_head_init(&nss_skb_list);
+#endif
+
 #if (NSS_PM_SUPPORT == 1)
 	/*
 	 * Setup Runtime Sample values
diff --git a/nss_stats.c b/nss_stats.c
index 15a91af..2864c9e 100644
--- a/nss_stats.c
+++ b/nss_stats.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
  * above copyright notice and this permission notice appear in all copies.
@@ -160,7 +160,8 @@
 	"rx_skb_simple",
 	"rx_skb_nr_frags",
 	"rx_skb_fraglist",
-	"rx_bad_desciptor"
+	"rx_bad_desciptor",
+	"nss_skb_count"
 };
 
 /*