b.a.t.m.a.n.lists.open-mesh.org archive mirror
 help / color / mirror / Atom feed
From: Sven Eckelmann <sven@narfation.org>
To: davem@davemloft.net
Cc: netdev@vger.kernel.org, b.a.t.m.a.n@lists.open-mesh.org,
	Marek Lindner <lindner_marek@yahoo.de>
Subject: [B.A.T.M.A.N.] [PATCH 08/28] batman-adv: protect originator nodes with reference counters
Date: Sat,  5 Mar 2011 13:28:22 +0100	[thread overview]
Message-ID: <1299328122-21468-9-git-send-email-sven@narfation.org> (raw)
In-Reply-To: <1299328122-21468-1-git-send-email-sven@narfation.org>

From: Marek Lindner <lindner_marek@yahoo.de>

Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
---
 net/batman-adv/originator.c |   61 ++++++++++++++++++++++++++++++++++++------
 net/batman-adv/originator.h |    1 +
 net/batman-adv/routing.c    |   33 ++++++++++++++++-------
 net/batman-adv/types.h      |    2 +
 4 files changed, 78 insertions(+), 19 deletions(-)

diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 5c32314..fcdb0b7 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -103,12 +103,13 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
 	return neigh_node;
 }
 
-static void free_orig_node(void *data, void *arg)
+void orig_node_free_ref(struct kref *refcount)
 {
 	struct hlist_node *node, *node_tmp;
 	struct neigh_node *neigh_node;
-	struct orig_node *orig_node = (struct orig_node *)data;
-	struct bat_priv *bat_priv = (struct bat_priv *)arg;
+	struct orig_node *orig_node;
+
+	orig_node = container_of(refcount, struct orig_node, refcount);
 
 	spin_lock_bh(&orig_node->neigh_list_lock);
 
@@ -122,7 +123,8 @@ static void free_orig_node(void *data, void *arg)
 	spin_unlock_bh(&orig_node->neigh_list_lock);
 
 	frag_list_free(&orig_node->frag_list);
-	hna_global_del_orig(bat_priv, orig_node, "originator timed out");
+	hna_global_del_orig(orig_node->bat_priv, orig_node,
+			    "originator timed out");
 
 	kfree(orig_node->bcast_own);
 	kfree(orig_node->bcast_own_sum);
@@ -131,17 +133,53 @@ static void free_orig_node(void *data, void *arg)
 
 void originator_free(struct bat_priv *bat_priv)
 {
-	if (!bat_priv->orig_hash)
+	struct hashtable_t *hash = bat_priv->orig_hash;
+	struct hlist_node *walk, *safe;
+	struct hlist_head *head;
+	struct element_t *bucket;
+	spinlock_t *list_lock; /* spinlock to protect write access */
+	struct orig_node *orig_node;
+	int i;
+
+	if (!hash)
 		return;
 
 	cancel_delayed_work_sync(&bat_priv->orig_work);
 
 	spin_lock_bh(&bat_priv->orig_hash_lock);
-	hash_delete(bat_priv->orig_hash, free_orig_node, bat_priv);
 	bat_priv->orig_hash = NULL;
+
+	for (i = 0; i < hash->size; i++) {
+		head = &hash->table[i];
+		list_lock = &hash->list_locks[i];
+
+		spin_lock_bh(list_lock);
+		hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) {
+			orig_node = bucket->data;
+
+			hlist_del_rcu(walk);
+			call_rcu(&bucket->rcu, bucket_free_rcu);
+			kref_put(&orig_node->refcount, orig_node_free_ref);
+		}
+		spin_unlock_bh(list_lock);
+	}
+
+	hash_destroy(hash);
 	spin_unlock_bh(&bat_priv->orig_hash_lock);
 }
 
+static void bucket_free_orig_rcu(struct rcu_head *rcu)
+{
+	struct element_t *bucket;
+	struct orig_node *orig_node;
+
+	bucket = container_of(rcu, struct element_t, rcu);
+	orig_node = bucket->data;
+
+	kref_put(&orig_node->refcount, orig_node_free_ref);
+	kfree(bucket);
+}
+
 /* this function finds or creates an originator entry for the given
  * address if it does not exits */
 struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
@@ -156,8 +194,10 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
 						   addr));
 	rcu_read_unlock();
 
-	if (orig_node)
+	if (orig_node) {
+		kref_get(&orig_node->refcount);
 		return orig_node;
+	}
 
 	bat_dbg(DBG_BATMAN, bat_priv,
 		"Creating new originator: %pM\n", addr);
@@ -168,7 +208,9 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
 
 	INIT_HLIST_HEAD(&orig_node->neigh_list);
 	spin_lock_init(&orig_node->neigh_list_lock);
