Skip to content

Commit 825619b

Browse files
sagigrimbergChristoph Hellwig
authored andcommitted
nvme-tcp: fix possible use-after-completion
Commit db5ad6b ("nvme-tcp: try to send request in queue_rq context") added a second context that may perform a network send. This means that now RX and TX are not serialized in nvme_tcp_io_work and can run concurrently. While there is correct mutual exclusion in the TX path (where the send_mutex protect the queue socket send activity) RX activity, and more specifically request completion may run concurrently. This means we must guarantee that any mutation of the request state related to its lifetime, bytes sent must not be accessed when a completion may have possibly arrived back (and processed). The race may trigger when a request completion arrives, processed _and_ reused as a fresh new request, exactly in the (relatively short) window between the last data payload sent and before the request iov_iter is advanced. Consider the following race: 1. 16K write request is queued 2. The nvme command and the data is sent to the controller (in-capsule or solicited by r2t) 3. After the last payload is sent but before the req.iter is advanced, the controller sends back a completion. 4. The completion is processed, the request is completed, and reused to transfer a new request (write or read) 5. The new request is queued, and the driver reset the request parameters (nvme_tcp_setup_cmd_pdu). 6. Now context in (2) resumes execution and advances the req.iter ==> use-after-completion as this is already a new request. Fix this by making sure the request is not advanced after the last data payload send, knowing that a completion may have arrived already. An alternative solution would have been to delay the request completion or state change waiting for reference counting on the TX path, but besides adding atomic operations to the hot-path, it may present challenges in multi-stage R2T scenarios where a r2t handler needs to be deferred to an async execution. Reported-by: Narayan Ayalasomayajula <[email protected]> Tested-by: Anil Mishra <[email protected]> Reviewed-by: Keith Busch <[email protected]> Cc: [email protected] # v5.8+ Signed-off-by: Sagi Grimberg <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent 03504e3 commit 825619b

File tree

1 file changed

+1
-1
lines changed

1 file changed

+1
-1
lines changed

drivers/nvme/host/tcp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -943,7 +943,6 @@ static int nvme_tcp_try_send_data(struct nvme_tcp_request *req)
943943
if (ret <= 0)
944944
return ret;
945945

946-
nvme_tcp_advance_req(req, ret);
947946
if (queue->data_digest)
948947
nvme_tcp_ddgst_update(queue->snd_hash, page,
949948
offset, ret);
@@ -960,6 +959,7 @@ static int nvme_tcp_try_send_data(struct nvme_tcp_request *req)
960959
}
961960
return 1;
962961
}
962+
nvme_tcp_advance_req(req, ret);
963963
}
964964
return -EAGAIN;
965965
}

0 commit comments

Comments
 (0)