aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/sock.h5
-rw-r--r--net/core/sock.c5
-rw-r--r--net/ipv4/tcp_output.c11
3 files changed, 20 insertions, 1 deletions
diff --git a/include/net/sock.h b/include/net/sock.h
index 7c4167bc8266..b9586a137cad 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1488,6 +1488,11 @@ static inline void sk_wmem_free_skb(struct sock *sk, struct sk_buff *skb)
1488 */ 1488 */
1489#define sock_owned_by_user(sk) ((sk)->sk_lock.owned) 1489#define sock_owned_by_user(sk) ((sk)->sk_lock.owned)
1490 1490
1491static inline void sock_release_ownership(struct sock *sk)
1492{
1493 sk->sk_lock.owned = 0;
1494}
1495
1491/* 1496/*
1492 * Macro so as to not evaluate some arguments when 1497 * Macro so as to not evaluate some arguments when
1493 * lockdep is not enabled. 1498 * lockdep is not enabled.
diff --git a/net/core/sock.c b/net/core/sock.c
index 5b6a9431b017..c0fc6bdad1e3 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -2357,10 +2357,13 @@ void release_sock(struct sock *sk)
2357 if (sk->sk_backlog.tail) 2357 if (sk->sk_backlog.tail)
2358 __release_sock(sk); 2358 __release_sock(sk);
2359 2359
2360 /* Warning : release_cb() might need to release sk ownership,
2361 * ie call sock_release_ownership(sk) before us.
2362 */
2360 if (sk->sk_prot->release_cb) 2363 if (sk->sk_prot->release_cb)
2361 sk->sk_prot->release_cb(sk); 2364 sk->sk_prot->release_cb(sk);
2362 2365
2363 sk->sk_lock.owned = 0; 2366 sock_release_ownership(sk);
2364 if (waitqueue_active(&sk->sk_lock.wq)) 2367 if (waitqueue_active(&sk->sk_lock.wq))
2365 wake_up(&sk->sk_lock.wq); 2368 wake_up(&sk->sk_lock.wq);
2366 spin_unlock_bh(&sk->sk_lock.slock); 2369 spin_unlock_bh(&sk->sk_lock.slock);
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index f0eb4e337ec8..17a11e65e57f 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -767,6 +767,17 @@ void tcp_release_cb(struct sock *sk)
767 if (flags & (1UL << TCP_TSQ_DEFERRED)) 767 if (flags & (1UL << TCP_TSQ_DEFERRED))
768 tcp_tsq_handler(sk); 768 tcp_tsq_handler(sk);
769 769
770 /* Here begins the tricky part :
771 * We are called from release_sock() with :
772 * 1) BH disabled
773 * 2) sk_lock.slock spinlock held
774 * 3) socket owned by us (sk->sk_lock.owned == 1)
775 *
776 * But following code is meant to be called from BH handlers,
777 * so we should keep BH disabled, but early release socket ownership
778 */
779 sock_release_ownership(sk);
780
770 if (flags & (1UL << TCP_WRITE_TIMER_DEFERRED)) { 781 if (flags & (1UL << TCP_WRITE_TIMER_DEFERRED)) {
771 tcp_write_timer_handler(sk); 782 tcp_write_timer_handler(sk);
772 __sock_put(sk); 783 __sock_put(sk);