]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
Add setsockopt support for SO_RDS_TRANSPORT
authorSowmini Varadhan <sowmini.varadhan@oracle.com>
Tue, 2 Jun 2015 00:26:29 +0000 (20:26 -0400)
committerMukesh Kacker <mukesh.kacker@oracle.com>
Wed, 8 Jul 2015 21:00:21 +0000 (14:00 -0700)
An application may deterministically attach the underlying transport for
a PF_RDS socket by invoking setsockopt(2) with the SO_RDS_TRANSPORT
option at the SOL_RDS level. The integer argument to setsockopt must be
one of the RDS_TRANS_* transport types, e.g., RDS_TRANS_TCP. The option
must be specified before invoking bind(2) on the socket, and may only
be used once on the socket. An attempt to set the option on a bound
socket, or to invoke the option after a successful SO_RDS_TRANSPORT
attachment, will return EOPNOTSUPP.

Orabug: 21061146

Signed-off-by: Sowmini Varadhan <sowmini.varadhan@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Mukesh Kacker <mukesh.kacker@oracle.com>
net/rds/af_rds.c
net/rds/bind.c
net/rds/rds.h
net/rds/transport.c

index 7f7b2baa8d3ef455aa510823f5a9e62d7be537ca..71806cb5587e76714bc66386f45d63c3739e10f1 100644 (file)
@@ -330,6 +330,28 @@ static int rds_user_reset(struct rds_sock *rs, char __user *optval, int optlen)
        return 0;
 }
 
+static int rds_set_transport(struct rds_sock *rs, char __user *optval,
+                            int optlen)
+{
+       int t_type;
+
+       if (rs->rs_transport)
+               return -EOPNOTSUPP; /* previously attached to transport */
+
+       if (optlen != sizeof(int))
+               return -EINVAL;
+
+       if (copy_from_user(&t_type, (int __user *)optval, sizeof(t_type)))
+               return -EFAULT;
+
+       if (t_type < 0 || t_type >= RDS_TRANS_COUNT)
+               return -EINVAL;
+
+       rs->rs_transport = rds_trans_get(t_type);
+
+       return rs->rs_transport ? 0 : -ENOPROTOOPT;
+}
+
 static int rds_setsockopt(struct socket *sock, int level, int optname,
                          char __user *optval, unsigned int optlen)
 {
@@ -363,6 +385,11 @@ static int rds_setsockopt(struct socket *sock, int level, int optname,
        case RDS_CONN_RESET:
                ret = rds_user_reset(rs, optval, optlen);
                break;
+       case SO_RDS_TRANSPORT:
+               lock_sock(sock->sk);
+               ret = rds_set_transport(rs, optval, optlen);
+               release_sock(sock->sk);
+               break;
        default:
                ret = -ENOPROTOOPT;
        }
index cbbabb3a82577516434be0135f70d091a3e28ba6..9510dc64691b4759d11426ec0a170b25306e7fc8 100644 (file)
@@ -197,6 +197,10 @@ int rds_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        if (ret)
                goto out;
 
+       if (rs->rs_transport) { /* previously bound */
+               ret = 0;
+               goto out;
+       }
        trans = rds_trans_get_preferred(sin->sin_addr.s_addr);
        if (!trans) {
                ret = -EADDRNOTAVAIL;
index 70f27f972f568da1c0f2bd2368fc6fc5ea3d76d4..63a65cddc7c4930d9ec4c683a2e5b622afbf2c72 100644 (file)
@@ -894,6 +894,7 @@ struct rds_transport *rds_trans_get_preferred(__be32 addr);
 void rds_trans_put(struct rds_transport *trans);
 unsigned int rds_trans_stats_info_copy(struct rds_info_iterator *iter,
                                       unsigned int avail);
+struct rds_transport *rds_trans_get(int t_type);
 int rds_trans_init(void);
 void rds_trans_exit(void);
 
index 2dd3de3e57f3ab253c004b104cb322d2b4dabe18..e3a4811d8245550e71627a27152c79cda08d9152 100644 (file)
@@ -101,6 +101,27 @@ struct rds_transport *rds_trans_get_preferred(__be32 addr)
        return ret;
 }
 
+struct rds_transport *rds_trans_get(int t_type)
+{
+       struct rds_transport *ret = NULL;
+       struct rds_transport *trans;
+       unsigned int i;
+
+       down_read(&rds_trans_sem);
+       for (i = 0; i < RDS_TRANS_COUNT; i++) {
+               trans = transports[i];
+
+               if (trans && trans->t_type == t_type &&
+                   (!trans->t_owner || try_module_get(trans->t_owner))) {
+                       ret = trans;
+                       break;
+               }
+       }
+       up_read(&rds_trans_sem);
+
+       return ret;
+}
+
 /*
  * This returns the number of stats entries in the snapshot and only
  * copies them using the iter if there is enough space for them.  The