@@ -66,6 +66,7 @@ static bool ovpn_socket_put(struct ovpn_peer *peer, struct ovpn_socket *sock)
66
66
void ovpn_socket_release (struct ovpn_peer * peer )
67
67
{
68
68
struct ovpn_socket * sock ;
69
+ struct sock * sk ;
69
70
bool released ;
70
71
71
72
might_sleep ();
@@ -75,13 +76,14 @@ void ovpn_socket_release(struct ovpn_peer *peer)
75
76
if (!sock )
76
77
return ;
77
78
78
- /* sanity check: we should not end up here if the socket
79
- * was already closed
79
+ /* sock->sk may be released concurrently, therefore we
80
+ * first attempt grabbing a reference.
81
+ * if sock->sk is NULL it means it is already being
82
+ * destroyed and we don't need any further cleanup
80
83
*/
81
- if (! sock -> sock -> sk ) {
82
- DEBUG_NET_WARN_ON_ONCE ( 1 );
84
+ sk = sock -> sock -> sk ;
85
+ if (! sk || ! refcount_inc_not_zero ( & sk -> sk_refcnt ))
83
86
return ;
84
- }
85
87
86
88
/* Drop the reference while holding the sock lock to avoid
87
89
* concurrent ovpn_socket_new call to mess up with a partially
@@ -90,18 +92,18 @@ void ovpn_socket_release(struct ovpn_peer *peer)
90
92
* Holding the lock ensures that a socket with refcnt 0 is fully
91
93
* detached before it can be picked by a concurrent reader.
92
94
*/
93
- lock_sock (sock -> sock -> sk );
95
+ lock_sock (sk );
94
96
released = ovpn_socket_put (peer , sock );
95
- release_sock (sock -> sock -> sk );
97
+ release_sock (sk );
96
98
97
99
/* align all readers with sk_user_data being NULL */
98
100
synchronize_rcu ();
99
101
100
102
/* following cleanup should happen with lock released */
101
103
if (released ) {
102
- if (sock -> sock -> sk -> sk_protocol == IPPROTO_UDP ) {
104
+ if (sk -> sk_protocol == IPPROTO_UDP ) {
103
105
netdev_put (sock -> ovpn -> dev , & sock -> dev_tracker );
104
- } else if (sock -> sock -> sk -> sk_protocol == IPPROTO_TCP ) {
106
+ } else if (sk -> sk_protocol == IPPROTO_TCP ) {
105
107
/* wait for TCP jobs to terminate */
106
108
ovpn_tcp_socket_wait_finish (sock );
107
109
ovpn_peer_put (sock -> peer );
@@ -111,6 +113,7 @@ void ovpn_socket_release(struct ovpn_peer *peer)
111
113
*/
112
114
kfree (sock );
113
115
}
116
+ sock_put (sk );
114
117
}
115
118
116
119
static bool ovpn_socket_hold (struct ovpn_socket * sock )
0 commit comments