@samitouri / QOSamiQemu / commits / 9ac85f4cc7

block/mirror: fix assertion failure upon duplicate complete for job using 'replaces'

If s->replace_blocker was already set by an earlier invocation of mirror_complete(), then there will be an assertion failure when error_setg() is called for it a second time. The bdrv_op_block_all() and bdrv_ref() operations should only be done a single time too. Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> Message-Id: <20260311145717.668492-2-f.ebner@proxmox.com> Reviewed-by: Hanna Czenczek <hreitz@redhat.com> Signed-off-by: Hanna Czenczek <hreitz@redhat.com>

Fiona Ebner committed Mar 11, 2026 at 15:54 UTC 9ac85f4cc7995217db8f736733b990d6addcb036
1 file changed +15 -13
block/mirror.c
+15 -13
@@ -1276,23 +1276,25 @@ static void mirror_complete(Job *job, Error **errp)
1276 return;
1277 }
1278
1279 - /* block all operations on to_replace bs */
1280 - if (s->replaces) {
1281 - s->to_replace = bdrv_find_node(s->replaces);
1282 - if (!s->to_replace) {
1283 - error_setg(errp, "Node name '%s' not found", s->replaces);
1284 - return;
1279 + if (!s->should_complete) {
1280 + /* block all operations on to_replace bs */
1281 + if (s->replaces) {
1282 + s->to_replace = bdrv_find_node(s->replaces);
1283 + if (!s->to_replace) {
1284 + error_setg(errp, "Node name '%s' not found", s->replaces);
1285 + return;
1286 + }
1287 +
1288 + /* TODO Translate this into child freeze system. */
1289 + error_setg(&s->replace_blocker,
1290 + "block device is in use by block-job-complete");
1291 + bdrv_op_block_all(s->to_replace, s->replace_blocker);
1292 + bdrv_ref(s->to_replace);
1293 }
1294
1287 - /* TODO Translate this into child freeze system. */
1288 - error_setg(&s->replace_blocker,
1289 - "block device is in use by block-job-complete");
1290 - bdrv_op_block_all(s->to_replace, s->replace_blocker);
1291 - bdrv_ref(s->to_replace);
1295 + s->should_complete = true;
1296 }
1297
1294 - s->should_complete = true;
1295 -
1298 /* If the job is paused, it will be re-entered when it is resumed */
1299 WITH_JOB_LOCK_GUARD() {
1300 if (!job->paused) {