+	kref_init(&orig_node->refcount);
 
+	orig_node->bat_priv = bat_priv;
 	memcpy(orig_node->orig, addr, ETH_ALEN);
 	orig_node->router = NULL;
 	orig_node->hna_buff = NULL;
@@ -197,6 +239,8 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
 	if (hash_added < 0)
 		goto free_bcast_own_sum;
 
+	/* extra reference for return */
+	kref_get(&orig_node->refcount);
 	return orig_node;
 free_bcast_own_sum:
 	kfree(orig_node->bcast_own_sum);
@@ -318,8 +362,7 @@ static void _purge_orig(struct bat_priv *bat_priv)
 				if (orig_node->gw_flags)
 					gw_node_delete(bat_priv, orig_node);
 				hlist_del_rcu(walk);
-				call_rcu(&bucket->rcu, bucket_free_rcu);
-				free_orig_node(orig_node, bat_priv);
+				call_rcu(&bucket->rcu, bucket_free_orig_rcu);
 				continue;
 			}
 
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h
index 88e5c60..edc64dc 100644
--- a/net/batman-adv/originator.h
+++ b/net/batman-adv/originator.h
@@ -25,6 +25,7 @@
 int originator_init(struct bat_priv *bat_priv);
 void originator_free(struct bat_priv *bat_priv);
 void purge_orig_ref(struct bat_priv *bat_priv);
+void orig_node_free_ref(struct kref *refcount);
 struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr);
 struct neigh_node *create_neighbor(struct orig_node *orig_node,
 				   struct orig_node *orig_neigh_node,
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 32ae04e..1c31a0e 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -311,6 +311,8 @@ static void update_orig(struct bat_priv *bat_priv,
 
 		neigh_node = create_neighbor(orig_node, orig_tmp,
 					     ethhdr->h_source, if_incoming);
+
+		kref_put(&orig_tmp->refcount, orig_node_free_ref);
 		if (!neigh_node)
 			goto unlock;
 	} else
@@ -438,7 +440,7 @@ static char count_real_packets(struct ethhdr *ethhdr,
 	/* signalize caller that the packet is to be dropped. */
 	if (window_protected(bat_priv, seq_diff,
 			     &orig_node->batman_seqno_reset))
-		return -1;
+		goto err;
 
 	rcu_read_lock();
 	hlist_for_each_entry_rcu(tmp_neigh_node, node,
@@ -471,7 +473,12 @@ static char count_real_packets(struct ethhdr *ethhdr,
 		orig_node->last_real_seqno = batman_packet->seqno;
 	}
 
+	kref_put(&orig_node->refcount, orig_node_free_ref);
 	return is_duplicate;
+
+err:
+	kref_put(&orig_node->refcount, orig_node_free_ref);
+	return -1;
 }
 
 /* copy primary address for bonding */
@@ -686,7 +693,6 @@ void receive_bat_packet(struct ethhdr *ethhdr,
 		int offset;
 
 		orig_neigh_node = get_orig_node(bat_priv, ethhdr->h_source);
-
 		if (!orig_neigh_node)
 			return;
 
@@ -707,6 +713,7 @@ void receive_bat_packet(struct ethhdr *ethhdr,
 
 		bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
 			"originator packet from myself (via neighbor)\n");
+		kref_put(&orig_neigh_node->refcount, orig_node_free_ref);
 		return;
 	}
 
@@ -727,13 +734,13 @@ void receive_bat_packet(struct ethhdr *ethhdr,
 		bat_dbg(DBG_BATMAN, bat_priv,
 			"Drop packet: packet within seqno protection time "
 			"(sender: %pM)\n", ethhdr->h_source);
-		return;
+		goto out;
 	}
 
 	if (batman_packet->tq == 0) {
 		bat_dbg(DBG_BATMAN, bat_priv,
 			"Drop packet: originator packet with tq equal 0\n");
-		return;
+		goto out;
 	}
 
 	/* avoid temporary routing loops */
@@ -747,7 +754,7 @@ void receive_bat_packet(struct ethhdr *ethhdr,
 		bat_dbg(DBG_BATMAN, bat_priv,
 			"Drop packet: ignoring all rebroadcast packets that "
 			"may make me loop (sender: %pM)\n", ethhdr->h_source);
-		return;
+		goto out;
 	}
 
 	/* if sender is a direct neighbor the sender mac equals
@@ -756,14 +763,14 @@ void receive_bat_packet(struct ethhdr *ethhdr,
 			   orig_node :
 			   get_orig_node(bat_priv, ethhdr->h_source));
 	if (!orig_neigh_node)
-		return;
+		goto out_neigh;
 
 	/* drop packet if sender is not a direct neighbor and if we
 	 * don't route towards it */
 	if (!is_single_hop_neigh && (!orig_neigh_node->router)) {
 		bat_dbg(DBG_BATMAN, bat_priv,
 			"Drop packet: OGM via unknown neighbor!\n");
-		return;
+		goto out_neigh;
 	}
 
 	is_bidirectional = is_bidirectional_neigh(orig_node, orig_neigh_node,
@@ -790,26 +797,32 @@ void receive_bat_packet(struct ethhdr *ethhdr,
 
 		bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: "
 			"rebroadcast neighbor packet with direct link flag\n");
-		return;
+		goto out_neigh;
 	}
 
 	/* multihop originator */
 	if (!is_bidirectional) {
 		bat_dbg(DBG_BATMAN, bat_priv,
 			"Drop packet: not received via bidirectional link\n");
-		return;
+		goto out_neigh;
 	}
 
 	if (is_duplicate) {
 		bat_dbg(DBG_BATMAN, bat_priv,
 			"Drop packet: duplicate packet received\n");
-		return;
+		goto out_neigh;
 	}
 
 	bat_dbg(DBG_BATMAN, bat_priv,
 		"Forwarding packet: rebroadcast originator packet\n");
 	schedule_forward_packet(orig_node, ethhdr, batman_packet,
 				0, hna_buff_len, if_incoming);
+
+out_neigh:
+	if (!is_single_hop_neigh)
+		kref_put(&orig_neigh_node->refcount, orig_node_free_ref);
+out:
+	kref_put(&orig_node->refcount, orig_node_free_ref);
 }
 
 int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if)
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index d4fa727..ca4d42d 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -86,6 +86,8 @@ struct orig_node {
 	struct hlist_head neigh_list;
 	struct list_head frag_list;
 	spinlock_t neigh_list_lock; /* protects neighbor list */
+	struct kref refcount;
+	struct bat_priv *bat_priv;
 	unsigned long last_frag_packet;
 	struct {
 		uint8_t candidates;
-- 
1.7.2.3


  parent reply	other threads:[~2011-03-05 12:28 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-03-05 12:28 [B.A.T.M.A.N.] pull request: batman-adv 2011-03-05 Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 01/28] batman-adv: Remove two duplicate includes Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 02/28] batman-adv: protect neighbor nodes with reference counters Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 03/28] batman-adv: convert neighbor list to hlist Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 04/28] batman-adv: protect neighbor list with rcu locks Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 05/28] batman-adv: free neighbors when an interface is deactivated Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 06/28] batman-adv: protect neigh_nodes used outside of rcu_locks with refcounting Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 07/28] batman-adv: protect each hash row with rcu locks Sven Eckelmann
