Hannes Reinecke wrote:
> 
> The network core will call the state_change() callback
> prior to the data_ready() callback, which might cause
> us to lose a connection state change.
> So we have to evaluate the socket state at the end
> of the data_ready() callback, too.
> 
> Signed-off-by: Hannes Reinecke <h...@suse.de>
> ---
>  drivers/scsi/iscsi_tcp.c |   28 +++++++++++++++++++++++++---
>  1 files changed, 25 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
> index f02ddf8..c330bdf 100644
> --- a/drivers/scsi/iscsi_tcp.c
> +++ b/drivers/scsi/iscsi_tcp.c
> @@ -99,6 +99,24 @@ static int iscsi_sw_tcp_recv(read_descriptor_t *rd_desc, 
> struct sk_buff *skb,
>       return total_consumed;
>  }
>  
> +/**
> + * iscsi_sw_sk_state_check - check socket state
> + * @sk: socket
> + *
> + * If the socket is in CLOSE or CLOSE_WAIT we should
> + * not close the connection if there is still some
> + * data pending.
> + */
> +static inline void iscsi_sw_sk_state_check(struct sock *sk)
> +{
> +     if ((sk->sk_state == TCP_CLOSE_WAIT ||
> +          sk->sk_state == TCP_CLOSE) &&
> +         !atomic_read(&sk->sk_rmem_alloc))
> +             return -ECONNRESET;
> +
> +     return 0;
> +}
> +
>  static void iscsi_sw_tcp_data_ready(struct sock *sk, int flag)
>  {
>       struct iscsi_conn *conn = sk->sk_user_data;
> @@ -117,6 +135,12 @@ static void iscsi_sw_tcp_data_ready(struct sock *sk, int 
> flag)
>       rd_desc.count = 1;
>       tcp_read_sock(sk, &rd_desc, iscsi_sw_tcp_recv);
>  
> +     if (iscsi_sw_sk_state_check(sk) < 0) {
> +             ISCSI_SW_TCP_DBG(conn, "iscsi_tcp_data_ready: "
> +                              "TCP_CLOSE|TCP_CLOSE_WAIT\n");
> +             iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
> +     }
> +

I fixed the return value compile error with the patch, and I want to 
also do the attached patch.

The problem is that with some targets it seems we can get the logout 
response in that last bit of data, so we hit this and throw a conn 
error. The conn error is harmless (iscsid might complain but it will 
just drop it), but I want to make sure that I can distinguish between a 
real conn error and this situation. Also in general it is nice to know 
if there is a problem due to a state change so we can differentiate it 
from the 1011 err value.


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"open-iscsi" group.
To post to this group, send email to open-iscsi@googlegroups.com
To unsubscribe from this group, send email to 
open-iscsi+unsubscr...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/open-iscsi
-~----------~----~----~----~------~----~------~--~---

diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 4160167..d00257e 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -109,11 +109,14 @@ static int iscsi_sw_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
  */
 static inline int iscsi_sw_sk_state_check(struct sock *sk)
 {
-	if ((sk->sk_state == TCP_CLOSE_WAIT ||
-	     sk->sk_state == TCP_CLOSE) &&
-	    !atomic_read(&sk->sk_rmem_alloc))
-		return -ECONNRESET;
+	struct iscsi_conn *conn = (struct iscsi_conn*)sk->sk_user_data;
 
+	if ((sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) &&
+	    !atomic_read(&sk->sk_rmem_alloc)) {
+		ISCSI_SW_TCP_DBG(conn, "TCP_CLOSE|TCP_CLOSE_WAIT\n");
+		iscsi_conn_failure(conn, ISCSI_ERR_TCP_CONN_CLOSE);
+		return -ECONNRESET;
+	}
 	return 0;
 }
 
@@ -135,11 +138,7 @@ static void iscsi_sw_tcp_data_ready(struct sock *sk, int flag)
 	rd_desc.count = 1;
 	tcp_read_sock(sk, &rd_desc, iscsi_sw_tcp_recv);
 
-	if (iscsi_sw_sk_state_check(sk) < 0) {
-		ISCSI_SW_TCP_DBG(conn, "iscsi_tcp_data_ready: "
-				 "TCP_CLOSE|TCP_CLOSE_WAIT\n");
-		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-	}
+	iscsi_sw_sk_state_check(sk);
 
 	read_unlock(&sk->sk_callback_lock);
 
@@ -161,11 +160,7 @@ static void iscsi_sw_tcp_state_change(struct sock *sk)
 	conn = (struct iscsi_conn*)sk->sk_user_data;
 	session = conn->session;
 
-	if (iscsi_sw_sk_state_check(sk) < 0) {
-		ISCSI_SW_TCP_DBG(conn, "iscsi_tcp_state_change: "
-				 "TCP_CLOSE|TCP_CLOSE_WAIT\n");
-		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-	}
+	iscsi_sw_sk_state_check(sk);
 
 	tcp_conn = conn->dd_data;
 	tcp_sw_conn = tcp_conn->dd_data;
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index 4426f00..d67dda2 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -262,6 +262,7 @@ enum iscsi_err {
 	ISCSI_ERR_NO_SCSI_CMD		= ISCSI_ERR_BASE + 17,
 	ISCSI_ERR_INVALID_HOST		= ISCSI_ERR_BASE + 18,
 	ISCSI_ERR_XMIT_FAILED		= ISCSI_ERR_BASE + 19,
+	ISCSI_ERR_TCP_CONN_CLOSE	= ISCSI_ERR_BASE + 20,
 };
 
 /*

Reply via email to