From 8a0208a422b0e385b3edb1c95e0a21a7deaa74b6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Linus=20L=C3=BCssing?= <linus.luessing@c0d3.blue>
Date: Tue, 18 Nov 2014 18:28:03 +0100
Subject: [PATCH] TT memory leak debug patch

---
 Makefile            |    6 +++---
 bat_iv_ogm.c        |    4 ++--
 gateway_client.c    |    8 ++++++++
 main.h              |   12 ++++++------
 originator.c        |   29 +++++++++++++++++++++++++++++
 soft-interface.c    |    2 +-
 translation-table.c |    2 ++
 types.h             |    2 ++
 8 files changed, 53 insertions(+), 12 deletions(-)

diff --git a/Makefile b/Makefile
index 4f6c30a..0b4882b 100644
--- a/Makefile
+++ b/Makefile
@@ -20,13 +20,13 @@
 # B.A.T.M.A.N. debugging:
 export CONFIG_BATMAN_ADV_DEBUG=n
 # B.A.T.M.A.N. bridge loop avoidance:
-export CONFIG_BATMAN_ADV_BLA=y
+export CONFIG_BATMAN_ADV_BLA=n
 # B.A.T.M.A.N. distributed ARP table:
-export CONFIG_BATMAN_ADV_DAT=y
+export CONFIG_BATMAN_ADV_DAT=n
 # B.A.T.M.A.N network coding (catwoman):
 export CONFIG_BATMAN_ADV_NC=n
 # B.A.T.M.A.N. multicast optimizations:
-export CONFIG_BATMAN_ADV_MCAST=y
+export CONFIG_BATMAN_ADV_MCAST=n
 
 PWD:=$(shell pwd)
 KERNELPATH ?= /lib/modules/$(shell uname -r)/build
diff --git a/bat_iv_ogm.c b/bat_iv_ogm.c
index 00e00e0..36635a6 100644
--- a/bat_iv_ogm.c
+++ b/bat_iv_ogm.c
@@ -1826,8 +1826,8 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv,
 			if (!n_ifinfo)
 				goto next;
 
-			if (n_ifinfo->bat_iv.tq_avg == 0)
-				goto next;
+//			if (n_ifinfo->bat_iv.tq_avg == 0)
+//				goto next;
 
 			last_seen_jiffies = jiffies - orig_node->last_seen;
 			last_seen_msecs = jiffies_to_msecs(last_seen_jiffies);
diff --git a/gateway_client.c b/gateway_client.c
index 27649e8..9c8d95e 100644
--- a/gateway_client.c
+++ b/gateway_client.c
@@ -81,6 +81,7 @@ batadv_gw_get_selected_orig(struct batadv_priv *bat_priv)
 	if (!orig_node)
 		goto unlock;
 
+printk("~~~ batadv_gw_get_selected() - refcount++ (%pM)!\n", orig_node->orig);
 	if (!atomic_inc_not_zero(&orig_node->refcount))
 		orig_node = NULL;
 
@@ -124,6 +125,7 @@ static void batadv_gw_select(struct batadv_priv *bat_priv,
  */
 void batadv_gw_reselect(struct batadv_priv *bat_priv)
 {
+printk("~~~ Calling batadv_gw_reselect\n");
 	atomic_set(&bat_priv->gw.reselect, 1);
 }
 
@@ -255,6 +257,7 @@ void batadv_gw_election(struct batadv_priv *bat_priv)
 	if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT)
 		goto out;
 
+printk("~~~ Doing batadv_gw_election\n");
 	curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
 
 	if (!batadv_atomic_dec_not_zero(&bat_priv->gw.reselect) && curr_gw)
