@@ -156,33 +156,21 @@ static int inet_csk_bind_conflict(const struct sock *sk,
156
156
return sk2 != NULL ;
157
157
}
158
158
159
- /* Obtain a reference to a local port for the given sock,
160
- * if snum is zero it means select any available local port.
161
- * We try to allocate an odd port (and leave even ports for connect())
159
+ /*
160
+ * Find an open port number for the socket. Returns with the
161
+ * inet_bind_hashbucket lock held.
162
162
*/
163
- int inet_csk_get_port (struct sock * sk , unsigned short snum )
163
+ static struct inet_bind_hashbucket *
164
+ inet_csk_find_open_port (struct sock * sk , struct inet_bind_bucket * * tb_ret , int * port_ret )
164
165
{
165
- bool reuse = sk -> sk_reuse && sk -> sk_state != TCP_LISTEN ;
166
166
struct inet_hashinfo * hinfo = sk -> sk_prot -> h .hashinfo ;
167
- int ret = 1 , port = snum ;
167
+ int port = 0 ;
168
168
struct inet_bind_hashbucket * head ;
169
169
struct net * net = sock_net (sk );
170
170
int i , low , high , attempt_half ;
171
171
struct inet_bind_bucket * tb ;
172
- kuid_t uid = sock_i_uid (sk );
173
172
u32 remaining , offset ;
174
- bool reuseport_ok = !!snum ;
175
173
176
- if (port ) {
177
- head = & hinfo -> bhash [inet_bhashfn (net , port ,
178
- hinfo -> bhash_size )];
179
- spin_lock_bh (& head -> lock );
180
- inet_bind_bucket_for_each (tb , & head -> chain )
181
- if (net_eq (ib_net (tb ), net ) && tb -> port == port )
182
- goto tb_found ;
183
-
184
- goto tb_not_found ;
185
- }
186
174
attempt_half = (sk -> sk_reuse == SK_CAN_REUSE ) ? 1 : 0 ;
187
175
other_half_scan :
188
176
inet_get_local_port_range (net , & low , & high );
@@ -219,11 +207,12 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum)
219
207
spin_lock_bh (& head -> lock );
220
208
inet_bind_bucket_for_each (tb , & head -> chain )
221
209
if (net_eq (ib_net (tb ), net ) && tb -> port == port ) {
222
- if (!inet_csk_bind_conflict (sk , tb , false, reuseport_ok ))
210
+ if (!inet_csk_bind_conflict (sk , tb , false, false ))
223
211
goto success ;
224
212
goto next_port ;
225
213
}
226
- goto tb_not_found ;
214
+ tb = NULL ;
215
+ goto success ;
227
216
next_port :
228
217
spin_unlock_bh (& head -> lock );
229
218
cond_resched ();
@@ -238,8 +227,41 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum)
238
227
attempt_half = 2 ;
239
228
goto other_half_scan ;
240
229
}
241
- return ret ;
230
+ return NULL ;
231
+ success :
232
+ * port_ret = port ;
233
+ * tb_ret = tb ;
234
+ return head ;
235
+ }
236
+
237
+ /* Obtain a reference to a local port for the given sock,
238
+ * if snum is zero it means select any available local port.
239
+ * We try to allocate an odd port (and leave even ports for connect())
240
+ */
241
+ int inet_csk_get_port (struct sock * sk , unsigned short snum )
242
+ {
243
+ bool reuse = sk -> sk_reuse && sk -> sk_state != TCP_LISTEN ;
244
+ struct inet_hashinfo * hinfo = sk -> sk_prot -> h .hashinfo ;
245
+ int ret = 1 , port = snum ;
246
+ struct inet_bind_hashbucket * head ;
247
+ struct net * net = sock_net (sk );
248
+ struct inet_bind_bucket * tb = NULL ;
249
+ kuid_t uid = sock_i_uid (sk );
242
250
251
+ if (!port ) {
252
+ head = inet_csk_find_open_port (sk , & tb , & port );
253
+ if (!head )
254
+ return ret ;
255
+ if (!tb )
256
+ goto tb_not_found ;
257
+ goto success ;
258
+ }
259
+ head = & hinfo -> bhash [inet_bhashfn (net , port ,
260
+ hinfo -> bhash_size )];
261
+ spin_lock_bh (& head -> lock );
262
+ inet_bind_bucket_for_each (tb , & head -> chain )
263
+ if (net_eq (ib_net (tb ), net ) && tb -> port == port )
264
+ goto tb_found ;
243
265
tb_not_found :
244
266
tb = inet_bind_bucket_create (hinfo -> bind_bucket_cachep ,
245
267
net , head , port );
@@ -255,7 +277,7 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum)
255
277
!rcu_access_pointer (sk -> sk_reuseport_cb ) &&
256
278
sk -> sk_reuseport && uid_eq (tb -> fastuid , uid )))
257
279
goto success ;
258
- if (inet_csk_bind_conflict (sk , tb , true, reuseport_ok ))
280
+ if (inet_csk_bind_conflict (sk , tb , true, true ))
259
281
goto fail_unlock ;
260
282
}
261
283
success :
0 commit comments