Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 523eeac6 authored by Hannes Reinecke's avatar Hannes Reinecke Committed by James Bottomley
Browse files

[SCSI] iscsi_tcp: Evaluate socket state in data_ready()



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: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarMike Christie <michaelc@cs.wisc.edu>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent ac280b67
Loading
Loading
Loading
Loading
+25 −3
Original line number Diff line number Diff line
@@ -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 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;

	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);
	}

	read_unlock(&sk->sk_callback_lock);

	/* If we had to (atomically) map a highmem page,
@@ -137,9 +161,7 @@ static void iscsi_sw_tcp_state_change(struct sock *sk)
	conn = (struct iscsi_conn*)sk->sk_user_data;
	session = conn->session;

	if ((sk->sk_state == TCP_CLOSE_WAIT ||
	     sk->sk_state == TCP_CLOSE) &&
	    !atomic_read(&sk->sk_rmem_alloc)) {
	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);