diff options
author | Andy Grover <andy.grover@oracle.com> | 2010-06-11 22:49:13 +0200 |
---|---|---|
committer | Andy Grover <andy.grover@oracle.com> | 2010-09-09 03:10:13 +0200 |
commit | 2dc393573430f853e56e25bf4b41c34ba2aa8fd6 (patch) | |
tree | f7a3ddb99aab472aa5054a10043419d4b22bb312 /net/rds/connection.c | |
parent | RDS: Fix locking in send on m_rs_lock (diff) | |
download | linux-2dc393573430f853e56e25bf4b41c34ba2aa8fd6.tar.xz linux-2dc393573430f853e56e25bf4b41c34ba2aa8fd6.zip |
RDS: move rds_shutdown_worker impl. to rds_conn_shutdown
This fits better in connection.c, rather than threads.c.
Signed-off-by: Andy Grover <andy.grover@oracle.com>
Diffstat (limited to 'net/rds/connection.c')
-rw-r--r-- | net/rds/connection.c | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/net/rds/connection.c b/net/rds/connection.c index 7619b671ca28..895e39cdc6a6 100644 --- a/net/rds/connection.c +++ b/net/rds/connection.c @@ -263,6 +263,59 @@ struct rds_connection *rds_conn_create_outgoing(__be32 laddr, __be32 faddr, } EXPORT_SYMBOL_GPL(rds_conn_create_outgoing); +void rds_conn_shutdown(struct rds_connection *conn) +{ + /* shut it down unless it's down already */ + if (!rds_conn_transition(conn, RDS_CONN_DOWN, RDS_CONN_DOWN)) { + /* + * Quiesce the connection mgmt handlers before we start tearing + * things down. We don't hold the mutex for the entire + * duration of the shutdown operation, else we may be + * deadlocking with the CM handler. Instead, the CM event + * handler is supposed to check for state DISCONNECTING + */ + mutex_lock(&conn->c_cm_lock); + if (!rds_conn_transition(conn, RDS_CONN_UP, RDS_CONN_DISCONNECTING) + && !rds_conn_transition(conn, RDS_CONN_ERROR, RDS_CONN_DISCONNECTING)) { + rds_conn_error(conn, "shutdown called in state %d\n", + atomic_read(&conn->c_state)); + mutex_unlock(&conn->c_cm_lock); + return; + } + mutex_unlock(&conn->c_cm_lock); + + mutex_lock(&conn->c_send_lock); + conn->c_trans->conn_shutdown(conn); + rds_conn_reset(conn); + mutex_unlock(&conn->c_send_lock); + + 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", + __func__, + atomic_read(&conn->c_state)); + return; + } + } + + /* 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_sync(&conn->c_conn_w); + if (!hlist_unhashed(&conn->c_hash_node)) + rds_queue_reconnect(conn); +} + +/* + * Stop and free a connection. + */ void rds_conn_destroy(struct rds_connection *conn) { struct rds_message *rm, *rtmp; |