@@ -152,6 +152,8 @@ static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu)
152
152
static void
153
153
batadv_tt_orig_list_entry_free_ref (struct batadv_tt_orig_list_entry * orig_entry )
154
154
{
155
+ if (!atomic_dec_and_test (& orig_entry -> refcount ))
156
+ return ;
155
157
/* to avoid race conditions, immediately decrease the tt counter */
156
158
atomic_dec (& orig_entry -> orig_node -> tt_size );
157
159
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)
625
627
spin_unlock_bh (& bat_priv -> tt_changes_list_lock );
626
628
}
627
629
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
630
634
*/
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 )
634
638
{
635
- struct batadv_tt_orig_list_entry * tmp_orig_entry ;
639
+ struct batadv_tt_orig_list_entry * tmp_orig_entry , * orig_entry = NULL ;
636
640
const struct hlist_head * head ;
637
641
struct hlist_node * node ;
638
- bool found = false;
639
642
640
643
rcu_read_lock ();
641
644
head = & entry -> orig_list ;
642
645
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 ;
647
653
}
648
654
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
+
649
675
return found ;
650
676
}
651
677
652
678
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 ,
654
680
struct batadv_orig_node * orig_node , int ttvn )
655
681
{
656
682
struct batadv_tt_orig_list_entry * orig_entry ;
657
683
684
+ orig_entry = batadv_tt_global_orig_entry_find (tt_global , orig_node );
685
+ if (orig_entry )
686
+ goto out ;
687
+
658
688
orig_entry = kzalloc (sizeof (* orig_entry ), GFP_ATOMIC );
659
689
if (!orig_entry )
660
- return ;
690
+ goto out ;
661
691
662
692
INIT_HLIST_NODE (& orig_entry -> list );
663
693
atomic_inc (& orig_node -> refcount );
664
694
atomic_inc (& orig_node -> tt_size );
665
695
orig_entry -> orig_node = orig_node ;
666
696
orig_entry -> ttvn = ttvn ;
697
+ atomic_set (& orig_entry -> refcount , 2 );
667
698
668
- spin_lock_bh (& tt_global_entry -> list_lock );
699
+ spin_lock_bh (& tt_global -> list_lock );
669
700
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 );
672
706
}
673
707
674
708
/* caller must hold orig_node refcount */
@@ -709,9 +743,6 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv,
709
743
batadv_tt_global_entry_free_ref (tt_global_entry );
710
744
goto out_remove ;
711
745
}
712
-
713
- batadv_tt_global_add_orig_entry (tt_global_entry , orig_node ,
714
- ttvn );
715
746
} else {
716
747
/* there is already a global entry, use this one. */
717
748
@@ -728,11 +759,9 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv,
728
759
tt_global_entry -> roam_at = 0 ;
729
760
}
730
761
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 );
735
762
}
763
+ /* add the new orig_entry (if needed) */
764
+ batadv_tt_global_orig_entry_add (tt_global_entry , orig_node , ttvn );
736
765
737
766
batadv_dbg (BATADV_DBG_TT , bat_priv ,
738
767
"Creating new global tt entry: %pM (via %pM)\n" ,
0 commit comments