[ 023/187] inetpeer: fix a race in inetpeer_gc_worker()

2012-07-12 Thread Greg Kroah-Hartman
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()

2012-07-12 Thread Greg Kroah-Hartman
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/