Re: [PATCH v27 14/17] vfio: Dirty page tracking when vIOMMU is enabled
On 10/23/2020 2:07 AM, Alex Williamson wrote: On Thu, 22 Oct 2020 16:42:04 +0530 Kirti Wankhede wrote: When vIOMMU is enabled, register MAP notifier from log_sync when all devices in container are in stop and copy phase of migration. Call replay and get dirty pages from notifier callback. Suggested-by: Alex Williamson Signed-off-by: Kirti Wankhede --- hw/vfio/common.c | 95 --- hw/vfio/trace-events | 1 + include/hw/vfio/vfio-common.h | 1 + 3 files changed, 91 insertions(+), 6 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 2634387df948..98c2b1f9b190 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -442,8 +442,8 @@ static bool vfio_listener_skipped_section(MemoryRegionSection *section) } /* Called with rcu_read_lock held. */ -static bool vfio_get_vaddr(IOMMUTLBEntry *iotlb, void **vaddr, - bool *read_only) +static bool vfio_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, + ram_addr_t *ram_addr, bool *read_only) { MemoryRegion *mr; hwaddr xlat; @@ -474,8 +474,17 @@ static bool vfio_get_vaddr(IOMMUTLBEntry *iotlb, void **vaddr, return false; } -*vaddr = memory_region_get_ram_ptr(mr) + xlat; -*read_only = !writable || mr->readonly; +if (vaddr) { +*vaddr = memory_region_get_ram_ptr(mr) + xlat; +} + +if (ram_addr) { +*ram_addr = memory_region_get_ram_addr(mr) + xlat; +} + +if (read_only) { +*read_only = !writable || mr->readonly; +} return true; } @@ -485,7 +494,6 @@ static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n); VFIOContainer *container = giommu->container; hwaddr iova = iotlb->iova + giommu->iommu_offset; -bool read_only; void *vaddr; int ret; @@ -501,7 +509,9 @@ static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) rcu_read_lock(); if ((iotlb->perm & IOMMU_RW) != IOMMU_NONE) { -if (!vfio_get_vaddr(iotlb, , _only)) { +bool read_only; + +if (!vfio_get_xlat_addr(iotlb, , NULL, _only)) { goto out; } /* @@ -899,11 +909,84 @@ err_out: return ret; } +static void vfio_iommu_map_dirty_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) +{ +VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, dirty_notify); +VFIOContainer *container = giommu->container; +hwaddr iova = iotlb->iova + giommu->iommu_offset; +ram_addr_t translated_addr; + +trace_vfio_iommu_map_dirty_notify(iova, iova + iotlb->addr_mask); + +if (iotlb->target_as != _space_memory) { +error_report("Wrong target AS \"%s\", only system memory is allowed", + iotlb->target_as->name ? iotlb->target_as->name : "none"); +return; +} + +rcu_read_lock(); + +if (vfio_get_xlat_addr(iotlb, NULL, _addr, NULL)) { +int ret; + +ret = vfio_get_dirty_bitmap(container, iova, iotlb->addr_mask + 1, +translated_addr); +if (ret) { +error_report("vfio_iommu_map_dirty_notify(%p, 0x%"HWADDR_PRIx", " + "0x%"HWADDR_PRIx") = %d (%m)", + container, iova, + iotlb->addr_mask + 1, ret); +} +} + +rcu_read_unlock(); +} + static int vfio_sync_dirty_bitmap(VFIOContainer *container, MemoryRegionSection *section) { ram_addr_t ram_addr; +if (memory_region_is_iommu(section->mr)) { +VFIOGuestIOMMU *giommu; +int ret = 0; + +QLIST_FOREACH(giommu, >giommu_list, giommu_next) { +if (MEMORY_REGION(giommu->iommu) == section->mr && +giommu->n.start == section->offset_within_region) { +Int128 llend; +Error *err = NULL; +int idx = memory_region_iommu_attrs_to_index(giommu->iommu, + MEMTXATTRS_UNSPECIFIED); + +llend = int128_add(int128_make64(section->offset_within_region), + section->size); +llend = int128_sub(llend, int128_one()); + +iommu_notifier_init(>dirty_notify, +vfio_iommu_map_dirty_notify, +IOMMU_NOTIFIER_MAP, +section->offset_within_region, +int128_get64(llend), +idx); +ret = memory_region_register_iommu_notifier(section->mr, + >dirty_notify, ); +if (ret) { +error_report_err(err); +break; +
Re: [PATCH v27 14/17] vfio: Dirty page tracking when vIOMMU is enabled
On Thu, 22 Oct 2020 16:42:04 +0530 Kirti Wankhede wrote: > When vIOMMU is enabled, register MAP notifier from log_sync when all > devices in container are in stop and copy phase of migration. Call replay > and get dirty pages from notifier callback. > > Suggested-by: Alex Williamson > Signed-off-by: Kirti Wankhede > --- > hw/vfio/common.c | 95 > --- > hw/vfio/trace-events | 1 + > include/hw/vfio/vfio-common.h | 1 + > 3 files changed, 91 insertions(+), 6 deletions(-) > > diff --git a/hw/vfio/common.c b/hw/vfio/common.c > index 2634387df948..98c2b1f9b190 100644 > --- a/hw/vfio/common.c > +++ b/hw/vfio/common.c > @@ -442,8 +442,8 @@ static bool > vfio_listener_skipped_section(MemoryRegionSection *section) > } > > /* Called with rcu_read_lock held. */ > -static bool vfio_get_vaddr(IOMMUTLBEntry *iotlb, void **vaddr, > - bool *read_only) > +static bool vfio_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, > + ram_addr_t *ram_addr, bool *read_only) > { > MemoryRegion *mr; > hwaddr xlat; > @@ -474,8 +474,17 @@ static bool vfio_get_vaddr(IOMMUTLBEntry *iotlb, void > **vaddr, > return false; > } > > -*vaddr = memory_region_get_ram_ptr(mr) + xlat; > -*read_only = !writable || mr->readonly; > +if (vaddr) { > +*vaddr = memory_region_get_ram_ptr(mr) + xlat; > +} > + > +if (ram_addr) { > +*ram_addr = memory_region_get_ram_addr(mr) + xlat; > +} > + > +if (read_only) { > +*read_only = !writable || mr->readonly; > +} > > return true; > } > @@ -485,7 +494,6 @@ static void vfio_iommu_map_notify(IOMMUNotifier *n, > IOMMUTLBEntry *iotlb) > VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n); > VFIOContainer *container = giommu->container; > hwaddr iova = iotlb->iova + giommu->iommu_offset; > -bool read_only; > void *vaddr; > int ret; > > @@ -501,7 +509,9 @@ static void vfio_iommu_map_notify(IOMMUNotifier *n, > IOMMUTLBEntry *iotlb) > rcu_read_lock(); > > if ((iotlb->perm & IOMMU_RW) != IOMMU_NONE) { > -if (!vfio_get_vaddr(iotlb, , _only)) { > +bool read_only; > + > +if (!vfio_get_xlat_addr(iotlb, , NULL, _only)) { > goto out; > } > /* > @@ -899,11 +909,84 @@ err_out: > return ret; > } > > +static void vfio_iommu_map_dirty_notify(IOMMUNotifier *n, IOMMUTLBEntry > *iotlb) > +{ > +VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, dirty_notify); > +VFIOContainer *container = giommu->container; > +hwaddr iova = iotlb->iova + giommu->iommu_offset; > +ram_addr_t translated_addr; > + > +trace_vfio_iommu_map_dirty_notify(iova, iova + iotlb->addr_mask); > + > +if (iotlb->target_as != _space_memory) { > +error_report("Wrong target AS \"%s\", only system memory is allowed", > + iotlb->target_as->name ? iotlb->target_as->name : > "none"); > +return; > +} > + > +rcu_read_lock(); > + > +if (vfio_get_xlat_addr(iotlb, NULL, _addr, NULL)) { > +int ret; > + > +ret = vfio_get_dirty_bitmap(container, iova, iotlb->addr_mask + 1, > +translated_addr); > +if (ret) { > +error_report("vfio_iommu_map_dirty_notify(%p, 0x%"HWADDR_PRIx", " > + "0x%"HWADDR_PRIx") = %d (%m)", > + container, iova, > + iotlb->addr_mask + 1, ret); > +} > +} > + > +rcu_read_unlock(); > +} > + > static int vfio_sync_dirty_bitmap(VFIOContainer *container, >MemoryRegionSection *section) > { > ram_addr_t ram_addr; > > +if (memory_region_is_iommu(section->mr)) { > +VFIOGuestIOMMU *giommu; > +int ret = 0; > + > +QLIST_FOREACH(giommu, >giommu_list, giommu_next) { > +if (MEMORY_REGION(giommu->iommu) == section->mr && > +giommu->n.start == section->offset_within_region) { > +Int128 llend; > +Error *err = NULL; > +int idx = memory_region_iommu_attrs_to_index(giommu->iommu, > + > MEMTXATTRS_UNSPECIFIED); > + > +llend = > int128_add(int128_make64(section->offset_within_region), > + section->size); > +llend = int128_sub(llend, int128_one()); > + > +iommu_notifier_init(>dirty_notify, > +vfio_iommu_map_dirty_notify, > +IOMMU_NOTIFIER_MAP, > +section->offset_within_region, > +int128_get64(llend), > +idx); > +ret =
[PATCH v27 14/17] vfio: Dirty page tracking when vIOMMU is enabled
When vIOMMU is enabled, register MAP notifier from log_sync when all devices in container are in stop and copy phase of migration. Call replay and get dirty pages from notifier callback. Suggested-by: Alex Williamson Signed-off-by: Kirti Wankhede --- hw/vfio/common.c | 95 --- hw/vfio/trace-events | 1 + include/hw/vfio/vfio-common.h | 1 + 3 files changed, 91 insertions(+), 6 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 2634387df948..98c2b1f9b190 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -442,8 +442,8 @@ static bool vfio_listener_skipped_section(MemoryRegionSection *section) } /* Called with rcu_read_lock held. */ -static bool vfio_get_vaddr(IOMMUTLBEntry *iotlb, void **vaddr, - bool *read_only) +static bool vfio_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, + ram_addr_t *ram_addr, bool *read_only) { MemoryRegion *mr; hwaddr xlat; @@ -474,8 +474,17 @@ static bool vfio_get_vaddr(IOMMUTLBEntry *iotlb, void **vaddr, return false; } -*vaddr = memory_region_get_ram_ptr(mr) + xlat; -*read_only = !writable || mr->readonly; +if (vaddr) { +*vaddr = memory_region_get_ram_ptr(mr) + xlat; +} + +if (ram_addr) { +*ram_addr = memory_region_get_ram_addr(mr) + xlat; +} + +if (read_only) { +*read_only = !writable || mr->readonly; +} return true; } @@ -485,7 +494,6 @@ static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n); VFIOContainer *container = giommu->container; hwaddr iova = iotlb->iova + giommu->iommu_offset; -bool read_only; void *vaddr; int ret; @@ -501,7 +509,9 @@ static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) rcu_read_lock(); if ((iotlb->perm & IOMMU_RW) != IOMMU_NONE) { -if (!vfio_get_vaddr(iotlb, , _only)) { +bool read_only; + +if (!vfio_get_xlat_addr(iotlb, , NULL, _only)) { goto out; } /* @@ -899,11 +909,84 @@ err_out: return ret; } +static void vfio_iommu_map_dirty_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) +{ +VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, dirty_notify); +VFIOContainer *container = giommu->container; +hwaddr iova = iotlb->iova + giommu->iommu_offset; +ram_addr_t translated_addr; + +trace_vfio_iommu_map_dirty_notify(iova, iova + iotlb->addr_mask); + +if (iotlb->target_as != _space_memory) { +error_report("Wrong target AS \"%s\", only system memory is allowed", + iotlb->target_as->name ? iotlb->target_as->name : "none"); +return; +} + +rcu_read_lock(); + +if (vfio_get_xlat_addr(iotlb, NULL, _addr, NULL)) { +int ret; + +ret = vfio_get_dirty_bitmap(container, iova, iotlb->addr_mask + 1, +translated_addr); +if (ret) { +error_report("vfio_iommu_map_dirty_notify(%p, 0x%"HWADDR_PRIx", " + "0x%"HWADDR_PRIx") = %d (%m)", + container, iova, + iotlb->addr_mask + 1, ret); +} +} + +rcu_read_unlock(); +} + static int vfio_sync_dirty_bitmap(VFIOContainer *container, MemoryRegionSection *section) { ram_addr_t ram_addr; +if (memory_region_is_iommu(section->mr)) { +VFIOGuestIOMMU *giommu; +int ret = 0; + +QLIST_FOREACH(giommu, >giommu_list, giommu_next) { +if (MEMORY_REGION(giommu->iommu) == section->mr && +giommu->n.start == section->offset_within_region) { +Int128 llend; +Error *err = NULL; +int idx = memory_region_iommu_attrs_to_index(giommu->iommu, + MEMTXATTRS_UNSPECIFIED); + +llend = int128_add(int128_make64(section->offset_within_region), + section->size); +llend = int128_sub(llend, int128_one()); + +iommu_notifier_init(>dirty_notify, +vfio_iommu_map_dirty_notify, +IOMMU_NOTIFIER_MAP, +section->offset_within_region, +int128_get64(llend), +idx); +ret = memory_region_register_iommu_notifier(section->mr, + >dirty_notify, ); +if (ret) { +error_report_err(err); +break; +} + +memory_region_iommu_replay(giommu->iommu, + >dirty_notify); + +