* the conn has been shutdown that no one else is referencing the connection.
* We can only ensure this in the rmmod path in the current code.
*/
-void rds_conn_destroy(struct rds_connection *conn)
+void rds_conn_destroy(struct rds_connection *conn, int shutdown)
{
struct rds_message *rm, *rtmp;
unsigned long flags;
+ LIST_HEAD(to_be_dropped);
rds_rtd(RDS_RTD_CM, "freeing conn %p <%u.%u.%u.%u,%u.%u.%u.%u,%d>\n",
conn, NIPQUAD(conn->c_laddr), NIPQUAD(conn->c_faddr),
conn->c_tos);
+ set_bit(RDS_DESTROY_PENDING, &conn->c_flags);
+
/* Ensure conn will not be scheduled for reconnect */
spin_lock_irq(&rds_conn_lock);
hlist_del_init_rcu(&conn->c_hash_node);
list_for_each_entry_safe(rm, rtmp,
&conn->c_send_queue,
m_conn_item) {
- list_del_init(&rm->m_conn_item);
- BUG_ON(!list_empty(&rm->m_sock_item));
- rds_message_put(rm);
+ if (shutdown) {
+ list_del_init(&rm->m_conn_item);
+ BUG_ON(!list_empty(&rm->m_sock_item));
+ rds_message_put(rm);
+ } else {
+ list_move_tail(&rm->m_conn_item, &to_be_dropped);
+ }
}
+
+ if (!list_empty(&to_be_dropped))
+ rds_send_remove_from_sock(&to_be_dropped, RDS_RDMA_SEND_DROPPED);
+
if (conn->c_xmit_rm)
rds_message_put(conn->c_xmit_rm);
container_of(_work, struct rds_ib_conn_destroy_work, work.work);
struct rds_connection *conn = work->conn;
- rds_conn_destroy(conn);
+ rds_conn_destroy(conn, 0);
kfree(work);
}
spin_unlock_irq(&ib_nodev_conns_lock);
list_for_each_entry_safe(ic, _ic, &tmp_list, ib_node)
- rds_conn_destroy(ic->conn);
+ rds_conn_destroy(ic->conn, 1);
}
static unsigned int get_unmap_fmr_cpu(struct rds_ib_device *rds_ibdev,
list_for_each_entry_safe(lc, _lc, &tmp_list, loop_node) {
WARN_ON(lc->conn->c_passive);
- rds_conn_destroy(lc->conn);
+ rds_conn_destroy(lc->conn, 1);
}
}
#define RDS_RECONNECT_PENDING 1
#define RDS_IN_XMIT 2
#define RDS_RECV_REFILL 3
+#define RDS_DESTROY_PENDING 4
#define RDS_RDMA_RESOLVE_TO_MAX_INDEX 5
#define RDS_ADDR_RES_TM_INDEX_MAX 5
__be32 faddr,
struct rds_transport *trans, u8 tos);
void rds_conn_shutdown(struct rds_connection *conn, int restart);
-void rds_conn_destroy(struct rds_connection *conn);
+void rds_conn_destroy(struct rds_connection *conn, int shutdown);
void rds_conn_reset(struct rds_connection *conn);
void rds_conn_drop(struct rds_connection *conn);
void rds_conn_laddr_list(__be32 laddr, struct list_head *laddr_conns);
goto out;
}
+ if (test_bit(RDS_DESTROY_PENDING, &conn->c_flags)) {
+ ret = -EAGAIN;
+ goto out;
+ }
+
/* Not accepting new sends until all the failed ops have been reaped */
if (rds_async_send_enabled && conn->c_pending_flush) {
ret = -EAGAIN;
list_for_each_entry_safe(tc, _tc, &tmp_list, t_tcp_node) {
if (tc->conn->c_passive)
- rds_conn_destroy(tc->conn->c_passive);
- rds_conn_destroy(tc->conn);
+ rds_conn_destroy(tc->conn->c_passive, 1);
+ rds_conn_destroy(tc->conn, 1);
}
}
sk->sk_prot->disconnect(sk, 0);
tcp_done(sk);
if (tc->conn->c_passive)
- rds_conn_destroy(tc->conn->c_passive);
- rds_conn_destroy(tc->conn);
+ rds_conn_destroy(tc->conn->c_passive, 1);
+ rds_conn_destroy(tc->conn, 1);
}
}