memory: Add Error** argument to .log_global_start() handler
Modify all .log_global_start() handlers to take an Error** parameter and return a bool. Adapt memory_global_dirty_log_start() to interrupt on the first error the loop on handlers. In such case, a rollback is performed to stop dirty logging on all listeners where it was previously enabled. Cc: Stefano Stabellini <sstabellini@kernel.org> Cc: Anthony Perard <anthony.perard@citrix.com> Cc: Paul Durrant <paul@xen.org> Cc: "Michael S. Tsirkin" <mst@redhat.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: David Hildenbrand <david@redhat.com> Signed-off-by: Cédric Le Goater <clg@redhat.com> Reviewed-by: Peter Xu <peterx@redhat.com> Link: https://lore.kernel.org/r/20240320064911.545001-10-clg@redhat.com [peterx: modify & enrich the comment for listener_add_address_space() ] Signed-off-by: Peter Xu <peterx@redhat.com>
This commit is contained in:
parent
e4fa064d56
commit
3688fec892
@ -457,11 +457,12 @@ static void xen_log_sync(MemoryListener *listener, MemoryRegionSection *section)
|
||||
int128_get64(section->size));
|
||||
}
|
||||
|
||||
static void xen_log_global_start(MemoryListener *listener)
|
||||
static bool xen_log_global_start(MemoryListener *listener, Error **errp)
|
||||
{
|
||||
if (xen_enabled()) {
|
||||
xen_in_migration = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void xen_log_global_stop(MemoryListener *listener)
|
||||
|
@ -1066,7 +1066,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void vfio_listener_log_global_start(MemoryListener *listener)
|
||||
static bool vfio_listener_log_global_start(MemoryListener *listener,
|
||||
Error **errp)
|
||||
{
|
||||
VFIOContainerBase *bcontainer = container_of(listener, VFIOContainerBase,
|
||||
listener);
|
||||
@ -1083,6 +1084,7 @@ static void vfio_listener_log_global_start(MemoryListener *listener)
|
||||
ret, strerror(-ret));
|
||||
vfio_set_migration_error(ret);
|
||||
}
|
||||
return !ret;
|
||||
}
|
||||
|
||||
static void vfio_listener_log_global_stop(MemoryListener *listener)
|
||||
|
@ -1044,7 +1044,7 @@ check_dev_state:
|
||||
return r;
|
||||
}
|
||||
|
||||
static void vhost_log_global_start(MemoryListener *listener)
|
||||
static bool vhost_log_global_start(MemoryListener *listener, Error **errp)
|
||||
{
|
||||
int r;
|
||||
|
||||
@ -1052,6 +1052,7 @@ static void vhost_log_global_start(MemoryListener *listener)
|
||||
if (r < 0) {
|
||||
abort();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void vhost_log_global_stop(MemoryListener *listener)
|
||||
|
@ -998,8 +998,11 @@ struct MemoryListener {
|
||||
* active at that time.
|
||||
*
|
||||
* @listener: The #MemoryListener.
|
||||
* @errp: pointer to Error*, to store an error if it happens.
|
||||
*
|
||||
* Return: true on success, else false setting @errp with error.
|
||||
*/
|
||||
void (*log_global_start)(MemoryListener *listener);
|
||||
bool (*log_global_start)(MemoryListener *listener, Error **errp);
|
||||
|
||||
/**
|
||||
* @log_global_stop:
|
||||
|
@ -2914,9 +2914,33 @@ static unsigned int postponed_stop_flags;
|
||||
static VMChangeStateEntry *vmstate_change;
|
||||
static void memory_global_dirty_log_stop_postponed_run(void);
|
||||
|
||||
static bool memory_global_dirty_log_do_start(Error **errp)
|
||||
{
|
||||
MemoryListener *listener;
|
||||
|
||||
QTAILQ_FOREACH(listener, &memory_listeners, link) {
|
||||
if (listener->log_global_start) {
|
||||
if (!listener->log_global_start(listener, errp)) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
err:
|
||||
while ((listener = QTAILQ_PREV(listener, link)) != NULL) {
|
||||
if (listener->log_global_stop) {
|
||||
listener->log_global_stop(listener);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void memory_global_dirty_log_start(unsigned int flags)
|
||||
{
|
||||
unsigned int old_flags;
|
||||
Error *local_err = NULL;
|
||||
|
||||
assert(flags && !(flags & (~GLOBAL_DIRTY_MASK)));
|
||||
|
||||
@ -2936,7 +2960,13 @@ void memory_global_dirty_log_start(unsigned int flags)
|
||||
trace_global_dirty_changed(global_dirty_tracking);
|
||||
|
||||
if (!old_flags) {
|
||||
MEMORY_LISTENER_CALL_GLOBAL(log_global_start, Forward);
|
||||
if (!memory_global_dirty_log_do_start(&local_err)) {
|
||||
global_dirty_tracking &= ~flags;
|
||||
trace_global_dirty_changed(global_dirty_tracking);
|
||||
error_report_err(local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
memory_region_transaction_begin();
|
||||
memory_region_update_pending = true;
|
||||
memory_region_transaction_commit();
|
||||
@ -3014,8 +3044,15 @@ static void listener_add_address_space(MemoryListener *listener,
|
||||
listener->begin(listener);
|
||||
}
|
||||
if (global_dirty_tracking) {
|
||||
/*
|
||||
* Currently only VFIO can fail log_global_start(), and it's not
|
||||
* yet allowed to hotplug any PCI device during migration. So this
|
||||
* should never fail when invoked, guard it with error_abort. If
|
||||
* it can start to fail in the future, we need to be able to fail
|
||||
* the whole listener_add_address_space() and its callers.
|
||||
*/
|
||||
if (listener->log_global_start) {
|
||||
listener->log_global_start(listener);
|
||||
listener->log_global_start(listener, &error_abort);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user