diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index f876375dffd2..c401dc0206c5 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -1430,6 +1430,19 @@ static int nvme_tcp_try_recv(struct nvme_tcp_queue *queue) lock_sock(sk); queue->nr_cqe = 0; consumed = sock->ops->read_sock(sk, &rd_desc, nvme_tcp_recv_skb); + /* + * nvme_tcp_recv_skb() handles its own errors, so a queue that is + * still enabled failed inside read_sock(). Handle it before + * release_sock() processes the backlog. + */ + if (unlikely(consumed < 0 && consumed != -EAGAIN && + queue->rd_enabled)) { + dev_err(queue->ctrl->ctrl.device, + "queue %d: receive failed: %d\n", + nvme_tcp_queue_id(queue), consumed); + queue->rd_enabled = false; + nvme_tcp_error_recovery(&queue->ctrl->ctrl); + } release_sock(sk); return consumed == -EAGAIN ? 0 : consumed; }