memory: switch memory listeners to a QTAILQ
This allows reverse iteration, which in turns allows consistent ordering among multiple listeners: l1->add l2->add l2->del l1->del Signed-off-by: Avi Kivity <avi@redhat.com> Reviewed-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
parent
946996e9c1
commit
72e22d2fe1
|
@ -751,6 +751,7 @@ int vhost_dev_init(struct vhost_dev *hdev, int devfd, bool force)
|
||||||
.log_sync = vhost_log_sync,
|
.log_sync = vhost_log_sync,
|
||||||
.log_global_start = vhost_log_global_start,
|
.log_global_start = vhost_log_global_start,
|
||||||
.log_global_stop = vhost_log_global_stop,
|
.log_global_stop = vhost_log_global_stop,
|
||||||
|
.priority = 10
|
||||||
};
|
};
|
||||||
hdev->mem = g_malloc0(offsetof(struct vhost_memory, regions));
|
hdev->mem = g_malloc0(offsetof(struct vhost_memory, regions));
|
||||||
hdev->n_mem_sections = 0;
|
hdev->n_mem_sections = 0;
|
||||||
|
|
|
@ -726,6 +726,7 @@ static MemoryListener kvm_memory_listener = {
|
||||||
.log_sync = kvm_log_sync,
|
.log_sync = kvm_log_sync,
|
||||||
.log_global_start = kvm_log_global_start,
|
.log_global_start = kvm_log_global_start,
|
||||||
.log_global_stop = kvm_log_global_stop,
|
.log_global_stop = kvm_log_global_stop,
|
||||||
|
.priority = 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void kvm_handle_interrupt(CPUState *env, int mask)
|
static void kvm_handle_interrupt(CPUState *env, int mask)
|
||||||
|
|
70
memory.c
70
memory.c
|
@ -27,8 +27,8 @@ unsigned memory_region_transaction_depth = 0;
|
||||||
static bool memory_region_update_pending = false;
|
static bool memory_region_update_pending = false;
|
||||||
static bool global_dirty_log = false;
|
static bool global_dirty_log = false;
|
||||||
|
|
||||||
static QLIST_HEAD(, MemoryListener) memory_listeners
|
static QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners
|
||||||
= QLIST_HEAD_INITIALIZER(memory_listeners);
|
= QTAILQ_HEAD_INITIALIZER(memory_listeners);
|
||||||
|
|
||||||
typedef struct AddrRange AddrRange;
|
typedef struct AddrRange AddrRange;
|
||||||
|
|
||||||
|
@ -678,17 +678,31 @@ static void address_space_update_ioeventfds(AddressSpace *as)
|
||||||
as->ioeventfd_nb = ioeventfd_nb;
|
as->ioeventfd_nb = ioeventfd_nb;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MEMORY_LISTENER_CALL(_callback, _args...) \
|
enum ListenerDirection { Forward, Reverse };
|
||||||
do { \
|
|
||||||
MemoryListener *_listener; \
|
#define MEMORY_LISTENER_CALL(_callback, _direction, _args...) \
|
||||||
\
|
do { \
|
||||||
QLIST_FOREACH(_listener, &memory_listeners, link) { \
|
MemoryListener *_listener; \
|
||||||
_listener->_callback(_listener, ##_args); \
|
\
|
||||||
} \
|
switch (_direction) { \
|
||||||
|
case Forward: \
|
||||||
|
QTAILQ_FOREACH(_listener, &memory_listeners, link) { \
|
||||||
|
_listener->_callback(_listener, ##_args); \
|
||||||
|
} \
|
||||||
|
break; \
|
||||||
|
case Reverse: \
|
||||||
|
QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners, \
|
||||||
|
memory_listeners, link) { \
|
||||||
|
_listener->_callback(_listener, ##_args); \
|
||||||
|
} \
|
||||||
|
break; \
|
||||||
|
default: \
|
||||||
|
abort(); \
|
||||||
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define MEMORY_LISTENER_UPDATE_REGION(fr, as, callback) \
|
#define MEMORY_LISTENER_UPDATE_REGION(fr, as, dir, callback) \
|
||||||
MEMORY_LISTENER_CALL(callback, &(MemoryRegionSection) { \
|
MEMORY_LISTENER_CALL(callback, dir, &(MemoryRegionSection) { \
|
||||||
.mr = (fr)->mr, \
|
.mr = (fr)->mr, \
|
||||||
.address_space = (as)->root, \
|
.address_space = (as)->root, \
|
||||||
.offset_within_region = (fr)->offset_in_region, \
|
.offset_within_region = (fr)->offset_in_region, \
|
||||||
|
@ -728,7 +742,7 @@ static void address_space_update_topology_pass(AddressSpace *as,
|
||||||
/* In old, but (not in new, or in new but attributes changed). */
|
/* In old, but (not in new, or in new but attributes changed). */
|
||||||
|
|
||||||
if (!adding) {
|
if (!adding) {
|
||||||
MEMORY_LISTENER_UPDATE_REGION(frold, as, region_del);
|
MEMORY_LISTENER_UPDATE_REGION(frold, as, Reverse, region_del);
|
||||||
as->ops->range_del(as, frold);
|
as->ops->range_del(as, frold);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -738,11 +752,11 @@ static void address_space_update_topology_pass(AddressSpace *as,
|
||||||
|
|
||||||
if (adding) {
|
if (adding) {
|
||||||
if (frold->dirty_log_mask && !frnew->dirty_log_mask) {
|
if (frold->dirty_log_mask && !frnew->dirty_log_mask) {
|
||||||
MEMORY_LISTENER_UPDATE_REGION(frnew, as, log_stop);
|
MEMORY_LISTENER_UPDATE_REGION(frnew, as, Reverse, log_stop);
|
||||||
as->ops->log_stop(as, frnew);
|
as->ops->log_stop(as, frnew);
|
||||||
} else if (frnew->dirty_log_mask && !frold->dirty_log_mask) {
|
} else if (frnew->dirty_log_mask && !frold->dirty_log_mask) {
|
||||||
as->ops->log_start(as, frnew);
|
as->ops->log_start(as, frnew);
|
||||||
MEMORY_LISTENER_UPDATE_REGION(frnew, as, log_start);
|
MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, log_start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -753,7 +767,7 @@ static void address_space_update_topology_pass(AddressSpace *as,
|
||||||
|
|
||||||
if (adding) {
|
if (adding) {
|
||||||
as->ops->range_add(as, frnew);
|
as->ops->range_add(as, frnew);
|
||||||
MEMORY_LISTENER_UPDATE_REGION(frnew, as, region_add);
|
MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, region_add);
|
||||||
}
|
}
|
||||||
|
|
||||||
++inew;
|
++inew;
|
||||||
|
@ -1142,7 +1156,8 @@ void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
|
||||||
|
|
||||||
FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) {
|
FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) {
|
||||||
if (fr->mr == mr) {
|
if (fr->mr == mr) {
|
||||||
MEMORY_LISTENER_UPDATE_REGION(fr, &address_space_memory, log_sync);
|
MEMORY_LISTENER_UPDATE_REGION(fr, &address_space_memory,
|
||||||
|
Forward, log_sync);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1469,7 +1484,7 @@ void memory_global_sync_dirty_bitmap(MemoryRegion *address_space)
|
||||||
FlatRange *fr;
|
FlatRange *fr;
|
||||||
|
|
||||||
FOR_EACH_FLAT_RANGE(fr, &as->current_map) {
|
FOR_EACH_FLAT_RANGE(fr, &as->current_map) {
|
||||||
MEMORY_LISTENER_UPDATE_REGION(fr, as, log_sync);
|
MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1477,13 +1492,13 @@ void memory_global_dirty_log_start(void)
|
||||||
{
|
{
|
||||||
cpu_physical_memory_set_dirty_tracking(1);
|
cpu_physical_memory_set_dirty_tracking(1);
|
||||||
global_dirty_log = true;
|
global_dirty_log = true;
|
||||||
MEMORY_LISTENER_CALL(log_global_start);
|
MEMORY_LISTENER_CALL(log_global_start, Forward);
|
||||||
}
|
}
|
||||||
|
|
||||||
void memory_global_dirty_log_stop(void)
|
void memory_global_dirty_log_stop(void)
|
||||||
{
|
{
|
||||||
global_dirty_log = false;
|
global_dirty_log = false;
|
||||||
MEMORY_LISTENER_CALL(log_global_stop);
|
MEMORY_LISTENER_CALL(log_global_stop, Reverse);
|
||||||
cpu_physical_memory_set_dirty_tracking(0);
|
cpu_physical_memory_set_dirty_tracking(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1509,14 +1524,27 @@ static void listener_add_address_space(MemoryListener *listener,
|
||||||
|
|
||||||
void memory_listener_register(MemoryListener *listener)
|
void memory_listener_register(MemoryListener *listener)
|
||||||
{
|
{
|
||||||
QLIST_INSERT_HEAD(&memory_listeners, listener, link);
|
MemoryListener *other = NULL;
|
||||||
|
|
||||||
|
if (QTAILQ_EMPTY(&memory_listeners)
|
||||||
|
|| listener->priority >= QTAILQ_LAST(&memory_listeners,
|
||||||
|
memory_listeners)->priority) {
|
||||||
|
QTAILQ_INSERT_TAIL(&memory_listeners, listener, link);
|
||||||
|
} else {
|
||||||
|
QTAILQ_FOREACH(other, &memory_listeners, link) {
|
||||||
|
if (listener->priority < other->priority) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QTAILQ_INSERT_BEFORE(other, listener, link);
|
||||||
|
}
|
||||||
listener_add_address_space(listener, &address_space_memory);
|
listener_add_address_space(listener, &address_space_memory);
|
||||||
listener_add_address_space(listener, &address_space_io);
|
listener_add_address_space(listener, &address_space_io);
|
||||||
}
|
}
|
||||||
|
|
||||||
void memory_listener_unregister(MemoryListener *listener)
|
void memory_listener_unregister(MemoryListener *listener)
|
||||||
{
|
{
|
||||||
QLIST_REMOVE(listener, link);
|
QTAILQ_REMOVE(&memory_listeners, listener, link);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_system_memory_map(MemoryRegion *mr)
|
void set_system_memory_map(MemoryRegion *mr)
|
||||||
|
|
4
memory.h
4
memory.h
|
@ -185,7 +185,9 @@ struct MemoryListener {
|
||||||
void (*log_sync)(MemoryListener *listener, MemoryRegionSection *section);
|
void (*log_sync)(MemoryListener *listener, MemoryRegionSection *section);
|
||||||
void (*log_global_start)(MemoryListener *listener);
|
void (*log_global_start)(MemoryListener *listener);
|
||||||
void (*log_global_stop)(MemoryListener *listener);
|
void (*log_global_stop)(MemoryListener *listener);
|
||||||
QLIST_ENTRY(MemoryListener) link;
|
/* Lower = earlier (during add), later (during del) */
|
||||||
|
unsigned priority;
|
||||||
|
QTAILQ_ENTRY(MemoryListener) link;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -495,6 +495,7 @@ static MemoryListener xen_memory_listener = {
|
||||||
.log_sync = xen_log_sync,
|
.log_sync = xen_log_sync,
|
||||||
.log_global_start = xen_log_global_start,
|
.log_global_start = xen_log_global_start,
|
||||||
.log_global_stop = xen_log_global_stop,
|
.log_global_stop = xen_log_global_stop,
|
||||||
|
.priority = 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* VCPU Operations, MMIO, IO ring ... */
|
/* VCPU Operations, MMIO, IO ring ... */
|
||||||
|
|
Loading…
Reference in New Issue