aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>2021-04-21 10:58:58 +0300
committerMax Reitz <mreitz@redhat.com>2021-05-14 16:14:10 +0200
commit9c785cd714b3c368503ba3aed4266a77056cae29 (patch)
tree2f1978b1bc246ff0dc57e48f71acbcdb496f1d47
parent78632a3d1685454fec83f83586c675e7f2a1a84a (diff)
downloadqemu-9c785cd714b3c368503ba3aed4266a77056cae29.zip
qemu-9c785cd714b3c368503ba3aed4266a77056cae29.tar.gz
qemu-9c785cd714b3c368503ba3aed4266a77056cae29.tar.bz2
mirror: stop cancelling in-flight requests on non-force cancel in READY
If mirror is READY than cancel operation is not discarding the whole result of the operation, but instead it's a documented way get a point-in-time snapshot of source disk. So, we should not cancel any requests if mirror is READ and force=false. Let's fix that case. Note, that bug that we have before this commit is not critical, as the only .bdrv_cancel_in_flight implementation is nbd_cancel_in_flight() and it cancels only requests waiting for reconnection, so it should be rare case. Fixes: 521ff8b779b11c394dbdc43f02e158dd99df308a Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Message-Id: <20210421075858.40197-1-vsementsov@virtuozzo.com> Signed-off-by: Max Reitz <mreitz@redhat.com>
-rw-r--r--block/backup.c2
-rw-r--r--block/mirror.c6
-rw-r--r--include/block/block_int.h2
-rw-r--r--include/qemu/job.h2
-rw-r--r--job.c2
-rwxr-xr-xtests/qemu-iotests/2642
6 files changed, 9 insertions, 7 deletions
diff --git a/block/backup.c b/block/backup.c
index 6cf2f97..bd3614c 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -331,7 +331,7 @@ static void coroutine_fn backup_set_speed(BlockJob *job, int64_t speed)
}
}
-static void backup_cancel(Job *job)
+static void backup_cancel(Job *job, bool force)
{
BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
diff --git a/block/mirror.c b/block/mirror.c
index 840b8e8..019f6de 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -1178,12 +1178,14 @@ static bool mirror_drained_poll(BlockJob *job)
return !!s->in_flight;
}
-static void mirror_cancel(Job *job)
+static void mirror_cancel(Job *job, bool force)
{
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
BlockDriverState *target = blk_bs(s->target);
- bdrv_cancel_in_flight(target);
+ if (force || !job_is_ready(job)) {
+ bdrv_cancel_in_flight(target);
+ }
}
static const BlockJobDriver mirror_job_driver = {
diff --git a/include/block/block_int.h b/include/block/block_int.h
index c823f5b..731ffed 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -357,7 +357,7 @@ struct BlockDriver {
* of in-flight requests, so don't waste the time if possible.
*
* One example usage is to avoid waiting for an nbd target node reconnect
- * timeout during job-cancel.
+ * timeout during job-cancel with force=true.
*/
void (*bdrv_cancel_in_flight)(BlockDriverState *bs);
diff --git a/include/qemu/job.h b/include/qemu/job.h
index efc6fa7..41162ed 100644
--- a/include/qemu/job.h
+++ b/include/qemu/job.h
@@ -254,7 +254,7 @@ struct JobDriver {
/**
* If the callback is not NULL, it will be invoked in job_cancel_async
*/
- void (*cancel)(Job *job);
+ void (*cancel)(Job *job, bool force);
/** Called when the job is freed */
diff --git a/job.c b/job.c
index 4aff13d..8775c18 100644
--- a/job.c
+++ b/job.c
@@ -716,7 +716,7 @@ static int job_finalize_single(Job *job)
static void job_cancel_async(Job *job, bool force)
{
if (job->driver->cancel) {
- job->driver->cancel(job);
+ job->driver->cancel(job, force);
}
if (job->user_paused) {
/* Do not call job_enter here, the caller will handle it. */
diff --git a/tests/qemu-iotests/264 b/tests/qemu-iotests/264
index 4f96825..bc431d1 100755
--- a/tests/qemu-iotests/264
+++ b/tests/qemu-iotests/264
@@ -95,7 +95,7 @@ class TestNbdReconnect(iotests.QMPTestCase):
self.assert_qmp(result, 'return', {})
def cancel_job(self):
- result = self.vm.qmp('block-job-cancel', device='drive0')
+ result = self.vm.qmp('block-job-cancel', device='drive0', force=True)
self.assert_qmp(result, 'return', {})
start_t = time.time()