nvme_tcp: Fix icreq/icresp handing with zcopy enabled.
There is a problem with TCP zcopy enabled:
1. TCP initiator sends icreq and start polling a qpair. Polling of qpair
actively calls nvme_tcp_read_pdu function
2. nvme_tcp_read_pdu: qpair is in NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_CH state,
it reads 8 bytes of common PDU header. It determines the type of the PDU
and finds the size of PDU_PSH header.
3. nvme_tcp_read_pdu: qpair is in NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_PSH state.
It should read 120 bytes of icresp PDU. The number of bytes which needs to be
read is pdu->psh_len - pdu->psh_valid_bytes. qpair receives 120 bytes
(the full PDU) and calls nvme_tcp_pdu_psh_handle -> nvme_tcp_icresp_handle.
Here we check that we haven't yet received buffer reclaim notification and
simply return from this function. At the same time we continue to poll the qpair.
4. nvme_tcp_read_pdu: qpair is in NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_PSH state
and tries to read data from a socket again. The number of bytes is
pdu->psh_len - pdu->psh_valid_bytes. But now pdu->psh_len == pdu->psh_valid_bytes,
so we call nvme_tcp_read_data with zero length.
readv with zero length is commonly used to check errors on the socket,
but in our case there is no errors and readv returns 0.
5. nvme_tcp_read_data treats zero as error and return NVME_TCP_CONNECTION_FATAL.
Fix is to handle icresp, but leave qpair in INITIALIZING state until
we receive acknowledgement for icreqsend_ack. We also move qpair to
NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_READY recv_state so recv_pdu
will be zerofied and qpair will try to read a common PDU header.
But since it is not initialized yet, it won't receive anything
from the target.
Fixes issue #1633
Signed-off-by: Alexey Marchuk <alexeymar@mellanox.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/4969 (master)
(cherry picked from commit d296fcd8d9
)
Change-Id: I22cedefe530a8ac3b51495988ed6265d8fad15bb
Signed-off-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/4976
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@mellanox.com>
This commit is contained in:
parent
2209decef9
commit
8a0f9cf3a7
@ -989,13 +989,13 @@ nvme_tcp_send_icreq_complete(void *cb_arg)
|
||||
{
|
||||
struct nvme_tcp_qpair *tqpair = cb_arg;
|
||||
|
||||
SPDK_DEBUGLOG(nvme, "Complete the icreq send for tqpair=%p\n", tqpair);
|
||||
SPDK_DEBUGLOG(nvme, "Complete the icreq send for tqpair=%p %u\n", tqpair, tqpair->qpair.id);
|
||||
|
||||
tqpair->flags.icreq_send_ack = true;
|
||||
|
||||
if (tqpair->state == NVME_TCP_QPAIR_STATE_INITIALIZING) {
|
||||
SPDK_DEBUGLOG(nvme, "qpair %u, finilize icresp\n", tqpair->qpair.id);
|
||||
nvme_tcp_icresp_handle(tqpair, &tqpair->recv_pdu);
|
||||
SPDK_DEBUGLOG(nvme, "tqpair %p %u, finilize icresp\n", tqpair, tqpair->qpair.id);
|
||||
tqpair->state = NVME_TCP_QPAIR_STATE_RUNNING;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1008,12 +1008,6 @@ nvme_tcp_icresp_handle(struct nvme_tcp_qpair *tqpair,
|
||||
enum spdk_nvme_tcp_term_req_fes fes;
|
||||
int recv_buf_size;
|
||||
|
||||
if (!tqpair->flags.icreq_send_ack) {
|
||||
tqpair->state = NVME_TCP_QPAIR_STATE_INITIALIZING;
|
||||
SPDK_DEBUGLOG(nvme, "qpair %u, waiting icreq ack\n", tqpair->qpair.id);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Only PFV 0 is defined currently */
|
||||
if (ic_resp->pfv != 0) {
|
||||
SPDK_ERRLOG("Expected ICResp PFV %u, got %u\n", 0u, ic_resp->pfv);
|
||||
@ -1064,8 +1058,15 @@ nvme_tcp_icresp_handle(struct nvme_tcp_qpair *tqpair,
|
||||
/* Not fatal. */
|
||||
}
|
||||
|
||||
tqpair->state = NVME_TCP_QPAIR_STATE_RUNNING;
|
||||
nvme_tcp_qpair_set_recv_state(tqpair, NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_READY);
|
||||
|
||||
if (!tqpair->flags.icreq_send_ack) {
|
||||
tqpair->state = NVME_TCP_QPAIR_STATE_INITIALIZING;
|
||||
SPDK_DEBUGLOG(nvme, "tqpair %p %u, waiting icreq ack\n", tqpair, tqpair->qpair.id);
|
||||
return;
|
||||
}
|
||||
|
||||
tqpair->state = NVME_TCP_QPAIR_STATE_RUNNING;
|
||||
return;
|
||||
end:
|
||||
nvme_tcp_qpair_send_h2c_term_req(tqpair, pdu, fes, error_offset);
|
||||
|
Loading…
Reference in New Issue
Block a user