In the current TT code, when a TT_Response containing a full table is received form an originator, the node first purges all the clients for that originator in the global translation-table and then merges the new received table. During the purging phase each client deletion is done by means of a call_rcu() invocation and at the end the global entry counter for that originator is set to 0. However the invoked rcu function decreases by one the global entry counter for that originator as well and since the rcu invocation is likely to be postponed, the node will end up in first setting the counter to 0 and then decreasing it one by one for each deleted client. To solve this problem the counter is not explicitly set to 0 anymore and the counter decrement is performed right before the invocation of call_rcu().
Signed-off-by: Antonio Quartulli ordex@autistici.org --- translation-table.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/translation-table.c b/translation-table.c index 2a6d7d6..b08cb76 100644 --- a/translation-table.c +++ b/translation-table.c @@ -145,7 +145,6 @@ 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); - atomic_dec(&orig_entry->orig_node->tt_size); batadv_orig_node_free_ref(orig_entry->orig_node); kfree(orig_entry); } @@ -153,6 +152,8 @@ static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu) static void batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry) { + /* to avoid race conditions, immediately decrease the tt counter */ + atomic_dec(&orig_entry->orig_node->tt_size); call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu); }
@@ -1025,7 +1026,6 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, } spin_unlock_bh(list_lock); } - atomic_set(&orig_node->tt_size, 0); orig_node->tt_initialised = false; }