Re: [PATCH v4 04/11] vfio: Support for RamDiscardMgr in the !vIOMMU case

2021-01-15 Thread David Hildenbrand
On 14.01.21 16:57, David Hildenbrand wrote:
> On 14.01.21 16:54, David Hildenbrand wrote:
>> On 14.01.21 00:27, Alex Williamson wrote:
>>> On Thu,  7 Jan 2021 14:34:16 +0100
>>> David Hildenbrand  wrote:
>>>
 Implement support for RamDiscardMgr, to prepare for virtio-mem
 support. Instead of mapping the whole memory section, we only map
 "populated" parts and update the mapping when notified about
 discarding/population of memory via the RamDiscardListener. Similarly, when
 syncing the dirty bitmaps, sync only the actually mapped (populated) parts
 by replaying via the notifier.

 Using virtio-mem with vfio is still blocked via
 ram_block_discard_disable()/ram_block_discard_require() after this patch.

 Cc: Paolo Bonzini 
 Cc: "Michael S. Tsirkin" 
 Cc: Alex Williamson 
 Cc: Dr. David Alan Gilbert 
 Cc: Igor Mammedov 
 Cc: Pankaj Gupta 
 Cc: Peter Xu 
 Cc: Auger Eric 
 Cc: Wei Yang 
 Cc: teawater 
 Cc: Marek Kedzierski 
 Signed-off-by: David Hildenbrand 
 ---
  hw/vfio/common.c  | 200 ++
  include/hw/vfio/vfio-common.h |  12 ++
  2 files changed, 212 insertions(+)

 diff --git a/hw/vfio/common.c b/hw/vfio/common.c
 index 6ff1daa763..2bd219cf1d 100644
 --- a/hw/vfio/common.c
 +++ b/hw/vfio/common.c
 @@ -654,6 +654,136 @@ out:
  rcu_read_unlock();
  }
  
 +static void vfio_ram_discard_notify_discard(RamDiscardListener *rdl,
 +const MemoryRegion *mr,
 +ram_addr_t offset, ram_addr_t 
 size)
 +{
 +VFIORamDiscardListener *vrdl = container_of(rdl, 
 VFIORamDiscardListener,
 +listener);
 +const hwaddr mr_start = MAX(offset, vrdl->offset_within_region);
 +const hwaddr mr_end = MIN(offset + size,
 +  vrdl->offset_within_region + vrdl->size);
 +const hwaddr iova = mr_start - vrdl->offset_within_region +
 +vrdl->offset_within_address_space;
 +int ret;
 +
 +if (mr_start >= mr_end) {
 +return;
 +}
 +
 +/* Unmap with a single call. */
 +ret = vfio_dma_unmap(vrdl->container, iova, mr_end - mr_start, NULL);
 +if (ret) {
 +error_report("%s: vfio_dma_unmap() failed: %s", __func__,
 + strerror(-ret));
 +}
 +}
 +
 +static int vfio_ram_discard_notify_populate(RamDiscardListener *rdl,
 +const MemoryRegion *mr,
 +ram_addr_t offset, ram_addr_t 
 size)
 +{
 +VFIORamDiscardListener *vrdl = container_of(rdl, 
 VFIORamDiscardListener,
 +listener);
 +const hwaddr mr_end = MIN(offset + size,
 +  vrdl->offset_within_region + vrdl->size);
 +hwaddr mr_start = MAX(offset, vrdl->offset_within_region);
 +hwaddr mr_next, iova;
 +void *vaddr;
 +int ret;
 +
 +/*
 + * Map in (aligned within memory region) minimum granularity, so we 
 can
 + * unmap in minimum granularity later.
 + */
 +for (; mr_start < mr_end; mr_start = mr_next) {
 +mr_next = ROUND_UP(mr_start + 1, vrdl->granularity);
 +mr_next = MIN(mr_next, mr_end);
 +
 +iova = mr_start - vrdl->offset_within_region +
 +   vrdl->offset_within_address_space;
 +vaddr = memory_region_get_ram_ptr(vrdl->mr) + mr_start;
 +
 +ret = vfio_dma_map(vrdl->container, iova, mr_next - mr_start,
 +   vaddr, mr->readonly);
 +if (ret) {
 +/* Rollback */
 +vfio_ram_discard_notify_discard(rdl, mr, offset, size);
 +return ret;
 +}
 +}
 +return 0;
 +}
 +
 +static void vfio_ram_discard_notify_discard_all(RamDiscardListener *rdl,
 +const MemoryRegion *mr)
 +{
 +VFIORamDiscardListener *vrdl = container_of(rdl, 
 VFIORamDiscardListener,
 +listener);
 +int ret;
 +
 +/* Unmap with a single call. */
 +ret = vfio_dma_unmap(vrdl->container, 
 vrdl->offset_within_address_space,
 + vrdl->size, NULL);
 +if (ret) {
 +error_report("%s: vfio_dma_unmap() failed: %s", __func__,
 + strerror(-ret));
 +}
 +}
 +
 +static void vfio_register_ram_discard_notifier(VFIOContainer *container,
 +   

Re: [PATCH v4 04/11] vfio: Support for RamDiscardMgr in the !vIOMMU case

2021-01-14 Thread David Hildenbrand
On 14.01.21 16:54, David Hildenbrand wrote:
> On 14.01.21 00:27, Alex Williamson wrote:
>> On Thu,  7 Jan 2021 14:34:16 +0100
>> David Hildenbrand  wrote:
>>
>>> Implement support for RamDiscardMgr, to prepare for virtio-mem
>>> support. Instead of mapping the whole memory section, we only map
>>> "populated" parts and update the mapping when notified about
>>> discarding/population of memory via the RamDiscardListener. Similarly, when
>>> syncing the dirty bitmaps, sync only the actually mapped (populated) parts
>>> by replaying via the notifier.
>>>
>>> Using virtio-mem with vfio is still blocked via
>>> ram_block_discard_disable()/ram_block_discard_require() after this patch.
>>>
>>> Cc: Paolo Bonzini 
>>> Cc: "Michael S. Tsirkin" 
>>> Cc: Alex Williamson 
>>> Cc: Dr. David Alan Gilbert 
>>> Cc: Igor Mammedov 
>>> Cc: Pankaj Gupta 
>>> Cc: Peter Xu 
>>> Cc: Auger Eric 
>>> Cc: Wei Yang 
>>> Cc: teawater 
>>> Cc: Marek Kedzierski 
>>> Signed-off-by: David Hildenbrand 
>>> ---
>>>  hw/vfio/common.c  | 200 ++
>>>  include/hw/vfio/vfio-common.h |  12 ++
>>>  2 files changed, 212 insertions(+)
>>>
>>> diff --git a/hw/vfio/common.c b/hw/vfio/common.c
>>> index 6ff1daa763..2bd219cf1d 100644
>>> --- a/hw/vfio/common.c
>>> +++ b/hw/vfio/common.c
>>> @@ -654,6 +654,136 @@ out:
>>>  rcu_read_unlock();
>>>  }
>>>  
>>> +static void vfio_ram_discard_notify_discard(RamDiscardListener *rdl,
>>> +const MemoryRegion *mr,
>>> +ram_addr_t offset, ram_addr_t 
>>> size)
>>> +{
>>> +VFIORamDiscardListener *vrdl = container_of(rdl, 
>>> VFIORamDiscardListener,
>>> +listener);
>>> +const hwaddr mr_start = MAX(offset, vrdl->offset_within_region);
>>> +const hwaddr mr_end = MIN(offset + size,
>>> +  vrdl->offset_within_region + vrdl->size);
>>> +const hwaddr iova = mr_start - vrdl->offset_within_region +
>>> +vrdl->offset_within_address_space;
>>> +int ret;
>>> +
>>> +if (mr_start >= mr_end) {
>>> +return;
>>> +}
>>> +
>>> +/* Unmap with a single call. */
>>> +ret = vfio_dma_unmap(vrdl->container, iova, mr_end - mr_start, NULL);
>>> +if (ret) {
>>> +error_report("%s: vfio_dma_unmap() failed: %s", __func__,
>>> + strerror(-ret));
>>> +}
>>> +}
>>> +
>>> +static int vfio_ram_discard_notify_populate(RamDiscardListener *rdl,
>>> +const MemoryRegion *mr,
>>> +ram_addr_t offset, ram_addr_t 
>>> size)
>>> +{
>>> +VFIORamDiscardListener *vrdl = container_of(rdl, 
>>> VFIORamDiscardListener,
>>> +listener);
>>> +const hwaddr mr_end = MIN(offset + size,
>>> +  vrdl->offset_within_region + vrdl->size);
>>> +hwaddr mr_start = MAX(offset, vrdl->offset_within_region);
>>> +hwaddr mr_next, iova;
>>> +void *vaddr;
>>> +int ret;
>>> +
>>> +/*
>>> + * Map in (aligned within memory region) minimum granularity, so we can
>>> + * unmap in minimum granularity later.
>>> + */
>>> +for (; mr_start < mr_end; mr_start = mr_next) {
>>> +mr_next = ROUND_UP(mr_start + 1, vrdl->granularity);
>>> +mr_next = MIN(mr_next, mr_end);
>>> +
>>> +iova = mr_start - vrdl->offset_within_region +
>>> +   vrdl->offset_within_address_space;
>>> +vaddr = memory_region_get_ram_ptr(vrdl->mr) + mr_start;
>>> +
>>> +ret = vfio_dma_map(vrdl->container, iova, mr_next - mr_start,
>>> +   vaddr, mr->readonly);
>>> +if (ret) {
>>> +/* Rollback */
>>> +vfio_ram_discard_notify_discard(rdl, mr, offset, size);
>>> +return ret;
>>> +}
>>> +}
>>> +return 0;
>>> +}
>>> +
>>> +static void vfio_ram_discard_notify_discard_all(RamDiscardListener *rdl,
>>> +const MemoryRegion *mr)
>>> +{
>>> +VFIORamDiscardListener *vrdl = container_of(rdl, 
>>> VFIORamDiscardListener,
>>> +listener);
>>> +int ret;
>>> +
>>> +/* Unmap with a single call. */
>>> +ret = vfio_dma_unmap(vrdl->container, 
>>> vrdl->offset_within_address_space,
>>> + vrdl->size, NULL);
>>> +if (ret) {
>>> +error_report("%s: vfio_dma_unmap() failed: %s", __func__,
>>> + strerror(-ret));
>>> +}
>>> +}
>>> +
>>> +static void vfio_register_ram_discard_notifier(VFIOContainer *container,
>>> +   MemoryRegionSection 
>>> *section)
>>> +{
>>> +RamDiscardMgr *rdm = memory_region_get_ram_discard_mgr(section->mr);
>>> +RamDiscardMgrClass *rdmc = 

Re: [PATCH v4 04/11] vfio: Support for RamDiscardMgr in the !vIOMMU case

2021-01-14 Thread David Hildenbrand
On 14.01.21 00:27, Alex Williamson wrote:
> On Thu,  7 Jan 2021 14:34:16 +0100
> David Hildenbrand  wrote:
> 
>> Implement support for RamDiscardMgr, to prepare for virtio-mem
>> support. Instead of mapping the whole memory section, we only map
>> "populated" parts and update the mapping when notified about
>> discarding/population of memory via the RamDiscardListener. Similarly, when
>> syncing the dirty bitmaps, sync only the actually mapped (populated) parts
>> by replaying via the notifier.
>>
>> Using virtio-mem with vfio is still blocked via
>> ram_block_discard_disable()/ram_block_discard_require() after this patch.
>>
>> Cc: Paolo Bonzini 
>> Cc: "Michael S. Tsirkin" 
>> Cc: Alex Williamson 
>> Cc: Dr. David Alan Gilbert 
>> Cc: Igor Mammedov 
>> Cc: Pankaj Gupta 
>> Cc: Peter Xu 
>> Cc: Auger Eric 
>> Cc: Wei Yang 
>> Cc: teawater 
>> Cc: Marek Kedzierski 
>> Signed-off-by: David Hildenbrand 
>> ---
>>  hw/vfio/common.c  | 200 ++
>>  include/hw/vfio/vfio-common.h |  12 ++
>>  2 files changed, 212 insertions(+)
>>
>> diff --git a/hw/vfio/common.c b/hw/vfio/common.c
>> index 6ff1daa763..2bd219cf1d 100644
>> --- a/hw/vfio/common.c
>> +++ b/hw/vfio/common.c
>> @@ -654,6 +654,136 @@ out:
>>  rcu_read_unlock();
>>  }
>>  
>> +static void vfio_ram_discard_notify_discard(RamDiscardListener *rdl,
>> +const MemoryRegion *mr,
>> +ram_addr_t offset, ram_addr_t 
>> size)
>> +{
>> +VFIORamDiscardListener *vrdl = container_of(rdl, VFIORamDiscardListener,
>> +listener);
>> +const hwaddr mr_start = MAX(offset, vrdl->offset_within_region);
>> +const hwaddr mr_end = MIN(offset + size,
>> +  vrdl->offset_within_region + vrdl->size);
>> +const hwaddr iova = mr_start - vrdl->offset_within_region +
>> +vrdl->offset_within_address_space;
>> +int ret;
>> +
>> +if (mr_start >= mr_end) {
>> +return;
>> +}
>> +
>> +/* Unmap with a single call. */
>> +ret = vfio_dma_unmap(vrdl->container, iova, mr_end - mr_start, NULL);
>> +if (ret) {
>> +error_report("%s: vfio_dma_unmap() failed: %s", __func__,
>> + strerror(-ret));
>> +}
>> +}
>> +
>> +static int vfio_ram_discard_notify_populate(RamDiscardListener *rdl,
>> +const MemoryRegion *mr,
>> +ram_addr_t offset, ram_addr_t 
>> size)
>> +{
>> +VFIORamDiscardListener *vrdl = container_of(rdl, VFIORamDiscardListener,
>> +listener);
>> +const hwaddr mr_end = MIN(offset + size,
>> +  vrdl->offset_within_region + vrdl->size);
>> +hwaddr mr_start = MAX(offset, vrdl->offset_within_region);
>> +hwaddr mr_next, iova;
>> +void *vaddr;
>> +int ret;
>> +
>> +/*
>> + * Map in (aligned within memory region) minimum granularity, so we can
>> + * unmap in minimum granularity later.
>> + */
>> +for (; mr_start < mr_end; mr_start = mr_next) {
>> +mr_next = ROUND_UP(mr_start + 1, vrdl->granularity);
>> +mr_next = MIN(mr_next, mr_end);
>> +
>> +iova = mr_start - vrdl->offset_within_region +
>> +   vrdl->offset_within_address_space;
>> +vaddr = memory_region_get_ram_ptr(vrdl->mr) + mr_start;
>> +
>> +ret = vfio_dma_map(vrdl->container, iova, mr_next - mr_start,
>> +   vaddr, mr->readonly);
>> +if (ret) {
>> +/* Rollback */
>> +vfio_ram_discard_notify_discard(rdl, mr, offset, size);
>> +return ret;
>> +}
>> +}
>> +return 0;
>> +}
>> +
>> +static void vfio_ram_discard_notify_discard_all(RamDiscardListener *rdl,
>> +const MemoryRegion *mr)
>> +{
>> +VFIORamDiscardListener *vrdl = container_of(rdl, VFIORamDiscardListener,
>> +listener);
>> +int ret;
>> +
>> +/* Unmap with a single call. */
>> +ret = vfio_dma_unmap(vrdl->container, vrdl->offset_within_address_space,
>> + vrdl->size, NULL);
>> +if (ret) {
>> +error_report("%s: vfio_dma_unmap() failed: %s", __func__,
>> + strerror(-ret));
>> +}
>> +}
>> +
>> +static void vfio_register_ram_discard_notifier(VFIOContainer *container,
>> +   MemoryRegionSection *section)
>> +{
>> +RamDiscardMgr *rdm = memory_region_get_ram_discard_mgr(section->mr);
>> +RamDiscardMgrClass *rdmc = RAM_DISCARD_MGR_GET_CLASS(rdm);
>> +VFIORamDiscardListener *vrdl;
>> +
>> +vrdl = g_new0(VFIORamDiscardListener, 1);
>> +vrdl->container = container;
>> +vrdl->mr = section->mr;
>> +

Re: [PATCH v4 04/11] vfio: Support for RamDiscardMgr in the !vIOMMU case

2021-01-13 Thread Alex Williamson
On Thu,  7 Jan 2021 14:34:16 +0100
David Hildenbrand  wrote:

> Implement support for RamDiscardMgr, to prepare for virtio-mem
> support. Instead of mapping the whole memory section, we only map
> "populated" parts and update the mapping when notified about
> discarding/population of memory via the RamDiscardListener. Similarly, when
> syncing the dirty bitmaps, sync only the actually mapped (populated) parts
> by replaying via the notifier.
> 
> Using virtio-mem with vfio is still blocked via
> ram_block_discard_disable()/ram_block_discard_require() after this patch.
> 
> Cc: Paolo Bonzini 
> Cc: "Michael S. Tsirkin" 
> Cc: Alex Williamson 
> Cc: Dr. David Alan Gilbert 
> Cc: Igor Mammedov 
> Cc: Pankaj Gupta 
> Cc: Peter Xu 
> Cc: Auger Eric 
> Cc: Wei Yang 
> Cc: teawater 
> Cc: Marek Kedzierski 
> Signed-off-by: David Hildenbrand 
> ---
>  hw/vfio/common.c  | 200 ++
>  include/hw/vfio/vfio-common.h |  12 ++
>  2 files changed, 212 insertions(+)
> 
> diff --git a/hw/vfio/common.c b/hw/vfio/common.c
> index 6ff1daa763..2bd219cf1d 100644
> --- a/hw/vfio/common.c
> +++ b/hw/vfio/common.c
> @@ -654,6 +654,136 @@ out:
>  rcu_read_unlock();
>  }
>  
> +static void vfio_ram_discard_notify_discard(RamDiscardListener *rdl,
> +const MemoryRegion *mr,
> +ram_addr_t offset, ram_addr_t 
> size)
> +{
> +VFIORamDiscardListener *vrdl = container_of(rdl, VFIORamDiscardListener,
> +listener);
> +const hwaddr mr_start = MAX(offset, vrdl->offset_within_region);
> +const hwaddr mr_end = MIN(offset + size,
> +  vrdl->offset_within_region + vrdl->size);
> +const hwaddr iova = mr_start - vrdl->offset_within_region +
> +vrdl->offset_within_address_space;
> +int ret;
> +
> +if (mr_start >= mr_end) {
> +return;
> +}
> +
> +/* Unmap with a single call. */
> +ret = vfio_dma_unmap(vrdl->container, iova, mr_end - mr_start, NULL);
> +if (ret) {
> +error_report("%s: vfio_dma_unmap() failed: %s", __func__,
> + strerror(-ret));
> +}
> +}
> +
> +static int vfio_ram_discard_notify_populate(RamDiscardListener *rdl,
> +const MemoryRegion *mr,
> +ram_addr_t offset, ram_addr_t 
> size)
> +{
> +VFIORamDiscardListener *vrdl = container_of(rdl, VFIORamDiscardListener,
> +listener);
> +const hwaddr mr_end = MIN(offset + size,
> +  vrdl->offset_within_region + vrdl->size);
> +hwaddr mr_start = MAX(offset, vrdl->offset_within_region);
> +hwaddr mr_next, iova;
> +void *vaddr;
> +int ret;
> +
> +/*
> + * Map in (aligned within memory region) minimum granularity, so we can
> + * unmap in minimum granularity later.
> + */
> +for (; mr_start < mr_end; mr_start = mr_next) {
> +mr_next = ROUND_UP(mr_start + 1, vrdl->granularity);
> +mr_next = MIN(mr_next, mr_end);
> +
> +iova = mr_start - vrdl->offset_within_region +
> +   vrdl->offset_within_address_space;
> +vaddr = memory_region_get_ram_ptr(vrdl->mr) + mr_start;
> +
> +ret = vfio_dma_map(vrdl->container, iova, mr_next - mr_start,
> +   vaddr, mr->readonly);
> +if (ret) {
> +/* Rollback */
> +vfio_ram_discard_notify_discard(rdl, mr, offset, size);
> +return ret;
> +}
> +}
> +return 0;
> +}
> +
> +static void vfio_ram_discard_notify_discard_all(RamDiscardListener *rdl,
> +const MemoryRegion *mr)
> +{
> +VFIORamDiscardListener *vrdl = container_of(rdl, VFIORamDiscardListener,
> +listener);
> +int ret;
> +
> +/* Unmap with a single call. */
> +ret = vfio_dma_unmap(vrdl->container, vrdl->offset_within_address_space,
> + vrdl->size, NULL);
> +if (ret) {
> +error_report("%s: vfio_dma_unmap() failed: %s", __func__,
> + strerror(-ret));
> +}
> +}
> +
> +static void vfio_register_ram_discard_notifier(VFIOContainer *container,
> +   MemoryRegionSection *section)
> +{
> +RamDiscardMgr *rdm = memory_region_get_ram_discard_mgr(section->mr);
> +RamDiscardMgrClass *rdmc = RAM_DISCARD_MGR_GET_CLASS(rdm);
> +VFIORamDiscardListener *vrdl;
> +
> +vrdl = g_new0(VFIORamDiscardListener, 1);
> +vrdl->container = container;
> +vrdl->mr = section->mr;
> +vrdl->offset_within_region = section->offset_within_region;
> +vrdl->offset_within_address_space = section->offset_within_address_space;
> +vrdl->size = int128_get64(section->size);

[PATCH v4 04/11] vfio: Support for RamDiscardMgr in the !vIOMMU case

2021-01-07 Thread David Hildenbrand
Implement support for RamDiscardMgr, to prepare for virtio-mem
support. Instead of mapping the whole memory section, we only map
"populated" parts and update the mapping when notified about
discarding/population of memory via the RamDiscardListener. Similarly, when
syncing the dirty bitmaps, sync only the actually mapped (populated) parts
by replaying via the notifier.

Using virtio-mem with vfio is still blocked via
ram_block_discard_disable()/ram_block_discard_require() after this patch.

Cc: Paolo Bonzini 
Cc: "Michael S. Tsirkin" 
Cc: Alex Williamson 
Cc: Dr. David Alan Gilbert 
Cc: Igor Mammedov 
Cc: Pankaj Gupta 
Cc: Peter Xu 
Cc: Auger Eric 
Cc: Wei Yang 
Cc: teawater 
Cc: Marek Kedzierski 
Signed-off-by: David Hildenbrand 
---
 hw/vfio/common.c  | 200 ++
 include/hw/vfio/vfio-common.h |  12 ++
 2 files changed, 212 insertions(+)

diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 6ff1daa763..2bd219cf1d 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -654,6 +654,136 @@ out:
 rcu_read_unlock();
 }
 
