spin_unlock_irq(&cm_id_priv->lock);
} else {
spin_unlock_irq(&cm_id_priv->lock);
+ if (!err)
+ err = -EINVAL;
ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED,
- NULL, 0, NULL, 0);
+ NULL, 0, &err, sizeof(err));
}
break;
case IB_CM_REP_SENT:
case IB_CM_REP_RCVD:
case IB_CM_MRA_REP_SENT:
spin_unlock_irq(&cm_id_priv->lock);
+ if (!err)
+ err = -EINVAL;
ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED,
- NULL, 0, NULL, 0);
+ NULL, 0, &err, sizeof(err));
break;
case IB_CM_ESTABLISHED:
spin_unlock_irq(&cm_id_priv->lock);
reject:
cma_modify_qp_err(id_priv);
ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED,
- NULL, 0, NULL, 0);
+ NULL, 0, &ret, sizeof(int));
return ret;
}
return 0;
reject:
cma_modify_qp_err(id_priv);
- rdma_reject(id, NULL, 0);
+ rdma_reject(id, &ret, sizeof(int));
return ret;
}
EXPORT_SYMBOL(rdma_accept);
INIT_DELAYED_WORK(&conn->c_recv_w, rds_recv_worker);
INIT_DELAYED_WORK(&conn->c_conn_w, rds_connect_worker);
INIT_DELAYED_WORK(&conn->c_hb_w, rds_hb_worker);
+ INIT_DELAYED_WORK(&conn->c_reject_w, rds_reject_worker);
INIT_WORK(&conn->c_down_w, rds_shutdown_worker);
mutex_init(&conn->c_cm_lock);
conn->c_flags = 0;
}
EXPORT_SYMBOL_GPL(rds_conn_find);
-void rds_conn_shutdown(struct rds_connection *conn)
+void rds_conn_shutdown(struct rds_connection *conn, int restart)
{
/* shut it down unless it's down already */
if (!rds_conn_transition(conn, RDS_CONN_DOWN, RDS_CONN_DOWN)) {
* conn - the reconnect is always triggered by the active peer. */
cancel_delayed_work_sync(&conn->c_conn_w);
rcu_read_lock();
- if (!hlist_unhashed(&conn->c_hash_node)) {
+ if (!hlist_unhashed(&conn->c_hash_node) && restart) {
rcu_read_unlock();
rds_queue_reconnect(conn);
} else {
void *buffer)
{
struct rds_info_rdma_connection *iinfo = buffer;
- struct rds_ib_connection *ic;
+ struct rds_ib_connection *ic = conn->c_transport_data;
/* We will only ever look at IB transports */
if (conn->c_trans != &rds_ib_transport)
memset(&iinfo->src_gid, 0, sizeof(iinfo->src_gid));
memset(&iinfo->dst_gid, 0, sizeof(iinfo->dst_gid));
+
+ if (ic) {
+ iinfo->tos = conn->c_tos;
+ iinfo->sl = ic->i_sl;
+ }
+
if (rds_conn_state(conn) == RDS_CONN_UP) {
struct rds_ib_device *rds_ibdev;
struct rdma_dev_addr *dev_addr;
iinfo->max_recv_wr = ic->i_recv_ring.w_nr;
iinfo->max_send_sge = rds_ibdev->max_sge;
rds_ib_get_mr_info(rds_ibdev, iinfo);
- iinfo->tos = ic->conn->c_tos;
- iinfo->sl = ic->i_sl;
iinfo->cache_allocs = atomic_read(&ic->i_cache_allocs);
}
return 1;
goto out;
}
- if (conn->c_reconnect && (conn->c_version > version)) {
- printk(KERN_WARNING "RDS/IB: connection "
- "<%u.%u.%u.%u,%u.%u.%u.%u,%d,%u.%u> rejecting version "
- "(%u/%u)\n",
- NIPQUAD(conn->c_laddr),
- NIPQUAD(conn->c_faddr),
- conn->c_tos,
- RDS_PROTOCOL_MAJOR(conn->c_version),
- RDS_PROTOCOL_MINOR(conn->c_version),
- RDS_PROTOCOL_MAJOR(version),
- RDS_PROTOCOL_MINOR(version));
-
- conn = NULL;
- goto out;
+ if (dp->dp_tos && !conn->c_base_conn) {
+ conn->c_base_conn = rds_conn_create(dp->dp_daddr, dp->dp_saddr,
+ &rds_ib_transport, 0, GFP_KERNEL);
+ if (IS_ERR(conn->c_base_conn)) {
+ conn = NULL;
+ goto out;
+ }
}
/*
}
#endif
- /* If the peer doesn't do protocol negotiation, we must
- * default to RDSv3.0 */
rds_ib_set_protocol(conn, RDS_PROTOCOL_4_1);
ic->i_flowctl = rds_ib_sysctl_flow_control; /* advertise flow control */
case RDMA_CM_EVENT_REJECTED:
err = (int *)event->param.conn.private_data;
if (conn) {
- if (!conn->c_reconnect || conn->c_committed_version ==
- RDS_PROTOCOL_COMPAT_VERSION) {
- if ((*err) == 0 &&
- event->status == RDS_REJ_CONSUMER_DEFINED) {
- /* rejection from 3.x protocol */
- if (!conn->c_tos) {
- /* retry the connect with a
- lower compatible protocol */
- conn->c_proposed_version =
- RDS_PROTOCOL_COMPAT_VERSION;
- }
- } else {
+ if (event->status == RDS_REJ_CONSUMER_DEFINED && (*err) == 0) {
+ /* Rejection from RDSV3.1 */
+ if (!conn->c_tos) {
conn->c_proposed_version =
- RDS_PROTOCOL_VERSION;
+ RDS_PROTOCOL_COMPAT_VERSION;
+ rds_conn_drop(conn);
+ } else {
+ queue_delayed_work(rds_wq,
+ &conn->c_reject_w,
+ msecs_to_jiffies(10));
}
- }
- rds_conn_drop(conn);
+ } else
+ rds_conn_drop(conn);
}
break;
struct delayed_work c_send_w;
struct delayed_work c_recv_w;
struct delayed_work c_conn_w;
+ struct delayed_work c_reject_w;
struct delayed_work c_hb_w;
struct work_struct c_down_w;
struct mutex c_cm_lock; /* protect conn state & cm */
/* Protocol version */
unsigned int c_proposed_version;
- unsigned int c_committed_version;
unsigned int c_version;
/* Re-connect stall diagnostics */
unsigned long c_hb_start;
struct rds_connection *c_base_conn;
+
+ unsigned int c_route_to_base;
};
#define RDS_FLAG_CONG_BITMAP 0x01
u8 tos, gfp_t gfp);
struct rds_connection *rds_conn_find(__be32 laddr, __be32 faddr,
struct rds_transport *trans, u8 tos);
-void rds_conn_shutdown(struct rds_connection *conn);
+void rds_conn_shutdown(struct rds_connection *conn, int restart);
void rds_conn_destroy(struct rds_connection *conn);
void rds_conn_reset(struct rds_connection *conn);
void rds_conn_drop(struct rds_connection *conn);
struct rm_rdma_op *);
int rds_send_internal(struct rds_connection *conn, struct rds_sock *rs,
struct sk_buff *skb, gfp_t gfp);
+void rds_route_to_base(struct rds_connection *conn);
extern unsigned int rds_async_send_enabled;
void rds_connect_worker(struct work_struct *);
void rds_shutdown_worker(struct work_struct *);
void rds_send_worker(struct work_struct *);
+void rds_reject_worker(struct work_struct *);
void rds_recv_worker(struct work_struct *);
void rds_hb_worker(struct work_struct *);
void rds_connect_complete(struct rds_connection *conn);
goto out;
} else if (conn->c_base_conn->c_version ==
RDS_PROTOCOL_COMPAT_VERSION) {
- conn = conn->c_base_conn;
+ if (!conn->c_reconnect ||
+ conn->c_route_to_base)
+ conn = conn->c_base_conn;
+ else {
+ ret = -EAGAIN;
+ goto out;
+ }
}
}
rds_message_put(rm);
return 0;
}
+
+void rds_route_to_base(struct rds_connection *conn)
+{
+ struct rds_message *rm, *tmp;
+ struct rds_connection *base_conn = conn->c_base_conn;
+ unsigned long flags;
+
+ BUG_ON(!conn->c_tos || rds_conn_up(conn) || !base_conn ||
+ !list_empty(&conn->c_retrans));
+
+ spin_lock_irqsave(&base_conn->c_lock, flags);
+ list_for_each_entry_safe(rm, tmp, &conn->c_send_queue, m_conn_item) {
+ list_del_init(&rm->m_conn_item);
+ rm->m_inc.i_conn = base_conn;
+ rm->m_inc.i_hdr.h_sequence =
+ cpu_to_be64(base_conn->c_next_tx_seq++);
+ list_add_tail(&rm->m_conn_item, &base_conn->c_send_queue);
+ }
+ spin_unlock_irqrestore(&base_conn->c_lock, flags);
+ conn->c_route_to_base = 1;
+ queue_delayed_work(rds_wq, &base_conn->c_send_w, 0);
+}
conn->c_connection_start = get_seconds();
conn->c_reconnect = 1;
- conn->c_committed_version = conn->c_version;
conn->c_proposed_version = RDS_PROTOCOL_VERSION;
+ conn->c_route_to_base = 0;
}
EXPORT_SYMBOL_GPL(rds_connect_complete);
}
}
+void rds_reject_worker(struct work_struct *work)
+{
+ struct rds_connection *conn = container_of(work, struct rds_connection, c_reject_w.work);
+
+ atomic_set(&conn->c_state, RDS_CONN_ERROR);
+ rds_conn_shutdown(conn, 0);
+ rds_route_to_base(conn);
+}
+
void rds_hb_worker(struct work_struct *work)
{
struct rds_connection *conn = container_of(work, struct rds_connection, c_hb_w.work);
{
struct rds_connection *conn = container_of(work, struct rds_connection, c_down_w);
- rds_conn_shutdown(conn);
+ rds_conn_shutdown(conn, 1);
}
void rds_threads_exit(void)