aboutsummaryrefslogtreecommitdiff
path: root/system
diff options
context:
space:
mode:
authorCédric Le Goater <clg@redhat.com>2024-03-20 07:49:05 +0100
committerPeter Xu <peterx@redhat.com>2024-04-23 18:36:01 -0400
commit3688fec8923101b3a44acde7f3db59b76f82b838 (patch)
treec24798c11326ab3e97313d5bbee60f2577a1120e /system
parente4fa064d5610a96e50b49c1ea34c98ef12d0034a (diff)
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>
Diffstat (limited to 'system')
-rw-r--r--system/memory.c41
1 files changed, 39 insertions, 2 deletions
diff --git a/system/memory.c b/system/memory.c
index a229a79988..86d6c33180 100644
--- a/system/memory.c
+++ b/system/memory.c
@@ -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);
}
}