[ofa-general] Re: [PATCH 6/8]: RDS: Use IB for loopback
Olaf Kirch
okir at lst.de
Thu Apr 24 02:12:19 PDT 2008
From 2a91ce118f8d4e7e644ea849f61bd8953faaacc6 Mon Sep 17 00:00:00 2001
From: Olaf Kirch <olaf.kirch at oracle.com>
Date: Thu, 24 Apr 2008 00:27:36 -0700
Subject: [PATCH] RDS: Use IB for loopback
Currently, when an application wants to send to a RDS port
on the local host, RDS will create a connection using the
special loopback transport.
In order to be able to test RDS (and RDS over RDMA) faithfully
on standalone machines, we want loopback traffic to use the IB
transport if possible.
This patch makes the necessary changes. This turns out to be a
little tricky, as we need two rds_connection objects with the same
address pair. The current code doesn't really handle this, so
we have to jump through some hoops.
- loopback connections for IB are represented by two
rds_connections; the "active" connection created when we
initiate the connect, and a "passive" connection created
when we accept the incoming RC.
- The active connection is used to transmit packets, which
are then received by the passive conn.
- the passive conn is never added to the global hash table;
instead it is kept in conn->c_passive.
Signed-off-by: Olaf Kirch <olaf.kirch at oracle.com>
---
net/rds/connection.c | 42 +++++++++++++++++++++++++++++++++++-------
net/rds/rds.h | 3 +++
net/rds/tcp.c | 1 +
net/rds/threads.c | 10 +++++++++-
4 files changed, 48 insertions(+), 8 deletions(-)
diff --git a/net/rds/connection.c b/net/rds/connection.c
index 585123a..5d7788e 100644
--- a/net/rds/connection.c
+++ b/net/rds/connection.c
@@ -130,15 +130,26 @@ void rds_conn_reset(struct rds_connection *conn)
*/
static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
struct rds_transport *trans, gfp_t gfp,
- int allow_loop_transport)
+ int is_outgoing)
{
- struct rds_connection *conn, *tmp;
+ struct rds_connection *conn, *tmp, *parent = NULL;
struct hlist_head *head = rds_conn_bucket(laddr, faddr);
unsigned long flags;
int ret;
spin_lock_irqsave(&rds_conn_lock, flags);
conn = rds_conn_lookup(head, laddr, faddr, trans);
+ if (conn
+ && conn->c_loopback
+ && conn->c_trans != &rds_loop_transport
+ && !is_outgoing) {
+ /* This is a looped back IB connection, and we're
+ * called by the code handling the incoming connect.
+ * We need a second connection object into which we
+ * can stick the other QP. */
+ parent = conn;
+ conn = parent->c_passive;
+ }
spin_unlock_irqrestore(&rds_conn_lock, flags);
if (conn)
goto out;
@@ -151,7 +162,7 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
memset(conn, 0, sizeof(*conn));
- /* hash_node below */
+ INIT_HLIST_NODE(&conn->c_hash_node);
conn->c_laddr = laddr;
conn->c_faddr = faddr;
spin_lock_init(&conn->c_lock);
@@ -173,8 +184,16 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
* can bind to the destination address then we'd rather the messages
* flow through loopback rather than either transport.
*/
- if (allow_loop_transport && rds_trans_get_preferred(faddr))
- trans = &rds_loop_transport;
+ if (rds_trans_get_preferred(faddr)) {
+ conn->c_loopback = 1;
+ if (is_outgoing && trans->t_prefer_loopback) {
+ /* "outgoing" connection - and the transport
+ * says it wants the connection handled by the
+ * loopback transport. This is what TCP does.
+ */
+ trans = &rds_loop_transport;
+ }
+ }
conn->c_trans = trans;
@@ -198,14 +217,21 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
NIPQUAD(laddr), NIPQUAD(faddr));
spin_lock_irqsave(&rds_conn_lock, flags);
- tmp = rds_conn_lookup(head, laddr, faddr, trans);
+ if (parent == NULL) {
+ tmp = rds_conn_lookup(head, laddr, faddr, trans);
+ if (tmp == NULL)
+ hlist_add_head(&conn->c_hash_node, head);
+ } else {
+ if ((tmp = parent->c_passive) == NULL)
+ parent->c_passive = conn;
+ }
+
if (tmp) {
trans->conn_free(conn->c_transport_data);
kmem_cache_free(rds_conn_slab, conn);
conn = tmp;
} else {
rds_cong_add_conn(conn);
- hlist_add_head(&conn->c_hash_node, head);
rds_conn_count++;
}
@@ -415,6 +441,8 @@ void __exit rds_conn_exit(void)
/* the conn won't reconnect once it's unhashed */
hlist_del_init(&conn->c_hash_node);
+ if (conn->c_passive)
+ __rds_conn_destroy(conn->c_passive);
__rds_conn_destroy(conn);
}
}
diff --git a/net/rds/rds.h b/net/rds/rds.h
index dc1ab4c..d5a966d 100644
--- a/net/rds/rds.h
+++ b/net/rds/rds.h
@@ -121,6 +121,8 @@ struct rds_connection {
struct hlist_node c_hash_node;
__be32 c_laddr;
__be32 c_faddr;
+ unsigned int c_loopback : 1;
+ struct rds_connection * c_passive;
spinlock_t c_lock;
struct rds_cong_map *c_lcong;
@@ -342,6 +344,7 @@ struct rds_transport {
struct list_head t_item;
struct module *t_owner;
char *t_name;
+ unsigned int t_prefer_loopback : 1;
int (*laddr_check)(__be32 addr);
int (*conn_alloc)(struct rds_connection *conn, gfp_t gfp);
void (*conn_free)(void *data);
diff --git a/net/rds/tcp.c b/net/rds/tcp.c
index baf876e..f4e6fce 100644
--- a/net/rds/tcp.c
+++ b/net/rds/tcp.c
@@ -252,6 +252,7 @@ struct rds_transport rds_tcp_transport = {
.exit = rds_tcp_exit,
.t_owner = THIS_MODULE,
.t_name = "tcp",
+ .t_prefer_loopback = 1,
};
int __init rds_tcp_init(void)
diff --git a/net/rds/threads.c b/net/rds/threads.c
index 2a5dc0b..b86fbc3 100644
--- a/net/rds/threads.c
+++ b/net/rds/threads.c
@@ -178,6 +178,11 @@ void rds_shutdown_worker(struct work_struct *work)
up(&conn->c_send_sem);
if (!rds_conn_transition(conn, RDS_CONN_DISCONNECTING, RDS_CONN_DOWN)) {
+ /* This can happen - eg when we're in the middle of tearing
+ * down the connection, and someone unloads the rds module.
+ * Quite reproduceable with loopback connections.
+ * Mostly harmless.
+ */
rds_conn_error(conn,
"%s: failed to transition to state DOWN, "
"current state is %d\n",
@@ -187,7 +192,10 @@ void rds_shutdown_worker(struct work_struct *work)
}
}
- /* then reconnect if it's still live */
+ /* Then reconnect if it's still live.
+ * The passive side of an IB loopback connection is never added
+ * to the conn hash, so we never trigger a reconnect on this
+ * conn - the reconnect is always triggered by the active peer. */
cancel_delayed_work(&conn->c_conn_w);
if (!hlist_unhashed(&conn->c_hash_node)) {
rds_queue_reconnect(conn);
--
1.5.4.rc3
--
Olaf Kirch | --- o --- Nous sommes du soleil we love when we play
okir at lst.de | / | \ sol.dhoop.naytheet.ah kin.ir.samse.qurax
More information about the general
mailing list