diff mbox series

[RFC,06/10] vfio/iommufd: Add HWPT_SET_DIRTY support

Message ID 20220428211351.3897-7-joao.m.martins@oracle.com (mailing list archive)
State New, archived
Headers show
Series hw/vfio, x86/iommu: IOMMUFD Dirty Tracking | expand

Commit Message

Joao Martins April 28, 2022, 9:13 p.m. UTC
ioctl(iommufd, IOMMU_HWPT_SET_DIRTY, arg) is the UAPI
that enables or disables dirty page tracking. We set it
on the whole list of iommu domains we are tracking, and
set ::dirty_pages_supported accordingly, used when we
attempt at reading out the dirty bits from the hw pagetables.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
---
 hw/iommufd/iommufd.c         | 18 ++++++++++++
 hw/iommufd/trace-events      |  1 +
 hw/vfio/iommufd.c            | 57 ++++++++++++++++++++++++++++++++++++
 include/hw/iommufd/iommufd.h |  1 +
 4 files changed, 77 insertions(+)
diff mbox series

Patch

diff --git a/hw/iommufd/iommufd.c b/hw/iommufd/iommufd.c
index 4e8179d612a5..e5aff5deaf14 100644
--- a/hw/iommufd/iommufd.c
+++ b/hw/iommufd/iommufd.c
@@ -201,6 +201,24 @@  int iommufd_copy_dma(int iommufd, uint32_t src_ioas, uint32_t dst_ioas,
     return !ret ? 0 : -errno;
 }
 
+int iommufd_set_dirty_tracking(int iommufd, uint32_t hwpt_id, bool start)
+{
+    int ret;
+    struct iommu_hwpt_set_dirty set_dirty = {
+            .size = sizeof(set_dirty),
+            .hwpt_id = hwpt_id,
+            .flags = !start ? IOMMU_DIRTY_TRACKING_DISABLED :
+                        IOMMU_DIRTY_TRACKING_ENABLED,
+    };
+
+    ret = ioctl(iommufd, IOMMU_HWPT_SET_DIRTY, &set_dirty);
+    trace_iommufd_set_dirty(iommufd, hwpt_id, start, ret);
+    if (ret) {
+        error_report("IOMMU_HWPT_SET_DIRTY failed: %s", strerror(errno));
+    }
+    return !ret ? 0 : -errno;
+}
+
 static void iommufd_register_types(void)
 {
     qemu_mutex_init(&iommufd_lock);
diff --git a/hw/iommufd/trace-events b/hw/iommufd/trace-events
index 615d80cdf42c..d3c2b5a0ab95 100644
--- a/hw/iommufd/trace-events
+++ b/hw/iommufd/trace-events
@@ -9,3 +9,4 @@  iommufd_put_ioas(int iommufd, uint32_t ioas) " iommufd=%d ioas=%d"
 iommufd_unmap_dma(int iommufd, uint32_t ioas, uint64_t iova, uint64_t size, int ret) " iommufd=%d ioas=%d iova=0x%"PRIx64" size=0x%"PRIx64" (%d)"
 iommufd_map_dma(int iommufd, uint32_t ioas, uint64_t iova, uint64_t size, void *vaddr, bool readonly, int ret) " iommufd=%d ioas=%d iova=0x%"PRIx64" size=0x%"PRIx64" addr=%p readonly=%d (%d)"
 iommufd_copy_dma(int iommufd, uint32_t src_ioas, uint32_t dst_ioas, uint64_t iova, uint64_t size, bool readonly, int ret) " iommufd=%d src_ioas=%d dst_ioas=%d iova=0x%"PRIx64" size=0x%"PRIx64" readonly=%d (%d)"
+iommufd_set_dirty(int iommufd, uint32_t hwpt_id, bool start, int ret) " iommufd=%d hwpt=%d enable=%d (%d)"
diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c
index 8ff5988b0773..8146407feedd 100644
--- a/hw/vfio/iommufd.c
+++ b/hw/vfio/iommufd.c
@@ -33,6 +33,7 @@ 
 #include "hw/qdev-core.h"
 #include "sysemu/reset.h"
 #include "qemu/cutils.h"
+#include "migration/migration.h"
 
 static bool iommufd_check_extension(VFIOContainer *bcontainer,
                                     VFIOContainerFeature feat)
@@ -82,6 +83,25 @@  static int iommufd_unmap(VFIOContainer *bcontainer,
                              container->ioas_id, iova, size);
 }
 