+static void vfio_ram_discard_notify_discard(RamDiscardListener *rdl,
+const MemoryRegion *mr,
+ram_addr_t offset, ram_addr_t size)
+{
+VFIORamDiscardListener *vrdl = container_of(rdl, VFIORamDiscardListener,
+listener);
+const hwaddr mr_start = MAX(offset, vrdl->offset_within_region);
+const hwaddr mr_end = MIN(offset + size,
+  vrdl->offset_within_region + vrdl->size);
+const hwaddr iova = mr_start - vrdl->offset_within_region +
+vrdl->offset_within_address_space;
+int ret;
+
+if (mr_start >= mr_end) {
+return;
+}
+
+/* Unmap with a single call. */
+ret = vfio_dma_unmap(vrdl->container, iova, mr_end - mr_start, NULL);
+if (ret) {
+error_report("%s: vfio_dma_unmap() failed: %s", __func__,
+ strerror(-ret));
+}
+}
+
+static int vfio_ram_discard_notify_populate(RamDiscardListener *rdl,
+const MemoryRegion *mr,
+ram_addr_t offset, ram_addr_t size)
+{
+VFIORamDiscardListener *vrdl = container_of(rdl, VFIORamDiscardListener,
+listener);
+const hwaddr mr_end = MIN(offset + size,
+  vrdl->offset_within_region + vrdl->size);
+hwaddr mr_start = MAX(offset, vrdl->offset_within_region);
+hwaddr mr_next, iova;
+void *vaddr;
+int ret;
+
+/*
+ * Map in (aligned within memory region) minimum granularity, so we can
+ * unmap in minimum granularity later.
+ */
+for (; mr_start < mr_end; mr_start = mr_next) {
+mr_next = ROUND_UP(mr_start + 1, vrdl->granularity);
+mr_next = MIN(mr_next, mr_end);
+
+iova = mr_start - vrdl->offset_within_region +
+   vrdl->offset_within_address_space;
+vaddr = memory_region_get_ram_ptr(vrdl->mr) + mr_start;
+
+ret = vfio_dma_map(vrdl->container, iova, mr_next - mr_start,
+   vaddr, mr->readonly);
+if (ret) {
+/* Rollback */
+vfio_ram_discard_notify_discard(rdl, mr, offset, size);
+return ret;
+}
+}
+return 0;
+}
+
+static void vfio_ram_discard_notify_discard_all(RamDiscardListener *rdl,
+const MemoryRegion *mr)
+{
+VFIORamDiscardListener *vrdl = container_of(rdl, VFIORamDiscardListener,
+listener);
+int ret;
+
+/* Unmap with a single call. */
+ret = vfio_dma_unmap(vrdl->container, vrdl->offset_within_address_space,
+ vrdl->size, NULL);
+if (ret) {
+error_report("%s: vfio_dma_unmap() failed: %s", __func__,
+ strerror(-ret));
+}
+}
+
+static void vfio_register_ram_discard_notifier(VFIOContainer *container,
+   MemoryRegionSection *section)
+{
+RamDiscardMgr *rdm = memory_region_get_ram_discard_mgr(section->mr);
+RamDiscardMgrClass *rdmc = RAM_DISCARD_MGR_GET_CLASS(rdm);
+VFIORamDiscardListener *vrdl;
+
+vrdl = g_new0(VFIORamDiscardListener, 1);
+vrdl->container = container;
+vrdl->mr = section->mr;
+vrdl->offset_within_region = section->offset_within_region;
+vrdl->offset_within_address_space = section->offset_within_address_space;
+vrdl->size = int128_get64(section->size);
+vrdl->granularity = rdmc->get_min_granularity(rdm, section->mr);
+
+/* Ignore some corner cases not relevant in practice. */
+g_assert(QEMU_IS_ALIGNED(vrdl->offset_within_region, TARGET_PAGE_SIZE));
+g_assert(QEMU_IS_ALIGNED(vrdl->offset_within_address_space,
+