diff options
author | David S. Miller <davem@davemloft.net> | 2011-12-23 17:13:56 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-12-23 17:13:56 -0500 |
commit | abb434cb0539fb355c1c921f8fd761efbbac3462 (patch) | |
tree | 24a7d99ec161f8fd4dc9ff03c9c4cc93be883ce6 /net/ipv4/route.c | |
parent | 2494654d4890316e7340fb8b3458daad0474a1b9 (diff) | |
parent | 6350323ad8def2ac00d77cdee3b79c9b9fba75c4 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Conflicts:
net/bluetooth/l2cap_core.c
Just two overlapping changes, one added an initialization of
a local variable, and another change added a new local variable.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r-- | net/ipv4/route.c | 112 |
1 files changed, 110 insertions, 2 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index f30112f7559a..bcacf54e5418 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -91,6 +91,7 @@ | |||
91 | #include <linux/rcupdate.h> | 91 | #include <linux/rcupdate.h> |
92 | #include <linux/times.h> | 92 | #include <linux/times.h> |
93 | #include <linux/slab.h> | 93 | #include <linux/slab.h> |
94 | #include <linux/prefetch.h> | ||
94 | #include <net/dst.h> | 95 | #include <net/dst.h> |
95 | #include <net/net_namespace.h> | 96 | #include <net/net_namespace.h> |
96 | #include <net/protocol.h> | 97 | #include <net/protocol.h> |
@@ -119,6 +120,7 @@ | |||
119 | 120 | ||
120 | static int ip_rt_max_size; | 121 | static int ip_rt_max_size; |
121 | static int ip_rt_gc_timeout __read_mostly = RT_GC_TIMEOUT; | 122 | static int ip_rt_gc_timeout __read_mostly = RT_GC_TIMEOUT; |
123 | static int ip_rt_gc_interval __read_mostly = 60 * HZ; | ||
122 | static int ip_rt_gc_min_interval __read_mostly = HZ / 2; | 124 | static int ip_rt_gc_min_interval __read_mostly = HZ / 2; |
123 | static int ip_rt_redirect_number __read_mostly = 9; | 125 | static int ip_rt_redirect_number __read_mostly = 9; |
124 | static int ip_rt_redirect_load __read_mostly = HZ / 50; | 126 | static int ip_rt_redirect_load __read_mostly = HZ / 50; |
@@ -132,6 +134,9 @@ static int ip_rt_min_advmss __read_mostly = 256; | |||
132 | static int rt_chain_length_max __read_mostly = 20; | 134 | static int rt_chain_length_max __read_mostly = 20; |
133 | static int redirect_genid; | 135 | static int redirect_genid; |
134 | 136 | ||
137 | static struct delayed_work expires_work; | ||
138 | static unsigned long expires_ljiffies; | ||
139 | |||
135 | /* | 140 | /* |
136 | * Interface to generic destination cache. | 141 | * Interface to generic destination cache. |
137 | */ | 142 | */ |
@@ -829,6 +834,97 @@ static int has_noalias(const struct rtable *head, const struct rtable *rth) | |||
829 | return ONE; | 834 | return ONE; |
830 | } | 835 | } |
831 | 836 | ||
837 | static void rt_check_expire(void) | ||
838 | { | ||
839 | static unsigned int rover; | ||
840 | unsigned int i = rover, goal; | ||
841 | struct rtable *rth; | ||
842 | struct rtable __rcu **rthp; | ||
843 | unsigned long samples = 0; | ||
844 | unsigned long sum = 0, sum2 = 0; | ||
845 | unsigned long delta; | ||
846 | u64 mult; | ||
847 | |||
848 | delta = jiffies - expires_ljiffies; | ||
849 | expires_ljiffies = jiffies; | ||
850 | mult = ((u64)delta) << rt_hash_log; | ||
851 | if (ip_rt_gc_timeout > 1) | ||
852 | do_div(mult, ip_rt_gc_timeout); | ||
853 | goal = (unsigned int)mult; | ||
854 | if (goal > rt_hash_mask) | ||
855 | goal = rt_hash_mask + 1; | ||
856 | for (; goal > 0; goal--) { | ||
857 | unsigned long tmo = ip_rt_gc_timeout; | ||
858 | unsigned long length; | ||
859 | |||
860 | i = (i + 1) & rt_hash_mask; | ||
861 | rthp = &rt_hash_table[i].chain; | ||
862 | |||
863 | if (need_resched()) | ||
864 | cond_resched(); | ||
865 | |||
866 | samples++; | ||
867 | |||
868 | if (rcu_dereference_raw(*rthp) == NULL) | ||
869 | continue; | ||
870 | length = 0; | ||
871 | spin_lock_bh(rt_hash_lock_addr(i)); | ||
872 | while ((rth = rcu_dereference_protected(*rthp, | ||
873 | lockdep_is_held(rt_hash_lock_addr(i)))) != NULL) { | ||
874 | prefetch(rth->dst.rt_next); | ||
875 | if (rt_is_expired(rth)) { | ||
876 | *rthp = rth->dst.rt_next; | ||
877 | rt_free(rth); | ||
878 | continue; | ||
879 | } | ||
880 | if (rth->dst.expires) { | ||
881 | /* Entry is expired even if it is in use */ | ||
882 | if (time_before_eq(jiffies, rth->dst.expires)) { | ||
883 | nofree: | ||
884 | tmo >>= 1; | ||
885 | rthp = &rth->dst.rt_next; | ||
886 | /* | ||
887 | * We only count entries on | ||
888 | * a chain with equal hash inputs once | ||
889 | * so that entries for different QOS | ||
890 | * levels, and other non-hash input | ||
891 | * attributes don't unfairly skew | ||
892 | * the length computation | ||
893 | */ | ||
894 | length += has_noalias(rt_hash_table[i].chain, rth); | ||
895 | continue; | ||
896 | } | ||
897 | } else if (!rt_may_expire(rth, tmo, ip_rt_gc_timeout)) | ||
898 | goto nofree; | ||
899 | |||
900 | /* Cleanup aged off entries. */ | ||
901 | *rthp = rth->dst.rt_next; | ||
902 | rt_free(rth); | ||
903 | } | ||
904 | spin_unlock_bh(rt_hash_lock_addr(i)); | ||
905 | sum += length; | ||
906 | sum2 += length*length; | ||
907 | } | ||
908 | if (samples) { | ||
909 | unsigned long avg = sum / samples; | ||
910 | unsigned long sd = int_sqrt(sum2 / samples - avg*avg); | ||
911 | rt_chain_length_max = max_t(unsigned long, | ||
912 | ip_rt_gc_elasticity, | ||
913 | (avg + 4*sd) >> FRACT_BITS); | ||
914 | } | ||
915 | rover = i; | ||
916 | } | ||
917 | |||
918 | /* | ||
919 | * rt_worker_func() is run in process context. | ||
920 | * we call rt_check_expire() to scan part of the hash table | ||
921 | */ | ||
922 | static void rt_worker_func(struct work_struct *work) | ||
923 | { | ||
924 | rt_check_expire(); | ||
925 | schedule_delayed_work(&expires_work, ip_rt_gc_interval); | ||
926 | } | ||
927 | |||
832 | /* | 928 | /* |
833 | * Perturbation of rt_genid by a small quantity [1..256] | 929 | * Perturbation of rt_genid by a small quantity [1..256] |
834 | * Using 8 bits of shuffling ensure we can call rt_cache_invalidate() | 930 | * Using 8 bits of shuffling ensure we can call rt_cache_invalidate() |
@@ -1265,7 +1361,7 @@ void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more) | |||
1265 | { | 1361 | { |
1266 | struct rtable *rt = (struct rtable *) dst; | 1362 | struct rtable *rt = (struct rtable *) dst; |
1267 | 1363 | ||
1268 | if (rt) { | 1364 | if (rt && !(rt->dst.flags & DST_NOPEER)) { |
1269 | if (rt->peer == NULL) | 1365 | if (rt->peer == NULL) |
1270 | rt_bind_peer(rt, rt->rt_dst, 1); | 1366 | rt_bind_peer(rt, rt->rt_dst, 1); |
1271 | 1367 | ||
@@ -1276,7 +1372,7 @@ void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more) | |||
1276 | iph->id = htons(inet_getid(rt->peer, more)); | 1372 | iph->id = htons(inet_getid(rt->peer, more)); |
1277 | return; | 1373 | return; |
1278 | } | 1374 | } |
1279 | } else | 1375 | } else if (!rt) |
1280 | printk(KERN_DEBUG "rt_bind_peer(0) @%p\n", | 1376 | printk(KERN_DEBUG "rt_bind_peer(0) @%p\n", |
1281 | __builtin_return_address(0)); | 1377 | __builtin_return_address(0)); |
1282 | 1378 | ||
@@ -3173,6 +3269,13 @@ static ctl_table ipv4_route_table[] = { | |||
3173 | .proc_handler = proc_dointvec_jiffies, | 3269 | .proc_handler = proc_dointvec_jiffies, |
3174 | }, | 3270 | }, |
3175 | { | 3271 | { |
3272 | .procname = "gc_interval", | ||
3273 | .data = &ip_rt_gc_interval, | ||
3274 | .maxlen = sizeof(int), | ||
3275 | .mode = 0644, | ||
3276 | .proc_handler = proc_dointvec_jiffies, | ||
3277 | }, | ||
3278 | { | ||
3176 | .procname = "redirect_load", | 3279 | .procname = "redirect_load", |
3177 | .data = &ip_rt_redirect_load, | 3280 | .data = &ip_rt_redirect_load, |
3178 | .maxlen = sizeof(int), | 3281 | .maxlen = sizeof(int), |
@@ -3382,6 +3485,11 @@ int __init ip_rt_init(void) | |||
3382 | devinet_init(); | 3485 | devinet_init(); |
3383 | ip_fib_init(); | 3486 | ip_fib_init(); |
3384 | 3487 | ||
3488 | INIT_DELAYED_WORK_DEFERRABLE(&expires_work, rt_worker_func); | ||
3489 | expires_ljiffies = jiffies; | ||
3490 | schedule_delayed_work(&expires_work, | ||
3491 | net_random() % ip_rt_gc_interval + ip_rt_gc_interval); | ||
3492 | |||
3385 | if (ip_rt_proc_init()) | 3493 | if (ip_rt_proc_init()) |
3386 | printk(KERN_ERR "Unable to create route proc files\n"); | 3494 | printk(KERN_ERR "Unable to create route proc files\n"); |
3387 | #ifdef CONFIG_XFRM | 3495 | #ifdef CONFIG_XFRM |