new file mode 100644
@@ -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_ */
@@ -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);
}
@@ -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;
}
@@ -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,
@@ -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;
};
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