Bug #474
opentt: Potential loss of originators in batadv_tt_global_add
0%
Description
Can deferring batadv_tt_global_del_orig_list() until after flags_lock is
dropped lose an originator entry added in between?The old code purged the originator list first and cleared
BATADV_TT_CLIENT_TEMP / BATADV_TT_CLIENT_ROAM afterwards, so a second
context still saw the flag and did its own purge. Now the cleared flag is
published before the list is wiped:
CPU0 batadv_tt_global_add() CPU1 batadv_tt_global_add()
spin_lock_bh(&common->flags_lock);
delete = true;
common->flags &= ~BATADV_TT_CLIENT_TEMP;
spin_unlock_bh(&common->flags_lock);
spin_lock_bh(&common->flags_lock);
/* TEMP already clear, so
* delete stays false
*/
spin_unlock_bh(&common->flags_lock);
batadv_tt_global_orig_entry_add()
batadv_tt_global_del_orig_list()
/* drops every orig entry,
* including CPU1's fresh one
*/
batadv_tt_global_del_orig_list() takes tt_global_entry->list_lock and
removes all entries:
spin_lock_bh(&tt_global_entry->list_lock);
head = &tt_global_entry->orig_list;
hlist_for_each_entry_safe(orig_entry, safe, head, list)
_batadv_tt_global_del_orig_entry(tt_global_entry, orig_entry);
Both callers return true in that case, so does the route via CPU1's
originator silently disappear until the next global CRC mismatch triggers
a fresh TT request? batadv_tt_global_add() is reached from received TT
TVLV data (serialized only per originator by orig_node->tt_lock) and from
batadv_tt_add_temporary_global_entry(), so two CPUs can process
announcements for the same client from different originators at the same
time.