@@ -142,6 +142,13 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
142
142
struct dccp_request_sock * dreq = dccp_rsk (req );
143
143
bool own_req ;
144
144
145
+ /* TCP/DCCP listeners became lockless.
146
+ * DCCP stores complex state in its request_sock, so we need
147
+ * a protection for them, now this code runs without being protected
148
+ * by the parent (listener) lock.
149
+ */
150
+ spin_lock_bh (& dreq -> dreq_lock );
151
+
145
152
/* Check for retransmitted REQUEST */
146
153
if (dccp_hdr (skb )-> dccph_type == DCCP_PKT_REQUEST ) {
147
154
@@ -156,7 +163,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
156
163
inet_rtx_syn_ack (sk , req );
157
164
}
158
165
/* Network Duplicate, discard packet */
159
- return NULL ;
166
+ goto out ;
160
167
}
161
168
162
169
DCCP_SKB_CB (skb )-> dccpd_reset_code = DCCP_RESET_CODE_PACKET_ERROR ;
@@ -182,20 +189,20 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
182
189
183
190
child = inet_csk (sk )-> icsk_af_ops -> syn_recv_sock (sk , skb , req , NULL ,
184
191
req , & own_req );
185
- if (! child )
186
- goto listen_overflow ;
187
-
188
- return inet_csk_complete_hashdance ( sk , child , req , own_req );
192
+ if (child ) {
193
+ child = inet_csk_complete_hashdance ( sk , child , req , own_req ) ;
194
+ goto out ;
195
+ }
189
196
190
- listen_overflow :
191
- dccp_pr_debug ("listen_overflow!\n" );
192
197
DCCP_SKB_CB (skb )-> dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY ;
193
198
drop :
194
199
if (dccp_hdr (skb )-> dccph_type != DCCP_PKT_RESET )
195
200
req -> rsk_ops -> send_reset (sk , skb );
196
201
197
202
inet_csk_reqsk_queue_drop (sk , req );
198
- return NULL ;
203
+ out :
204
+ spin_unlock_bh (& dreq -> dreq_lock );
205
+ return child ;
199
206
}
200
207
201
208
EXPORT_SYMBOL_GPL (dccp_check_req );
@@ -246,6 +253,7 @@ int dccp_reqsk_init(struct request_sock *req,
246
253
{
247
254
struct dccp_request_sock * dreq = dccp_rsk (req );
248
255
256
+ spin_lock_init (& dreq -> dreq_lock );
249
257
inet_rsk (req )-> ir_rmt_port = dccp_hdr (skb )-> dccph_sport ;
250
258
inet_rsk (req )-> ir_num = ntohs (dccp_hdr (skb )-> dccph_dport );
251
259
inet_rsk (req )-> acked = 0 ;
0 commit comments