RDMA/cma: Randomize local port allocation
Randomize local port allocation in the way sctp_get_port_local() does. Update rover at the end of loop since we're likely to pick a valid port on the first try. Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Reviewed-by: Sean Hefty <sean.hefty@intel.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
This commit is contained in:
parent
0eddb519b9
commit
5d7220e8dc
|
@ -79,7 +79,6 @@ static DEFINE_IDR(sdp_ps);
|
|||
static DEFINE_IDR(tcp_ps);
|
||||
static DEFINE_IDR(udp_ps);
|
||||
static DEFINE_IDR(ipoib_ps);
|
||||
static int next_port;
|
||||
|
||||
struct cma_device {
|
||||
struct list_head list;
|
||||
|
@ -1970,47 +1969,33 @@ err1:
|
|||
|
||||
static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv)
|
||||
{
|
||||
struct rdma_bind_list *bind_list;
|
||||
int port, ret, low, high;
|
||||
|
||||
bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL);
|
||||
if (!bind_list)
|
||||
return -ENOMEM;
|
||||
|
||||
retry:
|
||||
/* FIXME: add proper port randomization per like inet_csk_get_port */
|
||||
do {
|
||||
ret = idr_get_new_above(ps, bind_list, next_port, &port);
|
||||
} while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL));
|
||||
|
||||
if (ret)
|
||||
goto err1;
|
||||
static unsigned int last_used_port;
|
||||
int low, high, remaining;
|
||||
unsigned int rover;
|
||||
|
||||
inet_get_local_port_range(&low, &high);
|
||||
if (port > high) {
|
||||
if (next_port != low) {
|
||||
idr_remove(ps, port);
|
||||
next_port = low;
|
||||
goto retry;
|
||||
}
|
||||
ret = -EADDRNOTAVAIL;
|
||||
goto err2;
|
||||
remaining = (high - low) + 1;
|
||||
rover = net_random() % remaining + low;
|
||||
retry:
|
||||
if (last_used_port != rover &&
|
||||
!idr_find(ps, (unsigned short) rover)) {
|
||||
int ret = cma_alloc_port(ps, id_priv, rover);
|
||||
/*
|
||||
* Remember previously used port number in order to avoid
|
||||
* re-using same port immediately after it is closed.
|
||||
*/
|
||||
if (!ret)
|
||||
last_used_port = rover;
|
||||
if (ret != -EADDRNOTAVAIL)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (port == high)
|
||||
next_port = low;
|
||||
else
|
||||
next_port = port + 1;
|
||||
|
||||
bind_list->ps = ps;
|
||||
bind_list->port = (unsigned short) port;
|
||||
cma_bind_port(bind_list, id_priv);
|
||||
return 0;
|
||||
err2:
|
||||
idr_remove(ps, port);
|
||||
err1:
|
||||
kfree(bind_list);
|
||||
return ret;
|
||||
if (--remaining) {
|
||||
rover++;
|
||||
if ((rover < low) || (rover > high))
|
||||
rover = low;
|
||||
goto retry;
|
||||
}
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
|
||||
static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv)
|
||||
|
@ -2995,12 +2980,7 @@ static void cma_remove_one(struct ib_device *device)
|
|||
|
||||
static int __init cma_init(void)
|
||||
{
|
||||
int ret, low, high, remaining;
|
||||
|
||||
get_random_bytes(&next_port, sizeof next_port);
|
||||
inet_get_local_port_range(&low, &high);
|
||||
remaining = (high - low) + 1;
|
||||
next_port = ((unsigned int) next_port % remaining) + low;
|
||||
int ret;
|
||||
|
||||
cma_wq = create_singlethread_workqueue("rdma_cm");
|
||||
if (!cma_wq)
|
||||
|
|
Loading…
Reference in New Issue