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

Reply via email to