aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2012-03-12 15:44:07 -0400
committerIngo Molnar <mingo@elte.hu>2012-03-12 15:44:11 -0400
commit35239e23c66f1614c76739b62a299c3c92d6eb68 (patch)
tree7b1e068df888ec9a00b43c1dd7517a6490da6a94 /net/ipv4
parent3f33ab1c0c741bfab2138c14ba1918a7905a1e8b (diff)
parent87e24f4b67e68d9fd8df16e0bf9c66d1ad2a2533 (diff)
Merge branch 'perf/urgent' into perf/core
Merge reason: We are going to queue up a dependent patch. Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/inetpeer.c81
-rw-r--r--net/ipv4/route.c12
-rw-r--r--net/ipv4/tcp_input.c23
3 files changed, 97 insertions, 19 deletions
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index bf4a9c4808e1..d4d61b694fab 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -17,6 +17,7 @@
17#include <linux/kernel.h> 17#include <linux/kernel.h>
18#include <linux/mm.h> 18#include <linux/mm.h>
19#include <linux/net.h> 19#include <linux/net.h>
20#include <linux/workqueue.h>
20#include <net/ip.h> 21#include <net/ip.h>
21#include <net/inetpeer.h> 22#include <net/inetpeer.h>
22#include <net/secure_seq.h> 23#include <net/secure_seq.h>
@@ -66,6 +67,11 @@
66 67
67static struct kmem_cache *peer_cachep __read_mostly; 68static struct kmem_cache *peer_cachep __read_mostly;
68 69
70static LIST_HEAD(gc_list);
71static const int gc_delay = 60 * HZ;
72static struct delayed_work gc_work;
73static DEFINE_SPINLOCK(gc_lock);
74
69#define node_height(x) x->avl_height 75#define node_height(x) x->avl_height
70 76
71#define peer_avl_empty ((struct inet_peer *)&peer_fake_node) 77#define peer_avl_empty ((struct inet_peer *)&peer_fake_node)
@@ -102,6 +108,50 @@ int inet_peer_threshold __read_mostly = 65536 + 128; /* start to throw entries m
102int inet_peer_minttl __read_mostly = 120 * HZ; /* TTL under high load: 120 sec */ 108int inet_peer_minttl __read_mostly = 120 * HZ; /* TTL under high load: 120 sec */
103int inet_peer_maxttl __read_mostly = 10 * 60 * HZ; /* usual time to live: 10 min */ 109int inet_peer_maxttl __read_mostly = 10 * 60 * HZ; /* usual time to live: 10 min */
104 110
111static void inetpeer_gc_worker(struct work_struct *work)
112{
113 struct inet_peer *p, *n;
114 LIST_HEAD(list);
115
116 spin_lock_bh(&gc_lock);
117 list_replace_init(&gc_list, &list);
118 spin_unlock_bh(&gc_lock);
119
120 if (list_empty(&list))
121 return;
122
123 list_for_each_entry_safe(p, n, &list, gc_list) {
124
125 if(need_resched())
126 cond_resched();
127
128 if (p->avl_left != peer_avl_empty) {
129 list_add_tail(&p->avl_left->gc_list, &list);
130 p->avl_left = peer_avl_empty;
131 }
132
133 if (p->avl_right != peer_avl_empty) {
134 list_add_tail(&p->avl_right->gc_list, &list);
135 p->avl_right = peer_avl_empty;
136 }
137
138 n = list_entry(p->gc_list.next, struct inet_peer, gc_list);
139
140 if (!atomic_read(&p->refcnt)) {
141 list_del(&p->gc_list);
142 kmem_cache_free(peer_cachep, p);
143 }
144 }
145
146 if (list_empty(&list))
147 return;
148
149 spin_lock_bh(&gc_lock);
150 list_splice(&list, &gc_list);
151 spin_unlock_bh(&gc_lock);
152
153 schedule_delayed_work(&gc_work, gc_delay);
154}
105 155
106/* Called from ip_output.c:ip_init */ 156/* Called from ip_output.c:ip_init */
107void __init inet_initpeers(void) 157void __init inet_initpeers(void)
@@ -126,6 +176,7 @@ void __init inet_initpeers(void)
126 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, 176 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC,
127 NULL); 177 NULL);
128 178
179 INIT_DELAYED_WORK_DEFERRABLE(&gc_work, inetpeer_gc_worker);
129} 180}
130 181
131static int addr_compare(const struct inetpeer_addr *a, 182static int addr_compare(const struct inetpeer_addr *a,
@@ -447,9 +498,8 @@ relookup:
447 p->rate_last = 0; 498 p->rate_last = 0;
448 p->pmtu_expires = 0; 499 p->pmtu_expires = 0;
449 p->pmtu_orig = 0; 500 p->pmtu_orig = 0;
450 p->redirect_genid = 0;
451 memset(&p->redirect_learned, 0, sizeof(p->redirect_learned)); 501 memset(&p->redirect_learned, 0, sizeof(p->redirect_learned));
452 502 INIT_LIST_HEAD(&p->gc_list);
453 503
454 /* Link the node. */ 504 /* Link the node. */
455 link_to_pool(p, base); 505 link_to_pool(p, base);
@@ -509,3 +559,30 @@ bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout)
509 return rc; 559 return rc;
510} 560}
511EXPORT_SYMBOL(inet_peer_xrlim_allow); 561EXPORT_SYMBOL(inet_peer_xrlim_allow);
562
563void inetpeer_invalidate_tree(int family)
564{
565 struct inet_peer *old, *new, *prev;
566 struct inet_peer_base *base = family_to_base(family);
567
568 write_seqlock_bh(&base->lock);
569
570 old = base->root;
571 if (old == peer_avl_empty_rcu)
572 goto out;
573
574 new = peer_avl_empty_rcu;
575
576 prev = cmpxchg(&base->root, old, new);
577 if (prev == old) {
578 base->total = 0;
579 spin_lock(&gc_lock);
580 list_add_tail(&prev->gc_list, &gc_list);
581 spin_unlock(&gc_lock);
582 schedule_delayed_work(&gc_work, gc_delay);
583 }
584
585out:
586 write_sequnlock_bh(&base->lock);
587}
588EXPORT_SYMBOL(inetpeer_invalidate_tree);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index bcacf54e5418..019774796174 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -132,7 +132,6 @@ static int ip_rt_mtu_expires __read_mostly = 10 * 60 * HZ;
132static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; 132static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20;
133static int ip_rt_min_advmss __read_mostly = 256; 133static int ip_rt_min_advmss __read_mostly = 256;
134static int rt_chain_length_max __read_mostly = 20; 134static int rt_chain_length_max __read_mostly = 20;
135static int redirect_genid;
136 135
137static struct delayed_work expires_work; 136static struct delayed_work expires_work;
138static unsigned long expires_ljiffies; 137static unsigned long expires_ljiffies;
@@ -937,7 +936,7 @@ static void rt_cache_invalidate(struct net *net)
937 936
938 get_random_bytes(&shuffle, sizeof(shuffle)); 937 get_random_bytes(&shuffle, sizeof(shuffle));
939 atomic_add(shuffle + 1U, &net->ipv4.rt_genid); 938 atomic_add(shuffle + 1U, &net->ipv4.rt_genid);
940 redirect_genid++; 939 inetpeer_invalidate_tree(AF_INET);
941} 940}
942 941
943/* 942/*
@@ -1485,10 +1484,8 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
1485 1484
1486 peer = rt->peer; 1485 peer = rt->peer;
1487 if (peer) { 1486 if (peer) {
1488 if (peer->redirect_learned.a4 != new_gw || 1487 if (peer->redirect_learned.a4 != new_gw) {
1489 peer->redirect_genid != redirect_genid) {
1490 peer->redirect_learned.a4 = new_gw; 1488 peer->redirect_learned.a4 = new_gw;
1491 peer->redirect_genid = redirect_genid;
1492 atomic_inc(&__rt_peer_genid); 1489 atomic_inc(&__rt_peer_genid);
1493 } 1490 }
1494 check_peer_redir(&rt->dst, peer); 1491 check_peer_redir(&rt->dst, peer);
@@ -1793,8 +1790,6 @@ static void ipv4_validate_peer(struct rtable *rt)
1793 if (peer) { 1790 if (peer) {
1794 check_peer_pmtu(&rt->dst, peer); 1791 check_peer_pmtu(&rt->dst, peer);
1795 1792
1796 if (peer->redirect_genid != redirect_genid)
1797 peer->redirect_learned.a4 = 0;
1798 if (peer->redirect_learned.a4 && 1793 if (peer->redirect_learned.a4 &&
1799 peer->redirect_learned.a4 != rt->rt_gateway) 1794 peer->redirect_learned.a4 != rt->rt_gateway)
1800 check_peer_redir(&rt->dst, peer); 1795 check_peer_redir(&rt->dst, peer);
@@ -1958,8 +1953,7 @@ static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4,
1958 dst_init_metrics(&rt->dst, peer->metrics, false); 1953 dst_init_metrics(&rt->dst, peer->metrics, false);
1959 1954
1960 check_peer_pmtu(&rt->dst, peer); 1955 check_peer_pmtu(&rt->dst, peer);
1961 if (peer->redirect_genid != redirect_genid) 1956
1962 peer->redirect_learned.a4 = 0;
1963 if (peer->redirect_learned.a4 && 1957 if (peer->redirect_learned.a4 &&
1964 peer->redirect_learned.a4 != rt->rt_gateway) { 1958 peer->redirect_learned.a4 != rt->rt_gateway) {
1965 rt->rt_gateway = peer->redirect_learned.a4; 1959 rt->rt_gateway = peer->redirect_learned.a4;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 53c8ce4046b2..b5e315f13641 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1403,8 +1403,16 @@ static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
1403 1403
1404 BUG_ON(!pcount); 1404 BUG_ON(!pcount);
1405 1405
1406 /* Adjust hint for FACK. Non-FACK is handled in tcp_sacktag_one(). */ 1406 /* Adjust counters and hints for the newly sacked sequence
1407 if (tcp_is_fack(tp) && (skb == tp->lost_skb_hint)) 1407 * range but discard the return value since prev is already
1408 * marked. We must tag the range first because the seq
1409 * advancement below implicitly advances
1410 * tcp_highest_sack_seq() when skb is highest_sack.
1411 */
1412 tcp_sacktag_one(sk, state, TCP_SKB_CB(skb)->sacked,
1413 start_seq, end_seq, dup_sack, pcount);
1414
1415 if (skb == tp->lost_skb_hint)
1408 tp->lost_cnt_hint += pcount; 1416 tp->lost_cnt_hint += pcount;
1409 1417
1410 TCP_SKB_CB(prev)->end_seq += shifted; 1418 TCP_SKB_CB(prev)->end_seq += shifted;
@@ -1430,12 +1438,6 @@ static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
1430 skb_shinfo(skb)->gso_type = 0; 1438 skb_shinfo(skb)->gso_type = 0;
1431 } 1439 }
1432 1440
1433 /* Adjust counters and hints for the newly sacked sequence range but
1434 * discard the return value since prev is already marked.
1435 */
1436 tcp_sacktag_one(sk, state, TCP_SKB_CB(skb)->sacked,
1437 start_seq, end_seq, dup_sack, pcount);
1438
1439 /* Difference in this won't matter, both ACKed by the same cumul. ACK */ 1441 /* Difference in this won't matter, both ACKed by the same cumul. ACK */
1440 TCP_SKB_CB(prev)->sacked |= (TCP_SKB_CB(skb)->sacked & TCPCB_EVER_RETRANS); 1442 TCP_SKB_CB(prev)->sacked |= (TCP_SKB_CB(skb)->sacked & TCPCB_EVER_RETRANS);
1441 1443
@@ -1583,6 +1585,10 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb,
1583 } 1585 }
1584 } 1586 }
1585 1587
1588 /* tcp_sacktag_one() won't SACK-tag ranges below snd_una */
1589 if (!after(TCP_SKB_CB(skb)->seq + len, tp->snd_una))
1590 goto fallback;
1591
1586 if (!skb_shift(prev, skb, len)) 1592 if (!skb_shift(prev, skb, len))
1587 goto fallback; 1593 goto fallback;
1588 if (!tcp_shifted_skb(sk, skb, state, pcount, len, mss, dup_sack)) 1594 if (!tcp_shifted_skb(sk, skb, state, pcount, len, mss, dup_sack))
@@ -2567,6 +2573,7 @@ static void tcp_mark_head_lost(struct sock *sk, int packets, int mark_head)
2567 2573
2568 if (cnt > packets) { 2574 if (cnt > packets) {
2569 if ((tcp_is_sack(tp) && !tcp_is_fack(tp)) || 2575 if ((tcp_is_sack(tp) && !tcp_is_fack(tp)) ||
2576 (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED) ||
2570 (oldcnt >= packets)) 2577 (oldcnt >= packets))
2571 break; 2578 break;
2572 2579