diff options
-rw-r--r-- | include/net/inetpeer.h | 2 | ||||
-rw-r--r-- | net/ipv4/inetpeer.c | 28 | ||||
-rw-r--r-- | net/ipv4/route.c | 2 |
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 { | |||
68 | struct inet_peer_base { | 68 | struct 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); | |||
168 | extern bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout); | 169 | extern bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout); |
169 | 170 | ||
170 | extern void inetpeer_invalidate_tree(struct inet_peer_base *); | 171 | extern void inetpeer_invalidate_tree(struct inet_peer_base *); |
172 | extern 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 | } |
91 | EXPORT_SYMBOL_GPL(inet_peer_base_init); | 92 | EXPORT_SYMBOL_GPL(inet_peer_base_init); |
92 | 93 | ||
94 | static atomic_t v4_seq = ATOMIC_INIT(0); | ||
95 | static atomic_t v6_seq = ATOMIC_INIT(0); | ||
96 | |||
97 | static atomic_t *inetpeer_seq_ptr(int family) | ||
98 | { | ||
99 | return (family == AF_INET ? &v4_seq : &v6_seq); | ||
100 | } | ||
101 | |||
102 | static 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 | |||
112 | void 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 | /* |