Skip to content

Commit e371af0

Browse files
sagigrimbergChristoph Hellwig
authored andcommitted
nvme-tcp: fix incorrect h2cdata pdu offset accounting
When the controller sends us multiple r2t PDUs in a single request we need to account for it correctly as our send/recv context run concurrently (i.e. we get a new r2t with r2t_offset before we updated our iterator and req->data_sent marker). This can cause wrong offsets to be sent to the controller. To fix that, we will first know that this may happen only in the send sequence of the last page, hence we will take the r2t_offset to the h2c PDU data_offset, and in nvme_tcp_try_send_data loop, we make sure to increment the request markers also when we completed a PDU but we are expecting more r2t PDUs as we still did not send the entire data of the request. Fixes: 825619b ("nvme-tcp: fix possible use-after-completion") Reported-by: Nowak, Lukasz <[email protected]> Tested-by: Nowak, Lukasz <[email protected]> Signed-off-by: Sagi Grimberg <[email protected]> Reviewed-by: Keith Busch <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent bdaa136 commit e371af0

File tree

1 file changed

+10
-3
lines changed

1 file changed

+10
-3
lines changed

drivers/nvme/host/tcp.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@ static int nvme_tcp_setup_h2c_data_pdu(struct nvme_tcp_request *req,
620620
cpu_to_le32(data->hdr.hlen + hdgst + req->pdu_len + ddgst);
621621
data->ttag = pdu->ttag;
622622
data->command_id = nvme_cid(rq);
623-
data->data_offset = cpu_to_le32(req->data_sent);
623+
data->data_offset = pdu->r2t_offset;
624624
data->data_length = cpu_to_le32(req->pdu_len);
625625
return 0;
626626
}
@@ -953,7 +953,15 @@ static int nvme_tcp_try_send_data(struct nvme_tcp_request *req)
953953
nvme_tcp_ddgst_update(queue->snd_hash, page,
954954
offset, ret);
955955

956-
/* fully successful last write*/
956+
/*
957+
* update the request iterator except for the last payload send
958+
* in the request where we don't want to modify it as we may
959+
* compete with the RX path completing the request.
960+
*/
961+
if (req->data_sent + ret < req->data_len)
962+
nvme_tcp_advance_req(req, ret);
963+
964+
/* fully successful last send in current PDU */
957965
if (last && ret == len) {
958966
if (queue->data_digest) {
959967
nvme_tcp_ddgst_final(queue->snd_hash,
@@ -965,7 +973,6 @@ static int nvme_tcp_try_send_data(struct nvme_tcp_request *req)
965973
}
966974
return 1;
967975
}
968-
nvme_tcp_advance_req(req, ret);
969976
}
970977
return -EAGAIN;
971978
}

0 commit comments

Comments
 (0)