Skip to content

Commit f2ec48f

Browse files
committed
Merge tag 'for-upstream' of https://repo.or.cz/qemu/kevin into staging
Block layer patches - Managing inactive nodes (enables QSD migration with shared storage) - Fix swapped values for BLOCK_IO_ERROR 'device' and 'qom-path' - vpc: Read images exported from Azure correctly - scripts/qemu-gdb: Support coroutine dumps in coredumps - Minor cleanups # -----BEGIN PGP SIGNATURE----- # # iQJFBAABCAAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAmek34IRHGt3b2xmQHJl # ZGhhdC5jb20ACgkQfwmycsiPL9bDpxAAnTvwmdazAXG0g9GzqvrEB/+6rStjAsqE # 9MTWV4WxyN41d0RXxN8CYKb8CXSiTRyw6r3CSGNYEI2eShe9e934PriSkZm41HyX # n9Yh5YxqGZqitzvPtx62Ii/1KG+PcjQbfHuK1p4+rlKa0yQ2eGlio1JIIrZrCkBZ # ikZcQUrhIyD0XV8hTQ2+Ysa+ZN6itjnlTQIG3gS3m8f8WR7kyUXD8YFMQFJFyjVx # NrAIpLnc/ln9+5PZR9tje8U7XEn2KCgI5pgGaQnrd0h0G1H4ig8ogzYYnKTLhjU/ # AmQpS8np8Tyg6S1UZTiekEq0VuAhThEQc5b3sGbmHWH/R2ABMStyf18oCBAkPzZ7 # s6h+3XzTKKY2Q5Q3ZG/ANkUJjTNBhdj1fcaARvbSWsqsuk5CWX/I3jzvgihFtCSs # eGu+b/bLeW6P7hu4qPHBcgLHuB1Fc7Rd2t4BoIGM1wcO2CeC9DzUKOiIMZOEJIh0 # GGqCkEWDHgckDTakD4/vSqm0UDKt6FSlQC9ga/ILBY3IB5HpHoArY58selymy28i # X7MgAvbjdsmNuUuXDZZOiObcFt3j8jlmwPJpPyzXPQIiPX1RXeBPRhVAEeZCKn6Z # tfHr72SJdMeVOGXVTvOrJ2iW+4g03rPdmkDFCUhpOwo62RODq7ahvCIXsNf3nEFR # rSB3T1M/8EM= # =iQLP # -----END PGP SIGNATURE----- # gpg: Signature made Thu 06 Feb 2025 11:12:50 EST # gpg: using RSA key DC3DEB159A9AF95D3D7456FE7F09B272C88F2FD6 # gpg: issuer "kwolf@redhat.com" # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full] # Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6 * tag 'for-upstream' of https://repo.or.cz/qemu/kevin: (25 commits) block: remove unused BLOCK_OP_TYPE_DATAPLANE iotests: Add (NBD-based) tests for inactive nodes iotests: Add qsd-migrate case iotests: Add filter_qtest() nbd/server: Support inactive nodes block/export: Add option to allow export of inactive nodes block: Drain nodes before inactivating them block/export: Don't ignore image activation error in blk_exp_add() block: Support inactive nodes in blk_insert_bs() block: Add blockdev-set-active QMP command block: Add option to create inactive nodes block: Fix crash on block_resize on inactive node block: Don't attach inactive child to active node migration/block-active: Remove global active flag block: Inactivate external snapshot overlays when necessary block: Allow inactivating already inactive nodes block: Add 'active' field to BlockDeviceInfo block-backend: Fix argument order when calling 'qapi_event_send_block_io_error()' scripts/qemu-gdb: Support coroutine dumps in coredumps scripts/qemu-gdb: Simplify fs_base fetching for coroutines ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2 parents 4f1d018 + fc4e394 commit f2ec48f

35 files changed

+1133
-166
lines changed

block.c

+60-4
Original file line numberDiff line numberDiff line change
@@ -1573,6 +1573,10 @@ static void update_flags_from_options(int *flags, QemuOpts *opts)
15731573
if (qemu_opt_get_bool_del(opts, BDRV_OPT_AUTO_READ_ONLY, false)) {
15741574
*flags |= BDRV_O_AUTO_RDONLY;
15751575
}
1576+
1577+
if (!qemu_opt_get_bool_del(opts, BDRV_OPT_ACTIVE, true)) {
1578+
*flags |= BDRV_O_INACTIVE;
1579+
}
15761580
}
15771581

