Skip to content

Commit 70f437f

Browse files
keithbuschChristoph Hellwig
authored andcommitted
nvme-tcp: fix io_work priority inversion
Dispatching requests inline with the .queue_rq() call may block while holding the send_mutex. If the tcp io_work also happens to schedule, it may see the req_list is non-empty, leaving "pending" true and remaining in TASK_RUNNING. Since io_work is of higher scheduling priority, the .queue_rq task may not get a chance to run, blocking forward progress and leading to io timeouts. Instead of checking for pending requests within io_work, let the queueing restart io_work outside the send_mutex lock if there is more work to be done. Fixes: a0fdd14 ("nvme-tcp: rerun io_work if req_list is not empty") Reported-by: Samuel Jones <sjones@kalrayinc.com> Signed-off-by: Keith Busch <kbusch@kernel.org> Reviewed-by: Sagi Grimberg <sagi@grimberg.me> Signed-off-by: Christoph Hellwig <hch@lst.de>
1 parent 9817d76 commit 70f437f

File tree

1 file changed

+10
-10
lines changed

1 file changed

+10
-10
lines changed

drivers/nvme/host/tcp.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,12 @@ static inline void nvme_tcp_send_all(struct nvme_tcp_queue *queue)
274274
} while (ret > 0);
275275
}
276276

277+
static inline bool nvme_tcp_queue_more(struct nvme_tcp_queue *queue)
278+
{
279+
return !list_empty(&queue->send_list) ||
280+
!llist_empty(&queue->req_list) || queue->more_requests;
281+
}
282+
277283
static inline void nvme_tcp_queue_request(struct nvme_tcp_request *req,
278284
bool sync, bool last)
279285
{
@@ -294,9 +300,10 @@ static inline void nvme_tcp_queue_request(struct nvme_tcp_request *req,
294300
nvme_tcp_send_all(queue);
295301
queue->more_requests = false;
296302
mutex_unlock(&queue->send_mutex);
297-
} else if (last) {
298-
queue_work_on(queue->io_cpu, nvme_tcp_wq, &queue->io_work);
299303
}
304+
305+
if (last && nvme_tcp_queue_more(queue))
306+
queue_work_on(queue->io_cpu, nvme_tcp_wq, &queue->io_work);
300307
}
301308

302309
static void nvme_tcp_process_req_list(struct nvme_tcp_queue *queue)
@@ -906,12 +913,6 @@ static void nvme_tcp_state_change(struct sock *sk)
906913
read_unlock_bh(&sk->sk_callback_lock);
907914
}
908915

909-
static inline bool nvme_tcp_queue_more(struct nvme_tcp_queue *queue)
910-
{
911-
return !list_empty(&queue->send_list) ||
912-
!llist_empty(&queue->req_list) || queue->more_requests;
913-
}
914-
915916
static inline void nvme_tcp_done_send_req(struct nvme_tcp_queue *queue)
916917
{
917918
queue->request = NULL;
@@ -1145,8 +1146,7 @@ static void nvme_tcp_io_work(struct work_struct *w)
11451146
pending = true;
11461147
else if (unlikely(result < 0))
11471148
break;
1148-
} else
1149-
pending = !llist_empty(&queue->req_list);
1149+
}
11501150

11511151
result = nvme_tcp_try_recv(queue);
11521152
if (result > 0)

0 commit comments

Comments
 (0)