aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/inetpeer.h2
-rw-r--r--net/ipv4/inetpeer.c28
-rw-r--r--net/ipv4/route.c2
3 files changed, 31 insertions, 1 deletions
diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h
index d432489e7109..e15c0862a686 100644
--- a/include/net/inetpeer.h
+++ b/include/net/inetpeer.h
@@ -68,6 +68,7 @@ struct inet_peer {
68struct inet_peer_base { 68struct inet_peer_base {
69 struct inet_peer __rcu *root; 69 struct inet_peer __rcu *root;
70 seqlock_t lock; 70 seqlock_t lock;
71 u32 flush_seq;
71 int total; 72 int total;
72}; 73};
73 74
@@ -168,6 +169,7 @@ extern void inet_putpeer(struct inet_peer *p);
168extern bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout); 169extern bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout);
169 170
170extern void inetpeer_invalidate_tree(struct inet_peer_base *); 171extern void inetpeer_invalidate_tree(struct inet_peer_base *);
172extern void inetpeer_invalidate_family(int family);
171 173
172/* 174/*
173 * temporary check to make sure we dont access rid, ip_id_count, tcp_ts, 175 * temporary check to make sure we dont access rid, ip_id_count, tcp_ts,
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index e4cba56a5349..cac02ad1425d 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -86,10 +86,36 @@ void inet_peer_base_init(struct inet_peer_base *bp)
86{ 86{
87 bp->root = peer_avl_empty_rcu; 87 bp->root = peer_avl_empty_rcu;
88 seqlock_init(&bp->lock); 88 seqlock_init(&bp->lock);
89 bp->flush_seq = ~0U;
89 bp->total = 0; 90 bp->total = 0;
90} 91}
91EXPORT_SYMBOL_GPL(inet_peer_base_init); 92EXPORT_SYMBOL_GPL(inet_peer_base_init);
92 93
94static atomic_t v4_seq = ATOMIC_INIT(0);
95static atomic_t v6_seq = ATOMIC_INIT(0);
96
97static atomic_t *inetpeer_seq_ptr(int family)
98{
99 return (family == AF_INET ? &v4_seq : &v6_seq);
100}
101
102static inline void flush_check(struct inet_peer_base *base, int family)
103{
104 atomic_t *fp = inetpeer_seq_ptr(family);
105
106 if (unlikely(base->flush_seq != atomic_read(fp))) {
107 inetpeer_invalidate_tree(base);
108 base->flush_seq = atomic_read(fp);
109 }
110}
111
112void inetpeer_invalidate_family(int family)
113{
114 atomic_t *fp = inetpeer_seq_ptr(family);
115
116 atomic_inc(fp);
117}
118
93#define PEER_MAXDEPTH 40 /* sufficient for about 2^27 nodes */ 119#define PEER_MAXDEPTH 40 /* sufficient for about 2^27 nodes */
94 120
95/* Exported for sysctl_net_ipv4. */ 121/* Exported for sysctl_net_ipv4. */
@@ -437,6 +463,8 @@ struct inet_peer *inet_getpeer(struct inet_peer_base *base,
437 unsigned int sequence; 463 unsigned int sequence;
438 int invalidated, gccnt = 0; 464 int invalidated, gccnt = 0;
439 465
466 flush_check(base, daddr->family);
467
440 /* Attempt a lockless lookup first. 468 /* Attempt a lockless lookup first.
441 * Because of a concurrent writer, we might not find an existing entry. 469 * Because of a concurrent writer, we might not find an existing entry.
442 */ 470 */
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 4f5834c4a667..456a9470fb54 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -935,7 +935,7 @@ static void rt_cache_invalidate(struct net *net)
935 935
936 get_random_bytes(&shuffle, sizeof(shuffle)); 936 get_random_bytes(&shuffle, sizeof(shuffle));
937 atomic_add(shuffle + 1U, &net->ipv4.rt_genid); 937 atomic_add(shuffle + 1U, &net->ipv4.rt_genid);
938 inetpeer_invalidate_tree(net->ipv4.peers); 938 inetpeer_invalidate_family(AF_INET);
939} 939}
940 940
941/* 941/*