15781582
static void update_options_from_flags(QDict *options, int flags)
@@ -1799,6 +1803,11 @@ QemuOptsList bdrv_runtime_opts = {
17991803
.type = QEMU_OPT_BOOL,
18001804
.help = "Ignore flush requests",
18011805
},
1806+
{
1807+
.name = BDRV_OPT_ACTIVE,
1808+
.type = QEMU_OPT_BOOL,
1809+
.help = "Node is activated",
1810+
},
18021811
{
18031812
.name = BDRV_OPT_READ_ONLY,
18041813
.type = QEMU_OPT_BOOL,
@@ -3077,6 +3086,13 @@ bdrv_attach_child_common(BlockDriverState *child_bs,
30773086
assert(child_class->get_parent_desc);
30783087
GLOBAL_STATE_CODE();
30793088

3089+
if (bdrv_is_inactive(child_bs) && (perm & ~BLK_PERM_CONSISTENT_READ)) {
3090+
g_autofree char *perm_names = bdrv_perm_names(perm);
3091+
error_setg(errp, "Permission '%s' unavailable on inactive node",
3092+
perm_names);
3093+
return NULL;
3094+
}
3095+
30803096
new_child = g_new(BdrvChild, 1);
30813097
*new_child = (BdrvChild) {
30823098
.bs = NULL,
@@ -3183,6 +3199,11 @@ bdrv_attach_child_noperm(BlockDriverState *parent_bs,
31833199
child_bs->node_name, child_name, parent_bs->node_name);
31843200
return NULL;
31853201
}
3202+
if (bdrv_is_inactive(child_bs) && !bdrv_is_inactive(parent_bs)) {
3203+
error_setg(errp, "Inactive '%s' can't be a %s child of active '%s'",
3204+
child_bs->node_name, child_name, parent_bs->node_name);
3205+
return NULL;
3206+
}
31863207

31873208
bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm);
31883209
bdrv_child_perm(parent_bs, child_bs, NULL, child_role, NULL,
@@ -6824,6 +6845,10 @@ void bdrv_init_with_whitelist(void)
68246845
bdrv_init();
68256846
}
68266847

6848+
bool bdrv_is_inactive(BlockDriverState *bs) {
6849+
return bs->open_flags & BDRV_O_INACTIVE;
6850+
}
6851+
68276852
int bdrv_activate(BlockDriverState *bs, Error **errp)
68286853
{
68296854
BdrvChild *child, *parent;
@@ -6955,7 +6980,8 @@ bdrv_has_bds_parent(BlockDriverState *bs, bool only_active)
69556980
return false;
69566981
}
69576982

6958-
static int GRAPH_RDLOCK bdrv_inactivate_recurse(BlockDriverState *bs)
6983+
static int GRAPH_RDLOCK
6984+
bdrv_inactivate_recurse(BlockDriverState *bs, bool top_level)
69596985
{
69606986
BdrvChild *child, *parent;
69616987
int ret;
@@ -6973,7 +6999,14 @@ static int GRAPH_RDLOCK bdrv_inactivate_recurse(BlockDriverState *bs)
69736999
return 0;
69747000
}
69757001

6976-
assert(!(bs->open_flags & BDRV_O_INACTIVE));
7002+
/*
7003+
* Inactivating an already inactive node on user request is harmless, but if
7004+
* a child is already inactive before its parent, that's bad.
7005+
*/
7006+
if (bs->open_flags & BDRV_O_INACTIVE) {
7007+
assert(top_level);
7008+
return 0;
7009+
}
69777010

69787011
/* Inactivate this node */
69797012
if (bs->drv->bdrv_inactivate) {
@@ -6999,7 +7032,9 @@ static int GRAPH_RDLOCK bdrv_inactivate_recurse(BlockDriverState *bs)
69997032
return -EPERM;
70007033
}
70017034

7035+
bdrv_drained_begin(bs);
70027036
bs->open_flags |= BDRV_O_INACTIVE;
7037+
bdrv_drained_end(bs);
70037038

70047039
/*
70057040
* Update permissions, they may differ for inactive nodes.
@@ -7010,7 +7045,7 @@ static int GRAPH_RDLOCK bdrv_inactivate_recurse(BlockDriverState *bs)
70107045

70117046
/* Recursively inactivate children */
70127047
QLIST_FOREACH(child, &bs->children, next) {
7013-
ret = bdrv_inactivate_recurse(child->bs);
7048+
ret = bdrv_inactivate_recurse(child->bs, false);
70147049
if (ret < 0) {
70157050
return ret;
70167051
}
@@ -7019,6 +7054,27 @@ static int GRAPH_RDLOCK bdrv_inactivate_recurse(BlockDriverState *bs)
70197054
return 0;
70207055
}
70217056

7057+
int bdrv_inactivate(BlockDriverState *bs, Error **errp)
7058+
{
7059+
int ret;
7060+
7061+
GLOBAL_STATE_CODE();
7062+
GRAPH_RDLOCK_GUARD_MAINLOOP();
7063+
7064+
if (bdrv_has_bds_parent(bs, true)) {
7065+
error_setg(errp, "Node has active parent node");
7066+
return -EPERM;
7067+
}
7068+
7069+
ret = bdrv_inactivate_recurse(bs, true);
7070+
if (ret < 0) {
7071+
error_setg_errno(errp, -ret, "Failed to inactivate node");
7072+
return ret;
7073+
}
7074+
7075+
return 0;
7076+
}
7077+
70227078
int bdrv_inactivate_all(void)
70237079
{
70247080
BlockDriverState *bs = NULL;
@@ -7035,7 +7091,7 @@ int bdrv_inactivate_all(void)
70357091
if (bdrv_has_bds_parent(bs, false)) {
70367092
continue;
70377093
}
7038-
ret = bdrv_inactivate_recurse(bs);
7094+
ret = bdrv_inactivate_recurse(bs, true);
70397095
if (ret < 0) {
70407096
bdrv_next_cleanup(&it);
70417097
break;

block/block-backend.c

+23-9
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ static bool blk_can_inactivate(BlockBackend *blk)
253253
* guest. For block job BBs that satisfy this, we can just allow
254254
* it. This is the case for mirror job source, which is required
255255
* by libvirt non-shared block migration. */
256-
if (!(blk->perm & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED))) {
256+
if (!(blk->perm & ~BLK_PERM_CONSISTENT_READ)) {
257257
return true;
258258
}
259259

@@ -900,14 +900,24 @@ void blk_remove_bs(BlockBackend *blk)
900900
int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
901901
{
902902
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
903+
uint64_t perm, shared_perm;
903904

904905
GLOBAL_STATE_CODE();
905906
bdrv_ref(bs);
906907
bdrv_graph_wrlock();
908+
909+
if ((bs->open_flags & BDRV_O_INACTIVE) && blk_can_inactivate(blk)) {
910+
blk->disable_perm = true;
911+
perm = 0;
912+
shared_perm = BLK_PERM_ALL;
913+
} else {
914+
perm = blk->perm;
915+
shared_perm = blk->shared_perm;
916+
}
917+
907918
blk->root = bdrv_root_attach_child(bs, "root", &child_root,
908919
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
909-
blk->perm, blk->shared_perm,
910-
blk, errp);
920+
perm, shared_perm, blk, errp);
911921
bdrv_graph_wrunlock();
912922
if (blk->root == NULL) {
913923
return -EPERM;
@@ -1019,6 +1029,10 @@ DeviceState *blk_get_attached_dev(BlockBackend *blk)
10191029
return blk->dev;
10201030
}
10211031

1032+
/*
1033+
* The caller is responsible for releasing the value returned
1034+
* with g_free() after use.
1035+
*/
10221036
static char *blk_get_attached_dev_id_or_path(BlockBackend *blk, bool want_id)
10231037
{
10241038
DeviceState *dev = blk->dev;
@@ -1033,15 +1047,15 @@ static char *blk_get_attached_dev_id_or_path(BlockBackend *blk, bool want_id)
10331047
return object_get_canonical_path(OBJECT(dev)) ?: g_strdup("");
10341048
}
10351049

1036-
/*
1037-
* Return the qdev ID, or if no ID is assigned the QOM path, of the block
1038-
* device attached to the BlockBackend.
1039-
*/
10401050
char *blk_get_attached_dev_id(BlockBackend *blk)
10411051
{
10421052
return blk_get_attached_dev_id_or_path(blk, true);
10431053
}
10441054

1055+
/*
1056+
* The caller is responsible for releasing the value returned
1057+
* with g_free() after use.
1058+
*/
10451059
static char *blk_get_attached_dev_path(BlockBackend *blk)
10461060
{
10471061
return blk_get_attached_dev_id_or_path(blk, false);
@@ -2134,10 +2148,10 @@ static void send_qmp_error_event(BlockBackend *blk,
21342148
{
21352149
IoOperationType optype;
21362150
BlockDriverState *bs = blk_bs(blk);
2151+
g_autofree char *path = blk_get_attached_dev_path(blk);
21372152

21382153
optype = is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE;
2139-
qapi_event_send_block_io_error(blk_name(blk),
2140-
blk_get_attached_dev_path(blk),
2154+
qapi_event_send_block_io_error(path, blk_name(blk),
21412155
bs ? bdrv_get_node_name(bs) : NULL, optype,
21422156
action, blk_iostatus_is_enabled(blk),
21432157
error == ENOSPC, strerror(error));

block/export/export.c

+22-7
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ static const BlockExportDriver *blk_exp_find_driver(BlockExportType type)
7575
BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
7676
{
7777
bool fixed_iothread = export->has_fixed_iothread && export->fixed_iothread;
78+
bool allow_inactive = export->has_allow_inactive && export->allow_inactive;
7879
const BlockExportDriver *drv;
7980
BlockExport *exp = NULL;
8081
BlockDriverState *bs;
@@ -138,14 +139,25 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
138139
}
139140
}
140141

141-
/*
142-
* Block exports are used for non-shared storage migration. Make sure
143-
* that BDRV_O_INACTIVE is cleared and the image is ready for write
144-
* access since the export could be available before migration handover.
145-
* ctx was acquired in the caller.
146-
*/
147142
bdrv_graph_rdlock_main_loop();
148-
bdrv_activate(bs, NULL);
143+
if (allow_inactive) {
144+
if (!drv->supports_inactive) {
145+
error_setg(errp, "Export type does not support inactive exports");
146+
bdrv_graph_rdunlock_main_loop();
147+
goto fail;
148+
}
149+
} else {
150+
/*
151+
* Block exports are used for non-shared storage migration. Make sure
152+
* that BDRV_O_INACTIVE is cleared and the image is ready for write
153+
* access since the export could be available before migration handover.
154+
*/
155+
ret = bdrv_activate(bs, errp);
156+
if (ret < 0) {
157+
bdrv_graph_rdunlock_main_loop();
158+
goto fail;
159+
}
160+
}
149161
bdrv_graph_rdunlock_main_loop();
150162

151163
perm = BLK_PERM_CONSISTENT_READ;
@@ -158,6 +170,9 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
158170
if (!fixed_iothread) {
159171
blk_set_allow_aio_context_change(blk, true);
160172
}
173+
if (allow_inactive) {
174+
blk_set_force_allow_inactivate(blk);
175+
}
161176

162177
ret = blk_insert_bs(blk, bs, errp);
163178
if (ret < 0) {

block/monitor/block-hmp-cmds.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -630,11 +630,12 @@ static void print_block_info(Monitor *mon, BlockInfo *info,
630630
}
631631

632632
if (inserted) {
633-
monitor_printf(mon, ": %s (%s%s%s)\n",
633+
monitor_printf(mon, ": %s (%s%s%s%s)\n",
634634
inserted->file,
635635
inserted->drv,
636636
inserted->ro ? ", read-only" : "",
637-
inserted->encrypted ? ", encrypted" : "");
637+
inserted->encrypted ? ", encrypted" : "",
638+
inserted->active ? "" : ", inactive");
638639
} else {
639640
monitor_printf(mon, ": [not inserted]\n");
640641
}

block/qapi.c

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
6363
info->file = g_strdup(bs->filename);
6464
info->ro = bdrv_is_read_only(bs);
6565
info->drv = g_strdup(bs->drv->format_name);
66+
info->active = !bdrv_is_inactive(bs);
6667
info->encrypted = bs->encrypted;
6768

6869
info->cache = g_new(BlockdevCacheInfo, 1);

block/replication.c

-1
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,6 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
576576
return;
577577
}
578578
bdrv_op_block_all(top_bs, s->blocker);
579-
bdrv_op_unblock(top_bs, BLOCK_OP_TYPE_DATAPLANE, s->blocker);
580579

581580
bdrv_graph_wrunlock();
582581

block/vpc.c

+35-30
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,39 @@ static void vpc_parse_options(BlockDriverState *bs, QemuOpts *opts,
216216
}
217217
}
218218

219+
/*
220+
* Microsoft Virtual PC and Microsoft Hyper-V produce and read
221+
* VHD image sizes differently. VPC will rely on CHS geometry,
222+
* while Hyper-V and disk2vhd use the size specified in the footer.
223+
*
224+
* We use a couple of approaches to try and determine the correct method:
225+
* look at the Creator App field, and look for images that have CHS
226+
* geometry that is the maximum value.
227+
*
228+
* If the CHS geometry is the maximum CHS geometry, then we assume that
229+
* the size is the footer->current_size to avoid truncation. Otherwise,
230+
* we follow the table based on footer->creator_app:
231+
*
232+
* Known creator apps:
233+
* 'vpc ' : CHS Virtual PC (uses disk geometry)
234+
* 'qemu' : CHS QEMU (uses disk geometry)
235+
* 'qem2' : current_size QEMU (uses current_size)
236+
* 'win ' : current_size Hyper-V
237+
* 'd2v ' : current_size Disk2vhd
238+
* 'tap\0' : current_size XenServer
239+
* 'CTXS' : current_size XenConverter
240+
* 'wa\0\0': current_size Azure
241+
*
242+
* The user can override the table values via drive options, however
243+
* even with an override we will still use current_size for images
244+
* that have CHS geometry of the maximum size.
245+
*/
246+
static bool vpc_ignore_current_size(VHDFooter *footer)
247+
{
248+
return !strncmp(footer->creator_app, "vpc ", 4) ||
249+
!strncmp(footer->creator_app, "qemu", 4);
250+
}
251+
219252
static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
220253
Error **errp)
221254
{
@@ -304,36 +337,8 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
304337
bs->total_sectors = (int64_t)
305338
be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl;
306339

307-
/* Microsoft Virtual PC and Microsoft Hyper-V produce and read
308-
* VHD image sizes differently. VPC will rely on CHS geometry,
309-
* while Hyper-V and disk2vhd use the size specified in the footer.
310-
*
311-
* We use a couple of approaches to try and determine the correct method:
312-
* look at the Creator App field, and look for images that have CHS
313-
* geometry that is the maximum value.
314-
*
315-
* If the CHS geometry is the maximum CHS geometry, then we assume that
316-
* the size is the footer->current_size to avoid truncation. Otherwise,
317-
* we follow the table based on footer->creator_app:
318-
*
319-
* Known creator apps:
320-
* 'vpc ' : CHS Virtual PC (uses disk geometry)
321-
* 'qemu' : CHS QEMU (uses disk geometry)
322-
* 'qem2' : current_size QEMU (uses current_size)
323-
* 'win ' : current_size Hyper-V
324-
* 'd2v ' : current_size Disk2vhd
325-
* 'tap\0' : current_size XenServer
326-
* 'CTXS' : current_size XenConverter
327-
*
328-
* The user can override the table values via drive options, however
329-
* even with an override we will still use current_size for images
330-
* that have CHS geometry of the maximum size.
331-
*/
332-
use_chs = (!!strncmp(footer->creator_app, "win ", 4) &&
333-
!!strncmp(footer->creator_app, "qem2", 4) &&
334-
!!strncmp(footer->creator_app, "d2v ", 4) &&
335-
!!strncmp(footer->creator_app, "CTXS", 4) &&
336-
!!memcmp(footer->creator_app, "tap", 4)) || s->force_use_chs;
340+
/* Use CHS or current_size to determine the image size. */
341+
use_chs = vpc_ignore_current_size(footer) || s->force_use_chs;
337342

338343
if (!use_chs || bs->total_sectors == VHD_MAX_GEOMETRY || s->force_use_sz) {
339344
bs->total_sectors = be64_to_cpu(footer->current_size) /

0 commit comments

Comments
 (0)