From patchwork Wed Mar 23 10:26:18 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Lindner X-Patchwork-Id: 926 Return-Path: Received: from nm6-vm0.bullet.mail.ukl.yahoo.com (nm6-vm0.bullet.mail.ukl.yahoo.com [217.146.183.234]) by open-mesh.org (Postfix) with SMTP id 027651542EB for ; Wed, 23 Mar 2011 11:30:53 +0100 (CET) Authentication-Results: open-mesh.org; dkim=pass (1024-bit key) header.i=@yahoo.de; dkim-adsp=none Received: from [217.146.183.212] by nm6.bullet.mail.ukl.yahoo.com with NNFMP; 23 Mar 2011 10:30:52 -0000 Received: from [217.146.183.172] by tm5.bullet.mail.ukl.yahoo.com with NNFMP; 23 Mar 2011 10:30:51 -0000 Received: from [127.0.0.1] by omp1013.mail.ukl.yahoo.com with NNFMP; 23 Mar 2011 10:30:51 -0000 X-Yahoo-Newman-Id: 701921.22834.bm@omp1013.mail.ukl.yahoo.com Received: (qmail 87104 invoked from network); 23 Mar 2011 10:30:51 -0000 DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=s1024; d=yahoo.de; h=DKIM-Signature:Received:X-Yahoo-SMTP:X-YMail-OSG:X-Yahoo-Newman-Property:From:To:Cc:Subject:Date:Message-Id:X-Mailer; b=Cx4TitZ/bL7N88s5SzyGvmcGLBpK1aSVonzWeDxeri5sTH4MKol1nVPbMPqHWTnb650PpxLX0YDS5o1P9pxwASdaqUVvpnJqnskVgebWk7n+01r99sbap7B1gEdxyUYrueYkDI06r2r7E9If2/xdrVBM6ufgTSFfDCQH+JjTShY= ; DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.de; s=s1024; t=1300876251; bh=orisOp686b+/zDFu1HDOD3ho0pyU6VIF+ogHmBbK9Ks=; h=Received:X-Yahoo-SMTP:X-YMail-OSG:X-Yahoo-Newman-Property:From:To:Cc:Subject:Date:Message-Id:X-Mailer; b=rq91Q5DMxi5G1RjblXCQuUYA5LU5puslM0vP1Sawea18dWRIzGLRZ/yNkUndPi/YGrbFn6aaTPF/9cUl4ij8qofvxNdeX97zyNy+64QFByPlKuRloRWKRHLctCzWz8eVPZ1iS4p0lhfO34WPAwIwilGrriNmRnj20iTLmoLKcBU= Received: from localhost (lindner_marek@90.35.102.12 with plain) by smtp129.mail.ukl.yahoo.com with SMTP; 23 Mar 2011 10:30:51 +0000 GMT X-Yahoo-SMTP: tW.h3tiswBBMXO2coYcbPigGD5Lt6zY_.Zc- X-YMail-OSG: sryisE8VM1kLDw3tbyg2zR5vn1.hYgLDfSf2DCQqaQQEC9e Ibfr22xHTWnHp7kVhHlXjpErnrCpvDdheZKWSgZReb3Y.SQLfgEa8GW3IQgh tgCDD3cjbxfhNGeGQVpV5nXx8b4KC3c8OZmBJ2kL6bcJenYJ_Xan_Z7CV1Zq 6ttAX3kdQl_2QxI2E4Db7Q__WJzmaFYDZ7J3DRRsnqTbj8Chfp4J2tW0NFn3 sqhadvGj2hGzJcrzIhvI.UR33_3t_TmG_wkJT4Revw_M4aN6fFyrOE2sJkcy dx0eKBq2wA9I9um4sITLQk9gzi6wCfPLiHcy5tkwkAHXqA35e4C.dfQ-- X-Yahoo-Newman-Property: ymail-3 From: Marek Lindner To: b.a.t.m.a.n@lists.open-mesh.org Date: Wed, 23 Mar 2011 11:26:18 +0100 Message-Id: <1300875978-14600-1-git-send-email-lindner_marek@yahoo.de> X-Mailer: git-send-email 1.7.2.3 Cc: Marek Lindner Subject: [B.A.T.M.A.N.] [PATCH] batman-adv: concentrate all curr_gw related rcu operations in select/deselect functions X-BeenThere: b.a.t.m.a.n@lists.open-mesh.org X-Mailman-Version: 2.1.13 Precedence: list Reply-To: The list for a Better Approach To Mobile Ad-hoc Networking List-Id: The list for a Better Approach To Mobile Ad-hoc Networking List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 23 Mar 2011 10:30:54 -0000 Signed-off-by: Marek Lindner --- batman-adv/gateway_client.c | 166 +++++++++++++++++++++++++------------------ batman-adv/gateway_client.h | 2 +- batman-adv/unicast.c | 2 +- 3 files changed, 98 insertions(+), 72 deletions(-) diff --git a/batman-adv/gateway_client.c b/batman-adv/gateway_client.c index 42a8a7b..5a0427a 100644 --- a/batman-adv/gateway_client.c +++ b/batman-adv/gateway_client.c @@ -43,39 +43,46 @@ static void gw_node_free_ref(struct gw_node *gw_node) call_rcu(&gw_node->rcu, gw_node_free_rcu); } -struct orig_node *gw_get_selected(struct bat_priv *bat_priv) +static struct gw_node *gw_get_selected_gw_node(struct bat_priv *bat_priv) { - struct gw_node *curr_gateway_tmp; - struct orig_node *orig_node = NULL; + struct gw_node *gw_node; rcu_read_lock(); - curr_gateway_tmp = rcu_dereference(bat_priv->curr_gw); - if (!curr_gateway_tmp) - goto out; - - orig_node = curr_gateway_tmp->orig_node; - if (!orig_node) + gw_node = rcu_dereference(bat_priv->curr_gw); + if (!gw_node) goto out; - if (!atomic_inc_not_zero(&orig_node->refcount)) - orig_node = NULL; + if (!atomic_inc_not_zero(&gw_node->refcount)) + gw_node = NULL; out: rcu_read_unlock(); - return orig_node; + return gw_node; } -void gw_deselect(struct bat_priv *bat_priv) +struct orig_node *gw_get_selected_orig(struct bat_priv *bat_priv) { struct gw_node *gw_node; + struct orig_node *orig_node = NULL; - spin_lock_bh(&bat_priv->gw_list_lock); - gw_node = rcu_dereference(bat_priv->curr_gw); - rcu_assign_pointer(bat_priv->curr_gw, NULL); - spin_unlock_bh(&bat_priv->gw_list_lock); + gw_node = gw_get_selected_gw_node(bat_priv); + if (!gw_node) + goto out; + rcu_read_lock(); + orig_node = gw_node->orig_node; + if (!orig_node) + goto unlock; + + if (!atomic_inc_not_zero(&orig_node->refcount)) + orig_node = NULL; + +unlock: + rcu_read_unlock(); +out: if (gw_node) gw_node_free_ref(gw_node); + return orig_node; } static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node) @@ -85,8 +92,11 @@ static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node) if (new_gw_node && !atomic_inc_not_zero(&new_gw_node->refcount)) new_gw_node = NULL; - spin_lock_bh(&bat_priv->gw_list_lock); + rcu_read_lock(); curr_gw_node = rcu_dereference(bat_priv->curr_gw); + rcu_read_unlock(); + + spin_lock_bh(&bat_priv->gw_list_lock); rcu_assign_pointer(bat_priv->curr_gw, new_gw_node); spin_unlock_bh(&bat_priv->gw_list_lock); @@ -94,10 +104,15 @@ static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node) gw_node_free_ref(curr_gw_node); } +void gw_deselect(struct bat_priv *bat_priv) +{ + gw_select(bat_priv, NULL); +} + void gw_election(struct bat_priv *bat_priv) { struct hlist_node *node; - struct gw_node *gw_node, *curr_gw, *curr_gw_tmp = NULL; + struct gw_node *gw_node, *curr_gw = NULL, *curr_gw_tmp = NULL; struct neigh_node *router; uint8_t max_tq = 0; uint32_t max_gw_factor = 0, tmp_gw_factor = 0; @@ -112,25 +127,17 @@ void gw_election(struct bat_priv *bat_priv) if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT) return; - rcu_read_lock(); - curr_gw = rcu_dereference(bat_priv->curr_gw); - if (curr_gw) { - rcu_read_unlock(); - return; - } + curr_gw = gw_get_selected_gw_node(bat_priv); + if (!curr_gw) + goto out; + rcu_read_lock(); if (hlist_empty(&bat_priv->gw_list)) { - - if (curr_gw) { - rcu_read_unlock(); - bat_dbg(DBG_BATMAN, bat_priv, - "Removing selected gateway - " - "no gateway in range\n"); - gw_deselect(bat_priv); - } else - rcu_read_unlock(); - - return; + bat_dbg(DBG_BATMAN, bat_priv, + "Removing selected gateway - " + "no gateway in range\n"); + gw_deselect(bat_priv); + goto unlock; } hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { @@ -182,7 +189,7 @@ void gw_election(struct bat_priv *bat_priv) if (curr_gw != curr_gw_tmp) { router = orig_node_get_router(curr_gw_tmp->orig_node); if (!router) - goto out; + goto unlock; if ((curr_gw) && (!curr_gw_tmp)) bat_dbg(DBG_BATMAN, bat_priv, @@ -207,8 +214,11 @@ void gw_election(struct bat_priv *bat_priv) gw_select(bat_priv, curr_gw_tmp); } -out: +unlock: rcu_read_unlock(); +out: + if (curr_gw) + gw_node_free_ref(curr_gw); } void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) @@ -217,7 +227,7 @@ void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) struct neigh_node *router_gw = NULL, *router_orig = NULL; uint8_t gw_tq_avg, orig_tq_avg; - curr_gw_orig = gw_get_selected(bat_priv); + curr_gw_orig = gw_get_selected_orig(bat_priv); if (!curr_gw_orig) goto deselect; @@ -299,7 +309,11 @@ void gw_node_update(struct bat_priv *bat_priv, struct orig_node *orig_node, uint8_t new_gwflags) { struct hlist_node *node; - struct gw_node *gw_node; + struct gw_node *gw_node, *curr_gw; + + curr_gw = gw_get_selected_gw_node(bat_priv); + if (!curr_gw) + goto out; rcu_read_lock(); hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { @@ -320,22 +334,25 @@ void gw_node_update(struct bat_priv *bat_priv, "Gateway %pM removed from gateway list\n", orig_node->orig); - if (gw_node == rcu_dereference(bat_priv->curr_gw)) { - rcu_read_unlock(); - gw_deselect(bat_priv); - return; - } + if (gw_node == curr_gw) + goto deselect; } - rcu_read_unlock(); - return; + goto out; } - rcu_read_unlock(); if (new_gwflags == 0) - return; + goto out; gw_node_add(bat_priv, orig_node, new_gwflags); + goto out; + +deselect: + gw_deselect(bat_priv); +out: + rcu_read_unlock(); + if (curr_gw) + gw_node_free_ref(curr_gw); } void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node) @@ -345,9 +362,12 @@ void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node) void gw_node_purge(struct bat_priv *bat_priv) { - struct gw_node *gw_node; + struct gw_node *gw_node, *curr_gw; struct hlist_node *node, *node_tmp; unsigned long timeout = 2 * PURGE_TIMEOUT * HZ; + char do_deselect = 0; + + curr_gw = gw_get_selected_gw_node(bat_priv); spin_lock_bh(&bat_priv->gw_list_lock); @@ -358,15 +378,21 @@ void gw_node_purge(struct bat_priv *bat_priv) atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) continue; - if (rcu_dereference(bat_priv->curr_gw) == gw_node) - gw_deselect(bat_priv); + if (curr_gw == gw_node) + do_deselect = 1; hlist_del_rcu(&gw_node->list); gw_node_free_ref(gw_node); } - spin_unlock_bh(&bat_priv->gw_list_lock); + + /* gw_deselect() needs to acquire the gw_list_lock */ + if (do_deselect) + gw_deselect(bat_priv); + + if (curr_gw) + gw_node_free_ref(curr_gw); } /** @@ -385,22 +411,22 @@ static int _write_buffer_text(struct bat_priv *bat_priv, if (!router) goto out; - rcu_read_lock(); - curr_gw = rcu_dereference(bat_priv->curr_gw); + curr_gw = gw_get_selected_gw_node(bat_priv); ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n", - (curr_gw == gw_node ? "=>" : " "), - gw_node->orig_node->orig, - router->tq_avg, router->addr, - router->if_incoming->net_dev->name, - gw_node->orig_node->gw_flags, - (down > 2048 ? down / 1024 : down), - (down > 2048 ? "MBit" : "KBit"), - (up > 2048 ? up / 1024 : up), - (up > 2048 ? "MBit" : "KBit")); + (curr_gw == gw_node ? "=>" : " "), + gw_node->orig_node->orig, + router->tq_avg, router->addr, + router->if_incoming->net_dev->name, + gw_node->orig_node->gw_flags, + (down > 2048 ? down / 1024 : down), + (down > 2048 ? "MBit" : "KBit"), + (up > 2048 ? up / 1024 : up), + (up > 2048 ? "MBit" : "KBit")); - rcu_read_unlock(); neigh_node_free_ref(router); + if (curr_gw) + gw_node_free_ref(curr_gw); out: return ret; } @@ -459,6 +485,7 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) struct iphdr *iphdr; struct ipv6hdr *ipv6hdr; struct udphdr *udphdr; + struct gw_node *curr_gw; unsigned int header_len = 0; if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF) @@ -523,12 +550,11 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER) return -1; - rcu_read_lock(); - if (!rcu_dereference(bat_priv->curr_gw)) { - rcu_read_unlock(); + curr_gw = gw_get_selected_gw_node(bat_priv); + if (!curr_gw) return 0; - } - rcu_read_unlock(); + if (curr_gw) + gw_node_free_ref(curr_gw); return 1; } diff --git a/batman-adv/gateway_client.h b/batman-adv/gateway_client.h index 97c31d1..1ce8c60 100644 --- a/batman-adv/gateway_client.h +++ b/batman-adv/gateway_client.h @@ -24,7 +24,7 @@ void gw_deselect(struct bat_priv *bat_priv); void gw_election(struct bat_priv *bat_priv); -struct orig_node *gw_get_selected(struct bat_priv *bat_priv); +struct orig_node *gw_get_selected_orig(struct bat_priv *bat_priv); void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node); void gw_node_update(struct bat_priv *bat_priv, struct orig_node *orig_node, uint8_t new_gwflags); diff --git a/batman-adv/unicast.c b/batman-adv/unicast.c index 19f84bd..d46acc8 100644 --- a/batman-adv/unicast.c +++ b/batman-adv/unicast.c @@ -289,7 +289,7 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) /* get routing information */ if (is_multicast_ether_addr(ethhdr->h_dest)) { - orig_node = (struct orig_node *)gw_get_selected(bat_priv); + orig_node = (struct orig_node *)gw_get_selected_orig(bat_priv); if (orig_node) goto find_router; }