From 807ae45a76457ffd67e7e6dd53725e72f610f596 Mon Sep 17 00:00:00 2001 From: Israel Rukshin Date: Wed, 17 Aug 2016 07:27:53 +0000 Subject: [PATCH] isert: fix a race between timewait exit handler and poll cq Timewait exit event handler start to close iscsi conn before poll cq finish to handle all the good completions. This may lead to NULL deref at poll cq context or post recv after post drain. This commit close iscsi conn only when start getting flush. Flush is guaranteed if iscsi conn was created because when allocating iscsi conn we call post recv. Signed-off-by: Israel Rukshin git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@6945 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- iscsi-scst/kernel/isert-scst/iser_datamover.h | 3 +- iscsi-scst/kernel/isert-scst/iser_rdma.c | 6 +- iscsi-scst/kernel/isert-scst/isert.c | 3 +- iscsi-scst/kernel/isert-scst/isert.h | 2 +- iscsi-scst/kernel/isert-scst/isert_login.c | 64 ++++++++++++------- 5 files changed, 48 insertions(+), 30 deletions(-) diff --git a/iscsi-scst/kernel/isert-scst/iser_datamover.h b/iscsi-scst/kernel/isert-scst/iser_datamover.h index 9a41dc291..6191fcd10 100644 --- a/iscsi-scst/kernel/isert-scst/iser_datamover.h +++ b/iscsi-scst/kernel/isert-scst/iser_datamover.h @@ -86,7 +86,8 @@ int isert_data_in_sent(struct iscsi_cmnd *cmd); int isert_pdu_sent(struct iscsi_cmnd *pdu); void isert_pdu_err(struct iscsi_cmnd *pdu); -int isert_connection_closed(struct iscsi_conn *iscsi_conn); +void isert_connection_closed(struct iscsi_conn *iscsi_conn); +void isert_connection_abort(struct iscsi_conn *iscsi_conn); void *isert_get_priv(struct iscsi_conn *iscsi_conn); void isert_set_priv(struct iscsi_conn *iscsi_conn, void *priv); diff --git a/iscsi-scst/kernel/isert-scst/iser_rdma.c b/iscsi-scst/kernel/isert-scst/iser_rdma.c index 0c8d11014..af33d4fa9 100644 --- a/iscsi-scst/kernel/isert-scst/iser_rdma.c +++ b/iscsi-scst/kernel/isert-scst/iser_rdma.c @@ -610,8 +610,7 @@ static void isert_conn_closed_do_work(struct work_struct *work) #endif if (!test_bit(ISERT_CONNECTION_ABORTED, &isert_conn->flags)) - if (!test_and_set_bit(ISERT_DISCON_CALLED, &isert_conn->flags)) - isert_connection_closed(&isert_conn->iscsi); + isert_connection_abort(&isert_conn->iscsi); /* if connection established we have another refcount */ if (test_bit(ISERT_CONNECTION_EST, &isert_conn->flags)) { @@ -1657,9 +1656,8 @@ static int isert_cm_evt_handler(struct rdma_cm_id *cm_id, break; case RDMA_CM_EVENT_DEVICE_REMOVAL: - isert_cm_disconnect_handler(cm_id, cm_ev); - /* fallthrough */ case RDMA_CM_EVENT_TIMEWAIT_EXIT: + isert_cm_disconnect_handler(cm_id, cm_ev); err = isert_cm_timewait_exit_handler(cm_id, cm_ev); break; diff --git a/iscsi-scst/kernel/isert-scst/isert.c b/iscsi-scst/kernel/isert-scst/isert.c index c0562e379..4d51073f8 100644 --- a/iscsi-scst/kernel/isert-scst/isert.c +++ b/iscsi-scst/kernel/isert-scst/isert.c @@ -288,7 +288,7 @@ static void isert_free_conn(struct iscsi_conn *conn) isert_free_connection(conn); } -int isert_handle_close_connection(struct iscsi_conn *conn) +void isert_handle_close_connection(struct iscsi_conn *conn) { isert_mark_conn_closed(conn, 0); /* @@ -300,7 +300,6 @@ int isert_handle_close_connection(struct iscsi_conn *conn) isert_free_connection(conn); else start_close_conn(conn); - return 0; } int isert_pdu_rx(struct iscsi_cmnd *cmnd) diff --git a/iscsi-scst/kernel/isert-scst/isert.h b/iscsi-scst/kernel/isert-scst/isert.h index 0c5113edf..d9052bd10 100644 --- a/iscsi-scst/kernel/isert-scst/isert.h +++ b/iscsi-scst/kernel/isert-scst/isert.h @@ -129,7 +129,7 @@ int isert_conn_alloc(struct iscsi_session *session, struct iscsi_kern_conn_info *info, struct iscsi_conn **new_conn, struct iscsit_transport *t); -int isert_handle_close_connection(struct iscsi_conn *conn); +void isert_handle_close_connection(struct iscsi_conn *conn); void isert_close_all_portals(void); void isert_del_timer(struct isert_conn_dev *dev); diff --git a/iscsi-scst/kernel/isert-scst/isert_login.c b/iscsi-scst/kernel/isert-scst/isert_login.c index cfce8f744..1a780949d 100644 --- a/iscsi-scst/kernel/isert-scst/isert_login.c +++ b/iscsi-scst/kernel/isert-scst/isert_login.c @@ -49,6 +49,7 @@ #include "isert_dbg.h" #include "../iscsi.h" #include "isert.h" +#include "iser.h" #include "iser_datamover.h" static DEFINE_MUTEX(conn_mgmt_mutex); @@ -444,41 +445,60 @@ int isert_conn_established(struct iscsi_conn *iscsi_conn, return add_new_connection(&isert_listen_dev, iscsi_conn); } -int isert_connection_closed(struct iscsi_conn *iscsi_conn) +static void isert_dev_disconnect(struct iscsi_conn* iscsi_conn) { - int res = 0; + struct isert_conn_dev* dev = isert_get_priv(iscsi_conn); + if (dev) { + isert_del_timer(dev); + dev->state = CS_DISCONNECTED; + if (dev->login_req) { + isert_task_abort(dev->login_req); + spin_lock(&dev->pdu_lock); + dev->login_req = NULL; + spin_unlock(&dev->pdu_lock); + } + wake_up(&dev->waitqueue); + isert_dev_release(dev); + isert_set_priv(iscsi_conn, NULL); + } +} + +void isert_connection_closed(struct iscsi_conn *iscsi_conn) +{ TRACE_ENTRY(); mutex_lock(&conn_mgmt_mutex); if (iscsi_conn->rd_state) { mutex_unlock(&conn_mgmt_mutex); - res = isert_handle_close_connection(iscsi_conn); + isert_handle_close_connection(iscsi_conn); } else { - struct isert_conn_dev *dev = isert_get_priv(iscsi_conn); - - if (dev) { - isert_del_timer(dev); - dev->state = CS_DISCONNECTED; - if (dev->login_req) { - res = isert_task_abort(dev->login_req); - spin_lock(&dev->pdu_lock); - dev->login_req = NULL; - spin_unlock(&dev->pdu_lock); - } - - wake_up(&dev->waitqueue); - isert_dev_release(dev); - isert_set_priv(iscsi_conn, NULL); - } - + isert_dev_disconnect(iscsi_conn); mutex_unlock(&conn_mgmt_mutex); isert_free_connection(iscsi_conn); } - TRACE_EXIT_RES(res); - return res; + TRACE_EXIT(); +} + +void isert_connection_abort(struct iscsi_conn *iscsi_conn) +{ + struct isert_connection *isert_conn = (struct isert_connection *)iscsi_conn; + + TRACE_ENTRY(); + + mutex_lock(&conn_mgmt_mutex); + + if (!iscsi_conn->rd_state) { + if (!test_and_set_bit(ISERT_DISCON_CALLED, &isert_conn->flags)) { + isert_dev_disconnect(iscsi_conn); + isert_free_connection(iscsi_conn); + } + } + mutex_unlock(&conn_mgmt_mutex); + + TRACE_EXIT(); } static bool will_read_block(struct isert_conn_dev *dev)