+static void iommufd_set_dirty_page_tracking(VFIOContainer *bcontainer,
+                                            bool start)
+{
+    VFIOIOMMUFDContainer *container = container_of(bcontainer,
+                                                   VFIOIOMMUFDContainer, obj);
+    int ret;
+    VFIOIOASHwpt *hwpt;
+
+    QLIST_FOREACH(hwpt, &container->hwpt_list, next) {
+        ret = iommufd_set_dirty_tracking(container->iommufd,
+                                         hwpt->hwpt_id, start);
+        if (ret) {
+            return;
+        }
+    }
+
+    bcontainer->dirty_pages_supported = start;
+}
+
 static int vfio_get_devicefd(const char *sysfs_path, Error **errp)
 {
     long int vfio_id = -1, ret = -ENOTTY;
@@ -304,6 +324,40 @@  static int vfio_device_reset(VFIODevice *vbasedev)
     return 0;
 }
 
+static bool vfio_iommufd_devices_all_dirty_tracking(VFIOContainer *bcontainer)
+{
+    MigrationState *ms = migrate_get_current();
+    VFIOIOMMUFDContainer *container;
+    VFIODevice *vbasedev;
+    VFIOIOASHwpt *hwpt;
+
+    if (bcontainer->dirty_pages_supported) {
+        return true;
+    }
+
+    if (!migration_is_setup_or_active(ms->state)) {
+        return false;
+    }
+
+    container = container_of(bcontainer, VFIOIOMMUFDContainer, obj);
+
+    QLIST_FOREACH(hwpt, &container->hwpt_list, next) {
+        QLIST_FOREACH(vbasedev, &hwpt->device_list, hwpt_next) {
+            VFIOMigration *migration = vbasedev->migration;
+
+            if (!migration) {
+                return false;
+            }
+
+            if ((vbasedev->pre_copy_dirty_page_tracking == ON_OFF_AUTO_OFF)
+                && (migration->device_state & VFIO_DEVICE_STATE_RUNNING)) {
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
 static int vfio_iommufd_container_reset(VFIOContainer *bcontainer)
 {
     VFIOIOMMUFDContainer *container;
@@ -446,6 +500,7 @@  static int iommufd_attach_device(VFIODevice *vbasedev, AddressSpace *as,
      */
 
     vfio_as_add_container(space, bcontainer);
+    bcontainer->dirty_pages_supported = true;
     bcontainer->initialized = true;
 
 out:
@@ -554,6 +609,8 @@  static void vfio_iommufd_class_init(ObjectClass *klass,
     vccs->attach_device = iommufd_attach_device;
     vccs->detach_device = iommufd_detach_device;
     vccs->reset = vfio_iommufd_container_reset;
+    vccs->devices_all_dirty_tracking = vfio_iommufd_devices_all_dirty_tracking;
+    vccs->set_dirty_page_tracking = iommufd_set_dirty_page_tracking;
 }
 
 static const TypeInfo vfio_iommufd_info = {
diff --git a/include/hw/iommufd/iommufd.h b/include/hw/iommufd/iommufd.h
index 59835cddcacf..61fd83771099 100644
--- a/include/hw/iommufd/iommufd.h
+++ b/include/hw/iommufd/iommufd.h
@@ -33,5 +33,6 @@  int iommufd_map_dma(int iommufd, uint32_t ioas, hwaddr iova,
                     ram_addr_t size, void *vaddr, bool readonly);
 int iommufd_copy_dma(int iommufd, uint32_t src_ioas, uint32_t dst_ioas,
                      hwaddr iova, ram_addr_t size, bool readonly);
+int iommufd_set_dirty_tracking(int iommufd, uint32_t hwpt_id, bool start);
 bool iommufd_supported(void);
 #endif /* HW_IOMMUFD_IOMMUFD_H */