@@ -53,9 +53,11 @@ void *gw_get_selected(struct bat_priv *bat_priv)
goto out;
orig_node = curr_gateway_tmp->orig_node;
+ if (!orig_node)
+ goto out;
- if (orig_node)
- kref_get(&orig_node->refcount);
+ if (!atomic_inc_not_zero(&orig_node->refcount))
+ orig_node = NULL;
out:
rcu_read_unlock();
@@ -263,7 +263,7 @@ out:
if (neigh_node)
neigh_node_free_ref(neigh_node);
if (orig_node)
- kref_put(&orig_node->refcount, orig_node_free_ref);
+ orig_node_free_ref(orig_node);
return len;
}
@@ -99,13 +99,13 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
return neigh_node;
}
-void orig_node_free_ref(struct kref *refcount)
+static void orig_node_free_rcu(struct rcu_head *rcu)
{
struct hlist_node *node, *node_tmp;
struct neigh_node *neigh_node, *tmp_neigh_node;
struct orig_node *orig_node;
- orig_node = container_of(refcount, struct orig_node, refcount);
+ orig_node = container_of(rcu, struct orig_node, rcu);
spin_lock_bh(&orig_node->neigh_list_lock);
@@ -134,6 +134,12 @@ void orig_node_free_ref(struct kref *refcount)
kfree(orig_node);
}
+void orig_node_free_ref(struct orig_node *orig_node)
+{
+ if (atomic_dec_and_test(&orig_node->refcount))
+ call_rcu(&orig_node->rcu, orig_node_free_rcu);
+}
+
void originator_free(struct bat_priv *bat_priv)
{
struct hashtable_t *hash = bat_priv->orig_hash;
@@ -159,7 +165,7 @@ void originator_free(struct bat_priv *bat_priv)
head, hash_entry) {
hlist_del_rcu(node);
- kref_put(&orig_node->refcount, orig_node_free_ref);
+ orig_node_free_ref(orig_node);
}
spin_unlock_bh(list_lock);
}
@@ -191,7 +197,9 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
spin_lock_init(&orig_node->ogm_cnt_lock);
spin_lock_init(&orig_node->bcast_seqno_lock);
spin_lock_init(&orig_node->neigh_list_lock);
- kref_init(&orig_node->refcount);
+
+ /* extra reference for return */
+ atomic_set(&orig_node->refcount, 2);
orig_node->bat_priv = bat_priv;
memcpy(orig_node->orig, addr, ETH_ALEN);
@@ -224,8 +232,6 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
if (hash_added < 0)
goto free_bcast_own_sum;
- /* extra reference for return */
- kref_get(&orig_node->refcount);
return orig_node;
free_bcast_own_sum:
kfree(orig_node->bcast_own_sum);
@@ -27,7 +27,7 @@
int originator_init(struct bat_priv *bat_priv);
void originator_free(struct bat_priv *bat_priv);
void purge_orig_ref(struct bat_priv *bat_priv);
-void orig_node_free_ref(struct kref *refcount);
+void orig_node_free_ref(struct orig_node *orig_node);
struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr);
struct neigh_node *create_neighbor(struct orig_node *orig_node,
struct orig_node *orig_neigh_node,
@@ -88,8 +88,10 @@ static inline struct orig_node *orig_hash_find(struct bat_priv *bat_priv,
if (!compare_eth(orig_node, data))
continue;
+ if (!atomic_inc_not_zero(&orig_node->refcount))
+ continue;
+
orig_node_tmp = orig_node;
- kref_get(&orig_node_tmp->refcount);
break;
}
rcu_read_unlock();
@@ -416,7 +416,7 @@ static void update_orig(struct bat_priv *bat_priv,
neigh_node = create_neighbor(orig_node, orig_tmp,
ethhdr->h_source, if_incoming);
- kref_put(&orig_tmp->refcount, orig_node_free_ref);
+ orig_node_free_ref(orig_tmp);
if (!neigh_node)
goto unlock;
@@ -600,7 +600,7 @@ static char count_real_packets(struct ethhdr *ethhdr,
out:
spin_unlock_bh(&orig_node->ogm_cnt_lock);
- kref_put(&orig_node->refcount, orig_node_free_ref);
+ orig_node_free_ref(orig_node);
return ret;
}
@@ -726,7 +726,7 @@ void receive_bat_packet(struct ethhdr *ethhdr,
bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
"originator packet from myself (via neighbor)\n");
- kref_put(&orig_neigh_node->refcount, orig_node_free_ref);
+ orig_node_free_ref(orig_neigh_node);
return;
}
@@ -832,9 +832,9 @@ void receive_bat_packet(struct ethhdr *ethhdr,
out_neigh:
if ((orig_neigh_node) && (!is_single_hop_neigh))
- kref_put(&orig_neigh_node->refcount, orig_node_free_ref);
+ orig_node_free_ref(orig_neigh_node);
out:
- kref_put(&orig_node->refcount, orig_node_free_ref);
+ orig_node_free_ref(orig_node);
}
int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if)
@@ -935,7 +935,7 @@ out:
if (neigh_node)
neigh_node_free_ref(neigh_node);
if (orig_node)
- kref_put(&orig_node->refcount, orig_node_free_ref);
+ orig_node_free_ref(orig_node);
return ret;
}
@@ -1001,7 +1001,7 @@ out:
if (neigh_node)
neigh_node_free_ref(neigh_node);
if (orig_node)
- kref_put(&orig_node->refcount, orig_node_free_ref);
+ orig_node_free_ref(orig_node);
return ret;
}
@@ -1097,7 +1097,7 @@ out:
if (neigh_node)
neigh_node_free_ref(neigh_node);
if (orig_node)
- kref_put(&orig_node->refcount, orig_node_free_ref);
+ orig_node_free_ref(orig_node);
return ret;
}
@@ -1152,7 +1152,7 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
if (!primary_orig_node)
goto return_router;
- kref_put(&primary_orig_node->refcount, orig_node_free_ref);
+ orig_node_free_ref(primary_orig_node);
}
/* with less than 2 candidates, we can't do any
@@ -1354,7 +1354,7 @@ out:
if (neigh_node)
neigh_node_free_ref(neigh_node);
if (orig_node)
- kref_put(&orig_node->refcount, orig_node_free_ref);
+ orig_node_free_ref(orig_node);
return ret;
}
@@ -1492,7 +1492,7 @@ spin_unlock:
spin_unlock_bh(&orig_node->bcast_seqno_lock);
out:
if (orig_node)
- kref_put(&orig_node->refcount, orig_node_free_ref);
+ orig_node_free_ref(orig_node);
return ret;
}
@@ -589,17 +589,20 @@ void hna_global_free(struct bat_priv *bat_priv)
struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr)
{
struct hna_global_entry *hna_global_entry;
+ struct orig_node *orig_node = NULL;
spin_lock_bh(&bat_priv->hna_ghash_lock);
hna_global_entry = hna_global_hash_find(bat_priv, addr);
- if (hna_global_entry)
- kref_get(&hna_global_entry->orig_node->refcount);
+ if (!hna_global_entry)
+ goto out;
- spin_unlock_bh(&bat_priv->hna_ghash_lock);
+ if (!atomic_inc_not_zero(&hna_global_entry->orig_node->refcount))
+ goto out;
- if (!hna_global_entry)
- return NULL;
+ orig_node = hna_global_entry->orig_node;
- return hna_global_entry->orig_node;
+out:
+ spin_unlock_bh(&bat_priv->hna_ghash_lock);
+ return orig_node;
}
@@ -84,7 +84,8 @@ struct orig_node {
struct hlist_head neigh_list;
struct list_head frag_list;
spinlock_t neigh_list_lock; /* protects neighbor list */
- struct kref refcount;
+ atomic_t refcount;
+ struct rcu_head rcu;
struct hlist_node hash_entry;
struct bat_priv *bat_priv;
unsigned long last_frag_packet;
@@ -211,11 +211,9 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
if (*new_skb)
ret = NET_RX_SUCCESS;
- goto out;
-
out:
if (orig_node)
- kref_put(&orig_node->refcount, orig_node_free_ref);
+ orig_node_free_ref(orig_node);
return ret;
}
@@ -344,7 +342,7 @@ out:
if (neigh_node)
neigh_node_free_ref(neigh_node);
if (orig_node)
- kref_put(&orig_node->refcount, orig_node_free_ref);
+ orig_node_free_ref(orig_node);
if (ret == 1)
kfree_skb(skb);
return ret;
@@ -809,7 +809,7 @@ out:
if (neigh_node)
neigh_node_free_ref(neigh_node);
if (orig_node)
- kref_put(&orig_node->refcount, orig_node_free_ref);
+ orig_node_free_ref(orig_node);
return;
}