The neigh_list with batadv_hardif_neigh_node objects is accessed with only rcu_read_lock in batadv_neigh_node_get and batadv_iv_neigh_print. Thus is is not allowed to kfree the object before the rcu grace period ends which may still tries to access this object. Therefore the object has first to be removed from the neigh_list and then it has either wait with synchronize_rcu or call_rcu till the grace period ends before it can be freed.
Signed-off-by: Sven Eckelmann sven@narfation.org --- I have no idea why batadv_hardif_neigh_free_now is considered to be safe to call. The only caller is batadv_neigh_node_free_rcu but this function never makes sure that the previously mentioned two functions are actually not accessing it right now when hlist_del_rcu_init + kfree is called. --- net/batman-adv/originator.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 00b0437..2681c7d 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -217,10 +217,6 @@ static void batadv_hardif_neigh_free_rcu(struct rcu_head *rcu)
hardif_neigh = container_of(rcu, struct batadv_hardif_neigh_node, rcu);
- spin_lock_bh(&hardif_neigh->if_incoming->neigh_list_lock); - hlist_del_init_rcu(&hardif_neigh->list); - spin_unlock_bh(&hardif_neigh->if_incoming->neigh_list_lock); - batadv_hardif_free_ref_now(hardif_neigh->if_incoming); kfree(hardif_neigh); } @@ -233,8 +229,13 @@ static void batadv_hardif_neigh_free_rcu(struct rcu_head *rcu) static void batadv_hardif_neigh_free_now(struct batadv_hardif_neigh_node *hardif_neigh) { - if (atomic_dec_and_test(&hardif_neigh->refcount)) + if (atomic_dec_and_test(&hardif_neigh->refcount)) { + spin_lock_bh(&hardif_neigh->if_incoming->neigh_list_lock); + hlist_del_init_rcu(&hardif_neigh->list); + spin_unlock_bh(&hardif_neigh->if_incoming->neigh_list_lock); + batadv_hardif_neigh_free_rcu(&hardif_neigh->rcu); + } }
/** @@ -244,8 +245,13 @@ batadv_hardif_neigh_free_now(struct batadv_hardif_neigh_node *hardif_neigh) */ void batadv_hardif_neigh_free_ref(struct batadv_hardif_neigh_node *hardif_neigh) { - if (atomic_dec_and_test(&hardif_neigh->refcount)) + if (atomic_dec_and_test(&hardif_neigh->refcount)) { + spin_lock_bh(&hardif_neigh->if_incoming->neigh_list_lock); + hlist_del_init_rcu(&hardif_neigh->list); + spin_unlock_bh(&hardif_neigh->if_incoming->neigh_list_lock); + call_rcu(&hardif_neigh->rcu, batadv_hardif_neigh_free_rcu); + } }
/**
batadv_hardif_neigh_node perfectly resamples the examples for the kernel reference counter kref. So switch to kref instead of using the self-made, atomic_t-based implementation.
Signed-off-by: Sven Eckelmann sven@narfation.org --- compat-include/linux/kref.h | 39 ++++++++++++++++++ net/batman-adv/bat_iv_ogm.c | 2 +- net/batman-adv/originator.c | 96 +++++++++++++++++++++++++++++++-------------- net/batman-adv/originator.h | 2 +- net/batman-adv/types.h | 3 +- 5 files changed, 109 insertions(+), 33 deletions(-) create mode 100644 compat-include/linux/kref.h
diff --git a/compat-include/linux/kref.h b/compat-include/linux/kref.h new file mode 100644 index 0000000..08b6328 --- /dev/null +++ b/compat-include/linux/kref.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2007-2015 B.A.T.M.A.N. contributors: + * + * Marek Lindner, Simon Wunderlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see http://www.gnu.org/licenses/. + * + * This file contains macros for maintaining compatibility with older versions + * of the Linux kernel. + */ + +#ifndef _NET_BATMAN_ADV_COMPAT_LINUX_KREF_H_ +#define _NET_BATMAN_ADV_COMPAT_LINUX_KREF_H_ + +#include <linux/version.h> +#include_next <linux/kref.h> + +#include <linux/atomic.h> +#include <linux/kernel.h> + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) + +static inline int __must_check kref_get_unless_zero(struct kref *kref) +{ + return atomic_add_unless(&kref->refcount, 1, 0); +} + +#endif /* < KERNEL_VERSION(3, 8, 0) */ + +#endif /* _NET_BATMAN_ADV_COMPAT_LINUX_KREF_H_ */ diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 12bdffa..b9db667 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -1571,7 +1571,7 @@ out: if (orig_neigh_router) batadv_neigh_node_free_ref(orig_neigh_router); if (hardif_neigh) - batadv_hardif_neigh_free_ref(hardif_neigh); + batadv_hardif_neigh_put(hardif_neigh);
kfree_skb(skb_priv); } diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 2681c7d..24c62a8 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -23,6 +23,7 @@ #include <linux/fs.h> #include <linux/jiffies.h> #include <linux/kernel.h> +#include <linux/kref.h> #include <linux/list.h> #include <linux/lockdep.h> #include <linux/netdevice.h> @@ -208,6 +209,47 @@ void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo) }
/** + * batadv_hardif_neigh_free - remove unreferenced hardif neighbor + * @hardif_neigh: hardif neigh neighbor to free + */ +static void +batadv_hardif_neigh_free(struct batadv_hardif_neigh_node *hardif_neigh) +{ + batadv_hardif_free_ref_now(hardif_neigh->if_incoming); + kfree(hardif_neigh); +} + +/** + * batadv_hardif_neigh_release_now - release hardif neigh node from lists and + * free without waiting for rcu grace period + * @ref: kref pointer of the neigh_node + */ +static void batadv_hardif_neigh_release_now(struct kref *ref) +{ + struct batadv_hardif_neigh_node *hardif_neigh; + + hardif_neigh = container_of(ref, struct batadv_hardif_neigh_node, + refcount); + + spin_lock_bh(&hardif_neigh->if_incoming->neigh_list_lock); + hlist_del_init_rcu(&hardif_neigh->list); + spin_unlock_bh(&hardif_neigh->if_incoming->neigh_list_lock); + + batadv_hardif_neigh_free(hardif_neigh); +} + +/** + * batadv_hardif_neigh_put_now - decrement the hardif neighbors refcounter + * and possibly release it (without rcu callback) + * @hardif_neigh: hardif neigh neighbor to free + */ +static void +batadv_hardif_neigh_put_now(struct batadv_hardif_neigh_node *hardif_neigh) +{ + kref_put(&hardif_neigh->refcount, batadv_hardif_neigh_release_now); +} + +/** * batadv_hardif_neigh_free_rcu - free the hardif neigh_node * @rcu: rcu pointer of the neigh_node */ @@ -216,42 +258,36 @@ static void batadv_hardif_neigh_free_rcu(struct rcu_head *rcu) struct batadv_hardif_neigh_node *hardif_neigh;
hardif_neigh = container_of(rcu, struct batadv_hardif_neigh_node, rcu); - - batadv_hardif_free_ref_now(hardif_neigh->if_incoming); - kfree(hardif_neigh); + batadv_hardif_neigh_free(hardif_neigh); }
/** - * batadv_hardif_neigh_free_now - decrement the hardif neighbors refcounter - * and possibly free it (without rcu callback) - * @hardif_neigh: hardif neigh neighbor to free + * batadv_hardif_neigh_release_rcu - release hardif neigh node from lists and + * queue for free after rcu grace period + * * @ref: kref pointer of the neigh_node */ -static void -batadv_hardif_neigh_free_now(struct batadv_hardif_neigh_node *hardif_neigh) +static void batadv_hardif_neigh_release_rcu(struct kref *ref) { - if (atomic_dec_and_test(&hardif_neigh->refcount)) { - spin_lock_bh(&hardif_neigh->if_incoming->neigh_list_lock); - hlist_del_init_rcu(&hardif_neigh->list); - spin_unlock_bh(&hardif_neigh->if_incoming->neigh_list_lock); + struct batadv_hardif_neigh_node *hardif_neigh;
- batadv_hardif_neigh_free_rcu(&hardif_neigh->rcu); - } + hardif_neigh = container_of(ref, struct batadv_hardif_neigh_node, + refcount); + + spin_lock_bh(&hardif_neigh->if_incoming->neigh_list_lock); + hlist_del_init_rcu(&hardif_neigh->list); + spin_unlock_bh(&hardif_neigh->if_incoming->neigh_list_lock); + + call_rcu(&hardif_neigh->rcu, batadv_hardif_neigh_free_rcu); }
/** - * batadv_hardif_neigh_free_ref - decrement the hardif neighbors refcounter - * and possibly free it + * batadv_hardif_neigh_put - decrement the hardif neighbors refcounter + * and possibly release it * @hardif_neigh: hardif neigh neighbor to free */ -void batadv_hardif_neigh_free_ref(struct batadv_hardif_neigh_node *hardif_neigh) +void batadv_hardif_neigh_put(struct batadv_hardif_neigh_node *hardif_neigh) { - if (atomic_dec_and_test(&hardif_neigh->refcount)) { - spin_lock_bh(&hardif_neigh->if_incoming->neigh_list_lock); - hlist_del_init_rcu(&hardif_neigh->list); - spin_unlock_bh(&hardif_neigh->if_incoming->neigh_list_lock); - - call_rcu(&hardif_neigh->rcu, batadv_hardif_neigh_free_rcu); - } + kref_put(&hardif_neigh->refcount, batadv_hardif_neigh_release_rcu); }
/** @@ -278,8 +314,8 @@ static void batadv_neigh_node_free_rcu(struct rcu_head *rcu) neigh_node->addr); if (hardif_neigh) { /* batadv_hardif_neigh_get() increases refcount too */ - batadv_hardif_neigh_free_now(hardif_neigh); - batadv_hardif_neigh_free_now(hardif_neigh); + batadv_hardif_neigh_put_now(hardif_neigh); + batadv_hardif_neigh_put_now(hardif_neigh); }
if (bao->bat_neigh_free) @@ -576,7 +612,7 @@ batadv_hardif_neigh_create(struct batadv_hard_iface *hard_iface, hardif_neigh->if_incoming = hard_iface; hardif_neigh->last_seen = jiffies;
- atomic_set(&hardif_neigh->refcount, 1); + kref_init(&hardif_neigh->refcount);
if (bat_priv->bat_algo_ops->bat_hardif_neigh_init) bat_priv->bat_algo_ops->bat_hardif_neigh_init(hardif_neigh); @@ -631,7 +667,7 @@ batadv_hardif_neigh_get(const struct batadv_hard_iface *hard_iface, if (!batadv_compare_eth(tmp_hardif_neigh->addr, neigh_addr)) continue;
- if (!atomic_inc_not_zero(&tmp_hardif_neigh->refcount)) + if (!kref_get_unless_zero(&tmp_hardif_neigh->refcount)) continue;
hardif_neigh = tmp_hardif_neigh; @@ -695,7 +731,7 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node, spin_unlock_bh(&orig_node->neigh_list_lock);
/* increment unique neighbor refcount */ - atomic_inc(&hardif_neigh->refcount); + kref_get(&hardif_neigh->refcount);
batadv_dbg(BATADV_DBG_BATMAN, orig_node->bat_priv, "Creating new neighbor %pM for orig_node %pM on interface %s\n", @@ -703,7 +739,7 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node,
out: if (hardif_neigh) - batadv_hardif_neigh_free_ref(hardif_neigh); + batadv_hardif_neigh_put(hardif_neigh); return neigh_node; }
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index 2955775..0dd1beb 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -45,7 +45,7 @@ struct batadv_hardif_neigh_node * batadv_hardif_neigh_get(const struct batadv_hard_iface *hard_iface, const u8 *neigh_addr); void -batadv_hardif_neigh_free_ref(struct batadv_hardif_neigh_node *hardif_neigh); +batadv_hardif_neigh_put(struct batadv_hardif_neigh_node *hardif_neigh); struct batadv_neigh_node * batadv_neigh_node_new(struct batadv_orig_node *orig_node, struct batadv_hard_iface *hard_iface, diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 5e8c8df..091ad76 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -25,6 +25,7 @@ #include <linux/bitops.h> #include <linux/compiler.h> #include <linux/if_ether.h> +#include <linux/kref.h> #include <linux/netdevice.h> #include <linux/sched.h> /* for linux/wait.h */ #include <linux/spinlock.h> @@ -359,7 +360,7 @@ struct batadv_hardif_neigh_node { u8 addr[ETH_ALEN]; struct batadv_hard_iface *if_incoming; unsigned long last_seen; - atomic_t refcount; + struct kref refcount; struct rcu_head rcu; };
The batadv_hardif_neigh_put function uses call_rcu to delay the free of the batadv_hardif_neigh_node object until no (already started) rcu_read_lock is enabled anymore. This makes sure that no context still is trying to access the object which should be removed. But batadv_hardif_neigh_node also contains a reference to if_incoming which must be removed.
This if_incoming was done in the call_rcu function batadv_hardif_neigh_free_rcu but should actually be done in the batadv_hardif_neigh_release_rcu function to avoid nested call_rcus. This is important because rcu_barrier (e.g. batadv_softif_free or batadv_exit) will not detect the inner call_rcu as relevant for its execution because this barrier was most likely inserted in the queue before the callback of the first call_rcu was executed. The caller of rcu_barrier will therefore continue to run before the inner call_rcu callback finished.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/originator.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 24c62a8..18305d3 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -215,7 +215,6 @@ void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo) static void batadv_hardif_neigh_free(struct batadv_hardif_neigh_node *hardif_neigh) { - batadv_hardif_free_ref_now(hardif_neigh->if_incoming); kfree(hardif_neigh); }
@@ -235,6 +234,8 @@ static void batadv_hardif_neigh_release_now(struct kref *ref) hlist_del_init_rcu(&hardif_neigh->list); spin_unlock_bh(&hardif_neigh->if_incoming->neigh_list_lock);
+ batadv_hardif_free_ref_now(hardif_neigh->if_incoming); + batadv_hardif_neigh_free(hardif_neigh); }
@@ -277,6 +278,8 @@ static void batadv_hardif_neigh_release_rcu(struct kref *ref) hlist_del_init_rcu(&hardif_neigh->list); spin_unlock_bh(&hardif_neigh->if_incoming->neigh_list_lock);
+ batadv_hardif_free_ref(hardif_neigh->if_incoming); + call_rcu(&hardif_neigh->rcu, batadv_hardif_neigh_free_rcu); }
It is not allowed to free the memory of an object which is part of a list which is protected by rcu-read-side-critical sections without making sure that no other context is accessing the object anymore. This usually happens by removing the references to this object and then waiting until the rcu grace period is over and no one (allowedly) accesses it anymore.
But the _now functions ignore this completely. They delete the entry from the lists and immediately frees the entry. This has to be avoided and thus these functions must be removed and all functions have to use instead batadv_hardif_neigh_put.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/originator.c | 42 +++++------------------------------------- 1 file changed, 5 insertions(+), 37 deletions(-)
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 18305d3..7735118 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -219,38 +219,6 @@ batadv_hardif_neigh_free(struct batadv_hardif_neigh_node *hardif_neigh) }
/** - * batadv_hardif_neigh_release_now - release hardif neigh node from lists and - * free without waiting for rcu grace period - * @ref: kref pointer of the neigh_node - */ -static void batadv_hardif_neigh_release_now(struct kref *ref) -{ - struct batadv_hardif_neigh_node *hardif_neigh; - - hardif_neigh = container_of(ref, struct batadv_hardif_neigh_node, - refcount); - - spin_lock_bh(&hardif_neigh->if_incoming->neigh_list_lock); - hlist_del_init_rcu(&hardif_neigh->list); - spin_unlock_bh(&hardif_neigh->if_incoming->neigh_list_lock); - - batadv_hardif_free_ref_now(hardif_neigh->if_incoming); - - batadv_hardif_neigh_free(hardif_neigh); -} - -/** - * batadv_hardif_neigh_put_now - decrement the hardif neighbors refcounter - * and possibly release it (without rcu callback) - * @hardif_neigh: hardif neigh neighbor to free - */ -static void -batadv_hardif_neigh_put_now(struct batadv_hardif_neigh_node *hardif_neigh) -{ - kref_put(&hardif_neigh->refcount, batadv_hardif_neigh_release_now); -} - -/** * batadv_hardif_neigh_free_rcu - free the hardif neigh_node * @rcu: rcu pointer of the neigh_node */ @@ -263,11 +231,11 @@ static void batadv_hardif_neigh_free_rcu(struct rcu_head *rcu) }
/** - * batadv_hardif_neigh_release_rcu - release hardif neigh node from lists and + * batadv_hardif_neigh_release - release hardif neigh node from lists and * queue for free after rcu grace period * * @ref: kref pointer of the neigh_node */ -static void batadv_hardif_neigh_release_rcu(struct kref *ref) +static void batadv_hardif_neigh_release(struct kref *ref) { struct batadv_hardif_neigh_node *hardif_neigh;
@@ -290,7 +258,7 @@ static void batadv_hardif_neigh_release_rcu(struct kref *ref) */ void batadv_hardif_neigh_put(struct batadv_hardif_neigh_node *hardif_neigh) { - kref_put(&hardif_neigh->refcount, batadv_hardif_neigh_release_rcu); + kref_put(&hardif_neigh->refcount, batadv_hardif_neigh_release); }
/** @@ -317,8 +285,8 @@ static void batadv_neigh_node_free_rcu(struct rcu_head *rcu) neigh_node->addr); if (hardif_neigh) { /* batadv_hardif_neigh_get() increases refcount too */ - batadv_hardif_neigh_put_now(hardif_neigh); - batadv_hardif_neigh_put_now(hardif_neigh); + batadv_hardif_neigh_put(hardif_neigh); + batadv_hardif_neigh_put(hardif_neigh); }
if (bao->bat_neigh_free)
The refactoring of the batadv_hardif_neigh_node reference counting function converted batadv_hardif_neigh_free_rcu to basically kfree_rcu. Drop it and just use kfree_rcu instead.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/originator.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-)
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 7735118..f39a715 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -209,28 +209,6 @@ void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo) }
/** - * batadv_hardif_neigh_free - remove unreferenced hardif neighbor - * @hardif_neigh: hardif neigh neighbor to free - */ -static void -batadv_hardif_neigh_free(struct batadv_hardif_neigh_node *hardif_neigh) -{ - kfree(hardif_neigh); -} - -/** - * batadv_hardif_neigh_free_rcu - free the hardif neigh_node - * @rcu: rcu pointer of the neigh_node - */ -static void batadv_hardif_neigh_free_rcu(struct rcu_head *rcu) -{ - struct batadv_hardif_neigh_node *hardif_neigh; - - hardif_neigh = container_of(rcu, struct batadv_hardif_neigh_node, rcu); - batadv_hardif_neigh_free(hardif_neigh); -} - -/** * batadv_hardif_neigh_release - release hardif neigh node from lists and * queue for free after rcu grace period * * @ref: kref pointer of the neigh_node @@ -247,8 +225,7 @@ static void batadv_hardif_neigh_release(struct kref *ref) spin_unlock_bh(&hardif_neigh->if_incoming->neigh_list_lock);
batadv_hardif_free_ref(hardif_neigh->if_incoming); - - call_rcu(&hardif_neigh->rcu, batadv_hardif_neigh_free_rcu); + kfree_rcu(hardif_neigh, rcu); }
/**
So switch to kref instead of using the self-made, atomic_t-based implementation.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/gateway_client.c | 71 +++++++++++++++++++++++++---------------- net/batman-adv/types.h | 2 +- 2 files changed, 45 insertions(+), 28 deletions(-)
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 8350775..a7b9698 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -28,6 +28,7 @@ #include <linux/ip.h> #include <linux/ipv6.h> #include <linux/kernel.h> +#include <linux/kref.h> #include <linux/list.h> #include <linux/netdevice.h> #include <linux/rculist.h> @@ -59,12 +60,28 @@ */ #define BATADV_DHCP_CHADDR_OFFSET 28
-static void batadv_gw_node_free_ref(struct batadv_gw_node *gw_node) +/** + * batadv_gw_node_release - release gw_node from lists and queue for free after + * rcu grace period + * * @ref: kref pointer of the gw_node + */ +static void batadv_gw_node_release(struct kref *ref) { - if (atomic_dec_and_test(&gw_node->refcount)) { - batadv_orig_node_free_ref(gw_node->orig_node); - kfree_rcu(gw_node, rcu); - } + struct batadv_gw_node *gw_node; + + gw_node = container_of(ref, struct batadv_gw_node, refcount); + + batadv_orig_node_free_ref(gw_node->orig_node); + kfree_rcu(gw_node, rcu); +} + +/** + * batadv_gw_node_put - decrement the gw_node refcounter and possibly release it + * @gw_node: gateway node to free + */ +static void batadv_gw_node_put(struct batadv_gw_node *gw_node) +{ + kref_put(&gw_node->refcount, batadv_gw_node_release); }
static struct batadv_gw_node * @@ -77,7 +94,7 @@ batadv_gw_get_selected_gw_node(struct batadv_priv *bat_priv) if (!gw_node) goto out;
- if (!atomic_inc_not_zero(&gw_node->refcount)) + if (!kref_get_unless_zero(&gw_node->refcount)) gw_node = NULL;
out: @@ -107,7 +124,7 @@ unlock: rcu_read_unlock(); out: if (gw_node) - batadv_gw_node_free_ref(gw_node); + batadv_gw_node_put(gw_node); return orig_node; }
@@ -118,14 +135,14 @@ static void batadv_gw_select(struct batadv_priv *bat_priv,
spin_lock_bh(&bat_priv->gw.list_lock);
- if (new_gw_node && !atomic_inc_not_zero(&new_gw_node->refcount)) + if (new_gw_node && !kref_get_unless_zero(&new_gw_node->refcount)) new_gw_node = NULL;
curr_gw_node = rcu_dereference_protected(bat_priv->gw.curr_gw, 1); rcu_assign_pointer(bat_priv->gw.curr_gw, new_gw_node);
if (curr_gw_node) - batadv_gw_node_free_ref(curr_gw_node); + batadv_gw_node_put(curr_gw_node);
spin_unlock_bh(&bat_priv->gw.list_lock); } @@ -170,7 +187,7 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) if (!router_ifinfo) goto next;
- if (!atomic_inc_not_zero(&gw_node->refcount)) + if (!kref_get_unless_zero(&gw_node->refcount)) goto next;
tq_avg = router_ifinfo->bat_iv.tq_avg; @@ -186,9 +203,9 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) ((tmp_gw_factor == max_gw_factor) && (tq_avg > max_tq))) { if (curr_gw) - batadv_gw_node_free_ref(curr_gw); + batadv_gw_node_put(curr_gw); curr_gw = gw_node; - atomic_inc(&curr_gw->refcount); + kref_get(&curr_gw->refcount); } break;
@@ -201,9 +218,9 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) */ if (tq_avg > max_tq) { if (curr_gw) - batadv_gw_node_free_ref(curr_gw); + batadv_gw_node_put(curr_gw); curr_gw = gw_node; - atomic_inc(&curr_gw->refcount); + kref_get(&curr_gw->refcount); } break; } @@ -214,7 +231,7 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) if (tmp_gw_factor > max_gw_factor) max_gw_factor = tmp_gw_factor;
- batadv_gw_node_free_ref(gw_node); + batadv_gw_node_put(gw_node);
next: batadv_neigh_node_free_ref(router); @@ -255,7 +272,7 @@ void batadv_gw_check_client_stop(struct batadv_priv *bat_priv) */ batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_DEL, NULL);
- batadv_gw_node_free_ref(curr_gw); + batadv_gw_node_put(curr_gw); }
void batadv_gw_election(struct batadv_priv *bat_priv) @@ -330,9 +347,9 @@ void batadv_gw_election(struct batadv_priv *bat_priv)
out: if (curr_gw) - batadv_gw_node_free_ref(curr_gw); + batadv_gw_node_put(curr_gw); if (next_gw) - batadv_gw_node_free_ref(next_gw); + batadv_gw_node_put(next_gw); if (router) batadv_neigh_node_free_ref(router); if (router_ifinfo) @@ -436,7 +453,7 @@ static void batadv_gw_node_add(struct batadv_priv *bat_priv, gw_node->orig_node = orig_node; gw_node->bandwidth_down = ntohl(gateway->bandwidth_down); gw_node->bandwidth_up = ntohl(gateway->bandwidth_up); - atomic_set(&gw_node->refcount, 1); + kref_init(&gw_node->refcount);
spin_lock_bh(&bat_priv->gw.list_lock); hlist_add_head_rcu(&gw_node->list, &bat_priv->gw.list); @@ -469,7 +486,7 @@ batadv_gw_node_get(struct batadv_priv *bat_priv, if (gw_node_tmp->orig_node != orig_node) continue;
- if (!atomic_inc_not_zero(&gw_node_tmp->refcount)) + if (!kref_get_unless_zero(&gw_node_tmp->refcount)) continue;
gw_node = gw_node_tmp; @@ -530,19 +547,19 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv, hlist_del_init_rcu(&gw_node->list); spin_unlock_bh(&bat_priv->gw.list_lock);
- batadv_gw_node_free_ref(gw_node); + batadv_gw_node_put(gw_node);
curr_gw = batadv_gw_get_selected_gw_node(bat_priv); if (gw_node == curr_gw) batadv_gw_reselect(bat_priv);
if (curr_gw) - batadv_gw_node_free_ref(curr_gw); + batadv_gw_node_put(curr_gw); }
out: if (gw_node) - batadv_gw_node_free_ref(gw_node); + batadv_gw_node_put(gw_node); }
void batadv_gw_node_delete(struct batadv_priv *bat_priv, @@ -565,7 +582,7 @@ void batadv_gw_node_free(struct batadv_priv *bat_priv) hlist_for_each_entry_safe(gw_node, node_tmp, &bat_priv->gw.list, list) { hlist_del_init_rcu(&gw_node->list); - batadv_gw_node_free_ref(gw_node); + batadv_gw_node_put(gw_node); } spin_unlock_bh(&bat_priv->gw.list_lock); } @@ -602,7 +619,7 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv, ret = seq_has_overflowed(seq) ? -1 : 0;
if (curr_gw) - batadv_gw_node_free_ref(curr_gw); + batadv_gw_node_put(curr_gw); out: if (router_ifinfo) batadv_neigh_ifinfo_free_ref(router_ifinfo); @@ -862,9 +879,9 @@ out: if (orig_dst_node) batadv_orig_node_free_ref(orig_dst_node); if (curr_gw) - batadv_gw_node_free_ref(curr_gw); + batadv_gw_node_put(curr_gw); if (gw_node) - batadv_gw_node_free_ref(gw_node); + batadv_gw_node_put(gw_node); if (neigh_old) batadv_neigh_node_free_ref(neigh_old); if (neigh_curr) diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 091ad76..0b3cbdb 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -342,7 +342,7 @@ struct batadv_gw_node { struct batadv_orig_node *orig_node; u32 bandwidth_down; u32 bandwidth_up; - atomic_t refcount; + struct kref refcount; struct rcu_head rcu; };
So switch to kref instead of using the self-made, atomic_t-based implementation.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/main.c | 2 +- net/batman-adv/soft-interface.c | 45 ++++++++++++++++++++++++-------------- net/batman-adv/soft-interface.h | 2 +- net/batman-adv/sysfs.c | 7 +++--- net/batman-adv/translation-table.c | 20 ++++++++--------- net/batman-adv/types.h | 2 +- 6 files changed, 46 insertions(+), 32 deletions(-)
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 9d34be6..cfcc448 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -1234,7 +1234,7 @@ bool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid) vlan = batadv_softif_vlan_get(bat_priv, vid); if (vlan) { ap_isolation_enabled = atomic_read(&vlan->ap_isolation); - batadv_softif_vlan_free_ref(vlan); + batadv_softif_vlan_put(vlan); }
return ap_isolation_enabled; diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 6c65de9..7268feb 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -30,6 +30,7 @@ #include <linux/if_vlan.h> #include <linux/jiffies.h> #include <linux/kernel.h> +#include <linux/kref.h> #include <linux/list.h> #include <linux/lockdep.h> #include <linux/netdevice.h> @@ -478,22 +479,34 @@ out: }
/** - * batadv_softif_vlan_free_ref - decrease the vlan object refcounter and + * batadv_softif_vlan_release - release vlan from lists and queue for free after + * rcu grace period + * * @ref: kref pointer of the vlan object + */ +static void batadv_softif_vlan_release(struct kref *ref) +{ + struct batadv_softif_vlan *vlan; + + vlan = container_of(ref, struct batadv_softif_vlan, refcount); + + spin_lock_bh(&vlan->bat_priv->softif_vlan_list_lock); + hlist_del_rcu(&vlan->list); + spin_unlock_bh(&vlan->bat_priv->softif_vlan_list_lock); + + kfree_rcu(vlan, rcu); +} + +/** + * batadv_softif_vlan_put - decrease the vlan object refcounter and * possibly free it * @vlan: the vlan object to release */ -void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *vlan) +void batadv_softif_vlan_put(struct batadv_softif_vlan *vlan) { if (!vlan) return;
- if (atomic_dec_and_test(&vlan->refcount)) { - spin_lock_bh(&vlan->bat_priv->softif_vlan_list_lock); - hlist_del_rcu(&vlan->list); - spin_unlock_bh(&vlan->bat_priv->softif_vlan_list_lock); - - kfree_rcu(vlan, rcu); - } + kref_put(&vlan->refcount, batadv_softif_vlan_release); }
/** @@ -514,7 +527,7 @@ struct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv, if (vlan_tmp->vid != vid) continue;
- if (!atomic_inc_not_zero(&vlan_tmp->refcount)) + if (!kref_get_unless_zero(&vlan_tmp->refcount)) continue;
vlan = vlan_tmp; @@ -539,7 +552,7 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
vlan = batadv_softif_vlan_get(bat_priv, vid); if (vlan) { - batadv_softif_vlan_free_ref(vlan); + batadv_softif_vlan_put(vlan); return -EEXIST; }
@@ -549,7 +562,7 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
vlan->bat_priv = bat_priv; vlan->vid = vid; - atomic_set(&vlan->refcount, 1); + kref_init(&vlan->refcount);
atomic_set(&vlan->ap_isolation, 0);
@@ -588,7 +601,7 @@ static void batadv_softif_destroy_vlan(struct batadv_priv *bat_priv, vlan->vid, "vlan interface destroyed", false);
batadv_sysfs_del_vlan(bat_priv, vlan); - batadv_softif_vlan_free_ref(vlan); + batadv_softif_vlan_put(vlan); }
/** @@ -633,7 +646,7 @@ static int batadv_interface_add_vid(struct net_device *dev, __be16 proto, if (!vlan->kobj) { ret = batadv_sysfs_add_vlan(bat_priv->soft_iface, vlan); if (ret) { - batadv_softif_vlan_free_ref(vlan); + batadv_softif_vlan_put(vlan); return ret; } } @@ -680,7 +693,7 @@ static int batadv_interface_kill_vid(struct net_device *dev, __be16 proto, batadv_softif_destroy_vlan(bat_priv, vlan);
/* finally free the vlan object */ - batadv_softif_vlan_free_ref(vlan); + batadv_softif_vlan_put(vlan);
return 0; } @@ -736,7 +749,7 @@ static void batadv_softif_destroy_finish(struct work_struct *work) vlan = batadv_softif_vlan_get(bat_priv, BATADV_NO_FLAGS); if (vlan) { batadv_softif_destroy_vlan(bat_priv, vlan); - batadv_softif_vlan_free_ref(vlan); + batadv_softif_vlan_put(vlan); }
batadv_sysfs_del_meshif(soft_iface); diff --git a/net/batman-adv/soft-interface.h b/net/batman-adv/soft-interface.h index 8e82176..3fc7392 100644 --- a/net/batman-adv/soft-interface.h +++ b/net/batman-adv/soft-interface.h @@ -34,7 +34,7 @@ void batadv_softif_destroy_sysfs(struct net_device *soft_iface); int batadv_softif_is_valid(const struct net_device *net_dev); extern struct rtnl_link_ops batadv_link_ops; int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid); -void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *softif_vlan); +void batadv_softif_vlan_put(struct batadv_softif_vlan *softif_vlan); struct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv, unsigned short vid);
diff --git a/net/batman-adv/sysfs.c b/net/batman-adv/sysfs.c index f38d7b7..63a86c2 100644 --- a/net/batman-adv/sysfs.c +++ b/net/batman-adv/sysfs.c @@ -25,6 +25,7 @@ #include <linux/fs.h> #include <linux/if.h> #include <linux/if_vlan.h> +#include <linux/kref.h> #include <linux/kernel.h> #include <linux/netdevice.h> #include <linux/printk.h> @@ -97,7 +98,7 @@ batadv_kobj_to_vlan(struct batadv_priv *bat_priv, struct kobject *obj) if (vlan_tmp->kobj != obj) continue;
- if (!atomic_inc_not_zero(&vlan_tmp->refcount)) + if (!kref_get_unless_zero(&vlan_tmp->refcount)) continue;
vlan = vlan_tmp; @@ -215,7 +216,7 @@ ssize_t batadv_store_vlan_##_name(struct kobject *kobj, \ attr, &vlan->_name, \ bat_priv->soft_iface); \ \ - batadv_softif_vlan_free_ref(vlan); \ + batadv_softif_vlan_put(vlan); \ return res; \ }
@@ -230,7 +231,7 @@ ssize_t batadv_show_vlan_##_name(struct kobject *kobj, \ atomic_read(&vlan->_name) == 0 ? \ "disabled" : "enabled"); \ \ - batadv_softif_vlan_free_ref(vlan); \ + batadv_softif_vlan_put(vlan); \ return res; \ }
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 1ca8831..3cac667 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -280,7 +280,7 @@ static void batadv_tt_local_size_mod(struct batadv_priv *bat_priv,
atomic_add(v, &vlan->tt.num_entries);
- batadv_softif_vlan_free_ref(vlan); + batadv_softif_vlan_put(vlan); }
/** @@ -646,7 +646,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr, if (unlikely(hash_added != 0)) { /* remove the reference for the hash */ batadv_tt_local_entry_free_ref(tt_local); - batadv_softif_vlan_free_ref(vlan); + batadv_softif_vlan_put(vlan); goto out; }
@@ -1012,7 +1012,7 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) no_purge ? 0 : last_seen_msecs, vlan->tt.crc);
- batadv_softif_vlan_free_ref(vlan); + batadv_softif_vlan_put(vlan); } rcu_read_unlock(); } @@ -1102,8 +1102,8 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr, if (!vlan) goto out;
- batadv_softif_vlan_free_ref(vlan); - batadv_softif_vlan_free_ref(vlan); + batadv_softif_vlan_put(vlan); + batadv_softif_vlan_put(vlan);
out: if (tt_local_entry) @@ -1203,8 +1203,8 @@ static void batadv_tt_local_table_free(struct batadv_priv *bat_priv) vlan = batadv_softif_vlan_get(bat_priv, tt_common_entry->vid); if (vlan) { - batadv_softif_vlan_free_ref(vlan); - batadv_softif_vlan_free_ref(vlan); + batadv_softif_vlan_put(vlan); + batadv_softif_vlan_put(vlan); }
batadv_tt_local_entry_free_ref(tt_local); @@ -3298,8 +3298,8 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) /* decrease the reference held for this vlan */ vlan = batadv_softif_vlan_get(bat_priv, tt_common->vid); if (vlan) { - batadv_softif_vlan_free_ref(vlan); - batadv_softif_vlan_free_ref(vlan); + batadv_softif_vlan_put(vlan); + batadv_softif_vlan_put(vlan); }
batadv_tt_local_entry_free_ref(tt_local); @@ -3385,7 +3385,7 @@ bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, u8 *src, u8 *dst, ret = true;
out: - batadv_softif_vlan_free_ref(vlan); + batadv_softif_vlan_put(vlan); if (tt_global_entry) batadv_tt_global_entry_free_ref(tt_global_entry); if (tt_local_entry) diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 0b3cbdb..c6c3f0f 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -746,7 +746,7 @@ struct batadv_softif_vlan { atomic_t ap_isolation; /* boolean */ struct batadv_vlan_tt tt; struct hlist_node list; - atomic_t refcount; + struct kref refcount; struct rcu_head rcu; };
So switch to kref instead of using the self-made, atomic_t-based implementation.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/bridge_loop_avoidance.c | 50 ++++++++++++++++++++++------------ net/batman-adv/types.h | 2 +- 2 files changed, 34 insertions(+), 18 deletions(-)
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index d9b034a..4e5538a 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -31,6 +31,7 @@ #include <linux/jhash.h> #include <linux/jiffies.h> #include <linux/kernel.h> +#include <linux/kref.h> #include <linux/list.h> #include <linux/lockdep.h> #include <linux/netdevice.h> @@ -143,14 +144,28 @@ static int batadv_compare_claim(const struct hlist_node *node, }
/** - * batadv_compare_backbone_gw - free backbone gw + * batadv_backbone_gw_release - release backbone gw from lists and queue for + * free after rcu grace period + * * @ref: kref pointer of the backbone gw + */ +static void batadv_backbone_gw_release(struct kref *ref) +{ + struct batadv_bla_backbone_gw *backbone_gw; + + backbone_gw = container_of(ref, struct batadv_bla_backbone_gw, + refcount); + + kfree_rcu(backbone_gw, rcu); +} + +/** + * batadv_backbone_gw_put - decrement the backbone gw refcounter and possibly + * release it * @backbone_gw: backbone gateway to be free'd */ -static void -batadv_backbone_gw_free_ref(struct batadv_bla_backbone_gw *backbone_gw) +static void batadv_backbone_gw_put(struct batadv_bla_backbone_gw *backbone_gw) { - if (atomic_dec_and_test(&backbone_gw->refcount)) - kfree_rcu(backbone_gw, rcu); + kref_put(&backbone_gw->refcount, batadv_backbone_gw_release); }
/** @@ -163,7 +178,7 @@ static void batadv_claim_free_rcu(struct rcu_head *rcu)
claim = container_of(rcu, struct batadv_bla_claim, rcu);
- batadv_backbone_gw_free_ref(claim->backbone_gw); + batadv_backbone_gw_put(claim->backbone_gw); kfree(claim); }
@@ -249,7 +264,7 @@ batadv_backbone_hash_find(struct batadv_priv *bat_priv, u8 *addr, &search_entry)) continue;
- if (!atomic_inc_not_zero(&backbone_gw->refcount)) + if (!kref_get_unless_zero(&backbone_gw->refcount)) continue;
backbone_gw_tmp = backbone_gw; @@ -450,7 +465,8 @@ batadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, u8 *orig, ether_addr_copy(entry->orig, orig);
/* one for the hash, one for returning */ - atomic_set(&entry->refcount, 2); + kref_init(&entry->refcount); + kref_get(&entry->refcount);
hash_added = batadv_hash_add(bat_priv->bla.backbone_hash, batadv_compare_backbone_gw, @@ -506,7 +522,7 @@ batadv_bla_update_own_backbone_gw(struct batadv_priv *bat_priv, return;
backbone_gw->lasttime = jiffies; - batadv_backbone_gw_free_ref(backbone_gw); + batadv_backbone_gw_put(backbone_gw); }
/** @@ -555,7 +571,7 @@ static void batadv_bla_answer_request(struct batadv_priv *bat_priv,
/* finally, send an announcement frame */ batadv_bla_send_announce(bat_priv, backbone_gw); - batadv_backbone_gw_free_ref(backbone_gw); + batadv_backbone_gw_put(backbone_gw); }
/** @@ -663,10 +679,10 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv, spin_lock_bh(&claim->backbone_gw->crc_lock); claim->backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN); spin_unlock_bh(&claim->backbone_gw->crc_lock); - batadv_backbone_gw_free_ref(claim->backbone_gw); + batadv_backbone_gw_put(claim->backbone_gw); } /* set (new) backbone gw */ - atomic_inc(&backbone_gw->refcount); + kref_get(&backbone_gw->refcount); claim->backbone_gw = backbone_gw;
spin_lock_bh(&backbone_gw->crc_lock); @@ -764,7 +780,7 @@ static int batadv_handle_announce(struct batadv_priv *bat_priv, u8 *an_addr, } }
- batadv_backbone_gw_free_ref(backbone_gw); + batadv_backbone_gw_put(backbone_gw); return 1; }
@@ -835,7 +851,7 @@ static int batadv_handle_unclaim(struct batadv_priv *bat_priv, claim_addr, BATADV_PRINT_VID(vid), backbone_gw->orig);
batadv_bla_del_claim(bat_priv, claim_addr, vid); - batadv_backbone_gw_free_ref(backbone_gw); + batadv_backbone_gw_put(backbone_gw); return 1; }
@@ -872,7 +888,7 @@ static int batadv_handle_claim(struct batadv_priv *bat_priv,
/* TODO: we could call something like tt_local_del() here. */
- batadv_backbone_gw_free_ref(backbone_gw); + batadv_backbone_gw_put(backbone_gw); return 1; }
@@ -1135,7 +1151,7 @@ purge_now: batadv_bla_del_backbone_claims(backbone_gw);
hlist_del_rcu(&backbone_gw->hash_entry); - batadv_backbone_gw_free_ref(backbone_gw); + batadv_backbone_gw_put(backbone_gw); } spin_unlock_bh(list_lock); } @@ -1552,7 +1568,7 @@ int batadv_bla_is_backbone_gw(struct sk_buff *skb, if (!backbone_gw) return 0;
- batadv_backbone_gw_free_ref(backbone_gw); + batadv_backbone_gw_put(backbone_gw); return 1; }
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index c6c3f0f..098ec7f 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -930,7 +930,7 @@ struct batadv_bla_backbone_gw { atomic_t request_sent; u16 crc; spinlock_t crc_lock; /* protects crc */ - atomic_t refcount; + struct kref refcount; struct rcu_head rcu; };
So switch to kref instead of using the self-made, atomic_t-based implementation.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/bridge_loop_avoidance.c | 36 ++++++++++++++++++---------------- net/batman-adv/types.h | 2 +- 2 files changed, 20 insertions(+), 18 deletions(-)
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index 4e5538a..3315b27 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -169,27 +169,28 @@ static void batadv_backbone_gw_put(struct batadv_bla_backbone_gw *backbone_gw) }
/** - * batadv_claim_free_rcu - finally deinitialize the claim - * @rcu: rcu pointer within the claim structure + * batadv_claim_release - release claim from lists and queue for free after rcu + * grace period + * * @ref: kref pointer of the claim */ -static void batadv_claim_free_rcu(struct rcu_head *rcu) +static void batadv_claim_release(struct kref *ref) { struct batadv_bla_claim *claim;
- claim = container_of(rcu, struct batadv_bla_claim, rcu); + claim = container_of(ref, struct batadv_bla_claim, refcount);
batadv_backbone_gw_put(claim->backbone_gw); - kfree(claim); + kfree_rcu(claim, rcu); }
/** - * batadv_claim_free_rcu - free a claim + * batadv_claim_put - decrement the claim refcounter and possibly + * release it * @claim: claim to be free'd */ -static void batadv_claim_free_ref(struct batadv_bla_claim *claim) +static void batadv_claim_put(struct batadv_bla_claim *claim) { - if (atomic_dec_and_test(&claim->refcount)) - call_rcu(&claim->rcu, batadv_claim_free_rcu); + kref_put(&claim->refcount, batadv_claim_release); }
/** @@ -220,7 +221,7 @@ static struct batadv_bla_claim if (!batadv_compare_claim(&claim->hash_entry, data)) continue;
- if (!atomic_inc_not_zero(&claim->refcount)) + if (!kref_get_unless_zero(&claim->refcount)) continue;
claim_tmp = claim; @@ -303,7 +304,7 @@ batadv_bla_del_backbone_claims(struct batadv_bla_backbone_gw *backbone_gw) if (claim->backbone_gw != backbone_gw) continue;
- batadv_claim_free_ref(claim); + batadv_claim_put(claim); hlist_del_rcu(&claim->hash_entry); } spin_unlock_bh(list_lock); @@ -652,7 +653,8 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv, claim->lasttime = jiffies; claim->backbone_gw = backbone_gw;
- atomic_set(&claim->refcount, 2); + kref_init(&claim->refcount); + kref_get(&claim->refcount); batadv_dbg(BATADV_DBG_BLA, bat_priv, "bla_add_claim(): adding new entry %pM, vid %d to hash ...\n", mac, BATADV_PRINT_VID(vid)); @@ -691,7 +693,7 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv, backbone_gw->lasttime = jiffies;
claim_free_ref: - batadv_claim_free_ref(claim); + batadv_claim_put(claim); }
/** @@ -716,14 +718,14 @@ static void batadv_bla_del_claim(struct batadv_priv *bat_priv,
batadv_hash_remove(bat_priv->bla.claim_hash, batadv_compare_claim, batadv_choose_claim, claim); - batadv_claim_free_ref(claim); /* reference from the hash is gone */ + batadv_claim_put(claim); /* reference from the hash is gone */
spin_lock_bh(&claim->backbone_gw->crc_lock); claim->backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN); spin_unlock_bh(&claim->backbone_gw->crc_lock);
/* don't need the reference from hash_find() anymore */ - batadv_claim_free_ref(claim); + batadv_claim_put(claim); }
/** @@ -1691,7 +1693,7 @@ out: if (primary_if) batadv_hardif_free_ref(primary_if); if (claim) - batadv_claim_free_ref(claim); + batadv_claim_put(claim); return ret; }
@@ -1780,7 +1782,7 @@ out: if (primary_if) batadv_hardif_free_ref(primary_if); if (claim) - batadv_claim_free_ref(claim); + batadv_claim_put(claim); return ret; }
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 098ec7f..c56b99c 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -951,7 +951,7 @@ struct batadv_bla_claim { unsigned long lasttime; struct hlist_node hash_entry; struct rcu_head rcu; - atomic_t refcount; + struct kref refcount; }; #endif
So switch to kref instead of using the self-made, atomic_t-based implementation.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/network-coding.c | 36 +++++++++++++++++++----------------- net/batman-adv/types.h | 2 +- 2 files changed, 20 insertions(+), 18 deletions(-)
diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c index 56100c5..246cd90 100644 --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c @@ -32,6 +32,7 @@ #include <linux/jhash.h> #include <linux/jiffies.h> #include <linux/kernel.h> +#include <linux/kref.h> #include <linux/list.h> #include <linux/lockdep.h> #include <linux/netdevice.h> @@ -207,28 +208,28 @@ void batadv_nc_init_orig(struct batadv_orig_node *orig_node) }
/** - * batadv_nc_node_free_rcu - rcu callback to free an nc node and remove - * its refcount on the orig_node - * @rcu: rcu pointer of the nc node + * batadv_nc_node_release - release nc_node from lists and queue for free after + * rcu grace period + * * @ref: kref pointer of the nc_node */ -static void batadv_nc_node_free_rcu(struct rcu_head *rcu) +static void batadv_nc_node_release(struct kref *ref) { struct batadv_nc_node *nc_node;
- nc_node = container_of(rcu, struct batadv_nc_node, rcu); + nc_node = container_of(ref, struct batadv_nc_node, refcount); + batadv_orig_node_free_ref(nc_node->orig_node); - kfree(nc_node); + kfree_rcu(nc_node, rcu); }
/** - * batadv_nc_node_free_ref - decrements the nc node refcounter and possibly - * frees it - * @nc_node: the nc node to free + * batadv_nc_node_put - decrement the nc_node refcounter and possibly + * release it + * @nc_node: nc_node to be free'd */ -static void batadv_nc_node_free_ref(struct batadv_nc_node *nc_node) +static void batadv_nc_node_put(struct batadv_nc_node *nc_node) { - if (atomic_dec_and_test(&nc_node->refcount)) - call_rcu(&nc_node->rcu, batadv_nc_node_free_rcu); + kref_put(&nc_node->refcount, batadv_nc_node_release); }
/** @@ -342,7 +343,7 @@ batadv_nc_purge_orig_nc_nodes(struct batadv_priv *bat_priv, "Removing nc_node %pM -> %pM\n", nc_node->addr, nc_node->orig_node->orig); list_del_rcu(&nc_node->list); - batadv_nc_node_free_ref(nc_node); + batadv_nc_node_put(nc_node); } spin_unlock_bh(lock); } @@ -800,7 +801,7 @@ static struct batadv_nc_node if (!batadv_compare_eth(nc_node->addr, orig_node->orig)) continue;
- if (!atomic_inc_not_zero(&nc_node->refcount)) + if (!kref_get_unless_zero(&nc_node->refcount)) continue;
/* Found a match */ @@ -851,7 +852,8 @@ static struct batadv_nc_node INIT_LIST_HEAD(&nc_node->list); ether_addr_copy(nc_node->addr, orig_node->orig); nc_node->orig_node = orig_neigh_node; - atomic_set(&nc_node->refcount, 2); + kref_init(&nc_node->refcount); + kref_get(&nc_node->refcount);
/* Select ingoing or outgoing coding node */ if (in_coding) { @@ -927,9 +929,9 @@ void batadv_nc_update_nc_node(struct batadv_priv *bat_priv,
out: if (in_nc_node) - batadv_nc_node_free_ref(in_nc_node); + batadv_nc_node_put(in_nc_node); if (out_nc_node) - batadv_nc_node_free_ref(out_nc_node); + batadv_nc_node_put(out_nc_node); }
/** diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index c56b99c..9a2371a 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -1067,7 +1067,7 @@ struct batadv_tt_roam_node { struct batadv_nc_node { struct list_head list; u8 addr[ETH_ALEN]; - atomic_t refcount; + struct kref refcount; struct rcu_head rcu; struct batadv_orig_node *orig_node; unsigned long last_seen;
So switch to kref instead of using the self-made, atomic_t-based implementation.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/network-coding.c | 38 ++++++++++++++++++++++++++------------ net/batman-adv/types.h | 2 +- 2 files changed, 27 insertions(+), 13 deletions(-)
diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c index 246cd90..a2655ad 100644 --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c @@ -233,14 +233,27 @@ static void batadv_nc_node_put(struct batadv_nc_node *nc_node) }
/** - * batadv_nc_path_free_ref - decrements the nc path refcounter and possibly - * frees it - * @nc_path: the nc node to free + * batadv_nc_path_release - release nc_path from lists and queue for free after + * rcu grace period + * * @ref: kref pointer of the nc_path */ -static void batadv_nc_path_free_ref(struct batadv_nc_path *nc_path) +static void batadv_nc_path_release(struct kref *ref) { - if (atomic_dec_and_test(&nc_path->refcount)) - kfree_rcu(nc_path, rcu); + struct batadv_nc_path *nc_path; + + nc_path = container_of(ref, struct batadv_nc_path, refcount); + + kfree_rcu(nc_path, rcu); +} + +/** + * batadv_nc_path_put - decrement the nc_path refcounter and possibly + * release it + * @nc_path: nc_path to be free'd + */ +static void batadv_nc_path_put(struct batadv_nc_path *nc_path) +{ + kref_put(&nc_path->refcount, batadv_nc_path_release); }
/** @@ -250,7 +263,7 @@ static void batadv_nc_path_free_ref(struct batadv_nc_path *nc_path) static void batadv_nc_packet_free(struct batadv_nc_packet *nc_packet) { kfree_skb(nc_packet->skb); - batadv_nc_path_free_ref(nc_packet->nc_path); + batadv_nc_path_put(nc_packet->nc_path); kfree(nc_packet); }
@@ -454,7 +467,7 @@ static void batadv_nc_purge_paths(struct batadv_priv *bat_priv, "Remove nc_path %pM -> %pM\n", nc_path->prev_hop, nc_path->next_hop); hlist_del_rcu(&nc_path->hash_entry); - batadv_nc_path_free_ref(nc_path); + batadv_nc_path_put(nc_path); } spin_unlock_bh(lock); } @@ -545,7 +558,7 @@ batadv_nc_hash_find(struct batadv_hashtable *hash, if (!batadv_nc_hash_compare(&nc_path->hash_entry, data)) continue;
- if (!atomic_inc_not_zero(&nc_path->refcount)) + if (!kref_get_unless_zero(&nc_path->refcount)) continue;
nc_path_tmp = nc_path; @@ -972,7 +985,8 @@ static struct batadv_nc_path *batadv_nc_get_path(struct batadv_priv *bat_priv, /* Initialize nc_path */ INIT_LIST_HEAD(&nc_path->packet_list); spin_lock_init(&nc_path->packet_list_lock); - atomic_set(&nc_path->refcount, 2); + kref_init(&nc_path->refcount); + kref_get(&nc_path->refcount); nc_path->last_valid = jiffies; ether_addr_copy(nc_path->next_hop, dst); ether_addr_copy(nc_path->prev_hop, src); @@ -1541,7 +1555,7 @@ bool batadv_nc_skb_forward(struct sk_buff *skb, return true;
free_nc_path: - batadv_nc_path_free_ref(nc_path); + batadv_nc_path_put(nc_path); out: /* Packet is not consumed */ return false; @@ -1603,7 +1617,7 @@ void batadv_nc_skb_store_for_decoding(struct batadv_priv *bat_priv, free_skb: kfree_skb(skb); free_nc_path: - batadv_nc_path_free_ref(nc_path); + batadv_nc_path_put(nc_path); out: return; } diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 9a2371a..49f0270 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -1087,7 +1087,7 @@ struct batadv_nc_node { struct batadv_nc_path { struct hlist_node hash_entry; struct rcu_head rcu; - atomic_t refcount; + struct kref refcount; struct list_head packet_list; spinlock_t packet_list_lock; /* Protects packet_list */ u8 next_hop[ETH_ALEN];
So switch to kref instead of using the self-made, atomic_t-based implementation.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/distributed-arp-table.c | 43 +++++++++++++++++++++++----------- net/batman-adv/types.h | 2 +- 2 files changed, 30 insertions(+), 15 deletions(-)
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index 60df823..34d0950 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -30,6 +30,7 @@ #include <linux/in.h> #include <linux/jiffies.h> #include <linux/kernel.h> +#include <linux/kref.h> #include <linux/list.h> #include <linux/rculist.h> #include <linux/rcupdate.h> @@ -62,14 +63,27 @@ static void batadv_dat_start_timer(struct batadv_priv *bat_priv) }
/** - * batadv_dat_entry_free_ref - decrement the dat_entry refcounter and possibly - * free it - * @dat_entry: the entry to free + * batadv_dat_entry_release - release dat_entry from lists and queue for free + * after rcu grace period + * * @ref: kref pointer of the dat_entry */ -static void batadv_dat_entry_free_ref(struct batadv_dat_entry *dat_entry) +static void batadv_dat_entry_release(struct kref *ref) { - if (atomic_dec_and_test(&dat_entry->refcount)) - kfree_rcu(dat_entry, rcu); + struct batadv_dat_entry *dat_entry; + + dat_entry = container_of(ref, struct batadv_dat_entry, refcount); + + kfree_rcu(dat_entry, rcu); +} + +/** + * batadv_dat_entry_put - decrement the dat_entry refcounter and possibly + * free it + * @dat_entry: dat_entry to be free'd + */ +static void batadv_dat_entry_put(struct batadv_dat_entry *dat_entry) +{ + kref_put(&dat_entry->refcount, batadv_dat_entry_release); }
/** @@ -121,7 +135,7 @@ static void __batadv_dat_purge(struct batadv_priv *bat_priv, continue;
hlist_del_rcu(&dat_entry->hash_entry); - batadv_dat_entry_free_ref(dat_entry); + batadv_dat_entry_put(dat_entry); } spin_unlock_bh(list_lock); } @@ -281,7 +295,7 @@ batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip, if (dat_entry->ip != ip) continue;
- if (!atomic_inc_not_zero(&dat_entry->refcount)) + if (!kref_get_unless_zero(&dat_entry->refcount)) continue;
dat_entry_tmp = dat_entry; @@ -326,7 +340,8 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip, dat_entry->vid = vid; ether_addr_copy(dat_entry->mac_addr, mac_addr); dat_entry->last_update = jiffies; - atomic_set(&dat_entry->refcount, 2); + kref_init(&dat_entry->refcount); + kref_get(&dat_entry->refcount);
hash_added = batadv_hash_add(bat_priv->dat.hash, batadv_compare_dat, batadv_hash_dat, dat_entry, @@ -334,7 +349,7 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
if (unlikely(hash_added != 0)) { /* remove the reference for the hash */ - batadv_dat_entry_free_ref(dat_entry); + batadv_dat_entry_put(dat_entry); goto out; }
@@ -343,7 +358,7 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
out: if (dat_entry) - batadv_dat_entry_free_ref(dat_entry); + batadv_dat_entry_put(dat_entry); }
#ifdef CONFIG_BATMAN_ADV_DEBUG @@ -1014,7 +1029,7 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, } out: if (dat_entry) - batadv_dat_entry_free_ref(dat_entry); + batadv_dat_entry_put(dat_entry); return ret; }
@@ -1094,7 +1109,7 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, } out: if (dat_entry) - batadv_dat_entry_free_ref(dat_entry); + batadv_dat_entry_put(dat_entry); if (ret) kfree_skb(skb); return ret; @@ -1247,6 +1262,6 @@ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv,
out: if (dat_entry) - batadv_dat_entry_free_ref(dat_entry); + batadv_dat_entry_put(dat_entry); return ret; } diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 49f0270..a6ba6c0 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -1230,7 +1230,7 @@ struct batadv_dat_entry { unsigned short vid; unsigned long last_update; struct hlist_node hash_entry; - atomic_t refcount; + struct kref refcount; struct rcu_head rcu; };
So switch to kref instead of using the self-made, atomic_t-based implementation.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/main.c | 28 ++++++++++++++++++++-------- net/batman-adv/types.h | 2 +- 2 files changed, 21 insertions(+), 9 deletions(-)
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index cfcc448..0f9ed4d 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -29,6 +29,7 @@ #include <linux/ip.h> #include <linux/ipv6.h> #include <linux/kernel.h> +#include <linux/kref.h> #include <linux/list.h> #include <linux/lockdep.h> #include <linux/module.h> @@ -670,14 +671,25 @@ static struct batadv_tvlv_handler }
/** - * batadv_tvlv_container_free_ref - decrement the tvlv container refcounter and + * batadv_tvlv_container_release - release tvlv from lists and free + * * @ref: kref pointer of the tvlv + */ +static void batadv_tvlv_container_release(struct kref *ref) +{ + struct batadv_tvlv_container *tvlv; + + tvlv = container_of(ref, struct batadv_tvlv_container, refcount); + kfree(tvlv); +} + +/** + * batadv_tvlv_container_put - decrement the tvlv container refcounter and * possibly free it * @tvlv: the tvlv container to free */ -static void batadv_tvlv_container_free_ref(struct batadv_tvlv_container *tvlv) +static void batadv_tvlv_container_put(struct batadv_tvlv_container *tvlv) { - if (atomic_dec_and_test(&tvlv->refcount)) - kfree(tvlv); + kref_put(&tvlv->refcount, batadv_tvlv_container_release); }
/** @@ -704,7 +716,7 @@ static struct batadv_tvlv_container if (tvlv_tmp->tvlv_hdr.version != version) continue;
- if (!atomic_inc_not_zero(&tvlv_tmp->refcount)) + if (!kref_get_unless_zero(&tvlv_tmp->refcount)) continue;
tvlv = tvlv_tmp; @@ -757,8 +769,8 @@ static void batadv_tvlv_container_remove(struct batadv_priv *bat_priv, hlist_del(&tvlv->list);
/* first call to decrement the counter, second call to free */ - batadv_tvlv_container_free_ref(tvlv); - batadv_tvlv_container_free_ref(tvlv); + batadv_tvlv_container_put(tvlv); + batadv_tvlv_container_put(tvlv); }
/** @@ -810,7 +822,7 @@ void batadv_tvlv_container_register(struct batadv_priv *bat_priv,
memcpy(tvlv_new + 1, tvlv_value, ntohs(tvlv_new->tvlv_hdr.len)); INIT_HLIST_NODE(&tvlv_new->list); - atomic_set(&tvlv_new->refcount, 1); + kref_init(&tvlv_new->refcount);
spin_lock_bh(&bat_priv->tvlv.container_list_lock); tvlv_old = batadv_tvlv_container_get(bat_priv, type, version); diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index a6ba6c0..0ebd5a4 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -1266,7 +1266,7 @@ struct batadv_dat_candidate { struct batadv_tvlv_container { struct hlist_node list; struct batadv_tvlv_hdr tvlv_hdr; - atomic_t refcount; + struct kref refcount; };
/**
So switch to kref instead of using the self-made, atomic_t-based implementation.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/main.c | 33 ++++++++++++++++++++++----------- net/batman-adv/types.h | 2 +- 2 files changed, 23 insertions(+), 12 deletions(-)
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 0f9ed4d..eee2d82 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -625,15 +625,26 @@ __be32 batadv_skb_crc32(struct sk_buff *skb, u8 *payload_ptr) }
/** - * batadv_tvlv_handler_free_ref - decrement the tvlv handler refcounter and + * batadv_tvlv_handler_release - release tvlv handler from lists and queue for + * free after rcu grace period + * * @ref: kref pointer of the tvlv + */ +static void batadv_tvlv_handler_release(struct kref *ref) +{ + struct batadv_tvlv_handler *tvlv_handler; + + tvlv_handler = container_of(ref, struct batadv_tvlv_handler, refcount); + kfree_rcu(tvlv_handler, rcu); +} + +/** + * batadv_tvlv_handler_put - decrement the tvlv container refcounter and * possibly free it * @tvlv_handler: the tvlv handler to free */ -static void -batadv_tvlv_handler_free_ref(struct batadv_tvlv_handler *tvlv_handler) +static void batadv_tvlv_handler_put(struct batadv_tvlv_handler *tvlv_handler) { - if (atomic_dec_and_test(&tvlv_handler->refcount)) - kfree_rcu(tvlv_handler, rcu); + kref_put(&tvlv_handler->refcount, batadv_tvlv_handler_release); }
/** @@ -659,7 +670,7 @@ static struct batadv_tvlv_handler if (tvlv_handler_tmp->version != version) continue;
- if (!atomic_inc_not_zero(&tvlv_handler_tmp->refcount)) + if (!kref_get_unless_zero(&tvlv_handler_tmp->refcount)) continue;
tvlv_handler = tvlv_handler_tmp; @@ -1015,7 +1026,7 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, src, dst, tvlv_value, tvlv_value_cont_len); if (tvlv_handler) - batadv_tvlv_handler_free_ref(tvlv_handler); + batadv_tvlv_handler_put(tvlv_handler); tvlv_value = (u8 *)tvlv_value + tvlv_value_cont_len; tvlv_value_len -= tvlv_value_cont_len; } @@ -1095,7 +1106,7 @@ void batadv_tvlv_handler_register(struct batadv_priv *bat_priv,
tvlv_handler = batadv_tvlv_handler_get(bat_priv, type, version); if (tvlv_handler) { - batadv_tvlv_handler_free_ref(tvlv_handler); + batadv_tvlv_handler_put(tvlv_handler); return; }
@@ -1108,7 +1119,7 @@ void batadv_tvlv_handler_register(struct batadv_priv *bat_priv, tvlv_handler->type = type; tvlv_handler->version = version; tvlv_handler->flags = flags; - atomic_set(&tvlv_handler->refcount, 1); + kref_init(&tvlv_handler->refcount); INIT_HLIST_NODE(&tvlv_handler->list);
spin_lock_bh(&bat_priv->tvlv.handler_list_lock); @@ -1132,11 +1143,11 @@ void batadv_tvlv_handler_unregister(struct batadv_priv *bat_priv, if (!tvlv_handler) return;
- batadv_tvlv_handler_free_ref(tvlv_handler); + batadv_tvlv_handler_put(tvlv_handler); spin_lock_bh(&bat_priv->tvlv.handler_list_lock); hlist_del_rcu(&tvlv_handler->list); spin_unlock_bh(&bat_priv->tvlv.handler_list_lock); - batadv_tvlv_handler_free_ref(tvlv_handler); + batadv_tvlv_handler_put(tvlv_handler); }
/** diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 0ebd5a4..60d304b 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -1293,7 +1293,7 @@ struct batadv_tvlv_handler { u8 type; u8 version; u8 flags; - atomic_t refcount; + struct kref refcount; struct rcu_head rcu; };
So switch to kref instead of using the self-made, atomic_t-based implementation.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/originator.c | 11 -------- net/batman-adv/originator.h | 1 - net/batman-adv/translation-table.c | 54 +++++++++++++++++++++----------------- net/batman-adv/types.h | 2 +- 4 files changed, 31 insertions(+), 37 deletions(-)
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index f39a715..0e836bd 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -819,17 +819,6 @@ void batadv_orig_node_free_ref(struct batadv_orig_node *orig_node) call_rcu(&orig_node->rcu, batadv_orig_node_free_rcu); }
-/** - * batadv_orig_node_free_ref_now - decrement the orig node refcounter and - * possibly free it (without rcu callback) - * @orig_node: the orig node to free - */ -void batadv_orig_node_free_ref_now(struct batadv_orig_node *orig_node) -{ - if (atomic_dec_and_test(&orig_node->refcount)) - batadv_orig_node_free_rcu(&orig_node->rcu); -} - void batadv_originator_free(struct batadv_priv *bat_priv) { struct batadv_hashtable *hash = bat_priv->orig_hash; diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index 0dd1beb..dc5cefa 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -38,7 +38,6 @@ int batadv_originator_init(struct batadv_priv *bat_priv); void batadv_originator_free(struct batadv_priv *bat_priv); void batadv_purge_orig_ref(struct batadv_priv *bat_priv); void batadv_orig_node_free_ref(struct batadv_orig_node *orig_node); -void batadv_orig_node_free_ref_now(struct batadv_orig_node *orig_node); struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, const u8 *addr); struct batadv_hardif_neigh_node * diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 3cac667..096804e 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -31,6 +31,7 @@ #include <linux/jhash.h> #include <linux/jiffies.h> #include <linux/kernel.h> +#include <linux/kref.h> #include <linux/list.h> #include <linux/lockdep.h> #include <linux/netdevice.h> @@ -248,20 +249,6 @@ int batadv_tt_global_hash_count(struct batadv_priv *bat_priv, return count; }
-static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu) -{ - struct batadv_tt_orig_list_entry *orig_entry; - - orig_entry = container_of(rcu, struct batadv_tt_orig_list_entry, rcu); - - /* We are in an rcu callback here, therefore we cannot use - * batadv_orig_node_free_ref() and its call_rcu(): - * An rcu_barrier() wouldn't wait for that to finish - */ - batadv_orig_node_free_ref_now(orig_entry->orig_node); - kfree(orig_entry); -} - /** * batadv_tt_local_size_mod - change the size by v of the local table identified * by vid @@ -357,13 +344,31 @@ static void batadv_tt_global_size_dec(struct batadv_orig_node *orig_node, batadv_tt_global_size_mod(orig_node, vid, -1); }
-static void -batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry) +/** + * batadv_tt_orig_list_entry_release - release tt orig entry from lists and + * queue for free after rcu grace period + * * @ref: kref pointer of the tt orig entry + */ +static void batadv_tt_orig_list_entry_release(struct kref *ref) { - if (!atomic_dec_and_test(&orig_entry->refcount)) - return; + struct batadv_tt_orig_list_entry *orig_entry;
- call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu); + orig_entry = container_of(ref, struct batadv_tt_orig_list_entry, + refcount); + + batadv_orig_node_free_ref(orig_entry->orig_node); + kfree_rcu(orig_entry, rcu); +} + +/** + * batadv_tt_orig_list_entry_put - decrement the tt orig entry refcounter and + * possibly release it + * @orig_entry: tt orig entry to be free'd + */ +static void +batadv_tt_orig_list_entry_put(struct batadv_tt_orig_list_entry *orig_entry) +{ + kref_put(&orig_entry->refcount, batadv_tt_orig_list_entry_release); }
/** @@ -1272,7 +1277,7 @@ batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry, hlist_for_each_entry_rcu(tmp_orig_entry, head, list) { if (tmp_orig_entry->orig_node != orig_node) continue; - if (!atomic_inc_not_zero(&tmp_orig_entry->refcount)) + if (!kref_get_unless_zero(&tmp_orig_entry->refcount)) continue;
orig_entry = tmp_orig_entry; @@ -1303,7 +1308,7 @@ batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry, orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node); if (orig_entry) { found = true; - batadv_tt_orig_list_entry_free_ref(orig_entry); + batadv_tt_orig_list_entry_put(orig_entry); }
return found; @@ -1333,7 +1338,8 @@ batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global, batadv_tt_global_size_inc(orig_node, tt_global->common.vid); orig_entry->orig_node = orig_node; orig_entry->ttvn = ttvn; - atomic_set(&orig_entry->refcount, 2); + kref_init(&orig_entry->refcount); + kref_get(&orig_entry->refcount);
spin_lock_bh(&tt_global->list_lock); hlist_add_head_rcu(&orig_entry->list, @@ -1343,7 +1349,7 @@ batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,
out: if (orig_entry) - batadv_tt_orig_list_entry_free_ref(orig_entry); + batadv_tt_orig_list_entry_put(orig_entry); }
/** @@ -1709,7 +1715,7 @@ _batadv_tt_global_del_orig_entry(struct batadv_tt_global_entry *tt_global_entry, * being part of a list */ hlist_del_rcu(&orig_entry->list); - batadv_tt_orig_list_entry_free_ref(orig_entry); + batadv_tt_orig_list_entry_put(orig_entry); }
/* deletes the orig list of a tt_global_entry */ diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 60d304b..58ae09e 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -1014,7 +1014,7 @@ struct batadv_tt_orig_list_entry { struct batadv_orig_node *orig_node; u8 ttvn; struct hlist_node list; - atomic_t refcount; + struct kref refcount; struct rcu_head rcu; };
So switch to kref instead of using the self-made, atomic_t-based implementation.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/bat_iv_ogm.c | 24 ++++++++++++------------ net/batman-adv/gateway_client.c | 14 +++++++------- net/batman-adv/network-coding.c | 4 ++-- net/batman-adv/originator.c | 41 +++++++++++++++-------------------------- net/batman-adv/originator.h | 2 +- net/batman-adv/types.h | 2 +- 6 files changed, 38 insertions(+), 49 deletions(-)
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index b9db667..cfd2afe 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -1023,7 +1023,7 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, neigh_ifinfo->bat_iv.tq_avg = tq_avg; spin_unlock_bh(&tmp_neigh_node->ifinfo_lock);
- batadv_neigh_ifinfo_free_ref(neigh_ifinfo); + batadv_neigh_ifinfo_put(neigh_ifinfo); neigh_ifinfo = NULL; }
@@ -1117,9 +1117,9 @@ out: if (router) batadv_neigh_node_free_ref(router); if (neigh_ifinfo) - batadv_neigh_ifinfo_free_ref(neigh_ifinfo); + batadv_neigh_ifinfo_put(neigh_ifinfo); if (router_ifinfo) - batadv_neigh_ifinfo_free_ref(router_ifinfo); + batadv_neigh_ifinfo_put(router_ifinfo); }
/** @@ -1189,7 +1189,7 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing); if (neigh_ifinfo) { neigh_rq_count = neigh_ifinfo->bat_iv.real_packet_count; - batadv_neigh_ifinfo_free_ref(neigh_ifinfo); + batadv_neigh_ifinfo_put(neigh_ifinfo); } else { neigh_rq_count = 0; } @@ -1350,7 +1350,7 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, packet_count = bitmap_weight(bitmap, BATADV_TQ_LOCAL_WINDOW_SIZE); neigh_ifinfo->bat_iv.real_packet_count = packet_count; - batadv_neigh_ifinfo_free_ref(neigh_ifinfo); + batadv_neigh_ifinfo_put(neigh_ifinfo); } rcu_read_unlock();
@@ -1563,7 +1563,7 @@ out_neigh: batadv_orig_node_free_ref(orig_neigh_node); out: if (router_ifinfo) - batadv_neigh_ifinfo_free_ref(router_ifinfo); + batadv_neigh_ifinfo_put(router_ifinfo); if (router) batadv_neigh_node_free_ref(router); if (router_router) @@ -1802,7 +1802,7 @@ batadv_iv_ogm_orig_print_neigh(struct batadv_orig_node *orig_node, neigh_node->addr, n_ifinfo->bat_iv.tq_avg);
- batadv_neigh_ifinfo_free_ref(n_ifinfo); + batadv_neigh_ifinfo_put(n_ifinfo); } }
@@ -1867,7 +1867,7 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv, next: batadv_neigh_node_free_ref(neigh_node); if (n_ifinfo) - batadv_neigh_ifinfo_free_ref(n_ifinfo); + batadv_neigh_ifinfo_put(n_ifinfo); } rcu_read_unlock(); } @@ -1961,9 +1961,9 @@ static int batadv_iv_ogm_neigh_cmp(struct batadv_neigh_node *neigh1,
out: if (neigh1_ifinfo) - batadv_neigh_ifinfo_free_ref(neigh1_ifinfo); + batadv_neigh_ifinfo_put(neigh1_ifinfo); if (neigh2_ifinfo) - batadv_neigh_ifinfo_free_ref(neigh2_ifinfo); + batadv_neigh_ifinfo_put(neigh2_ifinfo);
return diff; } @@ -2004,9 +2004,9 @@ batadv_iv_ogm_neigh_is_sob(struct batadv_neigh_node *neigh1,
out: if (neigh1_ifinfo) - batadv_neigh_ifinfo_free_ref(neigh1_ifinfo); + batadv_neigh_ifinfo_put(neigh1_ifinfo); if (neigh2_ifinfo) - batadv_neigh_ifinfo_free_ref(neigh2_ifinfo); + batadv_neigh_ifinfo_put(neigh2_ifinfo);
return ret; } diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index a7b9698..8d9933a 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -236,7 +236,7 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) next: batadv_neigh_node_free_ref(router); if (router_ifinfo) - batadv_neigh_ifinfo_free_ref(router_ifinfo); + batadv_neigh_ifinfo_put(router_ifinfo); } rcu_read_unlock();
@@ -353,7 +353,7 @@ out: if (router) batadv_neigh_node_free_ref(router); if (router_ifinfo) - batadv_neigh_ifinfo_free_ref(router_ifinfo); + batadv_neigh_ifinfo_put(router_ifinfo); }
void batadv_gw_check_election(struct batadv_priv *bat_priv, @@ -420,9 +420,9 @@ out: if (router_orig) batadv_neigh_node_free_ref(router_orig); if (router_gw_tq) - batadv_neigh_ifinfo_free_ref(router_gw_tq); + batadv_neigh_ifinfo_put(router_gw_tq); if (router_orig_tq) - batadv_neigh_ifinfo_free_ref(router_orig_tq); + batadv_neigh_ifinfo_put(router_orig_tq); }
/** @@ -622,7 +622,7 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv, batadv_gw_node_put(curr_gw); out: if (router_ifinfo) - batadv_neigh_ifinfo_free_ref(router_ifinfo); + batadv_neigh_ifinfo_put(router_ifinfo); if (router) batadv_neigh_node_free_ref(router); return ret; @@ -855,7 +855,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, goto out;
curr_tq_avg = curr_ifinfo->bat_iv.tq_avg; - batadv_neigh_ifinfo_free_ref(curr_ifinfo); + batadv_neigh_ifinfo_put(curr_ifinfo);
break; case BATADV_GW_MODE_OFF: @@ -873,7 +873,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
if ((curr_tq_avg - old_ifinfo->bat_iv.tq_avg) > BATADV_GW_THRESHOLD) out_of_range = true; - batadv_neigh_ifinfo_free_ref(old_ifinfo); + batadv_neigh_ifinfo_put(old_ifinfo);
out: if (orig_dst_node) diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c index a2655ad..9e96e7c 100644 --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c @@ -1232,9 +1232,9 @@ out: if (router_coding) batadv_neigh_node_free_ref(router_coding); if (router_neigh_ifinfo) - batadv_neigh_ifinfo_free_ref(router_neigh_ifinfo); + batadv_neigh_ifinfo_put(router_neigh_ifinfo); if (router_coding_ifinfo) - batadv_neigh_ifinfo_free_ref(router_coding_ifinfo); + batadv_neigh_ifinfo_put(router_coding_ifinfo); return res; }
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 0e836bd..0a00757 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -170,42 +170,30 @@ err: }
/** - * batadv_neigh_ifinfo_free_rcu - free the neigh_ifinfo object - * @rcu: rcu pointer of the neigh_ifinfo object + * batadv_neigh_ifinfo_release - release neigh_ifinfo from lists and queue for + * free after rcu grace period + * * @ref: kref pointer of the neigh_ifinfo */ -static void batadv_neigh_ifinfo_free_rcu(struct rcu_head *rcu) +static void batadv_neigh_ifinfo_release(struct kref *ref) { struct batadv_neigh_ifinfo *neigh_ifinfo;
- neigh_ifinfo = container_of(rcu, struct batadv_neigh_ifinfo, rcu); + neigh_ifinfo = container_of(ref, struct batadv_neigh_ifinfo, refcount);
if (neigh_ifinfo->if_outgoing != BATADV_IF_DEFAULT) - batadv_hardif_free_ref_now(neigh_ifinfo->if_outgoing); + batadv_hardif_free_ref(neigh_ifinfo->if_outgoing);
- kfree(neigh_ifinfo); + kfree_rcu(neigh_ifinfo, rcu); }
/** - * batadv_neigh_ifinfo_free_now - decrement the refcounter and possibly free - * the neigh_ifinfo (without rcu callback) - * @neigh_ifinfo: the neigh_ifinfo object to release - */ -static void -batadv_neigh_ifinfo_free_ref_now(struct batadv_neigh_ifinfo *neigh_ifinfo) -{ - if (atomic_dec_and_test(&neigh_ifinfo->refcount)) - batadv_neigh_ifinfo_free_rcu(&neigh_ifinfo->rcu); -} - -/** - * batadv_neigh_ifinfo_free_ref - decrement the refcounter and possibly free + * batadv_neigh_ifinfo_put - decrement the refcounter and possibly free * the neigh_ifinfo * @neigh_ifinfo: the neigh_ifinfo object to release */ -void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo) +void batadv_neigh_ifinfo_put(struct batadv_neigh_ifinfo *neigh_ifinfo) { - if (atomic_dec_and_test(&neigh_ifinfo->refcount)) - call_rcu(&neigh_ifinfo->rcu, batadv_neigh_ifinfo_free_rcu); + kref_put(&neigh_ifinfo->refcount, batadv_neigh_ifinfo_release); }
/** @@ -255,7 +243,7 @@ static void batadv_neigh_node_free_rcu(struct rcu_head *rcu)
hlist_for_each_entry_safe(neigh_ifinfo, node_tmp, &neigh_node->ifinfo_list, list) { - batadv_neigh_ifinfo_free_ref_now(neigh_ifinfo); + batadv_neigh_ifinfo_put(neigh_ifinfo); }
hardif_neigh = batadv_hardif_neigh_get(neigh_node->if_incoming, @@ -432,7 +420,7 @@ batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh, if (tmp_neigh_ifinfo->if_outgoing != if_outgoing) continue;
- if (!atomic_inc_not_zero(&tmp_neigh_ifinfo->refcount)) + if (!kref_get_unless_zero(&tmp_neigh_ifinfo->refcount)) continue;
neigh_ifinfo = tmp_neigh_ifinfo; @@ -477,7 +465,8 @@ batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh, }
INIT_HLIST_NODE(&neigh_ifinfo->list); - atomic_set(&neigh_ifinfo->refcount, 2); + kref_init(&neigh_ifinfo->refcount); + kref_get(&neigh_ifinfo->refcount); neigh_ifinfo->if_outgoing = if_outgoing;
hlist_add_head_rcu(&neigh_ifinfo->list, &neigh->ifinfo_list); @@ -965,7 +954,7 @@ batadv_purge_neigh_ifinfo(struct batadv_priv *bat_priv, neigh->addr, if_outgoing->net_dev->name);
hlist_del_rcu(&neigh_ifinfo->list); - batadv_neigh_ifinfo_free_ref(neigh_ifinfo); + batadv_neigh_ifinfo_put(neigh_ifinfo); }
spin_unlock_bh(&neigh->ifinfo_lock); diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index dc5cefa..5b2dc06 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -59,7 +59,7 @@ batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh, struct batadv_neigh_ifinfo * batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh, struct batadv_hard_iface *if_outgoing); -void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo); +void batadv_neigh_ifinfo_put(struct batadv_neigh_ifinfo *neigh_ifinfo);
int batadv_hardif_neigh_seq_print_text(struct seq_file *seq, void *offset);
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 58ae09e..7831bf0 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -420,7 +420,7 @@ struct batadv_neigh_ifinfo { struct batadv_hard_iface *if_outgoing; struct batadv_neigh_ifinfo_bat_iv bat_iv; u8 last_ttl; - atomic_t refcount; + struct kref refcount; struct rcu_head rcu; };
So switch to kref instead of using the self-made, atomic_t-based implementation.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/bat_iv_ogm.c | 4 ++-- net/batman-adv/network-coding.c | 2 +- net/batman-adv/originator.c | 46 ++++++++++++++++------------------------- net/batman-adv/originator.h | 2 +- net/batman-adv/routing.c | 13 ++++++------ net/batman-adv/types.h | 2 +- 6 files changed, 30 insertions(+), 39 deletions(-)
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index cfd2afe..f128e60 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -1365,7 +1365,7 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, out: spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); batadv_orig_node_free_ref(orig_node); - batadv_orig_ifinfo_free_ref(orig_ifinfo); + batadv_orig_ifinfo_put(orig_ifinfo); return ret; }
@@ -1511,7 +1511,7 @@ batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset, ogm_packet, if_incoming, if_outgoing, dup_status); } - batadv_orig_ifinfo_free_ref(orig_ifinfo); + batadv_orig_ifinfo_put(orig_ifinfo);
/* only forward for specific interface, not for the default one. */ if (if_outgoing == BATADV_IF_DEFAULT) diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c index 9e96e7c..329219b 100644 --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c @@ -772,7 +772,7 @@ static bool batadv_can_nc_with_orig(struct batadv_priv *bat_priv,
last_ttl = orig_ifinfo->last_ttl; last_real_seqno = orig_ifinfo->last_real_seqno; - batadv_orig_ifinfo_free_ref(orig_ifinfo); + batadv_orig_ifinfo_put(orig_ifinfo);
if (last_real_seqno != ntohl(ogm_packet->seqno)) return false; diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 0a00757..919f464 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -339,7 +339,7 @@ batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node, if (tmp->if_outgoing != if_outgoing) continue;
- if (!atomic_inc_not_zero(&tmp->refcount)) + if (!kref_get_unless_zero(&tmp->refcount)) continue;
orig_ifinfo = tmp; @@ -390,7 +390,8 @@ batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node, orig_ifinfo->batman_seqno_reset = reset_time; orig_ifinfo->if_outgoing = if_outgoing; INIT_HLIST_NODE(&orig_ifinfo->list); - atomic_set(&orig_ifinfo->refcount, 2); + kref_init(&orig_ifinfo->refcount); + kref_get(&orig_ifinfo->refcount); hlist_add_head_rcu(&orig_ifinfo->list, &orig_node->ifinfo_list); out: @@ -715,47 +716,36 @@ int batadv_hardif_neigh_seq_print_text(struct seq_file *seq, void *offset) }
/** - * batadv_orig_ifinfo_free_rcu - free the orig_ifinfo object - * @rcu: rcu pointer of the orig_ifinfo object + * batadv_orig_ifinfo_release - release orig_ifinfo from lists and queue for + * free after rcu grace period + * @ref: kref pointer of the orig_ifinfo */ -static void batadv_orig_ifinfo_free_rcu(struct rcu_head *rcu) +static void batadv_orig_ifinfo_release(struct kref *ref) { struct batadv_orig_ifinfo *orig_ifinfo; struct batadv_neigh_node *router;
- orig_ifinfo = container_of(rcu, struct batadv_orig_ifinfo, rcu); + orig_ifinfo = container_of(ref, struct batadv_orig_ifinfo, refcount);
if (orig_ifinfo->if_outgoing != BATADV_IF_DEFAULT) - batadv_hardif_free_ref_now(orig_ifinfo->if_outgoing); + batadv_hardif_free_ref(orig_ifinfo->if_outgoing);
/* this is the last reference to this object */ router = rcu_dereference_protected(orig_ifinfo->router, true); if (router) - batadv_neigh_node_free_ref_now(router); - kfree(orig_ifinfo); + batadv_neigh_node_free_ref(router); + + kfree_rcu(orig_ifinfo, rcu); }
/** - * batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly free - * the orig_ifinfo (without rcu callback) - * @orig_ifinfo: the orig_ifinfo object to release - */ -static void -batadv_orig_ifinfo_free_ref_now(struct batadv_orig_ifinfo *orig_ifinfo) -{ - if (atomic_dec_and_test(&orig_ifinfo->refcount)) - batadv_orig_ifinfo_free_rcu(&orig_ifinfo->rcu); -} - -/** - * batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly free + * batadv_orig_ifinfo_put - decrement the refcounter and possibly free * the orig_ifinfo * @orig_ifinfo: the orig_ifinfo object to release */ -void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo) +void batadv_orig_ifinfo_put(struct batadv_orig_ifinfo *orig_ifinfo) { - if (atomic_dec_and_test(&orig_ifinfo->refcount)) - call_rcu(&orig_ifinfo->rcu, batadv_orig_ifinfo_free_rcu); + kref_put(&orig_ifinfo->refcount, batadv_orig_ifinfo_release); }
static void batadv_orig_node_free_rcu(struct rcu_head *rcu) @@ -779,7 +769,7 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu) hlist_for_each_entry_safe(orig_ifinfo, node_tmp, &orig_node->ifinfo_list, list) { hlist_del_rcu(&orig_ifinfo->list); - batadv_orig_ifinfo_free_ref_now(orig_ifinfo); + batadv_orig_ifinfo_put(orig_ifinfo); } spin_unlock_bh(&orig_node->neigh_list_lock);
@@ -1000,10 +990,10 @@ batadv_purge_orig_ifinfo(struct batadv_priv *bat_priv, ifinfo_purged = true;
hlist_del_rcu(&orig_ifinfo->list); - batadv_orig_ifinfo_free_ref(orig_ifinfo); + batadv_orig_ifinfo_put(orig_ifinfo); if (orig_node->last_bonding_candidate == orig_ifinfo) { orig_node->last_bonding_candidate = NULL; - batadv_orig_ifinfo_free_ref(orig_ifinfo); + batadv_orig_ifinfo_put(orig_ifinfo); } }
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index 5b2dc06..db1a65d 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -69,7 +69,7 @@ batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node, struct batadv_orig_ifinfo * batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node, struct batadv_hard_iface *if_outgoing); -void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo); +void batadv_orig_ifinfo_put(struct batadv_orig_ifinfo *orig_ifinfo);
int batadv_orig_seq_print_text(struct seq_file *seq, void *offset); int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset); diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 0ba5993..1018148 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -25,6 +25,7 @@ #include <linux/etherdevice.h> #include <linux/if_ether.h> #include <linux/jiffies.h> +#include <linux/kref.h> #include <linux/netdevice.h> #include <linux/printk.h> #include <linux/rculist.h> @@ -106,7 +107,7 @@ static void _batadv_update_route(struct batadv_priv *bat_priv, spin_lock_bh(&orig_node->neigh_list_lock); rcu_assign_pointer(orig_ifinfo->router, neigh_node); spin_unlock_bh(&orig_node->neigh_list_lock); - batadv_orig_ifinfo_free_ref(orig_ifinfo); + batadv_orig_ifinfo_put(orig_ifinfo);
/* decrease refcount of previous best neighbor */ if (curr_router) @@ -497,7 +498,7 @@ batadv_find_router(struct batadv_priv *bat_priv,
hlist_for_each_entry_rcu(cand, &orig_node->ifinfo_list, list) { /* acquire some structures and references ... */ - if (!atomic_inc_not_zero(&cand->refcount)) + if (!kref_get_unless_zero(&cand->refcount)) continue;
cand_router = rcu_dereference(cand->router); @@ -524,7 +525,7 @@ batadv_find_router(struct batadv_priv *bat_priv, /* mark the first possible candidate */ if (!first_candidate) { atomic_inc(&cand_router->refcount); - atomic_inc(&cand->refcount); + kref_get(&cand->refcount); first_candidate = cand; first_candidate_router = cand_router; } @@ -547,13 +548,13 @@ next: batadv_neigh_node_free_ref(cand_router); cand_router = NULL; } - batadv_orig_ifinfo_free_ref(cand); + batadv_orig_ifinfo_put(cand); } rcu_read_unlock();
/* last_bonding_candidate is reset below, remove the old reference. */ if (orig_node->last_bonding_candidate) - batadv_orig_ifinfo_free_ref(orig_node->last_bonding_candidate); + batadv_orig_ifinfo_put(orig_node->last_bonding_candidate);
/* After finding candidates, handle the three cases: * 1) there is a next candidate, use that @@ -566,7 +567,7 @@ next: /* remove references to first candidate, we don't need it. */ if (first_candidate) { batadv_neigh_node_free_ref(first_candidate_router); - batadv_orig_ifinfo_free_ref(first_candidate); + batadv_orig_ifinfo_put(first_candidate); } router = next_candidate_router; orig_node->last_bonding_candidate = next_candidate; diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 7831bf0..a5e4310 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -141,7 +141,7 @@ struct batadv_orig_ifinfo { u32 last_real_seqno; u8 last_ttl; unsigned long batman_seqno_reset; - atomic_t refcount; + struct kref refcount; struct rcu_head rcu; };
So switch to kref instead of using the self-made, atomic_t-based implementation.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/bat_iv_ogm.c | 21 ++++++------- net/batman-adv/distributed-arp-table.c | 2 +- net/batman-adv/fragmentation.c | 2 +- net/batman-adv/gateway_client.c | 14 ++++----- net/batman-adv/hard-interface.h | 12 -------- net/batman-adv/icmp_socket.c | 2 +- net/batman-adv/network-coding.c | 4 +-- net/batman-adv/originator.c | 54 +++++++++++++--------------------- net/batman-adv/originator.h | 2 +- net/batman-adv/routing.c | 22 +++++++------- net/batman-adv/send.c | 2 +- net/batman-adv/translation-table.c | 6 ++-- net/batman-adv/types.h | 2 +- 13 files changed, 61 insertions(+), 84 deletions(-)
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index f128e60..7d61afb 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -31,6 +31,7 @@ #include <linux/init.h> #include <linux/jiffies.h> #include <linux/list.h> +#include <linux/kref.h> #include <linux/netdevice.h> #include <linux/pkt_sched.h> #include <linux/printk.h> @@ -1000,9 +1001,9 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, neigh_addr = tmp_neigh_node->addr; if (batadv_compare_eth(neigh_addr, ethhdr->h_source) && tmp_neigh_node->if_incoming == if_incoming && - atomic_inc_not_zero(&tmp_neigh_node->refcount)) { + kref_get_unless_zero(&tmp_neigh_node->refcount)) { if (WARN(neigh_node, "too many matching neigh_nodes")) - batadv_neigh_node_free_ref(neigh_node); + batadv_neigh_node_put(neigh_node); neigh_node = tmp_neigh_node; continue; } @@ -1113,9 +1114,9 @@ unlock: rcu_read_unlock(); out: if (neigh_node) - batadv_neigh_node_free_ref(neigh_node); + batadv_neigh_node_put(neigh_node); if (router) - batadv_neigh_node_free_ref(router); + batadv_neigh_node_put(router); if (neigh_ifinfo) batadv_neigh_ifinfo_put(neigh_ifinfo); if (router_ifinfo) @@ -1159,7 +1160,7 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, if (tmp_neigh_node->if_incoming != if_incoming) continue;
- if (!atomic_inc_not_zero(&tmp_neigh_node->refcount)) + if (!kref_get_unless_zero(&tmp_neigh_node->refcount)) continue;
neigh_node = tmp_neigh_node; @@ -1262,7 +1263,7 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
out: if (neigh_node) - batadv_neigh_node_free_ref(neigh_node); + batadv_neigh_node_put(neigh_node); return ret; }
@@ -1565,11 +1566,11 @@ out: if (router_ifinfo) batadv_neigh_ifinfo_put(router_ifinfo); if (router) - batadv_neigh_node_free_ref(router); + batadv_neigh_node_put(router); if (router_router) - batadv_neigh_node_free_ref(router_router); + batadv_neigh_node_put(router_router); if (orig_neigh_router) - batadv_neigh_node_free_ref(orig_neigh_router); + batadv_neigh_node_put(orig_neigh_router); if (hardif_neigh) batadv_hardif_neigh_put(hardif_neigh);
@@ -1865,7 +1866,7 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv, batman_count++;
next: - batadv_neigh_node_free_ref(neigh_node); + batadv_neigh_node_put(neigh_node); if (n_ifinfo) batadv_neigh_ifinfo_put(n_ifinfo); } diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index 34d0950..fa605c3 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -674,7 +674,7 @@ static bool batadv_dat_send_data(struct batadv_priv *bat_priv, ret = true; } free_neigh: - batadv_neigh_node_free_ref(neigh_node); + batadv_neigh_node_put(neigh_node); free_orig: batadv_orig_node_free_ref(cand[i].orig_node); } diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c index 80eddf4..87b127c 100644 --- a/net/batman-adv/fragmentation.c +++ b/net/batman-adv/fragmentation.c @@ -387,7 +387,7 @@ out: if (orig_node_dst) batadv_orig_node_free_ref(orig_node_dst); if (neigh_node) - batadv_neigh_node_free_ref(neigh_node); + batadv_neigh_node_put(neigh_node); return ret; }
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 8d9933a..a5b92ef 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -234,7 +234,7 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) batadv_gw_node_put(gw_node);
next: - batadv_neigh_node_free_ref(router); + batadv_neigh_node_put(router); if (router_ifinfo) batadv_neigh_ifinfo_put(router_ifinfo); } @@ -351,7 +351,7 @@ out: if (next_gw) batadv_gw_node_put(next_gw); if (router) - batadv_neigh_node_free_ref(router); + batadv_neigh_node_put(router); if (router_ifinfo) batadv_neigh_ifinfo_put(router_ifinfo); } @@ -416,9 +416,9 @@ out: if (curr_gw_orig) batadv_orig_node_free_ref(curr_gw_orig); if (router_gw) - batadv_neigh_node_free_ref(router_gw); + batadv_neigh_node_put(router_gw); if (router_orig) - batadv_neigh_node_free_ref(router_orig); + batadv_neigh_node_put(router_orig); if (router_gw_tq) batadv_neigh_ifinfo_put(router_gw_tq); if (router_orig_tq) @@ -624,7 +624,7 @@ out: if (router_ifinfo) batadv_neigh_ifinfo_put(router_ifinfo); if (router) - batadv_neigh_node_free_ref(router); + batadv_neigh_node_put(router); return ret; }
@@ -883,8 +883,8 @@ out: if (gw_node) batadv_gw_node_put(gw_node); if (neigh_old) - batadv_neigh_node_free_ref(neigh_old); + batadv_neigh_node_put(neigh_old); if (neigh_curr) - batadv_neigh_node_free_ref(neigh_curr); + batadv_neigh_node_put(neigh_curr); return out_of_range; } diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h index 5a31420..7b12ea8 100644 --- a/net/batman-adv/hard-interface.h +++ b/net/batman-adv/hard-interface.h @@ -75,18 +75,6 @@ batadv_hardif_free_ref(struct batadv_hard_iface *hard_iface) call_rcu(&hard_iface->rcu, batadv_hardif_free_rcu); }
-/** - * batadv_hardif_free_ref_now - decrement the hard interface refcounter and - * possibly free it (without rcu callback) - * @hard_iface: the hard interface to free - */ -static inline void -batadv_hardif_free_ref_now(struct batadv_hard_iface *hard_iface) -{ - if (atomic_dec_and_test(&hard_iface->refcount)) - batadv_hardif_free_rcu(&hard_iface->rcu); -} - static inline struct batadv_hard_iface * batadv_primary_if_get_selected(struct batadv_priv *bat_priv) { diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c index bcabb5e..d6574cb 100644 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c @@ -290,7 +290,7 @@ out: if (primary_if) batadv_hardif_free_ref(primary_if); if (neigh_node) - batadv_neigh_node_free_ref(neigh_node); + batadv_neigh_node_put(neigh_node); if (orig_node) batadv_orig_node_free_ref(orig_node); return len; diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c index 329219b..41f0c2c 100644 --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c @@ -1228,9 +1228,9 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv, res = true; out: if (router_neigh) - batadv_neigh_node_free_ref(router_neigh); + batadv_neigh_node_put(router_neigh); if (router_coding) - batadv_neigh_node_free_ref(router_coding); + batadv_neigh_node_put(router_coding); if (router_neigh_ifinfo) batadv_neigh_ifinfo_put(router_neigh_ifinfo); if (router_coding_ifinfo) diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 919f464..1f10658 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -227,10 +227,11 @@ void batadv_hardif_neigh_put(struct batadv_hardif_neigh_node *hardif_neigh) }
/** - * batadv_neigh_node_free_rcu - free the neigh_node - * @rcu: rcu pointer of the neigh_node + * batadv_neigh_node_release - release neigh_node from lists and queue for + * free after rcu grace period + * @ref: kref pointer of the neigh_node */ -static void batadv_neigh_node_free_rcu(struct rcu_head *rcu) +static void batadv_neigh_node_release(struct kref *ref) { struct hlist_node *node_tmp; struct batadv_neigh_node *neigh_node; @@ -238,7 +239,7 @@ static void batadv_neigh_node_free_rcu(struct rcu_head *rcu) struct batadv_neigh_ifinfo *neigh_ifinfo; struct batadv_algo_ops *bao;
- neigh_node = container_of(rcu, struct batadv_neigh_node, rcu); + neigh_node = container_of(ref, struct batadv_neigh_node, refcount); bao = neigh_node->orig_node->bat_priv->bat_algo_ops;
hlist_for_each_entry_safe(neigh_ifinfo, node_tmp, @@ -257,32 +258,18 @@ static void batadv_neigh_node_free_rcu(struct rcu_head *rcu) if (bao->bat_neigh_free) bao->bat_neigh_free(neigh_node);
- batadv_hardif_free_ref_now(neigh_node->if_incoming); + batadv_hardif_free_ref(neigh_node->if_incoming);
- kfree(neigh_node); + kfree_rcu(neigh_node, rcu); }
/** - * batadv_neigh_node_free_ref_now - decrement the neighbors refcounter - * and possibly free it (without rcu callback) + * batadv_neigh_node_put - decrement the neighbors refcounter and possibly free * @neigh_node: neigh neighbor to free */ -static void -batadv_neigh_node_free_ref_now(struct batadv_neigh_node *neigh_node) +void batadv_neigh_node_put(struct batadv_neigh_node *neigh_node) { - if (atomic_dec_and_test(&neigh_node->refcount)) - batadv_neigh_node_free_rcu(&neigh_node->rcu); -} - -/** - * batadv_neigh_node_free_ref - decrement the neighbors refcounter - * and possibly free it - * @neigh_node: neigh neighbor to free - */ -void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node) -{ - if (atomic_dec_and_test(&neigh_node->refcount)) - call_rcu(&neigh_node->rcu, batadv_neigh_node_free_rcu); + kref_put(&neigh_node->refcount, batadv_neigh_node_release); }
/** @@ -311,7 +298,7 @@ batadv_orig_router_get(struct batadv_orig_node *orig_node, break; }
- if (router && !atomic_inc_not_zero(&router->refcount)) + if (router && !kref_get_unless_zero(&router->refcount)) router = NULL;
rcu_read_unlock(); @@ -504,7 +491,7 @@ batadv_neigh_node_get(const struct batadv_orig_node *orig_node, if (tmp_neigh_node->if_incoming != hard_iface) continue;
- if (!atomic_inc_not_zero(&tmp_neigh_node->refcount)) + if (!kref_get_unless_zero(&tmp_neigh_node->refcount)) continue;
res = tmp_neigh_node; @@ -662,7 +649,8 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node, neigh_node->orig_node = orig_node;
/* extra reference for return */ - atomic_set(&neigh_node->refcount, 2); + kref_init(&neigh_node->refcount); + kref_get(&neigh_node->refcount);
spin_lock_bh(&orig_node->neigh_list_lock); hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list); @@ -733,7 +721,7 @@ static void batadv_orig_ifinfo_release(struct kref *ref) /* this is the last reference to this object */ router = rcu_dereference_protected(orig_ifinfo->router, true); if (router) - batadv_neigh_node_free_ref(router); + batadv_neigh_node_put(router);
kfree_rcu(orig_ifinfo, rcu); } @@ -763,7 +751,7 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu) hlist_for_each_entry_safe(neigh_node, node_tmp, &orig_node->neigh_list, list) { hlist_del_rcu(&neigh_node->list); - batadv_neigh_node_free_ref_now(neigh_node); + batadv_neigh_node_put(neigh_node); }
hlist_for_each_entry_safe(orig_ifinfo, node_tmp, @@ -1047,7 +1035,7 @@ batadv_purge_orig_neighbors(struct batadv_priv *bat_priv, neigh_purged = true;
hlist_del_rcu(&neigh_node->list); - batadv_neigh_node_free_ref(neigh_node); + batadv_neigh_node_put(neigh_node); } else { /* only necessary if not the whole neighbor is to be * deleted, but some interface has been removed. @@ -1082,11 +1070,11 @@ batadv_find_best_neighbor(struct batadv_priv *bat_priv, best, if_outgoing) <= 0)) continue;
- if (!atomic_inc_not_zero(&neigh->refcount)) + if (!kref_get_unless_zero(&neigh->refcount)) continue;
if (best) - batadv_neigh_node_free_ref(best); + batadv_neigh_node_put(best);
best = neigh; } @@ -1132,7 +1120,7 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, batadv_update_route(bat_priv, orig_node, BATADV_IF_DEFAULT, best_neigh_node); if (best_neigh_node) - batadv_neigh_node_free_ref(best_neigh_node); + batadv_neigh_node_put(best_neigh_node);
/* ... then for all other interfaces. */ rcu_read_lock(); @@ -1149,7 +1137,7 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, batadv_update_route(bat_priv, orig_node, hard_iface, best_neigh_node); if (best_neigh_node) - batadv_neigh_node_free_ref(best_neigh_node); + batadv_neigh_node_put(best_neigh_node); } rcu_read_unlock();
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index db1a65d..b0506ba 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -49,7 +49,7 @@ struct batadv_neigh_node * batadv_neigh_node_new(struct batadv_orig_node *orig_node, struct batadv_hard_iface *hard_iface, const u8 *neigh_addr); -void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node); +void batadv_neigh_node_put(struct batadv_neigh_node *neigh_node); struct batadv_neigh_node * batadv_orig_router_get(struct batadv_orig_node *orig_node, const struct batadv_hard_iface *if_outgoing); diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 1018148..787da48 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -73,7 +73,7 @@ static void _batadv_update_route(struct batadv_priv *bat_priv,
rcu_read_lock(); curr_router = rcu_dereference(orig_ifinfo->router); - if (curr_router && !atomic_inc_not_zero(&curr_router->refcount)) + if (curr_router && !kref_get_unless_zero(&curr_router->refcount)) curr_router = NULL; rcu_read_unlock();
@@ -98,10 +98,10 @@ static void _batadv_update_route(struct batadv_priv *bat_priv, }
if (curr_router) - batadv_neigh_node_free_ref(curr_router); + batadv_neigh_node_put(curr_router);
/* increase refcount of new best neighbor */ - if (neigh_node && !atomic_inc_not_zero(&neigh_node->refcount)) + if (neigh_node && !kref_get_unless_zero(&neigh_node->refcount)) neigh_node = NULL;
spin_lock_bh(&orig_node->neigh_list_lock); @@ -111,7 +111,7 @@ static void _batadv_update_route(struct batadv_priv *bat_priv,
/* decrease refcount of previous best neighbor */ if (curr_router) - batadv_neigh_node_free_ref(curr_router); + batadv_neigh_node_put(curr_router); }
/** @@ -138,7 +138,7 @@ void batadv_update_route(struct batadv_priv *bat_priv,
out: if (router) - batadv_neigh_node_free_ref(router); + batadv_neigh_node_put(router); }
/** @@ -505,7 +505,7 @@ batadv_find_router(struct batadv_priv *bat_priv, if (!cand_router) goto next;
- if (!atomic_inc_not_zero(&cand_router->refcount)) { + if (!kref_get_unless_zero(&cand_router->refcount)) { cand_router = NULL; goto next; } @@ -524,7 +524,7 @@ batadv_find_router(struct batadv_priv *bat_priv,
/* mark the first possible candidate */ if (!first_candidate) { - atomic_inc(&cand_router->refcount); + kref_get(&cand_router->refcount); kref_get(&cand->refcount); first_candidate = cand; first_candidate_router = cand_router; @@ -545,7 +545,7 @@ batadv_find_router(struct batadv_priv *bat_priv, next: /* free references */ if (cand_router) { - batadv_neigh_node_free_ref(cand_router); + batadv_neigh_node_put(cand_router); cand_router = NULL; } batadv_orig_ifinfo_put(cand); @@ -562,17 +562,17 @@ next: * 3) there is no candidate at all, return the default router */ if (next_candidate) { - batadv_neigh_node_free_ref(router); + batadv_neigh_node_put(router);
/* remove references to first candidate, we don't need it. */ if (first_candidate) { - batadv_neigh_node_free_ref(first_candidate_router); + batadv_neigh_node_put(first_candidate_router); batadv_orig_ifinfo_put(first_candidate); } router = next_candidate_router; orig_node->last_bonding_candidate = next_candidate; } else if (first_candidate) { - batadv_neigh_node_free_ref(router); + batadv_neigh_node_put(router);
/* refcounting has already been done in the loop above. */ router = first_candidate_router; diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index c188f46..06e21fa 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -153,7 +153,7 @@ int batadv_send_skb_to_orig(struct sk_buff *skb,
out: if (neigh_node) - batadv_neigh_node_free_ref(neigh_node); + batadv_neigh_node_put(neigh_node);
return ret; } diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 096804e..f25b533 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -1548,20 +1548,20 @@ batadv_transtable_best_orig(struct batadv_priv *bat_priv, if (best_router && bao->bat_neigh_cmp(router, BATADV_IF_DEFAULT, best_router, BATADV_IF_DEFAULT) <= 0) { - batadv_neigh_node_free_ref(router); + batadv_neigh_node_put(router); continue; }
/* release the refcount for the "old" best */ if (best_router) - batadv_neigh_node_free_ref(best_router); + batadv_neigh_node_put(best_router);
best_entry = orig_entry; best_router = router; }
if (best_router) - batadv_neigh_node_free_ref(best_router); + batadv_neigh_node_put(best_router);
return best_entry; } diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index a5e4310..75e1b45 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -384,7 +384,7 @@ struct batadv_neigh_node { spinlock_t ifinfo_lock; /* protects ifinfo_list and its members */ struct batadv_hard_iface *if_incoming; unsigned long last_seen; - atomic_t refcount; + struct kref refcount; struct rcu_head rcu; };
So switch to kref instead of using the self-made, atomic_t-based implementation.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/bat_iv_ogm.c | 14 +++++------ net/batman-adv/bridge_loop_avoidance.c | 18 +++++++------- net/batman-adv/distributed-arp-table.c | 2 +- net/batman-adv/fragmentation.c | 2 +- net/batman-adv/gateway_client.c | 2 +- net/batman-adv/hard-interface.c | 45 ++++++++++++++++++++-------------- net/batman-adv/hard-interface.h | 15 +++++------- net/batman-adv/icmp_socket.c | 2 +- net/batman-adv/main.c | 2 +- net/batman-adv/network-coding.c | 2 +- net/batman-adv/originator.c | 24 +++++++++--------- net/batman-adv/routing.c | 8 +++--- net/batman-adv/send.c | 8 +++--- net/batman-adv/soft-interface.c | 6 ++--- net/batman-adv/sysfs.c | 8 +++--- net/batman-adv/translation-table.c | 10 ++++---- net/batman-adv/types.h | 2 +- 17 files changed, 88 insertions(+), 82 deletions(-)
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 7d61afb..95399c9 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -513,7 +513,7 @@ static void batadv_iv_ogm_emit(struct batadv_forw_packet *forw_packet)
out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); }
/** @@ -615,7 +615,7 @@ batadv_iv_ogm_can_aggregate(const struct batadv_ogm_packet *new_bat_ogm_packet,
out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); return res; }
@@ -642,10 +642,10 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff, unsigned char *skb_buff; unsigned int skb_size;
- if (!atomic_inc_not_zero(&if_incoming->refcount)) + if (!kref_get_unless_zero(&if_incoming->refcount)) return;
- if (!atomic_inc_not_zero(&if_outgoing->refcount)) + if (!kref_get_unless_zero(&if_outgoing->refcount)) goto out_free_incoming;
/* own packet should always be scheduled */ @@ -709,9 +709,9 @@ out_nomem: if (!own_packet) atomic_inc(&bat_priv->batman_queue_left); out_free_outgoing: - batadv_hardif_free_ref(if_outgoing); + batadv_hardif_put(if_outgoing); out_free_incoming: - batadv_hardif_free_ref(if_incoming); + batadv_hardif_put(if_incoming); }
/* aggregate a new packet into the existing ogm packet */ @@ -956,7 +956,7 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); }
/** diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index 3315b27..e58bc6c 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -423,7 +423,7 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, u8 *mac, netif_rx(skb); out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); }
/** @@ -1281,7 +1281,7 @@ void batadv_bla_status_update(struct net_device *net_dev) * so just call that one. */ batadv_bla_update_orig_address(bat_priv, primary_if, primary_if); - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); }
/** @@ -1355,7 +1355,7 @@ static void batadv_bla_periodic_work(struct work_struct *work) } out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if);
queue_delayed_work(batadv_event_workqueue, &bat_priv->bla.work, msecs_to_jiffies(BATADV_BLA_PERIOD_LENGTH)); @@ -1394,7 +1394,7 @@ int batadv_bla_init(struct batadv_priv *bat_priv) if (primary_if) { crc = crc16(0, primary_if->net_dev->dev_addr, ETH_ALEN); bat_priv->bla.claim_dest.group = htons(crc); - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); } else { bat_priv->bla.claim_dest.group = 0; /* will be set later */ } @@ -1598,7 +1598,7 @@ void batadv_bla_free(struct batadv_priv *bat_priv) bat_priv->bla.backbone_hash = NULL; } if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); }
/** @@ -1691,7 +1691,7 @@ handled:
out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); if (claim) batadv_claim_put(claim); return ret; @@ -1780,7 +1780,7 @@ handled: ret = 1; out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); if (claim) batadv_claim_put(claim); return ret; @@ -1838,7 +1838,7 @@ int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset) } out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); return 0; }
@@ -1903,6 +1903,6 @@ int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, void *offset) } out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); return 0; } diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index fa605c3..782e80a 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -840,7 +840,7 @@ int batadv_dat_cache_seq_print_text(struct seq_file *seq, void *offset)
out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); return 0; }
diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c index 87b127c..69edc0b 100644 --- a/net/batman-adv/fragmentation.c +++ b/net/batman-adv/fragmentation.c @@ -512,7 +512,7 @@ bool batadv_frag_send_packet(struct sk_buff *skb,
out_err: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if);
return ret; } diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index a5b92ef..33ddd7d 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -661,7 +661,7 @@ int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset)
out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); return 0; }
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 49e05d2..de8e54b 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -18,6 +18,7 @@ #include "hard-interface.h" #include "main.h"
+#include <linux/atomic.h> #include <linux/bug.h> #include <linux/byteorder/generic.h> #include <linux/errno.h> @@ -26,6 +27,7 @@ #include <linux/if_ether.h> #include <linux/if.h> #include <linux/kernel.h> +#include <linux/kref.h> #include <linux/list.h> #include <linux/netdevice.h> #include <linux/printk.h> @@ -47,13 +49,19 @@ #include "sysfs.h" #include "translation-table.h"
-void batadv_hardif_free_rcu(struct rcu_head *rcu) +/** + * batadv_hardif_release - release hard interface from lists and queue for + * free after rcu grace period + * @ref: kref pointer of the hard interface + */ +void batadv_hardif_release(struct kref *ref) { struct batadv_hard_iface *hard_iface;
- hard_iface = container_of(rcu, struct batadv_hard_iface, rcu); + hard_iface = container_of(ref, struct batadv_hard_iface, refcount); dev_put(hard_iface->net_dev); - kfree(hard_iface); + + kfree_rcu(hard_iface, rcu); }
struct batadv_hard_iface * @@ -64,7 +72,7 @@ batadv_hardif_get_by_netdev(const struct net_device *net_dev) rcu_read_lock(); list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { if (hard_iface->net_dev == net_dev && - atomic_inc_not_zero(&hard_iface->refcount)) + kref_get_unless_zero(&hard_iface->refcount)) goto out; }
@@ -169,7 +177,7 @@ batadv_hardif_get_active(const struct net_device *soft_iface) continue;
if (hard_iface->if_status == BATADV_IF_ACTIVE && - atomic_inc_not_zero(&hard_iface->refcount)) + kref_get_unless_zero(&hard_iface->refcount)) goto out; }
@@ -193,7 +201,7 @@ static void batadv_primary_if_update_addr(struct batadv_priv *bat_priv, batadv_bla_update_orig_address(bat_priv, primary_if, oldif); out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); }
static void batadv_primary_if_select(struct batadv_priv *bat_priv, @@ -203,7 +211,7 @@ static void batadv_primary_if_select(struct batadv_priv *bat_priv,
ASSERT_RTNL();
- if (new_hard_iface && !atomic_inc_not_zero(&new_hard_iface->refcount)) + if (new_hard_iface && !kref_get_unless_zero(&new_hard_iface->refcount)) new_hard_iface = NULL;
curr_hard_iface = rcu_dereference_protected(bat_priv->primary_if, 1); @@ -217,7 +225,7 @@ static void batadv_primary_if_select(struct batadv_priv *bat_priv,
out: if (curr_hard_iface) - batadv_hardif_free_ref(curr_hard_iface); + batadv_hardif_put(curr_hard_iface); }
static bool @@ -376,7 +384,7 @@ batadv_hardif_activate_interface(struct batadv_hard_iface *hard_iface)
out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); }
static void @@ -431,7 +439,7 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, if (hard_iface->if_status != BATADV_IF_NOT_IN_USE) goto out;
- if (!atomic_inc_not_zero(&hard_iface->refcount)) + if (!kref_get_unless_zero(&hard_iface->refcount)) goto out;
soft_iface = dev_get_by_name(&init_net, iface_name); @@ -529,7 +537,7 @@ err_dev: hard_iface->soft_iface = NULL; dev_put(soft_iface); err: - batadv_hardif_free_ref(hard_iface); + batadv_hardif_put(hard_iface); return ret; }
@@ -560,7 +568,7 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface, batadv_primary_if_select(bat_priv, new_if);
if (new_if) - batadv_hardif_free_ref(new_if); + batadv_hardif_put(new_if); }
bat_priv->bat_algo_ops->bat_iface_disable(hard_iface); @@ -583,11 +591,11 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface, }
hard_iface->soft_iface = NULL; - batadv_hardif_free_ref(hard_iface); + batadv_hardif_put(hard_iface);
out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); }
/** @@ -606,7 +614,7 @@ static void batadv_hardif_remove_interface_finish(struct work_struct *work)
batadv_debugfs_del_hardif(hard_iface); batadv_sysfs_del_hardif(&hard_iface->hardif_obj); - batadv_hardif_free_ref(hard_iface); + batadv_hardif_put(hard_iface); }
static struct batadv_hard_iface * @@ -652,7 +660,8 @@ batadv_hardif_add_interface(struct net_device *net_dev) hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS;
/* extra reference for return */ - atomic_set(&hard_iface->refcount, 2); + kref_init(&hard_iface->refcount); + kref_get(&hard_iface->refcount);
batadv_check_known_mac_addr(hard_iface->net_dev); list_add_tail_rcu(&hard_iface->list, &batadv_hardif_list); @@ -760,10 +769,10 @@ static int batadv_hard_if_event(struct notifier_block *this, }
hardif_put: - batadv_hardif_free_ref(hard_iface); + batadv_hardif_put(hard_iface); out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); return NOTIFY_DONE; }
diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h index 7b12ea8..16a6aec 100644 --- a/net/batman-adv/hard-interface.h +++ b/net/batman-adv/hard-interface.h @@ -20,8 +20,8 @@
#include "main.h"
-#include <linux/atomic.h> #include <linux/compiler.h> +#include <linux/kref.h> #include <linux/notifier.h> #include <linux/rcupdate.h> #include <linux/stddef.h> @@ -61,18 +61,15 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface, void batadv_hardif_remove_interfaces(void); int batadv_hardif_min_mtu(struct net_device *soft_iface); void batadv_update_min_mtu(struct net_device *soft_iface); -void batadv_hardif_free_rcu(struct rcu_head *rcu); +void batadv_hardif_release(struct kref *ref);
/** - * batadv_hardif_free_ref - decrement the hard interface refcounter and - * possibly free it + * batadv_hardif_put - decrement the hard interface refcounter and possibly free * @hard_iface: the hard interface to free */ -static inline void -batadv_hardif_free_ref(struct batadv_hard_iface *hard_iface) +static inline void batadv_hardif_put(struct batadv_hard_iface *hard_iface) { - if (atomic_dec_and_test(&hard_iface->refcount)) - call_rcu(&hard_iface->rcu, batadv_hardif_free_rcu); + kref_put(&hard_iface->refcount, batadv_hardif_release); }
static inline struct batadv_hard_iface * @@ -85,7 +82,7 @@ batadv_primary_if_get_selected(struct batadv_priv *bat_priv) if (!hard_iface) goto out;
- if (!atomic_inc_not_zero(&hard_iface->refcount)) + if (!kref_get_unless_zero(&hard_iface->refcount)) hard_iface = NULL;
out: diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c index d6574cb..27be960 100644 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c @@ -288,7 +288,7 @@ free_skb: kfree_skb(skb); out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); if (neigh_node) batadv_neigh_node_put(neigh_node); if (orig_node) diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index eee2d82..33ac461 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -287,7 +287,7 @@ batadv_seq_print_text_primary_if_get(struct seq_file *seq) seq_printf(seq, "BATMAN mesh %s disabled - primary interface not active\n", net_dev->name); - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); primary_if = NULL;
out: diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c index 41f0c2c..96e1390 100644 --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c @@ -1950,7 +1950,7 @@ int batadv_nc_nodes_seq_print_text(struct seq_file *seq, void *offset)
out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); return 0; }
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 1f10658..a6eac81 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -181,7 +181,7 @@ static void batadv_neigh_ifinfo_release(struct kref *ref) neigh_ifinfo = container_of(ref, struct batadv_neigh_ifinfo, refcount);
if (neigh_ifinfo->if_outgoing != BATADV_IF_DEFAULT) - batadv_hardif_free_ref(neigh_ifinfo->if_outgoing); + batadv_hardif_put(neigh_ifinfo->if_outgoing);
kfree_rcu(neigh_ifinfo, rcu); } @@ -212,7 +212,7 @@ static void batadv_hardif_neigh_release(struct kref *ref) hlist_del_init_rcu(&hardif_neigh->list); spin_unlock_bh(&hardif_neigh->if_incoming->neigh_list_lock);
- batadv_hardif_free_ref(hardif_neigh->if_incoming); + batadv_hardif_put(hardif_neigh->if_incoming); kfree_rcu(hardif_neigh, rcu); }
@@ -258,7 +258,7 @@ static void batadv_neigh_node_release(struct kref *ref) if (bao->bat_neigh_free) bao->bat_neigh_free(neigh_node);
- batadv_hardif_free_ref(neigh_node->if_incoming); + batadv_hardif_put(neigh_node->if_incoming);
kfree_rcu(neigh_node, rcu); } @@ -366,7 +366,7 @@ batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node, goto out;
if (if_outgoing != BATADV_IF_DEFAULT && - !atomic_inc_not_zero(&if_outgoing->refcount)) { + !kref_get_unless_zero(&if_outgoing->refcount)) { kfree(orig_ifinfo); orig_ifinfo = NULL; goto out; @@ -446,7 +446,7 @@ batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh, if (!neigh_ifinfo) goto out;
- if (if_outgoing && !atomic_inc_not_zero(&if_outgoing->refcount)) { + if (if_outgoing && !kref_get_unless_zero(&if_outgoing->refcount)) { kfree(neigh_ifinfo); neigh_ifinfo = NULL; goto out; @@ -523,12 +523,12 @@ batadv_hardif_neigh_create(struct batadv_hard_iface *hard_iface, if (hardif_neigh) goto out;
- if (!atomic_inc_not_zero(&hard_iface->refcount)) + if (!kref_get_unless_zero(&hard_iface->refcount)) goto out;
hardif_neigh = kzalloc(sizeof(*hardif_neigh), GFP_ATOMIC); if (!hardif_neigh) { - batadv_hardif_free_ref(hard_iface); + batadv_hardif_put(hard_iface); goto out; }
@@ -634,7 +634,7 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node, if (!neigh_node) goto out;
- if (!atomic_inc_not_zero(&hard_iface->refcount)) { + if (!kref_get_unless_zero(&hard_iface->refcount)) { kfree(neigh_node); neigh_node = NULL; goto out; @@ -691,7 +691,7 @@ int batadv_hardif_neigh_seq_print_text(struct seq_file *seq, void *offset) primary_if->net_dev->dev_addr, net_dev->name, bat_priv->bat_algo_ops->name);
- batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if);
if (!bat_priv->bat_algo_ops->bat_neigh_print) { seq_puts(seq, @@ -716,7 +716,7 @@ static void batadv_orig_ifinfo_release(struct kref *ref) orig_ifinfo = container_of(ref, struct batadv_orig_ifinfo, refcount);
if (orig_ifinfo->if_outgoing != BATADV_IF_DEFAULT) - batadv_hardif_free_ref(orig_ifinfo->if_outgoing); + batadv_hardif_put(orig_ifinfo->if_outgoing);
/* this is the last reference to this object */ router = rcu_dereference_protected(orig_ifinfo->router, true); @@ -1216,7 +1216,7 @@ int batadv_orig_seq_print_text(struct seq_file *seq, void *offset) primary_if->net_dev->dev_addr, net_dev->name, bat_priv->bat_algo_ops->name);
- batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if);
if (!bat_priv->bat_algo_ops->bat_orig_print) { seq_puts(seq, @@ -1272,7 +1272,7 @@ int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset)
out: if (hard_iface) - batadv_hardif_free_ref(hard_iface); + batadv_hardif_put(hard_iface); return 0; }
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 787da48..43b5875 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -269,7 +269,7 @@ static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv, } out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); if (orig_node) batadv_orig_node_free_ref(orig_node); return ret; @@ -317,7 +317,7 @@ static int batadv_recv_icmp_ttl_exceeded(struct batadv_priv *bat_priv,
out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); if (orig_node) batadv_orig_node_free_ref(orig_node); return ret; @@ -702,7 +702,7 @@ batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, ret = true; out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); if (orig_node) batadv_orig_node_free_ref(orig_node);
@@ -808,7 +808,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
ether_addr_copy(unicast_packet->dest, primary_if->net_dev->dev_addr);
- batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if);
unicast_packet->ttvn = curr_ttvn;
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 06e21fa..be8011c 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -246,7 +246,7 @@ bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv, ret = true; out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); return ret; }
@@ -409,9 +409,9 @@ static void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet) { kfree_skb(forw_packet->skb); if (forw_packet->if_incoming) - batadv_hardif_free_ref(forw_packet->if_incoming); + batadv_hardif_put(forw_packet->if_incoming); if (forw_packet->if_outgoing) - batadv_hardif_free_ref(forw_packet->if_outgoing); + batadv_hardif_put(forw_packet->if_outgoing); kfree(forw_packet); }
@@ -497,7 +497,7 @@ out_and_inc: atomic_inc(&bat_priv->bcast_queue_left); out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); return NETDEV_TX_BUSY; }
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 7268feb..c868afa 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -377,7 +377,7 @@ dropped_freed: batadv_inc_counter(bat_priv, BATADV_CNT_TX_DROPPED); end: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); return NETDEV_TX_OK; }
@@ -878,7 +878,7 @@ static int batadv_softif_slave_add(struct net_device *dev,
out: if (hard_iface) - batadv_hardif_free_ref(hard_iface); + batadv_hardif_put(hard_iface); return ret; }
@@ -905,7 +905,7 @@ static int batadv_softif_slave_del(struct net_device *dev,
out: if (hard_iface) - batadv_hardif_free_ref(hard_iface); + batadv_hardif_put(hard_iface); return ret; }
diff --git a/net/batman-adv/sysfs.c b/net/batman-adv/sysfs.c index 63a86c2..acf85d9 100644 --- a/net/batman-adv/sysfs.c +++ b/net/batman-adv/sysfs.c @@ -771,7 +771,7 @@ static ssize_t batadv_show_mesh_iface(struct kobject *kobj,
length = sprintf(buff, "%s\n", ifname);
- batadv_hardif_free_ref(hard_iface); + batadv_hardif_put(hard_iface);
return length; } @@ -795,7 +795,7 @@ static ssize_t batadv_store_mesh_iface(struct kobject *kobj, if (strlen(buff) >= IFNAMSIZ) { pr_err("Invalid parameter for 'mesh_iface' setting received: interface name too long '%s'\n", buff); - batadv_hardif_free_ref(hard_iface); + batadv_hardif_put(hard_iface); return -EINVAL; }
@@ -829,7 +829,7 @@ static ssize_t batadv_store_mesh_iface(struct kobject *kobj, unlock: rtnl_unlock(); out: - batadv_hardif_free_ref(hard_iface); + batadv_hardif_put(hard_iface); return ret; }
@@ -863,7 +863,7 @@ static ssize_t batadv_show_iface_status(struct kobject *kobj, break; }
- batadv_hardif_free_ref(hard_iface); + batadv_hardif_put(hard_iface);
return length; } diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index f25b533..1ebdcd7 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -1023,7 +1023,7 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) } out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); return 0; }
@@ -1687,7 +1687,7 @@ int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset) } out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); return 0; }
@@ -2600,7 +2600,7 @@ static int batadv_send_tt_request(struct batadv_priv *bat_priv,
out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); if (ret && tt_req_node) { spin_lock_bh(&bat_priv->tt.req_list_lock); /* hlist_del_init() verifies tt_req_node still is in the list */ @@ -2857,7 +2857,7 @@ out: if (orig_node) batadv_orig_node_free_ref(orig_node); if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); kfree(tvlv_tt_data); /* The packet was for this host, so it doesn't need to be re-routed */ return true; @@ -3180,7 +3180,7 @@ static void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client,
out: if (primary_if) - batadv_hardif_free_ref(primary_if); + batadv_hardif_put(primary_if); }
static void batadv_tt_purge(struct work_struct *work) diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 75e1b45..d69be62 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -111,7 +111,7 @@ struct batadv_hard_iface { struct net_device *net_dev; u8 num_bcasts; struct kobject *hardif_obj; - atomic_t refcount; + struct kref refcount; struct packet_type batman_adv_ptype; struct net_device *soft_iface; struct rcu_head rcu;
So switch to kref instead of using the self-made, atomic_t-based implementation.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/originator.c | 28 +++++++++++++++++++++------- net/batman-adv/originator.h | 2 +- net/batman-adv/translation-table.c | 10 +++++----- net/batman-adv/types.h | 2 +- 4 files changed, 28 insertions(+), 14 deletions(-)
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index a6eac81..a7b70b5 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -82,7 +82,7 @@ batadv_orig_node_vlan_get(struct batadv_orig_node *orig_node, if (tmp->vid != vid) continue;
- if (!atomic_inc_not_zero(&tmp->refcount)) + if (!kref_get_unless_zero(&tmp->refcount)) continue;
vlan = tmp; @@ -123,7 +123,8 @@ batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node, if (!vlan) goto out;
- atomic_set(&vlan->refcount, 2); + kref_init(&vlan->refcount); + kref_get(&vlan->refcount); vlan->vid = vid;
hlist_add_head_rcu(&vlan->list, &orig_node->vlan_list); @@ -135,14 +136,27 @@ out: }
/** - * batadv_orig_node_vlan_free_ref - decrement the refcounter and possibly free + * batadv_orig_node_vlan_release - release originator-vlan object from lists + * and queue for free after rcu grace period + * * @ref: kref pointer of the originator-vlan object + */ +static void batadv_orig_node_vlan_release(struct kref *ref) +{ + struct batadv_orig_node_vlan *orig_vlan; + + orig_vlan = container_of(ref, struct batadv_orig_node_vlan, refcount); + + kfree_rcu(orig_vlan, rcu); +} + +/** + * batadv_orig_node_vlan_put - decrement the refcounter and possibly free * the originator-vlan object * @orig_vlan: the originator-vlan object to release */ -void batadv_orig_node_vlan_free_ref(struct batadv_orig_node_vlan *orig_vlan) +void batadv_orig_node_vlan_put(struct batadv_orig_node_vlan *orig_vlan) { - if (atomic_dec_and_test(&orig_vlan->refcount)) - kfree_rcu(orig_vlan, rcu); + kref_put(&orig_vlan->refcount, batadv_orig_node_vlan_release); }
int batadv_originator_init(struct batadv_priv *bat_priv) @@ -883,7 +897,7 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, * Immediately release vlan since it is not needed anymore in this * context */ - batadv_orig_node_vlan_free_ref(vlan); + batadv_orig_node_vlan_put(vlan);
for (i = 0; i < BATADV_FRAG_BUFFER_COUNT; i++) { INIT_HLIST_HEAD(&orig_node->fragments[i].head); diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index b0506ba..0bad6cc 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -83,7 +83,7 @@ batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node, struct batadv_orig_node_vlan * batadv_orig_node_vlan_get(struct batadv_orig_node *orig_node, unsigned short vid); -void batadv_orig_node_vlan_free_ref(struct batadv_orig_node_vlan *orig_vlan); +void batadv_orig_node_vlan_put(struct batadv_orig_node_vlan *orig_vlan);
/* hashfunction to choose an entry in a hash table of given size * hash algorithm from http://en.wikipedia.org/wiki/Hash_table diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 1ebdcd7..ac66771 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -314,10 +314,10 @@ static void batadv_tt_global_size_mod(struct batadv_orig_node *orig_node, spin_lock_bh(&orig_node->vlan_list_lock); hlist_del_init_rcu(&vlan->list); spin_unlock_bh(&orig_node->vlan_list_lock); - batadv_orig_node_vlan_free_ref(vlan); + batadv_orig_node_vlan_put(vlan); }
- batadv_orig_node_vlan_free_ref(vlan); + batadv_orig_node_vlan_put(vlan); }
/** @@ -1614,7 +1614,7 @@ batadv_tt_global_print_entry(struct batadv_priv *bat_priv, ((flags & BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'), ((flags & BATADV_TT_CLIENT_TEMP) ? 'T' : '.'));
- batadv_orig_node_vlan_free_ref(vlan); + batadv_orig_node_vlan_put(vlan); }
print_list: @@ -1646,7 +1646,7 @@ print_list: ((flags & BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'), ((flags & BATADV_TT_CLIENT_TEMP) ? 'T' : '.'));
- batadv_orig_node_vlan_free_ref(vlan); + batadv_orig_node_vlan_put(vlan); } }
@@ -2465,7 +2465,7 @@ static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node, return false;
crc = vlan->tt.crc; - batadv_orig_node_vlan_free_ref(vlan); + batadv_orig_node_vlan_put(vlan);
if (crc != ntohl(tt_vlan_tmp->crc)) return false; diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index d69be62..441ebd9 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -197,7 +197,7 @@ struct batadv_orig_node_vlan { unsigned short vid; struct batadv_vlan_tt tt; struct hlist_node list; - atomic_t refcount; + struct kref refcount; struct rcu_head rcu; };
So switch to kref instead of using the self-made, atomic_t-based implementation.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/bat_iv_ogm.c | 16 +++++----- net/batman-adv/bridge_loop_avoidance.c | 4 +-- net/batman-adv/distributed-arp-table.c | 6 ++-- net/batman-adv/fragmentation.c | 2 +- net/batman-adv/gateway_client.c | 12 ++++---- net/batman-adv/icmp_socket.c | 2 +- net/batman-adv/main.c | 2 +- net/batman-adv/multicast.c | 7 +++-- net/batman-adv/network-coding.c | 6 ++-- net/batman-adv/originator.c | 53 +++++++++++++++++++++++----------- net/batman-adv/originator.h | 6 ++-- net/batman-adv/routing.c | 18 ++++++------ net/batman-adv/send.c | 2 +- net/batman-adv/translation-table.c | 18 ++++++------ net/batman-adv/types.h | 2 +- 15 files changed, 88 insertions(+), 68 deletions(-)
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 95399c9..02d5ace 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -285,8 +285,8 @@ batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const u8 *addr)
free_orig_node: /* free twice, as batadv_orig_node_new sets refcount to 2 */ - batadv_orig_node_free_ref(orig_node); - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); + batadv_orig_node_put(orig_node);
return NULL; } @@ -1039,7 +1039,7 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, ethhdr->h_source, orig_node, orig_tmp);
- batadv_orig_node_free_ref(orig_tmp); + batadv_orig_node_put(orig_tmp); if (!neigh_node) goto unlock; } else { @@ -1304,7 +1304,7 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing); if (WARN_ON(!orig_ifinfo)) { - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); return 0; }
@@ -1365,7 +1365,7 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
out: spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); batadv_orig_ifinfo_put(orig_ifinfo); return ret; } @@ -1561,7 +1561,7 @@ batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset,
out_neigh: if ((orig_neigh_node) && (!is_single_hop_neigh)) - batadv_orig_node_free_ref(orig_neigh_node); + batadv_orig_node_put(orig_neigh_node); out: if (router_ifinfo) batadv_neigh_ifinfo_put(router_ifinfo); @@ -1695,7 +1695,7 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset,
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Drop packet: originator packet from myself (via neighbor)\n"); - batadv_orig_node_free_ref(orig_neigh_node); + batadv_orig_node_put(orig_neigh_node); return; }
@@ -1733,7 +1733,7 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset, } rcu_read_unlock();
- batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); }
static int batadv_iv_ogm_receive(struct sk_buff *skb, diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index e58bc6c..5370add 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -485,7 +485,7 @@ batadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, u8 *orig, if (orig_node) { batadv_tt_global_del_orig(bat_priv, orig_node, vid, "became a backbone gateway"); - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); }
if (own_backbone) { @@ -964,7 +964,7 @@ static int batadv_check_claim_group(struct batadv_priv *bat_priv, bla_dst_own->group = bla_dst->group; }
- batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node);
return 2; } diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index 782e80a..695cd52 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -542,12 +542,12 @@ static void batadv_choose_next_candidate(struct batadv_priv *bat_priv, max_orig_node)) continue;
- if (!atomic_inc_not_zero(&orig_node->refcount)) + if (!kref_get_unless_zero(&orig_node->refcount)) continue;
max = tmp_max; if (max_orig_node) - batadv_orig_node_free_ref(max_orig_node); + batadv_orig_node_put(max_orig_node); max_orig_node = orig_node; } rcu_read_unlock(); @@ -676,7 +676,7 @@ static bool batadv_dat_send_data(struct batadv_priv *bat_priv, free_neigh: batadv_neigh_node_put(neigh_node); free_orig: - batadv_orig_node_free_ref(cand[i].orig_node); + batadv_orig_node_put(cand[i].orig_node); }
out: diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c index 69edc0b..9a3f7af 100644 --- a/net/batman-adv/fragmentation.c +++ b/net/batman-adv/fragmentation.c @@ -385,7 +385,7 @@ bool batadv_frag_skb_fwd(struct sk_buff *skb,
out: if (orig_node_dst) - batadv_orig_node_free_ref(orig_node_dst); + batadv_orig_node_put(orig_node_dst); if (neigh_node) batadv_neigh_node_put(neigh_node); return ret; diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 33ddd7d..46c44b6 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -71,7 +71,7 @@ static void batadv_gw_node_release(struct kref *ref)
gw_node = container_of(ref, struct batadv_gw_node, refcount);
- batadv_orig_node_free_ref(gw_node->orig_node); + batadv_orig_node_put(gw_node->orig_node); kfree_rcu(gw_node, rcu); }
@@ -117,7 +117,7 @@ batadv_gw_get_selected_orig(struct batadv_priv *bat_priv) if (!orig_node) goto unlock;
- if (!atomic_inc_not_zero(&orig_node->refcount)) + if (!kref_get_unless_zero(&orig_node->refcount)) orig_node = NULL;
unlock: @@ -414,7 +414,7 @@ reselect: batadv_gw_reselect(bat_priv); out: if (curr_gw_orig) - batadv_orig_node_free_ref(curr_gw_orig); + batadv_orig_node_put(curr_gw_orig); if (router_gw) batadv_neigh_node_put(router_gw); if (router_orig) @@ -440,12 +440,12 @@ static void batadv_gw_node_add(struct batadv_priv *bat_priv, if (gateway->bandwidth_down == 0) return;
- if (!atomic_inc_not_zero(&orig_node->refcount)) + if (!kref_get_unless_zero(&orig_node->refcount)) return;
gw_node = kzalloc(sizeof(*gw_node), GFP_ATOMIC); if (!gw_node) { - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); return; }
@@ -877,7 +877,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
out: if (orig_dst_node) - batadv_orig_node_free_ref(orig_dst_node); + batadv_orig_node_put(orig_dst_node); if (curr_gw) batadv_gw_node_put(curr_gw); if (gw_node) diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c index 27be960..5b6d415 100644 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c @@ -292,7 +292,7 @@ out: if (neigh_node) batadv_neigh_node_put(neigh_node); if (orig_node) - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); return len; }
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 33ac461..19ad0bb 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -1207,7 +1207,7 @@ void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, u8 *src, if (batadv_send_skb_to_orig(skb, orig_node, NULL) == NET_XMIT_DROP) kfree_skb(skb); out: - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); }
/** diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c index 8abf488..288844f 100644 --- a/net/batman-adv/multicast.c +++ b/net/batman-adv/multicast.c @@ -30,6 +30,7 @@ #include <linux/in.h> #include <linux/ip.h> #include <linux/ipv6.h> +#include <linux/kref.h> #include <linux/list.h> #include <linux/lockdep.h> #include <linux/netdevice.h> @@ -447,7 +448,7 @@ batadv_mcast_forw_ipv4_node_get(struct batadv_priv *bat_priv) hlist_for_each_entry_rcu(tmp_orig_node, &bat_priv->mcast.want_all_ipv4_list, mcast_want_all_ipv4_node) { - if (!atomic_inc_not_zero(&tmp_orig_node->refcount)) + if (!kref_get_unless_zero(&tmp_orig_node->refcount)) continue;
orig_node = tmp_orig_node; @@ -474,7 +475,7 @@ batadv_mcast_forw_ipv6_node_get(struct batadv_priv *bat_priv) hlist_for_each_entry_rcu(tmp_orig_node, &bat_priv->mcast.want_all_ipv6_list, mcast_want_all_ipv6_node) { - if (!atomic_inc_not_zero(&tmp_orig_node->refcount)) + if (!kref_get_unless_zero(&tmp_orig_node->refcount)) continue;
orig_node = tmp_orig_node; @@ -525,7 +526,7 @@ batadv_mcast_forw_unsnoop_node_get(struct batadv_priv *bat_priv) hlist_for_each_entry_rcu(tmp_orig_node, &bat_priv->mcast.want_all_unsnoopables_list, mcast_want_all_unsnoopables_node) { - if (!atomic_inc_not_zero(&tmp_orig_node->refcount)) + if (!kref_get_unless_zero(&tmp_orig_node->refcount)) continue;
orig_node = tmp_orig_node; diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c index 96e1390..fc3a729 100644 --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c @@ -218,7 +218,7 @@ static void batadv_nc_node_release(struct kref *ref)
nc_node = container_of(ref, struct batadv_nc_node, refcount);
- batadv_orig_node_free_ref(nc_node->orig_node); + batadv_orig_node_put(nc_node->orig_node); kfree_rcu(nc_node, rcu); }
@@ -858,7 +858,7 @@ static struct batadv_nc_node if (!nc_node) return NULL;
- if (!atomic_inc_not_zero(&orig_neigh_node->refcount)) + if (!kref_get_unless_zero(&orig_neigh_node->refcount)) goto free;
/* Initialize nc_node */ @@ -1372,7 +1372,7 @@ batadv_nc_skb_src_search(struct batadv_priv *bat_priv, } rcu_read_unlock();
- batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); return nc_packet; }
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index a7b70b5..86ae44a 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -18,6 +18,7 @@ #include "originator.h" #include "main.h"
+#include <linux/atomic.h> #include <linux/errno.h> #include <linux/etherdevice.h> #include <linux/fs.h> @@ -750,14 +751,40 @@ void batadv_orig_ifinfo_put(struct batadv_orig_ifinfo *orig_ifinfo) kref_put(&orig_ifinfo->refcount, batadv_orig_ifinfo_release); }
+/** + * batadv_orig_node_free_rcu - free the orig_node + * @rcu: rcu pointer of the orig_node + */ static void batadv_orig_node_free_rcu(struct rcu_head *rcu) { + struct batadv_orig_node *orig_node; + + orig_node = container_of(rcu, struct batadv_orig_node, rcu); + + batadv_mcast_purge_orig(orig_node); + + batadv_frag_purge_orig(orig_node, NULL); + + if (orig_node->bat_priv->bat_algo_ops->bat_orig_free) + orig_node->bat_priv->bat_algo_ops->bat_orig_free(orig_node); + + kfree(orig_node->tt_buff); + kfree(orig_node); +} + +/** + * batadv_orig_node_release - release orig_node from lists and queue for + * free after rcu grace period + * @ref: kref pointer of the orig_node + */ +static void batadv_orig_node_release(struct kref *ref) +{ struct hlist_node *node_tmp; struct batadv_neigh_node *neigh_node; struct batadv_orig_node *orig_node; struct batadv_orig_ifinfo *orig_ifinfo;
- orig_node = container_of(rcu, struct batadv_orig_node, rcu); + orig_node = container_of(ref, struct batadv_orig_node, refcount);
spin_lock_bh(&orig_node->neigh_list_lock);
@@ -775,29 +802,20 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu) } spin_unlock_bh(&orig_node->neigh_list_lock);
- batadv_mcast_purge_orig(orig_node); - /* Free nc_nodes */ batadv_nc_purge_orig(orig_node->bat_priv, orig_node, NULL);
- batadv_frag_purge_orig(orig_node, NULL); - - if (orig_node->bat_priv->bat_algo_ops->bat_orig_free) - orig_node->bat_priv->bat_algo_ops->bat_orig_free(orig_node); - - kfree(orig_node->tt_buff); - kfree(orig_node); + call_rcu(&orig_node->rcu, batadv_orig_node_free_rcu); }
/** - * batadv_orig_node_free_ref - decrement the orig node refcounter and possibly + * batadv_orig_node_put - decrement the orig node refcounter and possibly * schedule an rcu callback for freeing it * @orig_node: the orig node to free */ -void batadv_orig_node_free_ref(struct batadv_orig_node *orig_node) +void batadv_orig_node_put(struct batadv_orig_node *orig_node) { - if (atomic_dec_and_test(&orig_node->refcount)) - call_rcu(&orig_node->rcu, batadv_orig_node_free_rcu); + kref_put(&orig_node->refcount, batadv_orig_node_release); }
void batadv_originator_free(struct batadv_priv *bat_priv) @@ -824,7 +842,7 @@ void batadv_originator_free(struct batadv_priv *bat_priv) hlist_for_each_entry_safe(orig_node, node_tmp, head, hash_entry) { hlist_del_rcu(&orig_node->hash_entry); - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); } spin_unlock_bh(list_lock); } @@ -869,7 +887,8 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, batadv_nc_init_orig(orig_node);
/* extra reference for return */ - atomic_set(&orig_node->refcount, 2); + kref_init(&orig_node->refcount); + kref_get(&orig_node->refcount);
orig_node->bat_priv = bat_priv; ether_addr_copy(orig_node->orig, addr); @@ -1184,7 +1203,7 @@ static void _batadv_purge_orig(struct batadv_priv *bat_priv) batadv_tt_global_del_orig(orig_node->bat_priv, orig_node, -1, "originator timed out"); - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); continue; }
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index 0bad6cc..b67a6bc 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -20,10 +20,10 @@
#include "main.h"
-#include <linux/atomic.h> #include <linux/compiler.h> #include <linux/if_ether.h> #include <linux/jhash.h> +#include <linux/kref.h> #include <linux/rculist.h> #include <linux/rcupdate.h> #include <linux/stddef.h> @@ -37,7 +37,7 @@ int batadv_compare_orig(const struct hlist_node *node, const void *data2); int batadv_originator_init(struct batadv_priv *bat_priv); void batadv_originator_free(struct batadv_priv *bat_priv); void batadv_purge_orig_ref(struct batadv_priv *bat_priv); -void batadv_orig_node_free_ref(struct batadv_orig_node *orig_node); +void batadv_orig_node_put(struct batadv_orig_node *orig_node); struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, const u8 *addr); struct batadv_hardif_neigh_node * @@ -115,7 +115,7 @@ batadv_orig_hash_find(struct batadv_priv *bat_priv, const void *data) if (!batadv_compare_eth(orig_node, data)) continue;
- if (!atomic_inc_not_zero(&orig_node->refcount)) + if (!kref_get_unless_zero(&orig_node->refcount)) continue;
orig_node_tmp = orig_node; diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 43b5875..0aa9eb1 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -271,7 +271,7 @@ out: if (primary_if) batadv_hardif_put(primary_if); if (orig_node) - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); return ret; }
@@ -319,7 +319,7 @@ out: if (primary_if) batadv_hardif_put(primary_if); if (orig_node) - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); return ret; }
@@ -403,7 +403,7 @@ int batadv_recv_icmp_packet(struct sk_buff *skb,
out: if (orig_node) - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); return ret; }
@@ -649,7 +649,7 @@ static int batadv_route_unicast_packet(struct sk_buff *skb,
out: if (orig_node) - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); return ret; }
@@ -704,7 +704,7 @@ out: if (primary_if) batadv_hardif_put(primary_if); if (orig_node) - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node);
return ret; } @@ -768,7 +768,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, return 0;
curr_ttvn = (u8)atomic_read(&orig_node->last_ttvn); - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); }
/* check if the TTVN contained in the packet is fresher than what the @@ -908,7 +908,7 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
rx_success: if (orig_node) - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node);
return NET_RX_SUCCESS; } @@ -1019,7 +1019,7 @@ int batadv_recv_frag_packet(struct sk_buff *skb,
out: if (orig_node_src) - batadv_orig_node_free_ref(orig_node_src); + batadv_orig_node_put(orig_node_src);
return ret; } @@ -1124,6 +1124,6 @@ spin_unlock: spin_unlock_bh(&orig_node->bcast_seqno_lock); out: if (orig_node) - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); return ret; } diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index be8011c..b8e2d0e 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -317,7 +317,7 @@ int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
out: if (orig_node) - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); if (ret == NET_XMIT_DROP) kfree_skb(skb); return ret; diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index ac66771..dad9060 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -356,7 +356,7 @@ static void batadv_tt_orig_list_entry_release(struct kref *ref) orig_entry = container_of(ref, struct batadv_tt_orig_list_entry, refcount);
- batadv_orig_node_free_ref(orig_entry->orig_node); + batadv_orig_node_put(orig_entry->orig_node); kfree_rcu(orig_entry, rcu); }
@@ -1334,7 +1334,7 @@ batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global, goto out;
INIT_HLIST_NODE(&orig_entry->list); - atomic_inc(&orig_node->refcount); + kref_get(&orig_node->refcount); batadv_tt_global_size_inc(orig_node, tt_global->common.vid); orig_entry->orig_node = orig_node; orig_entry->ttvn = ttvn; @@ -2097,7 +2097,7 @@ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, /* found anything? */ if (best_entry) orig_node = best_entry->orig_node; - if (orig_node && !atomic_inc_not_zero(&orig_node->refcount)) + if (orig_node && !kref_get_unless_zero(&orig_node->refcount)) orig_node = NULL; rcu_read_unlock();
@@ -2738,9 +2738,9 @@ unlock:
out: if (res_dst_orig_node) - batadv_orig_node_free_ref(res_dst_orig_node); + batadv_orig_node_put(res_dst_orig_node); if (req_dst_orig_node) - batadv_orig_node_free_ref(req_dst_orig_node); + batadv_orig_node_put(req_dst_orig_node); kfree(tvlv_tt_data); return ret; } @@ -2855,7 +2855,7 @@ unlock: out: spin_unlock_bh(&bat_priv->tt.commit_lock); if (orig_node) - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); if (primary_if) batadv_hardif_put(primary_if); kfree(tvlv_tt_data); @@ -2943,7 +2943,7 @@ static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv,
out: if (orig_node) - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); }
static void batadv_tt_update_changes(struct batadv_priv *bat_priv, @@ -3049,7 +3049,7 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv, spin_unlock_bh(&bat_priv->tt.req_list_lock); out: if (orig_node) - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); }
static void batadv_tt_roam_list_free(struct batadv_priv *bat_priv) @@ -3764,7 +3764,7 @@ static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
out: if (orig_node) - batadv_orig_node_free_ref(orig_node); + batadv_orig_node_put(orig_node); return NET_RX_SUCCESS; }
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 441ebd9..c8c7ab8 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -299,7 +299,7 @@ struct batadv_orig_node { struct batadv_priv *bat_priv; /* bcast_seqno_lock protects: bcast_bits & last_bcast_seqno */ spinlock_t bcast_seqno_lock; - atomic_t refcount; + struct kref refcount; struct rcu_head rcu; #ifdef CONFIG_BATMAN_ADV_NC struct list_head in_coding_list;
So switch to kref instead of using the self-made, atomic_t-based implementation.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/translation-table.c | 116 ++++++++++++++++++++++++------------- net/batman-adv/types.h | 2 +- 2 files changed, 77 insertions(+), 41 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index dad9060..f717b5e 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -142,7 +142,7 @@ batadv_tt_hash_find(struct batadv_hashtable *hash, const u8 *addr, if (tt->vid != vid) continue;
- if (!atomic_inc_not_zero(&tt->refcount)) + if (!kref_get_unless_zero(&tt->refcount)) continue;
tt_tmp = tt; @@ -203,25 +203,59 @@ batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const u8 *addr, return tt_global_entry; }
-static void -batadv_tt_local_entry_free_ref(struct batadv_tt_local_entry *tt_local_entry) +/** + * batadv_tt_local_entry_release - release tt_local_entry from lists and queue + * for free after rcu grace period + * * @ref: kref pointer of the nc_node + */ +static void batadv_tt_local_entry_release(struct kref *ref) { - if (atomic_dec_and_test(&tt_local_entry->common.refcount)) - kfree_rcu(tt_local_entry, common.rcu); + struct batadv_tt_local_entry *tt_local_entry; + + tt_local_entry = container_of(ref, struct batadv_tt_local_entry, + common.refcount); + + kfree_rcu(tt_local_entry, common.rcu); }
/** - * batadv_tt_global_entry_free_ref - decrement the refcounter for a - * tt_global_entry and possibly free it - * @tt_global_entry: the object to free + * batadv_tt_local_entry_put - decrement the tt_local_entry refcounter and + * possibly release it + * @tt_local_entry: tt_local_entry to be free'd */ static void -batadv_tt_global_entry_free_ref(struct batadv_tt_global_entry *tt_global_entry) +batadv_tt_local_entry_put(struct batadv_tt_local_entry *tt_local_entry) { - if (atomic_dec_and_test(&tt_global_entry->common.refcount)) { - batadv_tt_global_del_orig_list(tt_global_entry); - kfree_rcu(tt_global_entry, common.rcu); - } + kref_put(&tt_local_entry->common.refcount, + batadv_tt_local_entry_release); +} + +/** + * batadv_tt_global_entry_release - release tt_global_entry from lists and queue + * for free after rcu grace period + * * @ref: kref pointer of the nc_node + */ +static void batadv_tt_global_entry_release(struct kref *ref) +{ + struct batadv_tt_global_entry *tt_global_entry; + + tt_global_entry = container_of(ref, struct batadv_tt_global_entry, + common.refcount); + + batadv_tt_global_del_orig_list(tt_global_entry); + kfree_rcu(tt_global_entry, common.rcu); +} + +/** + * batadv_tt_global_entry_put - decrement the tt_global_entry refcounter and + * possibly release it + * @tt_global_entry: tt_global_entry to be free'd + */ +static void +batadv_tt_global_entry_put(struct batadv_tt_global_entry *tt_global_entry) +{ + kref_put(&tt_global_entry->common.refcount, + batadv_tt_global_entry_release); }
/** @@ -244,7 +278,7 @@ int batadv_tt_global_hash_count(struct batadv_priv *bat_priv, return 0;
count = atomic_read(&tt_global_entry->orig_list_count); - batadv_tt_global_entry_free_ref(tt_global_entry); + batadv_tt_global_entry_put(tt_global_entry);
return count; } @@ -525,7 +559,7 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,
batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt, batadv_choose_tt, &tt_global->common); - batadv_tt_global_entry_free_ref(tt_global); + batadv_tt_global_entry_put(tt_global); }
/** @@ -633,7 +667,8 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr, tt_local->common.vid = vid; if (batadv_is_wifi_netdev(in_dev)) tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; - atomic_set(&tt_local->common.refcount, 2); + kref_init(&tt_local->common.refcount); + kref_get(&tt_local->common.refcount); tt_local->last_seen = jiffies; tt_local->common.added_at = tt_local->last_seen;
@@ -650,7 +685,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr,
if (unlikely(hash_added != 0)) { /* remove the reference for the hash */ - batadv_tt_local_entry_free_ref(tt_local); + batadv_tt_local_entry_put(tt_local); batadv_softif_vlan_put(vlan); goto out; } @@ -717,9 +752,9 @@ out: if (in_dev) dev_put(in_dev); if (tt_local) - batadv_tt_local_entry_free_ref(tt_local); + batadv_tt_local_entry_put(tt_local); if (tt_global) - batadv_tt_global_entry_free_ref(tt_global); + batadv_tt_global_entry_put(tt_global); return ret; }
@@ -1100,7 +1135,7 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr, goto out;
/* extra call to free the local tt entry */ - batadv_tt_local_entry_free_ref(tt_local_entry); + batadv_tt_local_entry_put(tt_local_entry);
/* decrease the reference held for this vlan */ vlan = batadv_softif_vlan_get(bat_priv, vid); @@ -1112,7 +1147,7 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
out: if (tt_local_entry) - batadv_tt_local_entry_free_ref(tt_local_entry); + batadv_tt_local_entry_put(tt_local_entry);
return curr_flags; } @@ -1212,7 +1247,7 @@ static void batadv_tt_local_table_free(struct batadv_priv *bat_priv) batadv_softif_vlan_put(vlan); }
- batadv_tt_local_entry_free_ref(tt_local); + batadv_tt_local_entry_put(tt_local); } spin_unlock_bh(list_lock); } @@ -1415,7 +1450,8 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv, */ if (flags & BATADV_TT_CLIENT_ROAM) tt_global_entry->roam_at = jiffies; - atomic_set(&common->refcount, 2); + kref_init(&common->refcount); + kref_get(&common->refcount); common->added_at = jiffies;
INIT_HLIST_HEAD(&tt_global_entry->orig_list); @@ -1429,7 +1465,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
if (unlikely(hash_added != 0)) { /* remove the reference for the hash */ - batadv_tt_global_entry_free_ref(tt_global_entry); + batadv_tt_global_entry_put(tt_global_entry); goto out_remove; } } else { @@ -1515,9 +1551,9 @@ out_remove:
out: if (tt_global_entry) - batadv_tt_global_entry_free_ref(tt_global_entry); + batadv_tt_global_entry_put(tt_global_entry); if (tt_local_entry) - batadv_tt_local_entry_free_ref(tt_local_entry); + batadv_tt_local_entry_put(tt_local_entry); return ret; }
@@ -1871,9 +1907,9 @@ static void batadv_tt_global_del(struct batadv_priv *bat_priv,
out: if (tt_global_entry) - batadv_tt_global_entry_free_ref(tt_global_entry); + batadv_tt_global_entry_put(tt_global_entry); if (local_entry) - batadv_tt_local_entry_free_ref(local_entry); + batadv_tt_local_entry_put(local_entry); }
/** @@ -1927,7 +1963,7 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, tt_global->common.addr, BATADV_PRINT_VID(vid), message); hlist_del_rcu(&tt_common_entry->hash_entry); - batadv_tt_global_entry_free_ref(tt_global); + batadv_tt_global_entry_put(tt_global); } } spin_unlock_bh(list_lock); @@ -1990,7 +2026,7 @@ static void batadv_tt_global_purge(struct batadv_priv *bat_priv)
hlist_del_rcu(&tt_common->hash_entry);
- batadv_tt_global_entry_free_ref(tt_global); + batadv_tt_global_entry_put(tt_global); } spin_unlock_bh(list_lock); } @@ -2022,7 +2058,7 @@ static void batadv_tt_global_table_free(struct batadv_priv *bat_priv) tt_global = container_of(tt_common_entry, struct batadv_tt_global_entry, common); - batadv_tt_global_entry_free_ref(tt_global); + batadv_tt_global_entry_put(tt_global); } spin_unlock_bh(list_lock); } @@ -2103,9 +2139,9 @@ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
out: if (tt_global_entry) - batadv_tt_global_entry_free_ref(tt_global_entry); + batadv_tt_global_entry_put(tt_global_entry); if (tt_local_entry) - batadv_tt_local_entry_free_ref(tt_local_entry); + batadv_tt_local_entry_put(tt_local_entry);
return orig_node; } @@ -2985,7 +3021,7 @@ bool batadv_is_my_client(struct batadv_priv *bat_priv, const u8 *addr, ret = true; out: if (tt_local_entry) - batadv_tt_local_entry_free_ref(tt_local_entry); + batadv_tt_local_entry_put(tt_local_entry); return ret; }
@@ -3308,7 +3344,7 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) batadv_softif_vlan_put(vlan); }
- batadv_tt_local_entry_free_ref(tt_local); + batadv_tt_local_entry_put(tt_local); } spin_unlock_bh(list_lock); } @@ -3393,9 +3429,9 @@ bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, u8 *src, u8 *dst, out: batadv_softif_vlan_put(vlan); if (tt_global_entry) - batadv_tt_global_entry_free_ref(tt_global_entry); + batadv_tt_global_entry_put(tt_global_entry); if (tt_local_entry) - batadv_tt_local_entry_free_ref(tt_local_entry); + batadv_tt_local_entry_put(tt_local_entry); return ret; }
@@ -3505,7 +3541,7 @@ bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, goto out;
ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM; - batadv_tt_global_entry_free_ref(tt_global_entry); + batadv_tt_global_entry_put(tt_global_entry); out: return ret; } @@ -3531,7 +3567,7 @@ bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, goto out;
ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM; - batadv_tt_local_entry_free_ref(tt_local_entry); + batadv_tt_local_entry_put(tt_local_entry); out: return ret; } @@ -3825,7 +3861,7 @@ bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv,
ret = tt->common.flags & BATADV_TT_CLIENT_ISOLA;
- batadv_tt_global_entry_free_ref(tt); + batadv_tt_global_entry_put(tt);
return ret; } diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index c8c7ab8..ef421ba 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -972,7 +972,7 @@ struct batadv_tt_common_entry { struct hlist_node hash_entry; u16 flags; unsigned long added_at; - atomic_t refcount; + struct kref refcount; struct rcu_head rcu; };
The batadv_tvlv_container* functions state in their kernel-doc that they require tvlv.container_list_lock. Add an assert to automatically detect when this might have been ignored by the caller.
Signed-off-by: Sven Eckelmann sven@narfation.org --- net/batman-adv/main.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 19ad0bb..c9b8205 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -720,6 +720,8 @@ static struct batadv_tvlv_container { struct batadv_tvlv_container *tvlv_tmp, *tvlv = NULL;
+ lockdep_assert_held(&bat_priv->tvlv.container_list_lock); + hlist_for_each_entry(tvlv_tmp, &bat_priv->tvlv.container_list, list) { if (tvlv_tmp->tvlv_hdr.type != type) continue; @@ -752,6 +754,8 @@ static u16 batadv_tvlv_container_list_size(struct batadv_priv *bat_priv) struct batadv_tvlv_container *tvlv; u16 tvlv_len = 0;
+ lockdep_assert_held(&bat_priv->tvlv.container_list_lock); + hlist_for_each_entry(tvlv, &bat_priv->tvlv.container_list, list) { tvlv_len += sizeof(struct batadv_tvlv_hdr); tvlv_len += ntohs(tvlv->tvlv_hdr.len);
Hi,
I think I should change the patchset slightly to have less noise in each patch and make it easier for the backporting efforts. But the end result (after applying all) will be exactly the same - so feel free to still check the them until I find time to go through the patches again.
Kind regards, Sven
b.a.t.m.a.n@lists.open-mesh.org