From 5784856c3576fc6fbfcca3b115f20116515575f0 Mon Sep 17 00:00:00 2001 From: Serapheim Dimitropoulos Date: Tue, 7 Mar 2023 13:37:23 -0800 Subject: [PATCH] DLPX-84985 target: iscsi: fix deadlock in the iSCSI login code (#22) --- drivers/target/iscsi/iscsi_target_login.c | 1 + drivers/target/iscsi/iscsi_target_nego.c | 48 ++++++++--------------- drivers/target/iscsi/iscsi_target_util.c | 28 +++++++++++++ drivers/target/iscsi/iscsi_target_util.h | 3 ++ include/target/iscsi/iscsi_target_core.h | 1 + 5 files changed, 50 insertions(+), 31 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 6fe44a31161cf..628d3eb5360e3 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -1117,6 +1117,7 @@ static struct iscsi_conn *iscsit_alloc_conn(struct iscsi_np *np) timer_setup(&conn->nopin_response_timer, iscsit_handle_nopin_response_timeout, 0); timer_setup(&conn->nopin_timer, iscsit_handle_nopin_timeout, 0); + timer_setup(&conn->login_timer, iscsit_login_timeout, 0); if (iscsit_conn_set_transport(conn, np->np_transport) < 0) goto free_conn; diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 5435f2b945d3c..1d360f213e98c 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -471,12 +471,18 @@ static int iscsi_target_do_login(struct iscsi_conn *, struct iscsi_login *); static bool __iscsi_target_sk_check_close(struct sock *sk) { - if (sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) { - pr_debug("__iscsi_target_sk_check_close: TCP_CLOSE_WAIT|TCP_CLOSE," + switch (sk->sk_state) { + case TCP_FIN_WAIT1: + case TCP_FIN_WAIT2: + case TCP_CLOSE_WAIT: + case TCP_LAST_ACK: + case TCP_CLOSE: + pr_debug("__iscsi_target_sk_check_close: socket closing," "returning TRUE\n"); return true; + default: + return false; } - return false; } static bool iscsi_target_sk_check_close(struct iscsi_conn *conn) @@ -534,25 +540,6 @@ static void iscsi_target_login_drop(struct iscsi_conn *conn, struct iscsi_login iscsi_target_login_sess_out(conn, zero_tsih, true); } -struct conn_timeout { - struct timer_list timer; - struct iscsi_conn *conn; -}; - -static void iscsi_target_login_timeout(struct timer_list *t) -{ - struct conn_timeout *timeout = from_timer(timeout, t, timer); - struct iscsi_conn *conn = timeout->conn; - - pr_debug("Entering iscsi_target_login_timeout >>>>>>>>>>>>>>>>>>>\n"); - - if (conn->login_kworker) { - pr_debug("Sending SIGINT to conn->login_kworker %s/%d\n", - conn->login_kworker->comm, conn->login_kworker->pid); - send_sig(SIGINT, conn->login_kworker, 1); - } -} - static void iscsi_target_do_login_rx(struct work_struct *work) { struct iscsi_conn *conn = container_of(work, @@ -561,7 +548,6 @@ static void iscsi_target_do_login_rx(struct work_struct *work) struct iscsi_np *np = login->np; struct iscsi_portal_group *tpg = conn->tpg; struct iscsi_tpg_np *tpg_np = conn->tpg_np; - struct conn_timeout timeout; int rc, zero_tsih = login->zero_tsih; bool state; @@ -599,14 +585,7 @@ static void iscsi_target_do_login_rx(struct work_struct *work) conn->login_kworker = current; allow_signal(SIGINT); - timeout.conn = conn; - timer_setup_on_stack(&timeout.timer, iscsi_target_login_timeout, 0); - mod_timer(&timeout.timer, jiffies + TA_LOGIN_TIMEOUT * HZ); - pr_debug("Starting login timer for %s/%d\n", current->comm, current->pid); - rc = conn->conn_transport->iscsit_get_login_rx(conn, login); - del_timer_sync(&timeout.timer); - destroy_timer_on_stack(&timeout.timer); flush_signals(current); conn->login_kworker = NULL; @@ -647,6 +626,7 @@ static void iscsi_target_do_login_rx(struct work_struct *work) goto err; } else if (rc == 1) { cancel_delayed_work(&conn->login_work); + iscsit_stop_login_timer(conn); iscsi_target_nego_release(conn); iscsi_post_login_handler(np, conn, zero_tsih); iscsit_deaccess_np(np, tpg, tpg_np); @@ -656,6 +636,7 @@ static void iscsi_target_do_login_rx(struct work_struct *work) err: iscsi_target_restore_sock_callbacks(conn); cancel_delayed_work(&conn->login_work); + iscsit_stop_login_timer(conn); iscsi_target_login_drop(conn, login); iscsit_deaccess_np(np, tpg, tpg_np); } @@ -1301,6 +1282,9 @@ int iscsi_target_start_negotiation( set_bit(LOGIN_FLAGS_INITIAL_PDU, &conn->login_flags); write_unlock_bh(&sk->sk_callback_lock); } + + iscsit_start_login_timer(conn); + /* * If iscsi_target_do_login returns zero to signal more PDU * exchanges are required to complete the login, go ahead and @@ -1319,8 +1303,10 @@ int iscsi_target_start_negotiation( iscsi_target_restore_sock_callbacks(conn); iscsi_remove_failed_auth_entry(conn); } - if (ret != 0) + if (ret != 0) { + iscsit_stop_login_timer(conn); iscsi_target_nego_release(conn); + } return ret; } diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 6dd5810e2af16..799d3f34a34f0 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -1040,6 +1040,34 @@ void iscsit_stop_nopin_timer(struct iscsi_conn *conn) spin_unlock_bh(&conn->nopin_timer_lock); } +void iscsit_login_timeout(struct timer_list *t) +{ + struct iscsi_conn *conn = from_timer(conn, t, login_timer); + + pr_debug("Entering iscsi_target_login_timeout >>>>>>>>>>>>>>>>>>>\n"); + + if (conn->login_kworker) { + pr_debug("Sending SIGINT to conn->login_kworker %s/%d\n", + conn->login_kworker->comm, conn->login_kworker->pid); + send_sig(SIGINT, conn->login_kworker, 1); + } else { + pr_debug("Shutting down the socket.\n"); + kernel_sock_shutdown(conn->sock, SHUT_RDWR); + } +} + +void iscsit_start_login_timer(struct iscsi_conn *conn) +{ + pr_debug("Login timer started\n"); + mod_timer(&conn->login_timer, jiffies + TA_LOGIN_TIMEOUT * HZ); +} + +void iscsit_stop_login_timer(struct iscsi_conn *conn) +{ + pr_debug("Login timer stopped\n"); + del_timer_sync(&conn->login_timer); +} + int iscsit_send_tx_data( struct iscsi_cmd *cmd, struct iscsi_conn *conn, diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h index 8ee1c133a9b7b..3246caa7fa9b8 100644 --- a/drivers/target/iscsi/iscsi_target_util.h +++ b/drivers/target/iscsi/iscsi_target_util.h @@ -56,6 +56,9 @@ extern void iscsit_handle_nopin_timeout(struct timer_list *t); extern void __iscsit_start_nopin_timer(struct iscsi_conn *); extern void iscsit_start_nopin_timer(struct iscsi_conn *); extern void iscsit_stop_nopin_timer(struct iscsi_conn *); +extern void iscsit_login_timeout(struct timer_list *t); +extern void iscsit_start_login_timer(struct iscsi_conn *); +extern void iscsit_stop_login_timer(struct iscsi_conn *); extern int iscsit_send_tx_data(struct iscsi_cmd *, struct iscsi_conn *, int); extern int iscsit_fe_sendpage_sg(struct iscsi_cmd *, struct iscsi_conn *); extern int iscsit_tx_login_rsp(struct iscsi_conn *, u8, u8); diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index 853e9be511c51..d4271744396e8 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -568,6 +568,7 @@ struct iscsi_conn { struct timer_list nopin_timer; struct timer_list nopin_response_timer; struct timer_list transport_timer; + struct timer_list login_timer; struct task_struct *login_kworker; /* Spinlock used for add/deleting cmd's from conn_cmd_list */ spinlock_t cmd_lock;