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 <[email protected]>
---
 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;
 };
 
-- 
2.6.4

Reply via email to