2011-03-05 12:28 ` Sven Eckelmann [this message]
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 09/28] batman-adv: protect ogm counter arrays with spinlock Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 10/28] batman-adv: protect bonding with rcu locks Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 11/28] batman-adv: Correct rcu refcounting for neigh_node Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 12/28] batman-adv: Correct rcu refcounting for gw_node Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 13/28] batman-adv: Correct rcu refcounting for softif_neigh Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 14/28] batman-adv: Correct rcu refcounting for batman_if Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 15/28] batman-adv: protect bit operations to count OGMs with spinlock Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 16/28] batman-adv: make broadcast seqno operations atomic Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 17/28] batman-adv: Make bat_priv->curr_gw an rcu protected pointer Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 18/28] batman-adv: Increase orig_node refcount before releasing rcu read lock Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 19/28] batman-adv: Fix possible buffer overflow in softif neigh list output Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 20/28] batman-adv: separate ethernet comparing calls from hash functions Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 21/28] batman-adv: remove extra layer between hash and hash element - hash bucket Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 22/28] batman-adv: Correct rcu refcounting for orig_node Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 23/28] batman-adv: increase refcount in create_neighbor to be consistent Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 24/28] batman-adv: remove orig_hash spinlock Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 25/28] batman-adv: rename global if_list to hardif_list Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 26/28] batman-adv: rename batman_if struct to hard_iface Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 27/28] batman-adv: Remove unused hdr_size variable in route_unicast_packet() Sven Eckelmann
2011-03-05 12:28 ` [B.A.T.M.A.N.] [PATCH 28/28] batman-adv: Disallow regular interface as mesh device Sven Eckelmann
2011-03-05 14:13 ` [B.A.T.M.A.N.] pull request: batman-adv 2011-03-05 Sven Eckelmann
2011-03-07  2:14 ` David Miller
2011-03-07  9:01   ` Sven Eckelmann
2011-03-07  9:19     ` David Miller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1299328122-21468-9-git-send-email-sven@narfation.org \
    --to=sven@narfation.org \
    --cc=b.a.t.m.a.n@lists.open-mesh.org \
    --cc=davem@davemloft.net \
    --cc=lindner_marek@yahoo.de \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).