#include "block/block.h"
#include "block/blockjob.h"
#include "block/block_int.h"
+#include "qapi/qmp/qerror.h"
#include "qapi/qmp/qjson.h"
#include "block/coroutine.h"
#include "qmp-commands.h"
BlockJob *job;
if (bs->job) {
- error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
+ error_setg(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
return NULL;
}
bdrv_ref(bs);
block_job_set_speed(job, speed, &local_err);
if (local_err) {
- bs->job = NULL;
- bdrv_op_unblock_all(bs, job->blocker);
- error_free(job->blocker);
- g_free(job);
+ block_job_release(bs);
error_propagate(errp, local_err);
return NULL;
}
return job;
}
-void block_job_completed(BlockJob *job, int ret)
+void block_job_release(BlockDriverState *bs)
{
- BlockDriverState *bs = job->bs;
+ BlockJob *job = bs->job;
- assert(bs->job == job);
- job->cb(job->opaque, ret);
bs->job = NULL;
bdrv_op_unblock_all(bs, job->blocker);
error_free(job->blocker);
g_free(job);
}
+void block_job_completed(BlockJob *job, int ret)
+{
+ BlockDriverState *bs = job->bs;
+
+ assert(bs->job == job);
+ job->cb(job->opaque, ret);
+ block_job_release(bs);
+}
+
void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
{
Error *local_err = NULL;
if (!job->driver->set_speed) {
- error_set(errp, QERR_UNSUPPORTED);
+ error_setg(errp, QERR_UNSUPPORTED);
return;
}
job->driver->set_speed(job, speed, &local_err);
void block_job_complete(BlockJob *job, Error **errp)
{
- if (job->paused || job->cancelled || !job->driver->complete) {
- error_set(errp, QERR_BLOCK_JOB_NOT_READY,
- bdrv_get_device_name(job->bs));
+ if (job->pause_count || job->cancelled || !job->driver->complete) {
+ error_setg(errp, QERR_BLOCK_JOB_NOT_READY,
+ bdrv_get_device_name(job->bs));
return;
}
void block_job_pause(BlockJob *job)
{
- job->paused = true;
+ job->pause_count++;
}
bool block_job_is_paused(BlockJob *job)
{
- return job->paused;
+ return job->pause_count > 0;
}
void block_job_resume(BlockJob *job)
{
- job->paused = false;
+ assert(job->pause_count > 0);
+ job->pause_count--;
+ if (job->pause_count) {
+ return;
+ }
+ block_job_enter(job);
+}
+
+void block_job_enter(BlockJob *job)
+{
block_job_iostatus_reset(job);
if (job->co && !job->busy) {
qemu_coroutine_enter(job->co, NULL);
void block_job_cancel(BlockJob *job)
{
job->cancelled = true;
- block_job_resume(job);
+ block_job_enter(job);
}
bool block_job_is_cancelled(BlockJob *job)
info->device = g_strdup(bdrv_get_device_name(job->bs));
info->len = job->len;
info->busy = job->busy;
- info->paused = job->paused;
+ info->paused = job->pause_count > 0;
info->offset = job->offset;
info->speed = job->speed;
info->io_status = job->iostatus;
IO_OPERATION_TYPE_WRITE,
action, &error_abort);
if (action == BLOCK_ERROR_ACTION_STOP) {
+ /* make the pause user visible, which will be resumed from QMP. */
+ job->user_paused = true;
block_job_pause(job);
block_job_iostatus_set_err(job, error);
if (bs != job->bs) {