qemu/migration
Peter Xu 8597af7615 migration/block: Rewrite disk activation
This patch proposes a flag to maintain disk activation status globally.  It
mostly rewrites disk activation mgmt for QEMU, including COLO and QMP
command xen_save_devices_state.

Backgrounds
===========

We have two problems on disk activations, one resolved, one not.

Problem 1: disk activation recover (for switchover interruptions)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When migration is either cancelled or failed during switchover, especially
when after the disks are inactivated, QEMU needs to remember re-activate
the disks again before vm starts.

It used to be done separately in two paths: one in qmp_migrate_cancel(),
the other one in the failure path of migration_completion().

It used to be fixed in different commits, all over the places in QEMU.  So
these are the relevant changes I saw, I'm not sure if it's complete list:

 - In 2016, commit fe904ea824 ("migration: regain control of images when
   migration fails to complete")

 - In 2017, commit 1d2acc3162 ("migration: re-active images while migration
   been canceled after inactive them")

 - In 2023, commit 6dab4c93ec ("migration: Attempt disk reactivation in
   more failure scenarios")

Now since we have a slightly better picture maybe we can unify the
reactivation in a single path.

One side benefit of doing so is, we can move the disk operation outside QMP
command "migrate_cancel".  It's possible that in the future we may want to
make "migrate_cancel" be OOB-compatible, while that requires the command
doesn't need BQL in the first place.  This will already do that and make
migrate_cancel command lightweight.

Problem 2: disk invalidation on top of invalidated disks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This is an unresolved bug for current QEMU.  Link in "Resolves:" at the
end.  It turns out besides the src switchover phase (problem 1 above), QEMU
also needs to remember block activation on destination.

Consider two continuous migration in a row, where the VM was always paused.
In that scenario, the disks are not activated even until migration
completed in the 1st round.  When the 2nd round starts, if QEMU doesn't
know the status of the disks, it needs to try inactivate the disk again.

Here the issue is the block layer API bdrv_inactivate_all() will crash a
QEMU if invoked on already inactive disks for the 2nd migration.  For
detail, see the bug link at the end.

Implementation
==============

This patch proposes to maintain disk activation with a global flag, so we
know:

  - If we used to inactivate disks for migration, but migration got
  cancelled, or failed, QEMU will know it should reactivate the disks.

  - On incoming side, if the disks are never activated but then another
  migration is triggered, QEMU should be able to tell that inactivate is
  not needed for the 2nd migration.

We used to have disk_inactive, but it only solves the 1st issue, not the
2nd.  Also, it's done in completely separate paths so it's extremely hard
to follow either how the flag changes, or the duration that the flag is
valid, and when we will reactivate the disks.

Convert the existing disk_inactive flag into that global flag (also invert
its naming), and maintain the disk activation status for the whole
lifecycle of qemu.  That includes the incoming QEMU.

Put both of the error cases of source migration (failure, cancelled)
together into migration_iteration_finish(), which will be invoked for
either of the scenario.  So from that part QEMU should behave the same as
before.  However with such global maintenance on disk activation status, we
not only cleanup quite a few temporary paths that we try to maintain the
disk activation status (e.g. in postcopy code), meanwhile it fixes the
crash for problem 2 in one shot.

For freshly started QEMU, the flag is initialized to TRUE showing that the
QEMU owns the disks by default.

For incoming migrated QEMU, the flag will be initialized to FALSE once and
for all showing that the dest QEMU doesn't own the disks until switchover.
That is guaranteed by the "once" variable.

Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2395
Signed-off-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
Message-Id: <20241206230838.1111496-7-peterx@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
2025-01-09 17:38:57 -03:00
..
block-active.c migration/block: Rewrite disk activation 2025-01-09 17:38:57 -03:00
block-dirty-bitmap.c include: Rename sysemu/ -> system/ 2024-12-20 17:44:56 +01:00
channel-block.c io: follow coroutine AioContext in qio_channel_yield() 2023-09-07 20:32:11 -05:00
channel-block.h migration: introduce a QIOChannel impl for BlockDriverState VMState 2022-06-22 19:33:43 +01:00
channel.c migration: Fix migration_channel_read_peek() error path 2024-01-04 09:52:42 +08:00
channel.h migration: check magic value for deciding the mapping of channels 2023-02-06 19:22:57 +01:00
colo-failover.c migration/colo: Improve an x-colo-lost-heartbeat error message 2023-02-23 14:10:17 +01:00
colo-stubs.c migration/colo: make colo_incoming_co() return void 2024-05-22 17:34:31 -03:00
colo.c migration/block: Rewrite disk activation 2025-01-09 17:38:57 -03:00
cpu-throttle.c include: Rename sysemu/ -> system/ 2024-12-20 17:44:56 +01:00
dirtyrate.c include: Rename sysemu/ -> system/ 2024-12-20 17:44:56 +01:00
dirtyrate.h include: Rename sysemu/ -> system/ 2024-12-20 17:44:56 +01:00
exec.c migration: simplify exec migration functions 2024-03-04 07:12:40 +01:00
exec.h migration: convert exec backend to accept MigrateAddress. 2023-11-02 11:35:04 +01:00
fd.c migration: Allow pipes to keep working for fd migrations 2024-11-25 16:21:55 -05:00
fd.h migration: Revert mapped-ram multifd support to fd: URI 2024-03-22 12:12:08 -04:00
file.c migration/multifd: Pass in MultiFDPages_t to file_write_ramblock_iov 2024-09-03 16:24:35 -03:00
file.h migration/multifd: Pass in MultiFDPages_t to file_write_ramblock_iov 2024-09-03 16:24:35 -03:00
global_state.c include: Rename sysemu/ -> system/ 2024-12-20 17:44:56 +01:00
meson.build migration/block: Rewrite disk activation 2025-01-09 17:38:57 -03:00
migration-hmp-cmds.c include: Rename sysemu/ -> system/ 2024-12-20 17:44:56 +01:00
migration-stats.c migration: migration_rate_limit_reset() don't need the QEMUFile 2023-10-31 08:44:33 +01:00
migration-stats.h migration: Remove transferred atomic counter 2023-10-31 08:44:33 +01:00
migration.c migration/block: Rewrite disk activation 2025-01-09 17:38:57 -03:00
migration.h migration/block: Rewrite disk activation 2025-01-09 17:38:57 -03:00
multifd-nocomp.c migration/multifd: Cleanup src flushes on condition check 2025-01-09 17:38:27 -03:00
multifd-qatzip.c migration/multifd: Fix build for qatzip 2024-09-17 17:50:45 -04:00
multifd-qpl.c migration/multifd: fix build error when qpl compression is enabled 2024-10-09 08:30:53 -04:00
multifd-uadk.c migration/multifd: Fix compile error caused by page_size usage 2025-01-09 17:37:50 -03:00
multifd-zero-page.c migration/multifd: Move pages accounting into multifd_send_zero_page_detect() 2024-09-03 16:24:35 -03:00
multifd-zlib.c migration/multifd: Make MultiFDMethods const 2024-09-03 16:24:36 -03:00
multifd-zstd.c migration/multifd: Fix loop conditions in multifd_zstd_send_prepare and multifd_zstd_recv 2024-09-18 14:27:24 -04:00
multifd.c migration/multifd: Fix compat with QEMU < 9.0 2025-01-09 17:38:35 -03:00
multifd.h migration/multifd: Cleanup src flushes on condition check 2025-01-09 17:38:27 -03:00
options.c Accel & Exec patch queue 2024-12-21 11:07:00 -05:00
options.h migration: Use device_class_set_props_n 2024-12-19 19:33:37 +01:00
page_cache.c migration: Fix cache_init()'s "Failed to allocate" error messages 2021-02-08 11:19:51 +00:00
page_cache.h migration: Clean up signed vs. unsigned XBZRLE cache-size 2021-02-08 11:19:51 +00:00
postcopy-ram.c include: Rename sysemu/ -> system/ 2024-12-20 17:44:56 +01:00
postcopy-ram.h migration/postcopy: Add postcopy-recover-setup phase 2024-06-21 09:47:59 -03:00
qemu-file.c migration: remove unnecessary zlib dependency 2024-05-25 13:28:02 +02:00
qemu-file.h migration: Remove non-multifd compression 2024-05-08 09:20:59 -03:00
ram.c migration/multifd: Document the reason to sync for save_setup() 2025-01-09 17:38:32 -03:00
ram.h migration/ram: Move RAM_SAVE_FLAG* into ram.h 2025-01-09 17:38:15 -03:00
rdma.c migration/rdma: Fix a memory issue for migration 2024-03-11 14:41:40 -04:00
rdma.h migration/ram: Move RAM_SAVE_FLAG* into ram.h 2025-01-09 17:38:15 -03:00
savevm.c migration/block: Rewrite disk activation 2025-01-09 17:38:57 -03:00
savevm.h migration: Add Error** argument to qemu_savevm_state_setup() 2024-04-23 18:36:01 -04:00
socket.c migration: Remove unused socket_send_channel_create_sync 2024-10-08 15:28:55 -04:00
socket.h migration: Remove unused socket_send_channel_create_sync 2024-10-08 15:28:55 -04:00
target.c migration: Add migration prefix to functions in target.c 2023-09-11 08:34:06 +02:00
threadinfo.c migration/multifd: Protect accesses to migration_threads 2023-07-26 10:55:56 +02:00
threadinfo.h migration/multifd: Protect accesses to migration_threads 2023-07-26 10:55:56 +02:00
tls.c migration: Drop unused parameter for migration_tls_client_create() 2023-05-03 11:24:20 +02:00
tls.h migration: Drop unused parameter for migration_tls_client_create() 2023-05-03 11:24:20 +02:00
trace-events migration/block: Rewrite disk activation 2025-01-09 17:38:57 -03:00
trace.h trace: switch position of headers to what Meson requires 2020-08-21 06:18:24 -04:00
vmstate-types.c Move CPU softfloat unions to cpu-float.h 2022-04-06 14:31:43 +02:00
vmstate.c migration: Ensure vmstate_save() sets errp 2024-10-31 15:48:18 -04:00
xbzrle.c migration/xbzrle: Use i386 host/cpuinfo.h 2023-05-23 16:51:18 -07:00
xbzrle.h migration/xbzrle: Use i386 host/cpuinfo.h 2023-05-23 16:51:18 -07:00
yank_functions.c migration/yank: Use channel features 2024-01-29 11:02:12 +08:00
yank_functions.h migration: Move the yank unregister of channel_close out 2021-07-26 12:45:03 +01:00