In-place page conversion requires operations to follow a specific sequence: unmap-before-conversion-to-private and map-after-conversion-to-shared. Currently, both attribute changes and VFIO DMA map/unmap operations are handled by PrivateSharedListeners, they need to be invoked in a specific order.
For private to shared conversion: - Change attribute to shared. - VFIO populates the shared mappings into the IOMMU. - Restore attribute if the operation fails. For shared to private conversion: - VFIO discards shared mapping from the IOMMU. - Change attribute to private. To faciliate this sequence, priority support is added to PrivateSharedListener so that listeners are stored in a determined order based on priority. A tail queue is used to store listeners, allowing traversal in either direction. Signed-off-by: Chenyi Qiang <chenyi.qi...@intel.com> --- Changes in v4: - Newly added. --- accel/kvm/kvm-all.c | 3 ++- hw/vfio/common.c | 3 ++- include/exec/memory.h | 19 +++++++++++++++++-- include/exec/ramblock.h | 2 +- system/ram-block-attribute.c | 23 +++++++++++++++++------ 5 files changed, 39 insertions(+), 11 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index aec64d559b..879c61b391 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -1745,7 +1745,8 @@ static void kvm_region_add(MemoryListener *listener, psl = &cpsl->listener; QLIST_INSERT_HEAD(&cgs->cvm_private_shared_list, cpsl, next); private_shared_listener_init(psl, kvm_private_shared_notify_to_shared, - kvm_private_shared_notify_to_private); + kvm_private_shared_notify_to_private, + PRIVATE_SHARED_LISTENER_PRIORITY_MIN); generic_state_manager_register_listener(gsm, &psl->scl, section); } diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 6e49ae597d..a8aacae26c 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -515,7 +515,8 @@ static void vfio_register_private_shared_listener(VFIOContainerBase *bcontainer, psl = &vpsl->listener; private_shared_listener_init(psl, vfio_private_shared_notify_to_shared, - vfio_private_shared_notify_to_private); + vfio_private_shared_notify_to_private, + PRIVATE_SHARED_LISTENER_PRIORITY_COMMON); generic_state_manager_register_listener(gsm, &psl->scl, section); QLIST_INSERT_HEAD(&bcontainer->vpsl_list, vpsl, next); } diff --git a/include/exec/memory.h b/include/exec/memory.h index 9472d9e9b4..3d06cc04a0 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -770,11 +770,24 @@ struct RamDiscardManagerClass { GenericStateManagerClass parent_class; }; +#define PRIVATE_SHARED_LISTENER_PRIORITY_MIN 0 +#define PRIVATE_SHARED_LISTENER_PRIORITY_COMMON 10 + typedef struct PrivateSharedListener PrivateSharedListener; struct PrivateSharedListener { struct StateChangeListener scl; - QLIST_ENTRY(PrivateSharedListener) next; + /* + * @priority: + * + * Govern the order in which ram discard listeners are invoked. Lower priorities + * are invoked earlier. + * The listener priority can help to undo the effects of previous listeners in + * a reverse order in case of a failure callback. + */ + int priority; + + QTAILQ_ENTRY(PrivateSharedListener) next; }; struct PrivateSharedManagerClass { @@ -787,9 +800,11 @@ struct PrivateSharedManagerClass { static inline void private_shared_listener_init(PrivateSharedListener *psl, NotifyStateSet populate_fn, - NotifyStateClear discard_fn) + NotifyStateClear discard_fn, + int priority) { state_change_listener_init(&psl->scl, populate_fn, discard_fn); + psl->priority = priority; } int private_shared_manager_state_change(PrivateSharedManager *mgr, diff --git a/include/exec/ramblock.h b/include/exec/ramblock.h index 78eb031819..7a3dd709bb 100644 --- a/include/exec/ramblock.h +++ b/include/exec/ramblock.h @@ -105,7 +105,7 @@ struct RamBlockAttribute { unsigned shared_bitmap_size; unsigned long *shared_bitmap; - QLIST_HEAD(, PrivateSharedListener) psl_list; + QTAILQ_HEAD(, PrivateSharedListener) psl_list; }; struct RamBlockAttributeClass { diff --git a/system/ram-block-attribute.c b/system/ram-block-attribute.c index 15c9aebd09..fd041148c7 100644 --- a/system/ram-block-attribute.c +++ b/system/ram-block-attribute.c @@ -158,12 +158,23 @@ static void ram_block_attribute_psm_register_listener(GenericStateManager *gsm, { RamBlockAttribute *attr = RAM_BLOCK_ATTRIBUTE(gsm); PrivateSharedListener *psl = container_of(scl, PrivateSharedListener, scl); + PrivateSharedListener *other = NULL; int ret; g_assert(section->mr == attr->mr); scl->section = memory_region_section_new_copy(section); - QLIST_INSERT_HEAD(&attr->psl_list, psl, next); + if (QTAILQ_EMPTY(&attr->psl_list) || + psl->priority >= QTAILQ_LAST(&attr->psl_list)->priority) { + QTAILQ_INSERT_TAIL(&attr->psl_list, psl, next); + } else { + QTAILQ_FOREACH(other, &attr->psl_list, next) { + if (psl->priority < other->priority) { + break; + } + } + QTAILQ_INSERT_BEFORE(other, psl, next); + } ret = ram_block_attribute_for_each_shared_section(attr, section, scl, ram_block_attribute_notify_shared_cb); @@ -192,7 +203,7 @@ static void ram_block_attribute_psm_unregister_listener(GenericStateManager *gsm memory_region_section_free_copy(scl->section); scl->section = NULL; - QLIST_REMOVE(psl, next); + QTAILQ_REMOVE(&attr->psl_list, psl, next); } typedef struct RamBlockAttributeReplayData { @@ -261,7 +272,7 @@ static void ram_block_attribute_notify_to_private(RamBlockAttribute *attr, PrivateSharedListener *psl; int ret; - QLIST_FOREACH(psl, &attr->psl_list, next) { + QTAILQ_FOREACH_REVERSE(psl, &attr->psl_list, next) { StateChangeListener *scl = &psl->scl; MemoryRegionSection tmp = *scl->section; @@ -283,7 +294,7 @@ static int ram_block_attribute_notify_to_shared(RamBlockAttribute *attr, PrivateSharedListener *psl, *psl2; int ret = 0, ret2 = 0; - QLIST_FOREACH(psl, &attr->psl_list, next) { + QTAILQ_FOREACH(psl, &attr->psl_list, next) { StateChangeListener *scl = &psl->scl; MemoryRegionSection tmp = *scl->section; @@ -298,7 +309,7 @@ static int ram_block_attribute_notify_to_shared(RamBlockAttribute *attr, if (ret) { /* Notify all already-notified listeners. */ - QLIST_FOREACH(psl2, &attr->psl_list, next) { + QTAILQ_FOREACH(psl2, &attr->psl_list, next) { StateChangeListener *scl2 = &psl2->scl; MemoryRegionSection tmp = *scl2->section; @@ -462,7 +473,7 @@ static void ram_block_attribute_init(Object *obj) { RamBlockAttribute *attr = RAM_BLOCK_ATTRIBUTE(obj); - QLIST_INIT(&attr->psl_list); + QTAILQ_INIT(&attr->psl_list); } static void ram_block_attribute_finalize(Object *obj) -- 2.43.5