virtio_pmem_host_ack() publishes the device response by setting done and waking the submitter. The submitter reads resp.ret after wait_event() observes done.
Use smp_store_release() on done and smp_load_acquire() in the wait condition so the response read is ordered after completion. Signed-off-by: Li Chen <[email protected]> --- Changes in v6: - New patch. drivers/nvdimm/nd_virtio.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/nvdimm/nd_virtio.c b/drivers/nvdimm/nd_virtio.c index 7b6761adf28bc..35d36bd36a526 100644 --- a/drivers/nvdimm/nd_virtio.c +++ b/drivers/nvdimm/nd_virtio.c @@ -17,6 +17,19 @@ static void virtio_pmem_req_release(struct kref *kref) kfree(req); } +static void virtio_pmem_signal_done(struct virtio_pmem_request *req) +{ + /* Pairs with smp_load_acquire() in virtio_pmem_req_done(). */ + smp_store_release(&req->done, true); + wake_up(&req->host_acked); +} + +static bool virtio_pmem_req_done(struct virtio_pmem_request *req) +{ + /* Pairs with smp_store_release() in virtio_pmem_signal_done(). */ + return smp_load_acquire(&req->done); +} + static void virtio_pmem_wake_one_waiter(struct virtio_pmem *vpmem) { struct virtio_pmem_request *req_buf; @@ -42,8 +55,7 @@ void virtio_pmem_host_ack(struct virtqueue *vq) spin_lock_irqsave(&vpmem->pmem_lock, flags); while ((req_data = virtqueue_get_buf(vq, &len)) != NULL) { virtio_pmem_wake_one_waiter(vpmem); - WRITE_ONCE(req_data->done, true); - wake_up(&req_data->host_acked); + virtio_pmem_signal_done(req_data); kref_put(&req_data->kref, virtio_pmem_req_release); } spin_unlock_irqrestore(&vpmem->pmem_lock, flags); @@ -130,7 +142,8 @@ static int virtio_pmem_flush(struct nd_region *nd_region) err = -EIO; } else { /* A host response results in "host_ack" getting called */ - wait_event(req_data->host_acked, READ_ONCE(req_data->done)); + wait_event(req_data->host_acked, + virtio_pmem_req_done(req_data)); err = le32_to_cpu(req_data->resp.ret); } -- 2.52.0

