@@ -587,13 +587,16 @@ static void check_lifetime(struct work_struct *work)
587
587
{
588
588
unsigned long now , next , next_sec , next_sched ;
589
589
struct in_ifaddr * ifa ;
590
+ struct hlist_node * n ;
590
591
int i ;
591
592
592
593
now = jiffies ;
593
594
next = round_jiffies_up (now + ADDR_CHECK_FREQUENCY );
594
595
595
- rcu_read_lock ();
596
596
for (i = 0 ; i < IN4_ADDR_HSIZE ; i ++ ) {
597
+ bool change_needed = false;
598
+
599
+ rcu_read_lock ();
597
600
hlist_for_each_entry_rcu (ifa , & inet_addr_lst [i ], hash ) {
598
601
unsigned long age ;
599
602
@@ -606,16 +609,7 @@ static void check_lifetime(struct work_struct *work)
606
609
607
610
if (ifa -> ifa_valid_lft != INFINITY_LIFE_TIME &&
608
611
age >= ifa -> ifa_valid_lft ) {
609
- struct in_ifaddr * * ifap ;
610
-
611
- rtnl_lock ();
612
- for (ifap = & ifa -> ifa_dev -> ifa_list ;
613
- * ifap != NULL ; ifap = & ifa -> ifa_next ) {
614
- if (* ifap == ifa )
615
- inet_del_ifa (ifa -> ifa_dev ,
616
- ifap , 1 );
617
- }
618
- rtnl_unlock ();
612
+ change_needed = true;
619
613
} else if (ifa -> ifa_preferred_lft ==
620
614
INFINITY_LIFE_TIME ) {
621
615
continue ;
@@ -625,19 +619,51 @@ static void check_lifetime(struct work_struct *work)
625
619
next = ifa -> ifa_tstamp +
626
620
ifa -> ifa_valid_lft * HZ ;
627
621
628
- if (!(ifa -> ifa_flags & IFA_F_DEPRECATED )) {
629
- ifa -> ifa_flags |= IFA_F_DEPRECATED ;
630
- rtmsg_ifa (RTM_NEWADDR , ifa , NULL , 0 );
631
- }
622
+ if (!(ifa -> ifa_flags & IFA_F_DEPRECATED ))
623
+ change_needed = true;
632
624
} else if (time_before (ifa -> ifa_tstamp +
633
625
ifa -> ifa_preferred_lft * HZ ,
634
626
next )) {
635
627
next = ifa -> ifa_tstamp +
636
628
ifa -> ifa_preferred_lft * HZ ;
637
629
}
638
630
}
631
+ rcu_read_unlock ();
632
+ if (!change_needed )
633
+ continue ;
634
+ rtnl_lock ();
635
+ hlist_for_each_entry_safe (ifa , n , & inet_addr_lst [i ], hash ) {
636
+ unsigned long age ;
637
+
638
+ if (ifa -> ifa_flags & IFA_F_PERMANENT )
639
+ continue ;
640
+
641
+ /* We try to batch several events at once. */
642
+ age = (now - ifa -> ifa_tstamp +
643
+ ADDRCONF_TIMER_FUZZ_MINUS ) / HZ ;
644
+
645
+ if (ifa -> ifa_valid_lft != INFINITY_LIFE_TIME &&
646
+ age >= ifa -> ifa_valid_lft ) {
647
+ struct in_ifaddr * * ifap ;
648
+
649
+ for (ifap = & ifa -> ifa_dev -> ifa_list ;
650
+ * ifap != NULL ; ifap = & (* ifap )-> ifa_next ) {
651
+ if (* ifap == ifa ) {
652
+ inet_del_ifa (ifa -> ifa_dev ,
653
+ ifap , 1 );
654
+ break ;
655
+ }
656
+ }
657
+ } else if (ifa -> ifa_preferred_lft !=
658
+ INFINITY_LIFE_TIME &&
659
+ age >= ifa -> ifa_preferred_lft &&
660
+ !(ifa -> ifa_flags & IFA_F_DEPRECATED )) {
661
+ ifa -> ifa_flags |= IFA_F_DEPRECATED ;
662
+ rtmsg_ifa (RTM_NEWADDR , ifa , NULL , 0 );
663
+ }
664
+ }
665
+ rtnl_unlock ();
639
666
}
640
- rcu_read_unlock ();
641
667
642
668
next_sec = round_jiffies_up (next );
643
669
next_sched = next ;
0 commit comments