static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv)
 {
        struct rdma_bind_list *bind_list;
-       int port, ret;
+       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;
 
-       if (port > sysctl_local_port_range[1]) {
-               if (next_port != sysctl_local_port_range[0]) {
+       inet_get_local_port_range(&low, &high);
+       if (port > high) {
+               if (next_port != low) {
                        idr_remove(ps, port);
-                       next_port = sysctl_local_port_range[0];
+                       next_port = low;
                        goto retry;
                }
                ret = -EADDRNOTAVAIL;
                goto err2;
        }
 
-       if (port == sysctl_local_port_range[1])
-               next_port = sysctl_local_port_range[0];
+       if (port == high)
+               next_port = low;
        else
                next_port = port + 1;
 
 
 static int cma_init(void)
 {
-       int ret;
+       int ret, low, high;
 
        get_random_bytes(&next_port, sizeof next_port);
-       next_port = ((unsigned int) next_port %
-                   (sysctl_local_port_range[1] - sysctl_local_port_range[0])) +
-                   sysctl_local_port_range[0];
+       inet_get_local_port_range(&low, &high);
+       next_port = ((unsigned int) next_port % (high - low)) + low;
+
        cma_wq = create_singlethread_workqueue("rdma_cm");
        if (!cma_wq)
                return -ENOMEM;
 
 extern int snmp_mib_init(void *ptr[2], size_t mibsize, size_t mibalign);
 extern void snmp_mib_free(void *ptr[2]);
 
-extern int sysctl_local_port_range[2];
+extern void inet_get_local_port_range(int *low, int *high);
+
 extern int sysctl_ip_default_ttl;
 extern int sysctl_ip_nonlocal_bind;
 
 
  * This array holds the first and last local port number.
  */
 int sysctl_local_port_range[2] = { 32768, 61000 };
+DEFINE_SEQLOCK(sysctl_port_range_lock);
+
+void inet_get_local_port_range(int *low, int *high)
+{
+       unsigned seq;
+       do {
+               seq = read_seqbegin(&sysctl_port_range_lock);
+
+               *low = sysctl_local_port_range[0];
+               *high = sysctl_local_port_range[1];
+       } while (read_seqretry(&sysctl_port_range_lock, seq));
+}
+EXPORT_SYMBOL(inet_get_local_port_range);
 
 int inet_csk_bind_conflict(const struct sock *sk,
                           const struct inet_bind_bucket *tb)
 
        local_bh_disable();
        if (!snum) {
-               int low = sysctl_local_port_range[0];
-               int high = sysctl_local_port_range[1];
-               int remaining = (high - low) + 1;
-               int rover = net_random() % (high - low) + low;
+               int remaining, rover, low, high;
+
+               inet_get_local_port_range(&low, &high);
+               remaining = high - low;
+               rover = net_random() % remaining + low;
 
                do {
                        head = &hashinfo->bhash[inet_bhashfn(rover, hashinfo->bhash_size)];
 
        int ret;
 
        if (!snum) {
-               int low = sysctl_local_port_range[0];
-               int high = sysctl_local_port_range[1];
-               int range = high - low;
-               int i;
-               int port;
+               int i, remaining, low, high, port;
                static u32 hint;
                u32 offset = hint + inet_sk_port_offset(sk);
                struct hlist_node *node;
                struct inet_timewait_sock *tw = NULL;
 
+               inet_get_local_port_range(&low, &high);
+               remaining = high - low;
+
                local_bh_disable();
-               for (i = 1; i <= range; i++) {
-                       port = low + (i + offset) % range;
+               for (i = 1; i <= remaining; i++) {
+                       port = low + (i + offset) % remaining;
                        head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)];
                        spin_lock(&head->lock);
 
 
 #include <linux/sysctl.h>
 #include <linux/igmp.h>
 #include <linux/inetdevice.h>
+#include <linux/seqlock.h>
 #include <net/snmp.h>
 #include <net/icmp.h>
 #include <net/ip.h>
        return 1;
 }
 
+extern seqlock_t sysctl_port_range_lock;
+extern int sysctl_local_port_range[2];
+
+/* Update system visible IP port range */
+static void set_local_port_range(int range[2])
+{
+       write_seqlock(&sysctl_port_range_lock);
+       sysctl_local_port_range[0] = range[0];
+       sysctl_local_port_range[1] = range[1];
+       write_sequnlock(&sysctl_port_range_lock);
+}
+
+/* Validate changes from /proc interface. */
+static int ipv4_local_port_range(ctl_table *table, int write, struct file *filp,
+                                void __user *buffer,
+                                size_t *lenp, loff_t *ppos)
+{
+       int ret;
+       int range[2] = { sysctl_local_port_range[0],
+                        sysctl_local_port_range[1] };
+       ctl_table tmp = {
+               .data = &range,
+               .maxlen = sizeof(range),
+               .mode = table->mode,
+               .extra1 = &ip_local_port_range_min,
+               .extra2 = &ip_local_port_range_max,
+       };
+
+       ret = proc_dointvec_minmax(&tmp, write, filp, buffer, lenp, ppos);
+
+       if (write && ret == 0) {
+               if (range[1] <= range[0])
+                       ret = -EINVAL;
+               else
+                       set_local_port_range(range);
+       }
+
+       return ret;
+}
+
+/* Validate changes from sysctl interface. */
+static int ipv4_sysctl_local_port_range(ctl_table *table, int __user *name,
+                                        int nlen, void __user *oldval,
+                                        size_t __user *oldlenp,
+                                       void __user *newval, size_t newlen)
+{
+       int ret;
+       int range[2] = { sysctl_local_port_range[0],
+                        sysctl_local_port_range[1] };
+       ctl_table tmp = {
+               .data = &range,
+               .maxlen = sizeof(range),
+               .mode = table->mode,
+               .extra1 = &ip_local_port_range_min,
+               .extra2 = &ip_local_port_range_max,
+       };
+
+       ret = sysctl_intvec(&tmp, name, nlen, oldval, oldlenp, newval, newlen);
+       if (ret == 0 && newval && newlen) {
+               if (range[1] <= range[0])
+                       ret = -EINVAL;
+               else
+                       set_local_port_range(range);
+       }
+       return ret;
+}
+
+
 static int proc_tcp_congestion_control(ctl_table *ctl, int write, struct file * filp,
                                       void __user *buffer, size_t *lenp, loff_t *ppos)
 {
                .data           = &sysctl_local_port_range,
                .maxlen         = sizeof(sysctl_local_port_range),
                .mode           = 0644,
-               .proc_handler   = &proc_dointvec_minmax,
-               .strategy       = &sysctl_intvec,
-               .extra1         = ip_local_port_range_min,
-               .extra2         = ip_local_port_range_max
+               .proc_handler   = &ipv4_local_port_range,
+               .strategy       = &ipv4_sysctl_local_port_range,
        },
        {
                .ctl_name       = NET_IPV4_ICMP_ECHO_IGNORE_ALL,
 
 EXPORT_SYMBOL(tcp_proc_register);
 EXPORT_SYMBOL(tcp_proc_unregister);
 #endif
-EXPORT_SYMBOL(sysctl_local_port_range);
 EXPORT_SYMBOL(sysctl_tcp_low_latency);
 
 
        write_lock_bh(&udp_hash_lock);
 
        if (!snum) {
-               int i;
-               int low = sysctl_local_port_range[0];
-               int high = sysctl_local_port_range[1];
+               int i, low, high;
                unsigned rover, best, best_size_so_far;
 
+               inet_get_local_port_range(&low, &high);
+
                best_size_so_far = UINT_MAX;
                best = rover = net_random() % (high - low) + low;
 
 
        int ret;
 
        if (snum == 0) {
-               const int low = sysctl_local_port_range[0];
-               const int high = sysctl_local_port_range[1];
-               const int range = high - low;
-               int i, port;
+               int i, port, low, high, remaining;
                static u32 hint;
                const u32 offset = hint + inet6_sk_port_offset(sk);
                struct hlist_node *node;
                struct inet_timewait_sock *tw = NULL;
 
+               inet_get_local_port_range(&low, &high);
+               remaining = high - low;
+
                local_bh_disable();
-               for (i = 1; i <= range; i++) {
-                       port = low + (i + offset) % range;
+               for (i = 1; i <= remaining; i++) {
+                       port = low + (i + offset) % remaining;
                        head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)];
                        spin_lock(&head->lock);
 
 
 
        if (snum == 0) {
                /* Search for an available port. */
-               unsigned int low = sysctl_local_port_range[0];
-               unsigned int high = sysctl_local_port_range[1];
-               unsigned int remaining = (high - low) + 1;
-               unsigned int rover = net_random() % remaining + low;
-               int index;
+               int low, high, remaining, index;
+               unsigned int rover;
+
+               inet_get_local_port_range(&low, &high);
+               remaining = (high - low) + 1;
+               rover = net_random() % remaining + low;
 
                do {
                        rover++;
 
 #include <linux/netfilter_ipv6.h>
 #include <linux/tty.h>
 #include <net/icmp.h>
-#include <net/ip.h>            /* for sysctl_local_port_range[] */
+#include <net/ip.h>            /* for local_port_range[] */
 #include <net/tcp.h>           /* struct or_callable used in sock_rcv_skb */
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
 /* Range of port numbers used to automatically bind.
    Need to determine whether we should perform a name_bind
    permission check between the socket and the port number. */
-#define ip_local_port_range_0 sysctl_local_port_range[0]
-#define ip_local_port_range_1 sysctl_local_port_range[1]
 
 static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
 {
                        addrp = (char *)&addr6->sin6_addr.s6_addr;
                }
 
-               if (snum&&(snum < max(PROT_SOCK,ip_local_port_range_0) ||
-                          snum > ip_local_port_range_1)) {
-                       err = security_port_sid(sk->sk_family, sk->sk_type,
-                                               sk->sk_protocol, snum, &sid);
-                       if (err)
-                               goto out;
-                       AVC_AUDIT_DATA_INIT(&ad,NET);
-                       ad.u.net.sport = htons(snum);
-                       ad.u.net.family = family;
-                       err = avc_has_perm(isec->sid, sid,
-                                          isec->sclass,
-                                          SOCKET__NAME_BIND, &ad);
-                       if (err)
-                               goto out;
+               if (snum) {
+                       int low, high;
+
+                       inet_get_local_port_range(&low, &high);
+
+                       if (snum < max(PROT_SOCK, low) || snum > high) {
+                               err = security_port_sid(sk->sk_family,
+                                                       sk->sk_type,
+                                                       sk->sk_protocol, snum,
+                                                       &sid);
+                               if (err)
+                                       goto out;
+                               AVC_AUDIT_DATA_INIT(&ad,NET);
+                               ad.u.net.sport = htons(snum);
+                               ad.u.net.family = family;
+                               err = avc_has_perm(isec->sid, sid,
+                                                  isec->sclass,
+                                                  SOCKET__NAME_BIND, &ad);
+                               if (err)
+                                       goto out;
+                       }
                }
                
                switch(isec->sclass) {