| From 8f0dfb3d8b1120c61f6e2cc3729290db10772b2d Mon Sep 17 00:00:00 2001 |
| From: Nicholas Bellinger <nab@linux-iscsi.org> |
| Date: Sat, 27 Feb 2016 18:15:46 -0800 |
| Subject: iscsi-target: Fix early sk_data_ready LOGIN_FLAGS_READY race |
| |
| From: Nicholas Bellinger <nab@linux-iscsi.org> |
| |
| commit 8f0dfb3d8b1120c61f6e2cc3729290db10772b2d upstream. |
| |
| There is a iscsi-target/tcp login race in LOGIN_FLAGS_READY |
| state assignment that can result in frequent errors during |
| iscsi discovery: |
| |
| "iSCSI Login negotiation failed." |
| |
| To address this bug, move the initial LOGIN_FLAGS_READY |
| assignment ahead of iscsi_target_do_login() when handling |
| the initial iscsi_target_start_negotiation() request PDU |
| during connection login. |
| |
| As iscsi_target_do_login_rx() work_struct callback is |
| clearing LOGIN_FLAGS_READ_ACTIVE after subsequent calls |
| to iscsi_target_do_login(), the early sk_data_ready |
| ahead of the first iscsi_target_do_login() expects |
| LOGIN_FLAGS_READY to also be set for the initial |
| login request PDU. |
| |
| As reported by Maged, this was first obsered using an |
| MSFT initiator running across multiple VMWare host |
| virtual machines with iscsi-target/tcp. |
| |
| Reported-by: Maged Mokhtar <mmokhtar@binarykinetics.com> |
| Tested-by: Maged Mokhtar <mmokhtar@binarykinetics.com> |
| Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| |
| --- |
| drivers/target/iscsi/iscsi_target_nego.c | 18 +++++++++--------- |
| 1 file changed, 9 insertions(+), 9 deletions(-) |
| |
| --- a/drivers/target/iscsi/iscsi_target_nego.c |
| +++ b/drivers/target/iscsi/iscsi_target_nego.c |
| @@ -1248,16 +1248,16 @@ int iscsi_target_start_negotiation( |
| { |
| int ret; |
| |
| - ret = iscsi_target_do_login(conn, login); |
| - if (!ret) { |
| - if (conn->sock) { |
| - struct sock *sk = conn->sock->sk; |
| + if (conn->sock) { |
| + struct sock *sk = conn->sock->sk; |
| |
| - write_lock_bh(&sk->sk_callback_lock); |
| - set_bit(LOGIN_FLAGS_READY, &conn->login_flags); |
| - write_unlock_bh(&sk->sk_callback_lock); |
| - } |
| - } else if (ret < 0) { |
| + write_lock_bh(&sk->sk_callback_lock); |
| + set_bit(LOGIN_FLAGS_READY, &conn->login_flags); |
| + write_unlock_bh(&sk->sk_callback_lock); |
| + } |
| + |
| + ret = iscsi_target_do_login(conn, login); |
| + if (ret < 0) { |
| cancel_delayed_work_sync(&conn->login_work); |
| cancel_delayed_work_sync(&conn->login_cleanup_work); |
| iscsi_target_restore_sock_callbacks(conn); |