• Sagi Grimberg's avatar
    nvme-tcp: fix regression that causes sporadic requests to time out · 3770a42b
    Sagi Grimberg authored
    When we queue requests, we strive to batch as much as possible and also
    signal the network stack that more data is about to be sent over a socket
    with MSG_SENDPAGE_NOTLAST. This flag looks at the pending requests queued
    as well as queue->more_requests that is derived from the block layer
    last-in-batch indication.
    
    We set more_request=true when we flush the request directly from
    .queue_rq submission context (in nvme_tcp_send_all), however this is
    wrongly assuming that no other requests may be queued during the
    execution of nvme_tcp_send_all.
    
    Due to this, a race condition may happen where:
    
     1. request X is queued as !last-in-batch
     2. request X submission context calls nvme_tcp_send_all directly
     3. nvme_tcp_send_all is preempted and schedules to a different cpu
     4. request Y is queued as last-in-batch
     5. nvme_tcp_send_all context sends request X+Y, however signals for
        both MSG_SENDPAGE_NOTLAST because queue->more_requests=true.
    
    ==> none of the requests is pushed down to the wire as the network
    stack is waiting for more data, both requests timeout.
    
    To fix this, we eliminate queue->more_requests and only rely on
    the queue req_list and send_list to be not-empty.
    
    Fixes: 122e5b9f ("nvme-tcp: optimize network stack with setting msg flags according to batch size")
    Reported-by: default avatarJonathan Nicklin <jnicklin@blockbridge.com>
    Signed-off-by: default avatarSagi Grimberg <sagi@grimberg.me>
    Tested-by: default avatarJonathan Nicklin <jnicklin@blockbridge.com>
    Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
    3770a42b
tcp.c 68.6 KB