提交 505f76b3 编写于 作者: T Tony Battersby 提交者: James Bottomley

[SCSI] iscsi_tcp: fix potential lockup with write commands

There is a race condition in iscsi_tcp.c that may cause it to forget
that it received a R2T from the target.  This race may cause a data-out
command (such as a write) to lock up.  The race occurs here:

static int
iscsi_send_unsol_pdu(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
{
	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
	int rc;

	if (tcp_ctask->xmstate & XMSTATE_UNS_HDR) {
		BUG_ON(!ctask->unsol_count);
		tcp_ctask->xmstate &= ~XMSTATE_UNS_HDR; <---- RACE
		...

static int
iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
{
	...
	tcp_ctask->xmstate |= XMSTATE_SOL_HDR_INIT; <---- RACE
	...

While iscsi_xmitworker() (called from scsi_queue_work()) is preparing to
send unsolicited data, iscsi_tcp_data_recv() (called from
tcp_read_sock()) interrupts it upon receipt of a R2T from the target.
Both contexts do read-modify-write of tcp_ctask->xmstate.  Usually, gcc
on x86 will make &= and |= atomic on UP (not guaranteed of course), but
in this case iscsi_send_unsol_pdu() reads the value of xmstate before
clearing the bit, which causes gcc to read xmstate into a CPU register,
test it, clear the bit, and then store it back to memory.  If the recv
interrupt happens during this sequence, then the XMSTATE_SOL_HDR_INIT
bit set by the recv interrupt will be lost, and the R2T will be
forgotten.

The patch below (against 2.6.24-rc1) converts accesses of xmstate to use
set_bit, clear_bit, and test_bit instead of |= and &=.  I have tested
this patch and verified that it fixes the problem.  Another possible
approach would be to hold a lock during most of the rx/tx setup and
post-processing, and drop the lock only for the actual rx/tx.
Signed-off-by: NTony Battersby <tonyb@cybernetics.com>
Signed-off-by: NMike Christie <michaelc@cs.wisc.edu>
Signed-off-by: NJames Bottomley <James.Bottomley@HansenPartnership.com>
上级 5f78e89b
...@@ -197,7 +197,7 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) ...@@ -197,7 +197,7 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
if (unlikely(!sc)) if (unlikely(!sc))
return; return;
tcp_ctask->xmstate = XMSTATE_IDLE; tcp_ctask->xmstate = XMSTATE_VALUE_IDLE;
tcp_ctask->r2t = NULL; tcp_ctask->r2t = NULL;
} }
...@@ -409,7 +409,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) ...@@ -409,7 +409,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
tcp_ctask->exp_datasn = r2tsn + 1; tcp_ctask->exp_datasn = r2tsn + 1;
__kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*)); __kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*));
tcp_ctask->xmstate |= XMSTATE_SOL_HDR_INIT; set_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate);
list_move_tail(&ctask->running, &conn->xmitqueue); list_move_tail(&ctask->running, &conn->xmitqueue);
scsi_queue_work(session->host, &conn->xmitwork); scsi_queue_work(session->host, &conn->xmitwork);
...@@ -1254,7 +1254,7 @@ static void iscsi_set_padding(struct iscsi_tcp_cmd_task *tcp_ctask, ...@@ -1254,7 +1254,7 @@ static void iscsi_set_padding(struct iscsi_tcp_cmd_task *tcp_ctask,
tcp_ctask->pad_count = ISCSI_PAD_LEN - tcp_ctask->pad_count; tcp_ctask->pad_count = ISCSI_PAD_LEN - tcp_ctask->pad_count;
debug_scsi("write padding %d bytes\n", tcp_ctask->pad_count); debug_scsi("write padding %d bytes\n", tcp_ctask->pad_count);
tcp_ctask->xmstate |= XMSTATE_W_PAD; set_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate);
} }
/** /**
...@@ -1269,7 +1269,7 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask) ...@@ -1269,7 +1269,7 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask)
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
BUG_ON(__kfifo_len(tcp_ctask->r2tqueue)); BUG_ON(__kfifo_len(tcp_ctask->r2tqueue));
tcp_ctask->xmstate = XMSTATE_CMD_HDR_INIT; tcp_ctask->xmstate = 1 << XMSTATE_BIT_CMD_HDR_INIT;
} }
/** /**
...@@ -1283,10 +1283,10 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask) ...@@ -1283,10 +1283,10 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask)
* xmit. * xmit.
* *
* Management xmit state machine consists of these states: * Management xmit state machine consists of these states:
* XMSTATE_IMM_HDR_INIT - calculate digest of PDU Header * XMSTATE_BIT_IMM_HDR_INIT - calculate digest of PDU Header
* XMSTATE_IMM_HDR - PDU Header xmit in progress * XMSTATE_BIT_IMM_HDR - PDU Header xmit in progress
* XMSTATE_IMM_DATA - PDU Data xmit in progress * XMSTATE_BIT_IMM_DATA - PDU Data xmit in progress
* XMSTATE_IDLE - management PDU is done * XMSTATE_VALUE_IDLE - management PDU is done
**/ **/
static int static int
iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
...@@ -1297,12 +1297,12 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) ...@@ -1297,12 +1297,12 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
debug_scsi("mtask deq [cid %d state %x itt 0x%x]\n", debug_scsi("mtask deq [cid %d state %x itt 0x%x]\n",
conn->id, tcp_mtask->xmstate, mtask->itt); conn->id, tcp_mtask->xmstate, mtask->itt);
if (tcp_mtask->xmstate & XMSTATE_IMM_HDR_INIT) { if (test_bit(XMSTATE_BIT_IMM_HDR_INIT, &tcp_mtask->xmstate)) {
iscsi_buf_init_iov(&tcp_mtask->headbuf, (char*)mtask->hdr, iscsi_buf_init_iov(&tcp_mtask->headbuf, (char*)mtask->hdr,
sizeof(struct iscsi_hdr)); sizeof(struct iscsi_hdr));
if (mtask->data_count) { if (mtask->data_count) {
tcp_mtask->xmstate |= XMSTATE_IMM_DATA; set_bit(XMSTATE_BIT_IMM_DATA, &tcp_mtask->xmstate);
iscsi_buf_init_iov(&tcp_mtask->sendbuf, iscsi_buf_init_iov(&tcp_mtask->sendbuf,
(char*)mtask->data, (char*)mtask->data,
mtask->data_count); mtask->data_count);
...@@ -1315,21 +1315,20 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) ...@@ -1315,21 +1315,20 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
(u8*)tcp_mtask->hdrext); (u8*)tcp_mtask->hdrext);
tcp_mtask->sent = 0; tcp_mtask->sent = 0;
tcp_mtask->xmstate &= ~XMSTATE_IMM_HDR_INIT; clear_bit(XMSTATE_BIT_IMM_HDR_INIT, &tcp_mtask->xmstate);
tcp_mtask->xmstate |= XMSTATE_IMM_HDR; set_bit(XMSTATE_BIT_IMM_HDR, &tcp_mtask->xmstate);
} }
if (tcp_mtask->xmstate & XMSTATE_IMM_HDR) { if (test_bit(XMSTATE_BIT_IMM_HDR, &tcp_mtask->xmstate)) {
rc = iscsi_sendhdr(conn, &tcp_mtask->headbuf, rc = iscsi_sendhdr(conn, &tcp_mtask->headbuf,
mtask->data_count); mtask->data_count);
if (rc) if (rc)
return rc; return rc;
tcp_mtask->xmstate &= ~XMSTATE_IMM_HDR; clear_bit(XMSTATE_BIT_IMM_HDR, &tcp_mtask->xmstate);
} }
if (tcp_mtask->xmstate & XMSTATE_IMM_DATA) { if (test_and_clear_bit(XMSTATE_BIT_IMM_DATA, &tcp_mtask->xmstate)) {
BUG_ON(!mtask->data_count); BUG_ON(!mtask->data_count);
tcp_mtask->xmstate &= ~XMSTATE_IMM_DATA;
/* FIXME: implement. /* FIXME: implement.
* Virtual buffer could be spreaded across multiple pages... * Virtual buffer could be spreaded across multiple pages...
*/ */
...@@ -1339,13 +1338,13 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) ...@@ -1339,13 +1338,13 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
rc = iscsi_sendpage(conn, &tcp_mtask->sendbuf, rc = iscsi_sendpage(conn, &tcp_mtask->sendbuf,
&mtask->data_count, &tcp_mtask->sent); &mtask->data_count, &tcp_mtask->sent);
if (rc) { if (rc) {
tcp_mtask->xmstate |= XMSTATE_IMM_DATA; set_bit(XMSTATE_BIT_IMM_DATA, &tcp_mtask->xmstate);
return rc; return rc;
} }
} while (mtask->data_count); } while (mtask->data_count);
} }
BUG_ON(tcp_mtask->xmstate != XMSTATE_IDLE); BUG_ON(tcp_mtask->xmstate != XMSTATE_VALUE_IDLE);
if (mtask->hdr->itt == RESERVED_ITT) { if (mtask->hdr->itt == RESERVED_ITT) {
struct iscsi_session *session = conn->session; struct iscsi_session *session = conn->session;
...@@ -1365,7 +1364,7 @@ iscsi_send_cmd_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) ...@@ -1365,7 +1364,7 @@ iscsi_send_cmd_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
int rc = 0; int rc = 0;
if (tcp_ctask->xmstate & XMSTATE_CMD_HDR_INIT) { if (test_bit(XMSTATE_BIT_CMD_HDR_INIT, &tcp_ctask->xmstate)) {
tcp_ctask->sent = 0; tcp_ctask->sent = 0;
tcp_ctask->sg_count = 0; tcp_ctask->sg_count = 0;
tcp_ctask->exp_datasn = 0; tcp_ctask->exp_datasn = 0;
...@@ -1390,21 +1389,21 @@ iscsi_send_cmd_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) ...@@ -1390,21 +1389,21 @@ iscsi_send_cmd_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
if (conn->hdrdgst_en) if (conn->hdrdgst_en)
iscsi_hdr_digest(conn, &tcp_ctask->headbuf, iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
(u8*)tcp_ctask->hdrext); (u8*)tcp_ctask->hdrext);
tcp_ctask->xmstate &= ~XMSTATE_CMD_HDR_INIT; clear_bit(XMSTATE_BIT_CMD_HDR_INIT, &tcp_ctask->xmstate);
tcp_ctask->xmstate |= XMSTATE_CMD_HDR_XMIT; set_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate);
} }
if (tcp_ctask->xmstate & XMSTATE_CMD_HDR_XMIT) { if (test_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate)) {
rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count); rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count);
if (rc) if (rc)
return rc; return rc;
tcp_ctask->xmstate &= ~XMSTATE_CMD_HDR_XMIT; clear_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate);
if (sc->sc_data_direction != DMA_TO_DEVICE) if (sc->sc_data_direction != DMA_TO_DEVICE)
return 0; return 0;
if (ctask->imm_count) { if (ctask->imm_count) {
tcp_ctask->xmstate |= XMSTATE_IMM_DATA; set_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate);
iscsi_set_padding(tcp_ctask, ctask->imm_count); iscsi_set_padding(tcp_ctask, ctask->imm_count);
if (ctask->conn->datadgst_en) { if (ctask->conn->datadgst_en) {
...@@ -1414,9 +1413,10 @@ iscsi_send_cmd_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) ...@@ -1414,9 +1413,10 @@ iscsi_send_cmd_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
} }
} }
if (ctask->unsol_count) if (ctask->unsol_count) {
tcp_ctask->xmstate |= set_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate);
XMSTATE_UNS_HDR | XMSTATE_UNS_INIT; set_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate);
}
} }
return rc; return rc;
} }
...@@ -1428,25 +1428,25 @@ iscsi_send_padding(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) ...@@ -1428,25 +1428,25 @@ iscsi_send_padding(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
int sent = 0, rc; int sent = 0, rc;
if (tcp_ctask->xmstate & XMSTATE_W_PAD) { if (test_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate)) {
iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad, iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad,
tcp_ctask->pad_count); tcp_ctask->pad_count);
if (conn->datadgst_en) if (conn->datadgst_en)
crypto_hash_update(&tcp_conn->tx_hash, crypto_hash_update(&tcp_conn->tx_hash,
&tcp_ctask->sendbuf.sg, &tcp_ctask->sendbuf.sg,
tcp_ctask->sendbuf.sg.length); tcp_ctask->sendbuf.sg.length);
} else if (!(tcp_ctask->xmstate & XMSTATE_W_RESEND_PAD)) } else if (!test_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate))
return 0; return 0;
tcp_ctask->xmstate &= ~XMSTATE_W_PAD; clear_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate);
tcp_ctask->xmstate &= ~XMSTATE_W_RESEND_PAD; clear_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate);
debug_scsi("sending %d pad bytes for itt 0x%x\n", debug_scsi("sending %d pad bytes for itt 0x%x\n",
tcp_ctask->pad_count, ctask->itt); tcp_ctask->pad_count, ctask->itt);
rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count, rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count,
&sent); &sent);
if (rc) { if (rc) {
debug_scsi("padding send failed %d\n", rc); debug_scsi("padding send failed %d\n", rc);
tcp_ctask->xmstate |= XMSTATE_W_RESEND_PAD; set_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate);
} }
return rc; return rc;
} }
...@@ -1465,11 +1465,11 @@ iscsi_send_digest(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, ...@@ -1465,11 +1465,11 @@ iscsi_send_digest(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
tcp_ctask = ctask->dd_data; tcp_ctask = ctask->dd_data;
tcp_conn = conn->dd_data; tcp_conn = conn->dd_data;
if (!(tcp_ctask->xmstate & XMSTATE_W_RESEND_DATA_DIGEST)) { if (!test_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate)) {
crypto_hash_final(&tcp_conn->tx_hash, (u8*)digest); crypto_hash_final(&tcp_conn->tx_hash, (u8*)digest);
iscsi_buf_init_iov(buf, (char*)digest, 4); iscsi_buf_init_iov(buf, (char*)digest, 4);
} }
tcp_ctask->xmstate &= ~XMSTATE_W_RESEND_DATA_DIGEST; clear_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate);
rc = iscsi_sendpage(conn, buf, &tcp_ctask->digest_count, &sent); rc = iscsi_sendpage(conn, buf, &tcp_ctask->digest_count, &sent);
if (!rc) if (!rc)
...@@ -1478,7 +1478,7 @@ iscsi_send_digest(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, ...@@ -1478,7 +1478,7 @@ iscsi_send_digest(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
else { else {
debug_scsi("sending digest 0x%x failed for itt 0x%x!\n", debug_scsi("sending digest 0x%x failed for itt 0x%x!\n",
*digest, ctask->itt); *digest, ctask->itt);
tcp_ctask->xmstate |= XMSTATE_W_RESEND_DATA_DIGEST; set_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate);
} }
return rc; return rc;
} }
...@@ -1526,8 +1526,8 @@ iscsi_send_unsol_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) ...@@ -1526,8 +1526,8 @@ iscsi_send_unsol_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
struct iscsi_data_task *dtask; struct iscsi_data_task *dtask;
int rc; int rc;
tcp_ctask->xmstate |= XMSTATE_UNS_DATA; set_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate);
if (tcp_ctask->xmstate & XMSTATE_UNS_INIT) { if (test_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate)) {
dtask = &tcp_ctask->unsol_dtask; dtask = &tcp_ctask->unsol_dtask;
iscsi_prep_unsolicit_data_pdu(ctask, &dtask->hdr); iscsi_prep_unsolicit_data_pdu(ctask, &dtask->hdr);
...@@ -1537,14 +1537,14 @@ iscsi_send_unsol_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) ...@@ -1537,14 +1537,14 @@ iscsi_send_unsol_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
iscsi_hdr_digest(conn, &tcp_ctask->headbuf, iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
(u8*)dtask->hdrext); (u8*)dtask->hdrext);
tcp_ctask->xmstate &= ~XMSTATE_UNS_INIT; clear_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate);
iscsi_set_padding(tcp_ctask, ctask->data_count); iscsi_set_padding(tcp_ctask, ctask->data_count);
} }
rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->data_count); rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->data_count);
if (rc) { if (rc) {
tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA; clear_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate);
tcp_ctask->xmstate |= XMSTATE_UNS_HDR; set_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate);
return rc; return rc;
} }
...@@ -1565,16 +1565,15 @@ iscsi_send_unsol_pdu(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) ...@@ -1565,16 +1565,15 @@ iscsi_send_unsol_pdu(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
int rc; int rc;
if (tcp_ctask->xmstate & XMSTATE_UNS_HDR) { if (test_and_clear_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate)) {
BUG_ON(!ctask->unsol_count); BUG_ON(!ctask->unsol_count);
tcp_ctask->xmstate &= ~XMSTATE_UNS_HDR;
send_hdr: send_hdr:
rc = iscsi_send_unsol_hdr(conn, ctask); rc = iscsi_send_unsol_hdr(conn, ctask);
if (rc) if (rc)
return rc; return rc;
} }
if (tcp_ctask->xmstate & XMSTATE_UNS_DATA) { if (test_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate)) {
struct iscsi_data_task *dtask = &tcp_ctask->unsol_dtask; struct iscsi_data_task *dtask = &tcp_ctask->unsol_dtask;
int start = tcp_ctask->sent; int start = tcp_ctask->sent;
...@@ -1584,14 +1583,14 @@ iscsi_send_unsol_pdu(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) ...@@ -1584,14 +1583,14 @@ iscsi_send_unsol_pdu(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
ctask->unsol_count -= tcp_ctask->sent - start; ctask->unsol_count -= tcp_ctask->sent - start;
if (rc) if (rc)
return rc; return rc;
tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA; clear_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate);
/* /*
* Done with the Data-Out. Next, check if we need * Done with the Data-Out. Next, check if we need
* to send another unsolicited Data-Out. * to send another unsolicited Data-Out.
*/ */
if (ctask->unsol_count) { if (ctask->unsol_count) {
debug_scsi("sending more uns\n"); debug_scsi("sending more uns\n");
tcp_ctask->xmstate |= XMSTATE_UNS_INIT; set_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate);
goto send_hdr; goto send_hdr;
} }
} }
...@@ -1607,7 +1606,7 @@ static int iscsi_send_sol_pdu(struct iscsi_conn *conn, ...@@ -1607,7 +1606,7 @@ static int iscsi_send_sol_pdu(struct iscsi_conn *conn,
struct iscsi_data_task *dtask; struct iscsi_data_task *dtask;
int left, rc; int left, rc;
if (tcp_ctask->xmstate & XMSTATE_SOL_HDR_INIT) { if (test_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate)) {
if (!tcp_ctask->r2t) { if (!tcp_ctask->r2t) {
spin_lock_bh(&session->lock); spin_lock_bh(&session->lock);
__kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t, __kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t,
...@@ -1621,19 +1620,19 @@ static int iscsi_send_sol_pdu(struct iscsi_conn *conn, ...@@ -1621,19 +1620,19 @@ static int iscsi_send_sol_pdu(struct iscsi_conn *conn,
if (conn->hdrdgst_en) if (conn->hdrdgst_en)
iscsi_hdr_digest(conn, &r2t->headbuf, iscsi_hdr_digest(conn, &r2t->headbuf,
(u8*)dtask->hdrext); (u8*)dtask->hdrext);
tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR_INIT; clear_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate);
tcp_ctask->xmstate |= XMSTATE_SOL_HDR; set_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate);
} }
if (tcp_ctask->xmstate & XMSTATE_SOL_HDR) { if (test_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate)) {
r2t = tcp_ctask->r2t; r2t = tcp_ctask->r2t;
dtask = &r2t->dtask; dtask = &r2t->dtask;
rc = iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count); rc = iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count);
if (rc) if (rc)
return rc; return rc;
tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR; clear_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate);
tcp_ctask->xmstate |= XMSTATE_SOL_DATA; set_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate);
if (conn->datadgst_en) { if (conn->datadgst_en) {
iscsi_data_digest_init(conn->dd_data, tcp_ctask); iscsi_data_digest_init(conn->dd_data, tcp_ctask);
...@@ -1646,7 +1645,7 @@ static int iscsi_send_sol_pdu(struct iscsi_conn *conn, ...@@ -1646,7 +1645,7 @@ static int iscsi_send_sol_pdu(struct iscsi_conn *conn,
r2t->sent); r2t->sent);
} }
if (tcp_ctask->xmstate & XMSTATE_SOL_DATA) { if (test_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate)) {
r2t = tcp_ctask->r2t; r2t = tcp_ctask->r2t;
dtask = &r2t->dtask; dtask = &r2t->dtask;
...@@ -1655,7 +1654,7 @@ static int iscsi_send_sol_pdu(struct iscsi_conn *conn, ...@@ -1655,7 +1654,7 @@ static int iscsi_send_sol_pdu(struct iscsi_conn *conn,
&dtask->digestbuf, &dtask->digest); &dtask->digestbuf, &dtask->digest);
if (rc) if (rc)
return rc; return rc;
tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA; clear_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate);
/* /*
* Done with this Data-Out. Next, check if we have * Done with this Data-Out. Next, check if we have
...@@ -1700,32 +1699,32 @@ static int iscsi_send_sol_pdu(struct iscsi_conn *conn, ...@@ -1700,32 +1699,32 @@ static int iscsi_send_sol_pdu(struct iscsi_conn *conn,
* xmit stages. * xmit stages.
* *
*iscsi_send_cmd_hdr() *iscsi_send_cmd_hdr()
* XMSTATE_CMD_HDR_INIT - prepare Header and Data buffers Calculate * XMSTATE_BIT_CMD_HDR_INIT - prepare Header and Data buffers Calculate
* Header Digest * Header Digest
* XMSTATE_CMD_HDR_XMIT - Transmit header in progress * XMSTATE_BIT_CMD_HDR_XMIT - Transmit header in progress
* *
*iscsi_send_padding *iscsi_send_padding
* XMSTATE_W_PAD - Prepare and send pading * XMSTATE_BIT_W_PAD - Prepare and send pading
* XMSTATE_W_RESEND_PAD - retry send pading * XMSTATE_BIT_W_RESEND_PAD - retry send pading
* *
*iscsi_send_digest *iscsi_send_digest
* XMSTATE_W_RESEND_DATA_DIGEST - Finalize and send Data Digest * XMSTATE_BIT_W_RESEND_DATA_DIGEST - Finalize and send Data Digest
* XMSTATE_W_RESEND_DATA_DIGEST - retry sending digest * XMSTATE_BIT_W_RESEND_DATA_DIGEST - retry sending digest
* *
*iscsi_send_unsol_hdr *iscsi_send_unsol_hdr
* XMSTATE_UNS_INIT - prepare un-solicit data header and digest * XMSTATE_BIT_UNS_INIT - prepare un-solicit data header and digest
* XMSTATE_UNS_HDR - send un-solicit header * XMSTATE_BIT_UNS_HDR - send un-solicit header
* *
*iscsi_send_unsol_pdu *iscsi_send_unsol_pdu
* XMSTATE_UNS_DATA - send un-solicit data in progress * XMSTATE_BIT_UNS_DATA - send un-solicit data in progress
* *
*iscsi_send_sol_pdu *iscsi_send_sol_pdu
* XMSTATE_SOL_HDR_INIT - solicit data header and digest initialize * XMSTATE_BIT_SOL_HDR_INIT - solicit data header and digest initialize
* XMSTATE_SOL_HDR - send solicit header * XMSTATE_BIT_SOL_HDR - send solicit header
* XMSTATE_SOL_DATA - send solicit data * XMSTATE_BIT_SOL_DATA - send solicit data
* *
*iscsi_tcp_ctask_xmit *iscsi_tcp_ctask_xmit
* XMSTATE_IMM_DATA - xmit managment data (??) * XMSTATE_BIT_IMM_DATA - xmit managment data (??)
**/ **/
static int static int
iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
...@@ -1742,13 +1741,13 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) ...@@ -1742,13 +1741,13 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
if (ctask->sc->sc_data_direction != DMA_TO_DEVICE) if (ctask->sc->sc_data_direction != DMA_TO_DEVICE)
return 0; return 0;
if (tcp_ctask->xmstate & XMSTATE_IMM_DATA) { if (test_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate)) {
rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg, rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg,
&tcp_ctask->sent, &ctask->imm_count, &tcp_ctask->sent, &ctask->imm_count,
&tcp_ctask->immbuf, &tcp_ctask->immdigest); &tcp_ctask->immbuf, &tcp_ctask->immdigest);
if (rc) if (rc)
return rc; return rc;
tcp_ctask->xmstate &= ~XMSTATE_IMM_DATA; clear_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate);
} }
rc = iscsi_send_unsol_pdu(conn, ctask); rc = iscsi_send_unsol_pdu(conn, ctask);
...@@ -1981,7 +1980,7 @@ static void ...@@ -1981,7 +1980,7 @@ static void
iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
{ {
struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data; struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
tcp_mtask->xmstate = XMSTATE_IMM_HDR_INIT; tcp_mtask->xmstate = 1 << XMSTATE_BIT_IMM_HDR_INIT;
} }
static int static int
......
...@@ -32,21 +32,21 @@ ...@@ -32,21 +32,21 @@
#define IN_PROGRESS_PAD_RECV 0x4 #define IN_PROGRESS_PAD_RECV 0x4
/* xmit state machine */ /* xmit state machine */
#define XMSTATE_IDLE 0x0 #define XMSTATE_VALUE_IDLE 0
#define XMSTATE_CMD_HDR_INIT 0x1 #define XMSTATE_BIT_CMD_HDR_INIT 0
#define XMSTATE_CMD_HDR_XMIT 0x2 #define XMSTATE_BIT_CMD_HDR_XMIT 1
#define XMSTATE_IMM_HDR 0x4 #define XMSTATE_BIT_IMM_HDR 2
#define XMSTATE_IMM_DATA 0x8 #define XMSTATE_BIT_IMM_DATA 3
#define XMSTATE_UNS_INIT 0x10 #define XMSTATE_BIT_UNS_INIT 4
#define XMSTATE_UNS_HDR 0x20 #define XMSTATE_BIT_UNS_HDR 5
#define XMSTATE_UNS_DATA 0x40 #define XMSTATE_BIT_UNS_DATA 6
#define XMSTATE_SOL_HDR 0x80 #define XMSTATE_BIT_SOL_HDR 7
#define XMSTATE_SOL_DATA 0x100 #define XMSTATE_BIT_SOL_DATA 8
#define XMSTATE_W_PAD 0x200 #define XMSTATE_BIT_W_PAD 9
#define XMSTATE_W_RESEND_PAD 0x400 #define XMSTATE_BIT_W_RESEND_PAD 10
#define XMSTATE_W_RESEND_DATA_DIGEST 0x800 #define XMSTATE_BIT_W_RESEND_DATA_DIGEST 11
#define XMSTATE_IMM_HDR_INIT 0x1000 #define XMSTATE_BIT_IMM_HDR_INIT 12
#define XMSTATE_SOL_HDR_INIT 0x2000 #define XMSTATE_BIT_SOL_HDR_INIT 13
#define ISCSI_PAD_LEN 4 #define ISCSI_PAD_LEN 4
#define ISCSI_SG_TABLESIZE SG_ALL #define ISCSI_SG_TABLESIZE SG_ALL
...@@ -122,7 +122,7 @@ struct iscsi_data_task { ...@@ -122,7 +122,7 @@ struct iscsi_data_task {
struct iscsi_tcp_mgmt_task { struct iscsi_tcp_mgmt_task {
struct iscsi_hdr hdr; struct iscsi_hdr hdr;
char hdrext[sizeof(__u32)]; /* Header-Digest */ char hdrext[sizeof(__u32)]; /* Header-Digest */
int xmstate; /* mgmt xmit progress */ unsigned long xmstate; /* mgmt xmit progress */
struct iscsi_buf headbuf; /* header buffer */ struct iscsi_buf headbuf; /* header buffer */
struct iscsi_buf sendbuf; /* in progress buffer */ struct iscsi_buf sendbuf; /* in progress buffer */
int sent; int sent;
...@@ -150,7 +150,7 @@ struct iscsi_tcp_cmd_task { ...@@ -150,7 +150,7 @@ struct iscsi_tcp_cmd_task {
int pad_count; /* padded bytes */ int pad_count; /* padded bytes */
struct iscsi_buf headbuf; /* header buf (xmit) */ struct iscsi_buf headbuf; /* header buf (xmit) */
struct iscsi_buf sendbuf; /* in progress buffer*/ struct iscsi_buf sendbuf; /* in progress buffer*/
int xmstate; /* xmit xtate machine */ unsigned long xmstate; /* xmit xtate machine */
int sent; int sent;
struct scatterlist *sg; /* per-cmd SG list */ struct scatterlist *sg; /* per-cmd SG list */
struct scatterlist *bad_sg; /* assert statement */ struct scatterlist *bad_sg; /* assert statement */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册