On 27.01.21 21:14, Dr. David Alan Gilbert wrote:
* David Hildenbrand ([email protected]) wrote:
Let's properly notify when (un)plugging blocks, after discarding memory
and before allowing the guest to consume memory. Handle errors from
notifiers gracefully (e.g., no remaining VFIO mappings) when plugging,
rolling back the change and telling the guest that the VM is busy.

One special case to take care of is replaying all notifications after
restoring the vmstate. The device starts out with all memory discarded,
so after loading the vmstate, we have to notify about all plugged
blocks.

Cc: Paolo Bonzini <[email protected]>
Cc: "Michael S. Tsirkin" <[email protected]>
Cc: Alex Williamson <[email protected]>
Cc: Dr. David Alan Gilbert <[email protected]>
Cc: Igor Mammedov <[email protected]>
Cc: Pankaj Gupta <[email protected]>
Cc: Peter Xu <[email protected]>
Cc: Auger Eric <[email protected]>
Cc: Wei Yang <[email protected]>
Cc: teawater <[email protected]>
Cc: Marek Kedzierski <[email protected]>
Signed-off-by: David Hildenbrand <[email protected]>
---
  hw/virtio/virtio-mem.c         | 258 ++++++++++++++++++++++++++++++++-
  include/hw/virtio/virtio-mem.h |   3 +
  2 files changed, 258 insertions(+), 3 deletions(-)

diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c
index 471e464171..6200813bb8 100644
--- a/hw/virtio/virtio-mem.c
+++ b/hw/virtio/virtio-mem.c
@@ -172,7 +172,110 @@ static int virtio_mem_for_each_unplugged_range(const 
VirtIOMEM *vmem, void *arg,
      return ret;
  }
-static bool virtio_mem_test_bitmap(VirtIOMEM *vmem, uint64_t start_gpa,
+static int virtio_mem_for_each_plugged_range(const VirtIOMEM *vmem, void *arg,
+                                             virtio_mem_range_cb cb)
+{
+    unsigned long first_bit, last_bit;
+    uint64_t offset, size;
+    int ret = 0;
+
+    first_bit = find_first_bit(vmem->bitmap, vmem->bitmap_size);
+    while (first_bit < vmem->bitmap_size) {
+        offset = first_bit * vmem->block_size;
+        last_bit = find_next_zero_bit(vmem->bitmap, vmem->bitmap_size,
+                                      first_bit + 1) - 1;
+        size = (last_bit - first_bit + 1) * vmem->block_size;
+
+        ret = cb(vmem, arg, offset, size);
+        if (ret) {
+            break;
+        }
+        first_bit = find_next_bit(vmem->bitmap, vmem->bitmap_size,
+                                  last_bit + 2);
+    }
+    return ret;
+}
+
+static void virtio_mem_notify_unplug(VirtIOMEM *vmem, uint64_t offset,
+                                     uint64_t size)
+{
+    RamDiscardListener *rdl;
+
+    QLIST_FOREACH(rdl, &vmem->rdl_list, next) {
+        rdl->notify_discard(rdl, &vmem->memdev->mr, offset, size);
+    }
+}
+
+static int virtio_mem_notify_plug(VirtIOMEM *vmem, uint64_t offset,
+                                  uint64_t size)
+{
+    RamDiscardListener *rdl, *rdl2;
+    int ret = 0, ret2;
+
+    QLIST_FOREACH(rdl, &vmem->rdl_list, next) {
+        ret = rdl->notify_populate(rdl, &vmem->memdev->mr, offset, size);
+        if (ret) {
+            break;
+        }
+    }
+
+    if (ret) {
+        /* Could be a mapping attempt resulted in memory getting populated. */
+        ret2 = ram_block_discard_range(vmem->memdev->mr.ram_block, offset,
+                                       size);
+        if (ret2) {
+            error_report("Unexpected error discarding RAM: %s",
+                         strerror(-ret2));

Not a blocker, but it's good to include the RAMBlock/offset/size in
errors like these.


We really only have the single RAMBlock managed by the device. offset and size can be useful, indeed.

As we have some other similar cases, I'll do a cleanup of that on top - unless I have to resend.

Thanks!

Dave


--
Thanks,

David / dhildenb


Reply via email to