diff options
| -rw-r--r-- | net/ipv4/devinet.c | 58 |
1 files changed, 42 insertions, 16 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 00386e02e708..c6287cd978c2 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
| @@ -587,13 +587,16 @@ static void check_lifetime(struct work_struct *work) | |||
| 587 | { | 587 | { |
| 588 | unsigned long now, next, next_sec, next_sched; | 588 | unsigned long now, next, next_sec, next_sched; |
| 589 | struct in_ifaddr *ifa; | 589 | struct in_ifaddr *ifa; |
| 590 | struct hlist_node *n; | ||
| 590 | int i; | 591 | int i; |
| 591 | 592 | ||
| 592 | now = jiffies; | 593 | now = jiffies; |
| 593 | next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY); | 594 | next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY); |
| 594 | 595 | ||
| 595 | rcu_read_lock(); | ||
| 596 | for (i = 0; i < IN4_ADDR_HSIZE; i++) { | 596 | for (i = 0; i < IN4_ADDR_HSIZE; i++) { |
| 597 | bool change_needed = false; | ||
| 598 | |||
| 599 | rcu_read_lock(); | ||
| 597 | hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) { | 600 | hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) { |
| 598 | unsigned long age; | 601 | unsigned long age; |
| 599 | 602 | ||
| @@ -606,16 +609,7 @@ static void check_lifetime(struct work_struct *work) | |||
| 606 | 609 | ||
| 607 | if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME && | 610 | if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME && |
| 608 | age >= ifa->ifa_valid_lft) { | 611 | age >= ifa->ifa_valid_lft) { |
| 609 | struct in_ifaddr **ifap ; | 612 | change_needed = true; |
| 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(); | ||
| 619 | } else if (ifa->ifa_preferred_lft == | 613 | } else if (ifa->ifa_preferred_lft == |
| 620 | INFINITY_LIFE_TIME) { | 614 | INFINITY_LIFE_TIME) { |
| 621 | continue; | 615 | continue; |
| @@ -625,10 +619,8 @@ static void check_lifetime(struct work_struct *work) | |||
| 625 | next = ifa->ifa_tstamp + | 619 | next = ifa->ifa_tstamp + |
| 626 | ifa->ifa_valid_lft * HZ; | 620 | ifa->ifa_valid_lft * HZ; |
| 627 | 621 | ||
| 628 | if (!(ifa->ifa_flags & IFA_F_DEPRECATED)) { | 622 | if (!(ifa->ifa_flags & IFA_F_DEPRECATED)) |
| 629 | ifa->ifa_flags |= IFA_F_DEPRECATED; | 623 | change_needed = true; |
| 630 | rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0); | ||
| 631 | } | ||
| 632 | } else if (time_before(ifa->ifa_tstamp + | 624 | } else if (time_before(ifa->ifa_tstamp + |
| 633 | ifa->ifa_preferred_lft * HZ, | 625 | ifa->ifa_preferred_lft * HZ, |
| 634 | next)) { | 626 | next)) { |
| @@ -636,8 +628,42 @@ static void check_lifetime(struct work_struct *work) | |||
| 636 | ifa->ifa_preferred_lft * HZ; | 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 | next_sec = round_jiffies_up(next); | 668 | next_sec = round_jiffies_up(next); |
| 643 | next_sched = next; | 669 | next_sched = next; |
