diff options
Diffstat (limited to 'net/core/neighbour.c')
-rw-r--r-- | net/core/neighbour.c | 95 |
1 files changed, 46 insertions, 49 deletions
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 163b4f5b0365..e587e6819698 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
@@ -692,75 +692,74 @@ static void neigh_connect(struct neighbour *neigh) | |||
692 | hh->hh_output = neigh->ops->hh_output; | 692 | hh->hh_output = neigh->ops->hh_output; |
693 | } | 693 | } |
694 | 694 | ||
695 | static void neigh_periodic_timer(unsigned long arg) | 695 | static void neigh_periodic_work(struct work_struct *work) |
696 | { | 696 | { |
697 | struct neigh_table *tbl = (struct neigh_table *)arg; | 697 | struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work); |
698 | struct neighbour *n, **np; | 698 | struct neighbour *n, **np; |
699 | unsigned long expire, now = jiffies; | 699 | unsigned int i; |
700 | 700 | ||
701 | NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs); | 701 | NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs); |
702 | 702 | ||
703 | write_lock(&tbl->lock); | 703 | write_lock_bh(&tbl->lock); |
704 | 704 | ||
705 | /* | 705 | /* |
706 | * periodically recompute ReachableTime from random function | 706 | * periodically recompute ReachableTime from random function |
707 | */ | 707 | */ |
708 | 708 | ||
709 | if (time_after(now, tbl->last_rand + 300 * HZ)) { | 709 | if (time_after(jiffies, tbl->last_rand + 300 * HZ)) { |
710 | struct neigh_parms *p; | 710 | struct neigh_parms *p; |
711 | tbl->last_rand = now; | 711 | tbl->last_rand = jiffies; |
712 | for (p = &tbl->parms; p; p = p->next) | 712 | for (p = &tbl->parms; p; p = p->next) |
713 | p->reachable_time = | 713 | p->reachable_time = |
714 | neigh_rand_reach_time(p->base_reachable_time); | 714 | neigh_rand_reach_time(p->base_reachable_time); |
715 | } | 715 | } |
716 | 716 | ||
717 | np = &tbl->hash_buckets[tbl->hash_chain_gc]; | 717 | for (i = 0 ; i <= tbl->hash_mask; i++) { |
718 | tbl->hash_chain_gc = ((tbl->hash_chain_gc + 1) & tbl->hash_mask); | 718 | np = &tbl->hash_buckets[i]; |
719 | 719 | ||
720 | while ((n = *np) != NULL) { | 720 | while ((n = *np) != NULL) { |
721 | unsigned int state; | 721 | unsigned int state; |
722 | 722 | ||
723 | write_lock(&n->lock); | 723 | write_lock(&n->lock); |
724 | 724 | ||
725 | state = n->nud_state; | 725 | state = n->nud_state; |
726 | if (state & (NUD_PERMANENT | NUD_IN_TIMER)) { | 726 | if (state & (NUD_PERMANENT | NUD_IN_TIMER)) { |
727 | write_unlock(&n->lock); | 727 | write_unlock(&n->lock); |
728 | goto next_elt; | 728 | goto next_elt; |
729 | } | 729 | } |
730 | 730 | ||
731 | if (time_before(n->used, n->confirmed)) | 731 | if (time_before(n->used, n->confirmed)) |
732 | n->used = n->confirmed; | 732 | n->used = n->confirmed; |
733 | 733 | ||
734 | if (atomic_read(&n->refcnt) == 1 && | 734 | if (atomic_read(&n->refcnt) == 1 && |
735 | (state == NUD_FAILED || | 735 | (state == NUD_FAILED || |
736 | time_after(now, n->used + n->parms->gc_staletime))) { | 736 | time_after(jiffies, n->used + n->parms->gc_staletime))) { |
737 | *np = n->next; | 737 | *np = n->next; |
738 | n->dead = 1; | 738 | n->dead = 1; |
739 | write_unlock(&n->lock); | ||
740 | neigh_cleanup_and_release(n); | ||
741 | continue; | ||
742 | } | ||
739 | write_unlock(&n->lock); | 743 | write_unlock(&n->lock); |
740 | neigh_cleanup_and_release(n); | ||
741 | continue; | ||
742 | } | ||
743 | write_unlock(&n->lock); | ||
744 | 744 | ||
745 | next_elt: | 745 | next_elt: |
746 | np = &n->next; | 746 | np = &n->next; |
747 | } | ||
748 | /* | ||
749 | * It's fine to release lock here, even if hash table | ||
750 | * grows while we are preempted. | ||
751 | */ | ||
752 | write_unlock_bh(&tbl->lock); | ||
753 | cond_resched(); | ||
754 | write_lock_bh(&tbl->lock); | ||
747 | } | 755 | } |
748 | |||
749 | /* Cycle through all hash buckets every base_reachable_time/2 ticks. | 756 | /* Cycle through all hash buckets every base_reachable_time/2 ticks. |
750 | * ARP entry timeouts range from 1/2 base_reachable_time to 3/2 | 757 | * ARP entry timeouts range from 1/2 base_reachable_time to 3/2 |
751 | * base_reachable_time. | 758 | * base_reachable_time. |
752 | */ | 759 | */ |
753 | expire = tbl->parms.base_reachable_time >> 1; | 760 | schedule_delayed_work(&tbl->gc_work, |
754 | expire /= (tbl->hash_mask + 1); | 761 | tbl->parms.base_reachable_time >> 1); |
755 | if (!expire) | 762 | write_unlock_bh(&tbl->lock); |
756 | expire = 1; | ||
757 | |||
758 | if (expire>HZ) | ||
759 | mod_timer(&tbl->gc_timer, round_jiffies(now + expire)); | ||
760 | else | ||
761 | mod_timer(&tbl->gc_timer, now + expire); | ||
762 | |||
763 | write_unlock(&tbl->lock); | ||
764 | } | 763 | } |
765 | 764 | ||
766 | static __inline__ int neigh_max_probes(struct neighbour *n) | 765 | static __inline__ int neigh_max_probes(struct neighbour *n) |
@@ -1316,7 +1315,7 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, | |||
1316 | } | 1315 | } |
1317 | EXPORT_SYMBOL(pneigh_enqueue); | 1316 | EXPORT_SYMBOL(pneigh_enqueue); |
1318 | 1317 | ||
1319 | static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl, | 1318 | static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl, |
1320 | struct net *net, int ifindex) | 1319 | struct net *net, int ifindex) |
1321 | { | 1320 | { |
1322 | struct neigh_parms *p; | 1321 | struct neigh_parms *p; |
@@ -1337,7 +1336,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, | |||
1337 | struct net *net = dev_net(dev); | 1336 | struct net *net = dev_net(dev); |
1338 | const struct net_device_ops *ops = dev->netdev_ops; | 1337 | const struct net_device_ops *ops = dev->netdev_ops; |
1339 | 1338 | ||
1340 | ref = lookup_neigh_params(tbl, net, 0); | 1339 | ref = lookup_neigh_parms(tbl, net, 0); |
1341 | if (!ref) | 1340 | if (!ref) |
1342 | return NULL; | 1341 | return NULL; |
1343 | 1342 | ||
@@ -1442,10 +1441,8 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl) | |||
1442 | get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd)); | 1441 | get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd)); |
1443 | 1442 | ||
1444 | rwlock_init(&tbl->lock); | 1443 | rwlock_init(&tbl->lock); |
1445 | setup_timer(&tbl->gc_timer, neigh_periodic_timer, (unsigned long)tbl); | 1444 | INIT_DELAYED_WORK_DEFERRABLE(&tbl->gc_work, neigh_periodic_work); |
1446 | tbl->gc_timer.expires = now + 1; | 1445 | schedule_delayed_work(&tbl->gc_work, tbl->parms.reachable_time); |
1447 | add_timer(&tbl->gc_timer); | ||
1448 | |||
1449 | setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl); | 1446 | setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl); |
1450 | skb_queue_head_init_class(&tbl->proxy_queue, | 1447 | skb_queue_head_init_class(&tbl->proxy_queue, |
1451 | &neigh_table_proxy_queue_class); | 1448 | &neigh_table_proxy_queue_class); |
@@ -1482,7 +1479,8 @@ int neigh_table_clear(struct neigh_table *tbl) | |||
1482 | struct neigh_table **tp; | 1479 | struct neigh_table **tp; |
1483 | 1480 | ||
1484 | /* It is not clean... Fix it to unload IPv6 module safely */ | 1481 | /* It is not clean... Fix it to unload IPv6 module safely */ |
1485 | del_timer_sync(&tbl->gc_timer); | 1482 | cancel_delayed_work(&tbl->gc_work); |
1483 | flush_scheduled_work(); | ||
1486 | del_timer_sync(&tbl->proxy_timer); | 1484 | del_timer_sync(&tbl->proxy_timer); |
1487 | pneigh_queue_purge(&tbl->proxy_queue); | 1485 | pneigh_queue_purge(&tbl->proxy_queue); |
1488 | neigh_ifdown(tbl, NULL); | 1486 | neigh_ifdown(tbl, NULL); |
@@ -1752,7 +1750,6 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl, | |||
1752 | .ndtc_last_rand = jiffies_to_msecs(rand_delta), | 1750 | .ndtc_last_rand = jiffies_to_msecs(rand_delta), |
1753 | .ndtc_hash_rnd = tbl->hash_rnd, | 1751 | .ndtc_hash_rnd = tbl->hash_rnd, |
1754 | .ndtc_hash_mask = tbl->hash_mask, | 1752 | .ndtc_hash_mask = tbl->hash_mask, |
1755 | .ndtc_hash_chain_gc = tbl->hash_chain_gc, | ||
1756 | .ndtc_proxy_qlen = tbl->proxy_queue.qlen, | 1753 | .ndtc_proxy_qlen = tbl->proxy_queue.qlen, |
1757 | }; | 1754 | }; |
1758 | 1755 | ||
@@ -1906,7 +1903,7 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
1906 | if (tbp[NDTPA_IFINDEX]) | 1903 | if (tbp[NDTPA_IFINDEX]) |
1907 | ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]); | 1904 | ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]); |
1908 | 1905 | ||
1909 | p = lookup_neigh_params(tbl, net, ifindex); | 1906 | p = lookup_neigh_parms(tbl, net, ifindex); |
1910 | if (p == NULL) { | 1907 | if (p == NULL) { |
1911 | err = -ENOENT; | 1908 | err = -ENOENT; |
1912 | goto errout_tbl_lock; | 1909 | goto errout_tbl_lock; |