#include "config-host.h"
#include "qemu-common.h"
#include "trace.h"
-#include "monitor/monitor.h"
#include "block/block.h"
#include "block/blockjob.h"
#include "block/block_int.h"
#include "block/coroutine.h"
#include "qmp-commands.h"
#include "qemu/timer.h"
+#include "qapi-event.h"
void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
int64_t speed, BlockDriverCompletionFunc *cb,
{
BlockJob *job;
- if (bs->job || bdrv_in_use(bs)) {
+ if (bs->job) {
error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
return NULL;
}
bdrv_ref(bs);
- bdrv_set_in_use(bs, 1);
-
job = g_malloc0(driver->instance_size);
+ error_setg(&job->blocker, "block device is in use by block job: %s",
+ BlockJobType_lookup[driver->job_type]);
+ bdrv_op_block_all(bs, job->blocker);
+
job->driver = driver;
job->bs = bs;
job->cb = cb;
Error *local_err = NULL;
block_job_set_speed(job, speed, &local_err);
- if (error_is_set(&local_err)) {
+ if (local_err) {
bs->job = NULL;
+ bdrv_op_unblock_all(bs, job->blocker);
+ error_free(job->blocker);
g_free(job);
- bdrv_set_in_use(bs, 0);
error_propagate(errp, local_err);
return NULL;
}
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);
- bdrv_set_in_use(bs, 0);
}
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_NOT_SUPPORTED);
+ error_set(errp, QERR_UNSUPPORTED);
return;
}
job->driver->set_speed(job, speed, &local_err);
- if (error_is_set(&local_err)) {
+ if (local_err) {
error_propagate(errp, local_err);
return;
}
job->opaque = &data;
block_job_cancel(job);
while (data.ret == -EINPROGRESS) {
- qemu_aio_wait();
+ aio_poll(bdrv_get_aio_context(bs), true);
}
return (data.cancelled && data.ret == 0) ? -ECANCELED : data.ret;
}
if (block_job_is_paused(job)) {
qemu_coroutine_yield();
} else {
- co_sleep_ns(type, ns);
+ co_aio_sleep_ns(bdrv_get_aio_context(job->bs), type, ns);
+ }
+ job->busy = true;
+}
+
+void block_job_yield(BlockJob *job)
+{
+ assert(job->busy);
+
+ /* Check cancellation *before* setting busy = false, too! */
+ if (block_job_is_cancelled(job)) {
+ return;
}
+
+ job->busy = false;
+ qemu_coroutine_yield();
job->busy = true;
}
BlockJobInfo *block_job_query(BlockJob *job)
{
BlockJobInfo *info = g_new0(BlockJobInfo, 1);
- info->type = g_strdup(job->driver->job_type);
+ info->type = g_strdup(BlockJobType_lookup[job->driver->job_type]);
info->device = g_strdup(bdrv_get_device_name(job->bs));
info->len = job->len;
info->busy = job->busy;
}
}
+void block_job_event_cancelled(BlockJob *job)
+{
+ qapi_event_send_block_job_cancelled(job->driver->job_type,
+ bdrv_get_device_name(job->bs),
+ job->len,
+ job->offset,
+ job->speed,
+ &error_abort);
+}
-QObject *qobject_from_block_job(BlockJob *job)
+void block_job_event_completed(BlockJob *job, const char *msg)
{
- return qobject_from_jsonf("{ 'type': %s,"
- "'device': %s,"
- "'len': %" PRId64 ","
- "'offset': %" PRId64 ","
- "'speed': %" PRId64 " }",
- job->driver->job_type,
- bdrv_get_device_name(job->bs),
- job->len,
- job->offset,
- job->speed);
+ qapi_event_send_block_job_completed(job->driver->job_type,
+ bdrv_get_device_name(job->bs),
+ job->len,
+ job->offset,
+ job->speed,
+ !!msg,
+ msg,
+ &error_abort);
}
-void block_job_ready(BlockJob *job)
+void block_job_event_ready(BlockJob *job)
{
- QObject *data = qobject_from_block_job(job);
- monitor_protocol_event(QEVENT_BLOCK_JOB_READY, data);
- qobject_decref(data);
+ qapi_event_send_block_job_ready(job->driver->job_type,
+ bdrv_get_device_name(job->bs),
+ job->len,
+ job->offset,
+ job->speed, &error_abort);
}
BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs,
switch (on_err) {
case BLOCKDEV_ON_ERROR_ENOSPC:
- action = (error == ENOSPC) ? BDRV_ACTION_STOP : BDRV_ACTION_REPORT;
+ action = (error == ENOSPC) ?
+ BLOCK_ERROR_ACTION_STOP : BLOCK_ERROR_ACTION_REPORT;
break;
case BLOCKDEV_ON_ERROR_STOP:
- action = BDRV_ACTION_STOP;
+ action = BLOCK_ERROR_ACTION_STOP;
break;
case BLOCKDEV_ON_ERROR_REPORT:
- action = BDRV_ACTION_REPORT;
+ action = BLOCK_ERROR_ACTION_REPORT;
break;
case BLOCKDEV_ON_ERROR_IGNORE:
- action = BDRV_ACTION_IGNORE;
+ action = BLOCK_ERROR_ACTION_IGNORE;
break;
default:
abort();
}
- bdrv_emit_qmp_error_event(job->bs, QEVENT_BLOCK_JOB_ERROR, action, is_read);
- if (action == BDRV_ACTION_STOP) {
+ qapi_event_send_block_job_error(bdrv_get_device_name(job->bs),
+ is_read ? IO_OPERATION_TYPE_READ :
+ IO_OPERATION_TYPE_WRITE,
+ action, &error_abort);
+ if (action == BLOCK_ERROR_ACTION_STOP) {
block_job_pause(job);
block_job_iostatus_set_err(job, error);
if (bs != job->bs) {