From 7d9401728ada53ff014a8a266f9dcc98707bc228 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 5 Jun 2012 03:00:18 +0000 Subject: [PATCH] --- yaml --- r: 310719 b: refs/heads/master c: 55432d2b543a4b6dfae54f5c432a566877a85d90 h: refs/heads/master i: 310717: c07472ee626f4f21c660420c8c4674509be58f8e 310715: 719256c7f4b183aa201a8acb55c954034b226754 310711: 087a5a9e4ba6c6a17eab59b48c7649541089a028 310703: ac084b17f48336045871a797033c67b6d82876bf 310687: 2267e6e36cfb96475ac3fc807cc6e0efe24fba7b 310655: 7d3a195024652bf2f6e3c2e35a860efd912f8be3 v: v3 --- [refs] | 2 +- trunk/include/net/inetpeer.h | 5 ++++- trunk/net/ipv4/inetpeer.c | 16 ++++++++++++---- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/[refs] b/[refs] index a0a8a1d16c0a..e29365db1eb6 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: dd03cff23d694cfb0fdae80cb618e7ced05ea696 +refs/heads/master: 55432d2b543a4b6dfae54f5c432a566877a85d90 diff --git a/trunk/include/net/inetpeer.h b/trunk/include/net/inetpeer.h index b94765e38e80..2040bff945d4 100644 --- a/trunk/include/net/inetpeer.h +++ b/trunk/include/net/inetpeer.h @@ -40,7 +40,10 @@ struct inet_peer { u32 pmtu_orig; u32 pmtu_learned; struct inetpeer_addr_base redirect_learned; - struct list_head gc_list; + union { + struct list_head gc_list; + struct rcu_head gc_rcu; + }; /* * Once inet_peer is queued for deletion (refcnt == -1), following fields * are not available: rid, ip_id_count, tcp_ts, tcp_ts_stamp diff --git a/trunk/net/ipv4/inetpeer.c b/trunk/net/ipv4/inetpeer.c index d4d61b694fab..dfba343b2509 100644 --- a/trunk/net/ipv4/inetpeer.c +++ b/trunk/net/ipv4/inetpeer.c @@ -560,6 +560,17 @@ bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout) } EXPORT_SYMBOL(inet_peer_xrlim_allow); +static void inetpeer_inval_rcu(struct rcu_head *head) +{ + struct inet_peer *p = container_of(head, struct inet_peer, gc_rcu); + + spin_lock_bh(&gc_lock); + list_add_tail(&p->gc_list, &gc_list); + spin_unlock_bh(&gc_lock); + + schedule_delayed_work(&gc_work, gc_delay); +} + void inetpeer_invalidate_tree(int family) { struct inet_peer *old, *new, *prev; @@ -576,10 +587,7 @@ void inetpeer_invalidate_tree(int family) prev = cmpxchg(&base->root, old, new); if (prev == old) { base->total = 0; - spin_lock(&gc_lock); - list_add_tail(&prev->gc_list, &gc_list); - spin_unlock(&gc_lock); - schedule_delayed_work(&gc_work, gc_delay); + call_rcu(&prev->gc_rcu, inetpeer_inval_rcu); } out: