aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/infiniband/core/cma.c66
1 files changed, 56 insertions, 10 deletions
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 9e0ab048c878..bc31b54e9cac 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -71,6 +71,7 @@ static struct workqueue_struct *cma_wq;
71static DEFINE_IDR(sdp_ps); 71static DEFINE_IDR(sdp_ps);
72static DEFINE_IDR(tcp_ps); 72static DEFINE_IDR(tcp_ps);
73static DEFINE_IDR(udp_ps); 73static DEFINE_IDR(udp_ps);
74static int next_port;
74 75
75struct cma_device { 76struct cma_device {
76 struct list_head list; 77 struct list_head list;
@@ -1722,33 +1723,74 @@ static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv,
1722 unsigned short snum) 1723 unsigned short snum)
1723{ 1724{
1724 struct rdma_bind_list *bind_list; 1725 struct rdma_bind_list *bind_list;
1725 int port, start, ret; 1726 int port, ret;
1726 1727
1727 bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); 1728 bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL);
1728 if (!bind_list) 1729 if (!bind_list)
1729 return -ENOMEM; 1730 return -ENOMEM;
1730 1731
1731 start = snum ? snum : sysctl_local_port_range[0]; 1732 do {
1733 ret = idr_get_new_above(ps, bind_list, snum, &port);
1734 } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL));
1735
1736 if (ret)
1737 goto err1;
1738
1739 if (port != snum) {
1740 ret = -EADDRNOTAVAIL;
1741 goto err2;
1742 }
1743
1744 bind_list->ps = ps;
1745 bind_list->port = (unsigned short) port;
1746 cma_bind_port(bind_list, id_priv);
1747 return 0;
1748err2:
1749 idr_remove(ps, port);
1750err1:
1751 kfree(bind_list);
1752 return ret;
1753}
1732 1754
1755static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv)
1756{
1757 struct rdma_bind_list *bind_list;
1758 int port, ret;
1759
1760 bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL);
1761 if (!bind_list)
1762 return -ENOMEM;
1763
1764retry:
1733 do { 1765 do {
1734 ret = idr_get_new_above(ps, bind_list, start, &port); 1766 ret = idr_get_new_above(ps, bind_list, next_port, &port);
1735 } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL)); 1767 } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL));
1736 1768
1737 if (ret) 1769 if (ret)
1738 goto err; 1770 goto err1;
1739 1771
1740 if ((snum && port != snum) || 1772 if (port > sysctl_local_port_range[1]) {
1741 (!snum && port > sysctl_local_port_range[1])) { 1773 if (next_port != sysctl_local_port_range[0]) {
1742 idr_remove(ps, port); 1774 idr_remove(ps, port);
1775 next_port = sysctl_local_port_range[0];
1776 goto retry;
1777 }
1743 ret = -EADDRNOTAVAIL; 1778 ret = -EADDRNOTAVAIL;
1744 goto err; 1779 goto err2;
1745 } 1780 }
1746 1781
1782 if (port == sysctl_local_port_range[1])
1783 next_port = sysctl_local_port_range[0];
1784 else
1785 next_port = port + 1;
1786
1747 bind_list->ps = ps; 1787 bind_list->ps = ps;
1748 bind_list->port = (unsigned short) port; 1788 bind_list->port = (unsigned short) port;
1749 cma_bind_port(bind_list, id_priv); 1789 cma_bind_port(bind_list, id_priv);
1750 return 0; 1790 return 0;
1751err: 1791err2:
1792 idr_remove(ps, port);
1793err1:
1752 kfree(bind_list); 1794 kfree(bind_list);
1753 return ret; 1795 return ret;
1754} 1796}
@@ -1811,7 +1853,7 @@ static int cma_get_port(struct rdma_id_private *id_priv)
1811 1853
1812 mutex_lock(&lock); 1854 mutex_lock(&lock);
1813 if (cma_any_port(&id_priv->id.route.addr.src_addr)) 1855 if (cma_any_port(&id_priv->id.route.addr.src_addr))
1814 ret = cma_alloc_port(ps, id_priv, 0); 1856 ret = cma_alloc_any_port(ps, id_priv);
1815 else 1857 else
1816 ret = cma_use_port(ps, id_priv); 1858 ret = cma_use_port(ps, id_priv);
1817 mutex_unlock(&lock); 1859 mutex_unlock(&lock);
@@ -2448,6 +2490,10 @@ static int cma_init(void)
2448{ 2490{
2449 int ret; 2491 int ret;
2450 2492
2493 get_random_bytes(&next_port, sizeof next_port);
2494 next_port = (next_port % (sysctl_local_port_range[1] -
2495 sysctl_local_port_range[0])) +
2496 sysctl_local_port_range[0];
2451 cma_wq = create_singlethread_workqueue("rdma_cm_wq"); 2497 cma_wq = create_singlethread_workqueue("rdma_cm_wq");
2452 if (!cma_wq) 2498 if (!cma_wq)
2453 return -ENOMEM; 2499 return -ENOMEM;