Skip to content

DLPX-84985 target: iscsi: fix deadlock in the iSCSI login code #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/target/iscsi/iscsi_target_login.c
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,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;
Expand Down
50 changes: 18 additions & 32 deletions drivers/target/iscsi/iscsi_target_nego.c
Original file line number Diff line number Diff line change
Expand Up @@ -479,12 +479,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,"
"returning FALSE\n");
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)
Expand Down Expand Up @@ -542,25 +548,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,
Expand All @@ -569,7 +556,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;

Expand Down Expand Up @@ -607,14 +593,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;

Expand All @@ -631,6 +610,7 @@ static void iscsi_target_do_login_rx(struct work_struct *work)
if (iscsi_target_sk_check_and_clear(conn, LOGIN_FLAGS_READ_ACTIVE))
goto err;
} else if (rc == 1) {
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);
Expand All @@ -639,6 +619,7 @@ static void iscsi_target_do_login_rx(struct work_struct *work)

err:
iscsi_target_restore_sock_callbacks(conn);
iscsit_stop_login_timer(conn);
iscsi_target_login_drop(conn, login);
iscsit_deaccess_np(np, tpg, tpg_np);
}
Expand Down Expand Up @@ -1283,6 +1264,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
Expand All @@ -1301,8 +1285,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;
}
Expand Down
28 changes: 28 additions & 0 deletions drivers/target/iscsi/iscsi_target_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,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,
Expand Down
3 changes: 3 additions & 0 deletions drivers/target/iscsi/iscsi_target_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions include/target/iscsi/iscsi_target_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,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;
Expand Down