Skip to content

Commit d657e62

Browse files
author
Antonio Quartulli
committed
batman-adv: add reference counting for type batadv_tt_orig_list_entry
The batadv_tt_orig_list_entry structure didn't have any refcounting mechanism so far. This patch introduces it and makes the structure being usable in much more complex context. Signed-off-by: Antonio Quartulli <[email protected]>
1 parent 3a7f291 commit d657e62

File tree

2 files changed

+53
-23
lines changed

2 files changed

+53
-23
lines changed

net/batman-adv/translation-table.c

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu)
152152
static void
153153
batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry)
154154
{
155+
if (!atomic_dec_and_test(&orig_entry->refcount))
156+
return;
155157
/* to avoid race conditions, immediately decrease the tt counter */
156158
atomic_dec(&orig_entry->orig_node->tt_size);
157159
call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu);
@@ -625,50 +627,82 @@ static void batadv_tt_changes_list_free(struct batadv_priv *bat_priv)
625627
spin_unlock_bh(&bat_priv->tt_changes_list_lock);
626628
}
627629

628-
/* find out if an orig_node is already in the list of a tt_global_entry.
629-
* returns 1 if found, 0 otherwise
630+
/* retrieves the orig_tt_list_entry belonging to orig_node from the
631+
* batadv_tt_global_entry list
632+
*
633+
* returns it with an increased refcounter, NULL if not found
630634
*/
631-
static bool
632-
batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry,
633-
const struct batadv_orig_node *orig_node)
635+
static struct batadv_tt_orig_list_entry *
636+
batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry,
637+
const struct batadv_orig_node *orig_node)
634638
{
635-
struct batadv_tt_orig_list_entry *tmp_orig_entry;
639+
struct batadv_tt_orig_list_entry *tmp_orig_entry, *orig_entry = NULL;
636640
const struct hlist_head *head;
637641
struct hlist_node *node;
638-
bool found = false;
639642

640643
rcu_read_lock();
641644
head = &entry->orig_list;
642645
hlist_for_each_entry_rcu(tmp_orig_entry, node, head, list) {
643-
if (tmp_orig_entry->orig_node == orig_node) {
644-
found = true;
645-
break;
646-
}
646+
if (tmp_orig_entry->orig_node != orig_node)
647+
continue;
648+
if (!atomic_inc_not_zero(&tmp_orig_entry->refcount))
649+
continue;
650+
651+
orig_entry = tmp_orig_entry;
652+
break;
647653
}
648654
rcu_read_unlock();
655+
656+
return orig_entry;
657+
}
658+
659+
/* find out if an orig_node is already in the list of a tt_global_entry.
660+
* returns true if found, false otherwise
661+
*/
662+
static bool
663+
batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry,
664+
const struct batadv_orig_node *orig_node)
665+
{
666+
struct batadv_tt_orig_list_entry *orig_entry;
667+
bool found = false;
668+
669+
orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node);
670+
if (orig_entry) {
671+
found = true;
672+
batadv_tt_orig_list_entry_free_ref(orig_entry);
673+
}
674+
649675
return found;
650676
}
651677

652678
static void
653-
batadv_tt_global_add_orig_entry(struct batadv_tt_global_entry *tt_global_entry,
679+
batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,
654680
struct batadv_orig_node *orig_node, int ttvn)
655681
{
656682
struct batadv_tt_orig_list_entry *orig_entry;
657683

684+
orig_entry = batadv_tt_global_orig_entry_find(tt_global, orig_node);
685+
if (orig_entry)
686+
goto out;
687+
658688
orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC);
659689
if (!orig_entry)
660-
return;
690+
goto out;
661691

662692
INIT_HLIST_NODE(&orig_entry->list);
663693
atomic_inc(&orig_node->refcount);
664694
atomic_inc(&orig_node->tt_size);
665695
orig_entry->orig_node = orig_node;
666696
orig_entry->ttvn = ttvn;
697+
atomic_set(&orig_entry->refcount, 2);
667698

668-
spin_lock_bh(&tt_global_entry->list_lock);
699+
spin_lock_bh(&tt_global->list_lock);
669700
hlist_add_head_rcu(&orig_entry->list,
670-
&tt_global_entry->orig_list);
671-
spin_unlock_bh(&tt_global_entry->list_lock);
701+
&tt_global->orig_list);
702+
spin_unlock_bh(&tt_global->list_lock);
703+
out:
704+
if (orig_entry)
705+
batadv_tt_orig_list_entry_free_ref(orig_entry);
672706
}
673707

674708
/* caller must hold orig_node refcount */
@@ -709,9 +743,6 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv,
709743
batadv_tt_global_entry_free_ref(tt_global_entry);
710744
goto out_remove;
711745
}
712-
713-
batadv_tt_global_add_orig_entry(tt_global_entry, orig_node,
714-
ttvn);
715746
} else {
716747
/* there is already a global entry, use this one. */
717748

@@ -728,11 +759,9 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv,
728759
tt_global_entry->roam_at = 0;
729760
}
730761

731-
if (!batadv_tt_global_entry_has_orig(tt_global_entry,
732-
orig_node))
733-
batadv_tt_global_add_orig_entry(tt_global_entry,
734-
orig_node, ttvn);
735762
}
763+
/* add the new orig_entry (if needed) */
764+
batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn);
736765

737766
batadv_dbg(BATADV_DBG_TT, bat_priv,
738767
"Creating new global tt entry: %pM (via %pM)\n",

net/batman-adv/types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ struct batadv_tt_global_entry {
282282
struct batadv_tt_orig_list_entry {
283283
struct batadv_orig_node *orig_node;
284284
uint8_t ttvn;
285+
atomic_t refcount;
285286
struct rcu_head rcu;
286287
struct hlist_node list;
287288
};

0 commit comments

Comments
 (0)