*/
#include "qemu/osdep.h"
+#include "block/aio-wait.h"
#include "block/block.h"
#include "block/blockjob_int.h"
#include "block/block_int.h"
#include "qapi/error.h"
#include "qapi/qapi-events-block-core.h"
#include "qapi/qmp/qerror.h"
-#include "qemu/coroutine.h"
#include "qemu/main-loop.h"
#include "qemu/timer.h"
return job ? container_of(job, BlockJob, job) : NULL;
}
-BlockJob *block_job_next(BlockJob *bjob)
-{
- JOB_LOCK_GUARD();
- return block_job_next_locked(bjob);
-}
-
BlockJob *block_job_get_locked(const char *id)
{
Job *job = job_get_locked(id);
}
}
-static void child_job_drained_end(BdrvChild *c, int *drained_end_counter)
+static void child_job_drained_end(BdrvChild *c)
{
BlockJob *job = c->opaque;
job_resume(&job->job);
}
-static bool child_job_can_set_aio_ctx(BdrvChild *c, AioContext *ctx,
- GSList **ignore, Error **errp)
+typedef struct BdrvStateChildJobContext {
+ AioContext *new_ctx;
+ BlockJob *job;
+} BdrvStateChildJobContext;
+
+static void child_job_set_aio_ctx_commit(void *opaque)
{
- BlockJob *job = c->opaque;
- GSList *l;
+ BdrvStateChildJobContext *s = opaque;
+ BlockJob *job = s->job;
- for (l = job->nodes; l; l = l->next) {
- BdrvChild *sibling = l->data;
- if (!bdrv_child_can_set_aio_context(sibling, ctx, ignore, errp)) {
- return false;
- }
- }
- return true;
+ job_set_aio_context(&job->job, s->new_ctx);
}
-static void child_job_set_aio_ctx(BdrvChild *c, AioContext *ctx,
- GSList **ignore)
+static TransactionActionDrv change_child_job_context = {
+ .commit = child_job_set_aio_ctx_commit,
+ .clean = g_free,
+};
+
+static bool child_job_change_aio_ctx(BdrvChild *c, AioContext *ctx,
+ GHashTable *visited, Transaction *tran,
+ Error **errp)
{
BlockJob *job = c->opaque;
+ BdrvStateChildJobContext *s;
GSList *l;
for (l = job->nodes; l; l = l->next) {
BdrvChild *sibling = l->data;
- if (g_slist_find(*ignore, sibling)) {
- continue;
+ if (!bdrv_child_change_aio_context(sibling, ctx, visited,
+ tran, errp)) {
+ return false;
}
- *ignore = g_slist_prepend(*ignore, sibling);
- bdrv_set_aio_context_ignore(sibling->bs, ctx, ignore);
}
- job->job.aio_context = ctx;
+ s = g_new(BdrvStateChildJobContext, 1);
+ *s = (BdrvStateChildJobContext) {
+ .new_ctx = ctx,
+ .job = job,
+ };
+
+ tran_add(tran, &change_child_job_context, s);
+ return true;
}
static AioContext *child_job_get_parent_aio_context(BdrvChild *c)
{
BlockJob *job = c->opaque;
+ IO_CODE();
+ JOB_LOCK_GUARD();
return job->job.aio_context;
}
.drained_begin = child_job_drained_begin,
.drained_poll = child_job_drained_poll,
.drained_end = child_job_drained_end,
- .can_set_aio_ctx = child_job_can_set_aio_ctx,
- .set_aio_ctx = child_job_set_aio_ctx,
+ .change_aio_ctx = child_job_change_aio_ctx,
.stay_at_node = true,
.get_parent_aio_context = child_job_get_parent_aio_context,
};
return 0;
}
-static void block_job_on_idle(Notifier *n, void *opaque)
+/* Called with job_mutex lock held. */
+static void block_job_on_idle_locked(Notifier *n, void *opaque)
{
aio_wait_kick();
}
return true;
}
-bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
+static bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
{
JOB_LOCK_GUARD();
return block_job_set_speed_locked(job, speed, errp);
info = g_new0(BlockJobInfo, 1);
info->type = g_strdup(job_type_str(&job->job));
info->device = g_strdup(job->job.id);
- info->busy = qatomic_read(&job->job.busy);
+ info->busy = job->job.busy;
info->paused = job->job.pause_count > 0;
info->offset = progress_current;
info->len = progress_total;
info->auto_finalize = job->job.auto_finalize;
info->auto_dismiss = job->job.auto_dismiss;
if (job->job.ret) {
- info->has_error = true;
info->error = job->job.err ?
g_strdup(error_get_pretty(job->job.err)) :
g_strdup(strerror(-job->job.ret));
return info;
}
-BlockJobInfo *block_job_query(BlockJob *job, Error **errp)
-{
- JOB_LOCK_GUARD();
- return block_job_query_locked(job, errp);
-}
-
-static void block_job_iostatus_set_err(BlockJob *job, int error)
+/* Called with job lock held */
+static void block_job_iostatus_set_err_locked(BlockJob *job, int error)
{
if (job->iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
job->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE :
}
}
-static void block_job_event_cancelled(Notifier *n, void *opaque)
+/* Called with job_mutex lock held. */
+static void block_job_event_cancelled_locked(Notifier *n, void *opaque)
{
BlockJob *job = opaque;
uint64_t progress_current, progress_total;
job->speed);
}
-static void block_job_event_completed(Notifier *n, void *opaque)
+/* Called with job_mutex lock held. */
+static void block_job_event_completed_locked(Notifier *n, void *opaque)
{
BlockJob *job = opaque;
const char *msg = NULL;
progress_total,
progress_current,
job->speed,
- !!msg,
msg);
}
-static void block_job_event_pending(Notifier *n, void *opaque)
+/* Called with job_mutex lock held. */
+static void block_job_event_pending_locked(Notifier *n, void *opaque)
{
BlockJob *job = opaque;
job->job.id);
}
-static void block_job_event_ready(Notifier *n, void *opaque)
+/* Called with job_mutex lock held. */
+static void block_job_event_ready_locked(Notifier *n, void *opaque)
{
BlockJob *job = opaque;
uint64_t progress_current, progress_total;
ratelimit_init(&job->limit);
- job->finalize_cancelled_notifier.notify = block_job_event_cancelled;
- job->finalize_completed_notifier.notify = block_job_event_completed;
- job->pending_notifier.notify = block_job_event_pending;
- job->ready_notifier.notify = block_job_event_ready;
- job->idle_notifier.notify = block_job_on_idle;
+ job->finalize_cancelled_notifier.notify = block_job_event_cancelled_locked;
+ job->finalize_completed_notifier.notify = block_job_event_completed_locked;
+ job->pending_notifier.notify = block_job_event_pending_locked;
+ job->ready_notifier.notify = block_job_event_ready_locked;
+ job->idle_notifier.notify = block_job_on_idle_locked;
WITH_JOB_LOCK_GUARD() {
notifier_list_add(&job->job.on_finalize_cancelled,
job->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
}
-void block_job_iostatus_reset(BlockJob *job)
+static void block_job_iostatus_reset(BlockJob *job)
{
JOB_LOCK_GUARD();
block_job_iostatus_reset_locked(job);
*/
job->job.user_paused = true;
}
+ block_job_iostatus_set_err_locked(job, error);
}
- block_job_iostatus_set_err(job, error);
}
return action;
}