@@ -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,
@@ -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;
}
@@ -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:
@@ -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;
@@ -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)
@@ -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;
}
@@ -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);
}
/**
@@ -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;
@@ -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;
}
@@ -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;
}
@@ -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;
@@ -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;
}
@@ -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;
@@ -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;
}
@@ -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;