nvmf/tcp: Verify DIF before sending C2H data in spdk_nvmf_tcp_send_c2h_data
If DIF mode is local and C2H data is extended LBA payload, DIF should be verified just before sending the payload. Add a helper function nvmf_tcp_pdu_verify_dif and call it in spdk_nvmf_tcp_send_c2h_data after completing nvme_tcp_pdu_set_data_buf. When nvmf_tcp_pdu_verify_dif returns error, treat the error as fatal transport error because the error is caused by the target itself. Handle the fatal NVMe/TCP transport error by terminating the connection as described in the NVMe specification. On the other hand, data digest error is treated as a non-fatal transport error because the error is caused outside the target. This is reasonable. Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com> Change-Id: I9680af2556c08f5888aeaf0a772097e4744182be Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/458921 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com> Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
This commit is contained in:
parent
a7a32ea052
commit
8448adaefa
@ -2177,6 +2177,23 @@ spdk_nvmf_tcp_req_parse_sgl(struct spdk_nvmf_tcp_transport *ttransport,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nvmf_tcp_pdu_verify_dif(struct nvme_tcp_pdu *pdu,
|
||||||
|
const struct spdk_dif_ctx *dif_ctx)
|
||||||
|
{
|
||||||
|
struct spdk_dif_error err_blk = {};
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = spdk_dif_verify_stream(pdu->data_iov, pdu->data_iovcnt,
|
||||||
|
0, pdu->data_len, pdu->dif_ctx, &err_blk);
|
||||||
|
if (rc != 0) {
|
||||||
|
SPDK_ERRLOG("DIF error detected. type=%d, offset=%" PRIu32 "\n",
|
||||||
|
err_blk.err_type, err_blk.err_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
spdk_nvmf_tcp_send_c2h_data(struct spdk_nvmf_tcp_qpair *tqpair,
|
spdk_nvmf_tcp_send_c2h_data(struct spdk_nvmf_tcp_qpair *tqpair,
|
||||||
struct spdk_nvmf_tcp_req *tcp_req)
|
struct spdk_nvmf_tcp_req *tcp_req)
|
||||||
@ -2184,6 +2201,7 @@ spdk_nvmf_tcp_send_c2h_data(struct spdk_nvmf_tcp_qpair *tqpair,
|
|||||||
struct nvme_tcp_pdu *rsp_pdu;
|
struct nvme_tcp_pdu *rsp_pdu;
|
||||||
struct spdk_nvme_tcp_c2h_data_hdr *c2h_data;
|
struct spdk_nvme_tcp_c2h_data_hdr *c2h_data;
|
||||||
uint32_t plen, pdo, alignment;
|
uint32_t plen, pdo, alignment;
|
||||||
|
int rc;
|
||||||
|
|
||||||
SPDK_DEBUGLOG(SPDK_LOG_NVMF_TCP, "enter\n");
|
SPDK_DEBUGLOG(SPDK_LOG_NVMF_TCP, "enter\n");
|
||||||
|
|
||||||
@ -2228,6 +2246,21 @@ spdk_nvmf_tcp_send_c2h_data(struct spdk_nvmf_tcp_qpair *tqpair,
|
|||||||
nvme_tcp_pdu_set_data_buf(rsp_pdu, tcp_req->req.iov, tcp_req->req.iovcnt,
|
nvme_tcp_pdu_set_data_buf(rsp_pdu, tcp_req->req.iov, tcp_req->req.iovcnt,
|
||||||
c2h_data->datao, c2h_data->datal);
|
c2h_data->datao, c2h_data->datal);
|
||||||
|
|
||||||
|
if (spdk_unlikely(rsp_pdu->dif_ctx != NULL)) {
|
||||||
|
rc = nvmf_tcp_pdu_verify_dif(rsp_pdu, rsp_pdu->dif_ctx);
|
||||||
|
if (rc != 0) {
|
||||||
|
/* Data digest error detected by the NVMe/TCP target is treated as non-fatal
|
||||||
|
* transport error because the cause will be outside the NVMe/TCP target.
|
||||||
|
*
|
||||||
|
* On the other hand, treat DIF check error as fatal transport error here
|
||||||
|
* here because the error is caused by the target itself. Fatal NVMe/TCP
|
||||||
|
* transport error is handled by terminating the connection.
|
||||||
|
*/
|
||||||
|
tqpair->state = NVME_TCP_QPAIR_STATE_EXITING;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tcp_req->c2h_data_offset += c2h_data->datal;
|
tcp_req->c2h_data_offset += c2h_data->datal;
|
||||||
if (tcp_req->c2h_data_offset == tcp_req->req.length) {
|
if (tcp_req->c2h_data_offset == tcp_req->req.length) {
|
||||||
SPDK_DEBUGLOG(SPDK_LOG_NVMF_TCP, "Last pdu for tcp_req=%p on tqpair=%p\n", tcp_req, tqpair);
|
SPDK_DEBUGLOG(SPDK_LOG_NVMF_TCP, "Last pdu for tcp_req=%p on tqpair=%p\n", tcp_req, tqpair);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user