[openib-general] [RFC] [PATCH] Re: CMA issue : bind selects the same port after close
Krishna Kumar
krkumar2 at in.ibm.com
Tue Sep 12 02:33:04 PDT 2006
> The basic problem in the CMA is in cma_alloc_port(). If the port number
> (passed in as snum) is 0, the first available port starting at
> sysctl_local_port_range[0] is used. We could instead start our search by
> adding an increasing counter or a random value to the lower-end of the port
> range. Then expand the code to handle searching below our starting value
> if we failed to find one above it.
Implement the above method where we start search for port# at a
random offset from the lower-end of the port range, and on failure
search at the lower-end of the port range.
(only compile tested)
Signed-off-by: Krishna Kumar <krkumar2 at in.ibm.com>
diff -ruNp org/core/cma.c new/core/cma.c
--- org/core/cma.c 2006-09-12 11:25:18.000000000 +0530
+++ new/core/cma.c 2006-09-12 14:28:26.000000000 +0530
@@ -1652,12 +1652,21 @@ static int cma_alloc_port(struct idr *ps
{
struct rdma_bind_list *bind_list;
int port, start, ret;
+ int out_of_range;
bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL);
if (!bind_list)
return -ENOMEM;
- start = snum ? snum : sysctl_local_port_range[0];
+ if (snum) {
+ start = snum;
+ } else {
+ int low = sysctl_local_port_range[0];
+ int high = sysctl_local_port_range[1];
+
+ get_random_bytes(&start, sizeof start);
+ start = start % (high - low) + low;
+ }
do {
ret = idr_get_new_above(ps, bind_list, start, &port);
@@ -1666,8 +1675,21 @@ static int cma_alloc_port(struct idr *ps
if (ret)
goto err;
- if ((snum && port != snum) ||
- (!snum && port > sysctl_local_port_range[1])) {
+ out_of_range = 0;
+ if (!snum && port > sysctl_local_port_range[1]) {
+ /*
+ * Couldn't find one from random() off of start, try from
+ * low.
+ */
+ idr_remove(ps, port);
+ start = sysctl_local_port_range[0];
+ do {
+ ret = idr_get_new_above(ps, bind_list, start, &port);
+ } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL));
+ if (port > sysctl_local_port_range[1])
+ out_of_range = 1;
+ }
+ if ((snum && port != snum) || out_of_range) {
idr_remove(ps, port);
ret = -EADDRNOTAVAIL;
goto err;
More information about the general
mailing list