diff options
| -rw-r--r-- | drivers/infiniband/core/cma.c | 66 |
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; | |||
| 71 | static DEFINE_IDR(sdp_ps); | 71 | static DEFINE_IDR(sdp_ps); |
| 72 | static DEFINE_IDR(tcp_ps); | 72 | static DEFINE_IDR(tcp_ps); |
| 73 | static DEFINE_IDR(udp_ps); | 73 | static DEFINE_IDR(udp_ps); |
| 74 | static int next_port; | ||
| 74 | 75 | ||
| 75 | struct cma_device { | 76 | struct 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; | ||
| 1748 | err2: | ||
| 1749 | idr_remove(ps, port); | ||
| 1750 | err1: | ||
| 1751 | kfree(bind_list); | ||
| 1752 | return ret; | ||
| 1753 | } | ||
| 1732 | 1754 | ||
| 1755 | static 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 | |||
| 1764 | retry: | ||
| 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; |
| 1751 | err: | 1791 | err2: |
| 1792 | idr_remove(ps, port); | ||
| 1793 | err1: | ||
| 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; |