@@ -408,6 +411,7 @@ static void batadv_gw_node_add(struct batadv_priv *bat_priv,
 	if (gateway->bandwidth_down == 0)
 		return;
 
+printk("~~~ batadv_gw_node_add() - refcount++ (%pM)!\n", orig_node->orig);
 	if (!atomic_inc_not_zero(&orig_node->refcount))
 		return;
 
@@ -446,6 +450,7 @@ batadv_gw_node_get(struct batadv_priv *bat_priv,
 		   struct batadv_orig_node *orig_node)
 {
 	struct batadv_gw_node *gw_node_tmp, *gw_node = NULL;
+//printk("~~~ Calling batadv_gw_node_get for %pM\n", orig_node->orig);
 
 	rcu_read_lock();
 	hlist_for_each_entry_rcu(gw_node_tmp, &bat_priv->gw.list, list) {
@@ -478,6 +483,7 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv,
 			   struct batadv_tvlv_gateway_data *gateway)
 {
 	struct batadv_gw_node *gw_node, *curr_gw = NULL;
+//printk("~~~ Calling batadv_gw_node_update for %pM\n", orig_node->orig);
 
 	gw_node = batadv_gw_node_get(bat_priv, orig_node);
 	if (!gw_node) {
@@ -530,6 +536,7 @@ void batadv_gw_node_delete(struct batadv_priv *bat_priv,
 			   struct batadv_orig_node *orig_node)
 {
 	struct batadv_tvlv_gateway_data gateway;
+printk("~~~ Calling batadv_gw_node_delete for %pM\n", orig_node->orig);
 
 	gateway.bandwidth_down = 0;
 	gateway.bandwidth_up = 0;
@@ -559,6 +566,7 @@ void batadv_gw_node_purge(struct batadv_priv *bat_priv)
 			do_reselect = 1;
 
 		hlist_del_rcu(&gw_node->list);
+printk("~~~ batadv_gw_node_purge for %pM%s\n", gw_node->orig_node->orig, do_reselect ? " (reselecting)" : "");
 		batadv_gw_node_free_ref(gw_node);
 	}
 
diff --git a/main.h b/main.h
index 52cb007..de609f8 100644
--- a/main.h
+++ b/main.h
@@ -38,13 +38,13 @@
 /* purge originators after time in seconds if no valid packet comes in
  * -> TODO: check influence on BATADV_TQ_LOCAL_WINDOW_SIZE
  */
-#define BATADV_PURGE_TIMEOUT 200000 /* 200 seconds */
-#define BATADV_TT_LOCAL_TIMEOUT 600000 /* in milliseconds */
-#define BATADV_TT_CLIENT_ROAM_TIMEOUT 600000 /* in milliseconds */
-#define BATADV_TT_CLIENT_TEMP_TIMEOUT 600000 /* in milliseconds */
+#define BATADV_PURGE_TIMEOUT 2000 /* 200 seconds */
+#define BATADV_TT_LOCAL_TIMEOUT 6000 /* in milliseconds */
+#define BATADV_TT_CLIENT_ROAM_TIMEOUT 6000 /* in milliseconds */
+#define BATADV_TT_CLIENT_TEMP_TIMEOUT 6000 /* in milliseconds */
 #define BATADV_TT_WORK_PERIOD 5000 /* 5 seconds */
-#define BATADV_ORIG_WORK_PERIOD 1000 /* 1 second */
-#define BATADV_DAT_ENTRY_TIMEOUT (5*60000) /* 5 mins in milliseconds */
+#define BATADV_ORIG_WORK_PERIOD 500 /* 1 second */
+#define BATADV_DAT_ENTRY_TIMEOUT (5*600) /* 5 mins in milliseconds */
 /* sliding packet range of received originator messages in sequence numbers
  * (should be a multiple of our word size)
  */
diff --git a/originator.c b/originator.c
index 6c2cb2d..b4b810e 100644
--- a/originator.c
+++ b/originator.c
@@ -547,6 +547,9 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
 
 	orig_node = container_of(rcu, struct batadv_orig_node, rcu);
 
+	atomic_set(&orig_node->curse_timeout, 0);
+	cancel_delayed_work_sync(&orig_node->curse);
+
 	spin_lock_bh(&orig_node->neigh_list_lock);
 
 	/* for all neighbors towards this originator ... */
@@ -634,6 +637,27 @@ void batadv_originator_free(struct batadv_priv *bat_priv)
 	batadv_hash_destroy(hash);
 }
 
+static void batadv_orig_node_cursed(struct work_struct *work)
+{
+	struct delayed_work *delayed_work;
+	struct batadv_orig_node *orig_node;
+	unsigned long timeout;
+
+	delayed_work = container_of(work, struct delayed_work, work);
+	orig_node = container_of(delayed_work, struct batadv_orig_node, curse);
+
+	timeout = atomic_inc_return(&orig_node->curse_timeout);
+	if (timeout <= 1)
+		return;
+
+	timeout = 15 * (2 << (timeout-2)) / 2;
+	pr_warn("Orig node %pM (%p) not purged after %lu seconds - did it become a zombie?\n", orig_node->orig, orig_node, timeout);
+	timeout = msecs_to_jiffies(1000*2*timeout);
+
+	queue_delayed_work(batadv_event_workqueue,
+			   &orig_node->curse, timeout);
+}
+
 /**
  * batadv_orig_node_new - creates a new orig_node
  * @bat_priv: the bat priv with all the soft interface information
@@ -661,6 +685,7 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
 	INIT_HLIST_HEAD(&orig_node->neigh_list);
 	INIT_LIST_HEAD(&orig_node->vlan_list);
 	INIT_HLIST_HEAD(&orig_node->ifinfo_list);
+	INIT_DELAYED_WORK(&orig_node->curse, batadv_orig_node_cursed);
 	spin_lock_init(&orig_node->bcast_seqno_lock);
 	spin_lock_init(&orig_node->neigh_list_lock);
 	spin_lock_init(&orig_node->tt_buff_lock);
@@ -977,6 +1002,10 @@ static void _batadv_purge_orig(struct batadv_priv *bat_priv)
 			if (batadv_purge_orig_node(bat_priv, orig_node)) {
 				batadv_gw_node_delete(bat_priv, orig_node);
 				hlist_del_rcu(&orig_node->hash_entry);
+				atomic_set(&orig_node->curse_timeout, 1);
+				queue_delayed_work(batadv_event_workqueue,
+						   &orig_node->curse,
+						   msecs_to_jiffies(15000));
 				batadv_orig_node_free_ref(orig_node);
 				continue;
 			}
diff --git a/soft-interface.c b/soft-interface.c
index 8748987..f6c6e34 100644
--- a/soft-interface.c
+++ b/soft-interface.c
@@ -755,7 +755,7 @@ static int batadv_softif_init_late(struct net_device *dev)
 	atomic_set(&bat_priv->gw_sel_class, 20);
 	atomic_set(&bat_priv->gw.bandwidth_down, 100);
 	atomic_set(&bat_priv->gw.bandwidth_up, 20);
-	atomic_set(&bat_priv->orig_interval, 1000);
+	atomic_set(&bat_priv->orig_interval, 100);
 	atomic_set(&bat_priv->hop_penalty, 30);
 #ifdef CONFIG_BATMAN_ADV_DEBUG
 	atomic_set(&bat_priv->log_level, 0);
diff --git a/translation-table.c b/translation-table.c
index 84e6f01..2452860 100644
--- a/translation-table.c
+++ b/translation-table.c
@@ -1985,6 +1985,8 @@ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
 	struct batadv_orig_node *orig_node = NULL;
 	struct batadv_tt_orig_list_entry *best_entry;
 
+printk("~~~ batadv_transtable_search() addr: %pM\n", addr);
+
 	if (src && batadv_vlan_ap_isola_get(bat_priv, vid)) {
 		tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid);
 		if (!tt_local_entry ||
diff --git a/types.h b/types.h
index 462a70c..a32c872 100644
--- a/types.h
+++ b/types.h
@@ -285,6 +285,8 @@ struct batadv_orig_node {
 	struct list_head vlan_list;
 	spinlock_t vlan_list_lock; /* protects vlan_list */
 	struct batadv_orig_bat_iv bat_iv;
+	struct delayed_work curse;
+	atomic_t curse_timeout;
 };
 
 /**
-- 
1.7.10.4

