@@ -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);
}
@@ -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);
}
@@ -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,
@@ -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 {
@@ -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)
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.qiang@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(-)