diff options
Diffstat (limited to 'system/memory.c')
| -rw-r--r-- | system/memory.c | 49 |
1 files changed, 45 insertions, 4 deletions
diff --git a/system/memory.c b/system/memory.c index a229a79988..49f1cb2c38 100644 --- a/system/memory.c +++ b/system/memory.c @@ -1850,6 +1850,11 @@ bool memory_region_is_protected(MemoryRegion *mr) return mr->ram && (mr->ram_block->flags & RAM_PROTECTED); } +bool memory_region_has_guest_memfd(MemoryRegion *mr) +{ + return mr->ram_block && mr->ram_block->guest_memfd >= 0; +} + uint8_t memory_region_get_dirty_log_mask(MemoryRegion *mr) { uint8_t mask = mr->dirty_log_mask; @@ -2914,7 +2919,30 @@ static unsigned int postponed_stop_flags; static VMChangeStateEntry *vmstate_change; static void memory_global_dirty_log_stop_postponed_run(void); -void memory_global_dirty_log_start(unsigned int flags) +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; +} + +bool memory_global_dirty_log_start(unsigned int flags, Error **errp) { unsigned int old_flags; @@ -2928,7 +2956,7 @@ void memory_global_dirty_log_start(unsigned int flags) flags &= ~global_dirty_tracking; if (!flags) { - return; + return true; } old_flags = global_dirty_tracking; @@ -2936,11 +2964,17 @@ 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(errp)) { + global_dirty_tracking &= ~flags; + trace_global_dirty_changed(global_dirty_tracking); + return false; + } + memory_region_transaction_begin(); memory_region_update_pending = true; memory_region_transaction_commit(); } + return true; } static void memory_global_dirty_log_do_stop(unsigned int flags) @@ -3014,8 +3048,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); } } |