[ 023/187] inetpeer: fix a race in inetpeer_gc_worker()
From: Greg KH 3.4-stable review patch. If anyone has any objections, please let me know. -- From: Eric Dumazet [ Upstream commit 55432d2b543a4b6dfae54f5c432a566877a85d90 ] commit 5faa5df1fa2024 (inetpeer: Invalidate the inetpeer tree along with the routing cache) added a race : Before freeing an inetpeer, we must respect a RCU grace period, and make sure no user will attempt to increase refcnt. inetpeer_invalidate_tree() waits for a RCU grace period before inserting inetpeer tree into gc_list and waking the worker. At that time, no concurrent lookup can find a inetpeer in this tree. Signed-off-by: Eric Dumazet Cc: Steffen Klassert Acked-by: Steffen Klassert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/inetpeer.h |5 - net/ipv4/inetpeer.c| 16 2 files changed, 16 insertions(+), 5 deletions(-) --- a/include/net/inetpeer.h +++ b/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_headgc_list; + union { + struct list_headgc_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 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -560,6 +560,17 @@ bool inet_peer_xrlim_allow(struct inet_p } 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(_lock); + list_add_tail(>gc_list, _list); + spin_unlock_bh(_lock); + + schedule_delayed_work(_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(>root, old, new); if (prev == old) { base->total = 0; - spin_lock(_lock); - list_add_tail(>gc_list, _list); - spin_unlock(_lock); - schedule_delayed_work(_work, gc_delay); + call_rcu(>gc_rcu, inetpeer_inval_rcu); } out: -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[ 023/187] inetpeer: fix a race in inetpeer_gc_worker()
From: Greg KH gre...@linuxfoundation.org 3.4-stable review patch. If anyone has any objections, please let me know. -- From: Eric Dumazet eduma...@google.com [ Upstream commit 55432d2b543a4b6dfae54f5c432a566877a85d90 ] commit 5faa5df1fa2024 (inetpeer: Invalidate the inetpeer tree along with the routing cache) added a race : Before freeing an inetpeer, we must respect a RCU grace period, and make sure no user will attempt to increase refcnt. inetpeer_invalidate_tree() waits for a RCU grace period before inserting inetpeer tree into gc_list and waking the worker. At that time, no concurrent lookup can find a inetpeer in this tree. Signed-off-by: Eric Dumazet eduma...@google.com Cc: Steffen Klassert steffen.klass...@secunet.com Acked-by: Steffen Klassert steffen.klass...@secunet.com Signed-off-by: David S. Miller da...@davemloft.net Signed-off-by: Greg Kroah-Hartman gre...@linuxfoundation.org --- include/net/inetpeer.h |5 - net/ipv4/inetpeer.c| 16 2 files changed, 16 insertions(+), 5 deletions(-) --- a/include/net/inetpeer.h +++ b/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_headgc_list; + union { + struct list_headgc_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 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -560,6 +560,17 @@ bool inet_peer_xrlim_allow(struct inet_p } 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: -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/