You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
qemu/migration/block-active.c

95 lines
2.5 KiB
C

/*
* Block activation tracking for migration purpose
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2024 Red Hat, Inc.
*/
#include "qemu/osdep.h"
#include "block/block.h"
#include "qapi/error.h"
#include "migration/migration.h"
#include "qemu/error-report.h"
#include "trace.h"
/*
* Migration-only cache to remember the block layer activation status.
* Protected by BQL.
*
* We need this because..
*
* - Migration can fail after block devices are invalidated (during
* switchover phase). When that happens, we need to be able to recover
* the block drive status by re-activating them.
*
* - Currently bdrv_inactivate_all() is not safe to be invoked on top of
* invalidated drives (even if bdrv_activate_all() is actually safe to be
* called any time!). It means remembering this could help migration to
* make sure it won't invalidate twice in a row, crashing QEMU. It can
* happen when we migrate a PAUSED VM from host1 to host2, then migrate
* again to host3 without starting it. TODO: a cleaner solution is to
* allow safe invoke of bdrv_inactivate_all() at anytime, like
* bdrv_activate_all().
*
* For freshly started QEMU, the flag is initialized to TRUE reflecting the
* scenario where QEMU owns block device ownerships.
*
* For incoming QEMU taking a migration stream, the flag is initialized to
* FALSE reflecting that the incoming side doesn't own the block devices,
* not until switchover happens.
*/
static bool migration_block_active;
/* Setup the disk activation status */
void migration_block_active_setup(bool active)
{
migration_block_active = active;
}
bool migration_block_activate(Error **errp)
{
ERRP_GUARD();
assert(bql_locked());
if (migration_block_active) {
trace_migration_block_activation("active-skipped");
return true;
}
trace_migration_block_activation("active");
bdrv_activate_all(errp);
if (*errp) {
error_report_err(error_copy(*errp));
return false;
}
migration_block_active = true;
return true;
}
bool migration_block_inactivate(void)
{
int ret;
assert(bql_locked());
if (!migration_block_active) {
trace_migration_block_activation("inactive-skipped");
return true;
}
trace_migration_block_activation("inactive");
ret = bdrv_inactivate_all();
if (ret) {
error_report("%s: bdrv_inactivate_all() failed: %d",
__func__, ret);
return false;
}
migration_block_active = false;
return true;
}