summary refs log tree commit diff stats
path: root/migration/block-active.c
blob: d477cf81828c0beb63a3a4da5e8d3e52dc65540b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/*
 * 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;
}