X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=blockjob.c;h=b7a29052b94fcb1a8a2ffb33ac8ac23962bd5c7d;hb=c2118e9e1ab34edb1b5d1b0b4092cb12271a593d;hp=d04f8040017b528fc654285917b0158e45581353;hpb=d59cb66de32c27443b12b774147b611f8e459e9b;p=qmiga%2Fqemu.git diff --git a/blockjob.c b/blockjob.c index d04f804001..b7a29052b9 100644 --- a/blockjob.c +++ b/blockjob.c @@ -24,6 +24,7 @@ */ #include "qemu/osdep.h" +#include "block/aio-wait.h" #include "block/block.h" #include "block/blockjob_int.h" #include "block/block_int.h" @@ -32,7 +33,6 @@ #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" @@ -56,12 +56,6 @@ BlockJob *block_job_next_locked(BlockJob *bjob) 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); @@ -126,49 +120,61 @@ static bool child_job_drained_poll(BdrvChild *c) } } -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_set_aio_context(&job->job, 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; - GLOBAL_STATE_CODE(); + IO_CODE(); + JOB_LOCK_GUARD(); return job->job.aio_context; } @@ -178,8 +184,7 @@ static const BdrvChildClass child_job = { .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, }; @@ -193,6 +198,9 @@ void block_job_remove_all_bdrv(BlockJob *job) * one to make sure that such a concurrent access does not attempt * to process an already freed BdrvChild. */ + aio_context_release(job->job.aio_context); + bdrv_graph_wrlock(NULL); + aio_context_acquire(job->job.aio_context); while (job->nodes) { GSList *l = job->nodes; BdrvChild *c = l->data; @@ -204,6 +212,7 @@ void block_job_remove_all_bdrv(BlockJob *job) g_slist_free_1(l); } + bdrv_graph_wrunlock_ctx(job->job.aio_context); } bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs) @@ -225,20 +234,27 @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs, uint64_t perm, uint64_t shared_perm, Error **errp) { BdrvChild *c; + AioContext *ctx = bdrv_get_aio_context(bs); bool need_context_ops; GLOBAL_STATE_CODE(); bdrv_ref(bs); - need_context_ops = bdrv_get_aio_context(bs) != job->job.aio_context; + need_context_ops = ctx != job->job.aio_context; - if (need_context_ops && job->job.aio_context != qemu_get_aio_context()) { - aio_context_release(job->job.aio_context); + if (need_context_ops) { + if (job->job.aio_context != qemu_get_aio_context()) { + aio_context_release(job->job.aio_context); + } + aio_context_acquire(ctx); } c = bdrv_root_attach_child(bs, name, &child_job, 0, perm, shared_perm, job, errp); - if (need_context_ops && job->job.aio_context != qemu_get_aio_context()) { - aio_context_acquire(job->job.aio_context); + if (need_context_ops) { + aio_context_release(ctx); + if (job->job.aio_context != qemu_get_aio_context()) { + aio_context_acquire(job->job.aio_context); + } } if (c == NULL) { return -EPERM; @@ -308,22 +324,61 @@ bool block_job_set_speed_locked(BlockJob *job, int64_t speed, Error **errp) 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); } -int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n) +void block_job_change_locked(BlockJob *job, BlockJobChangeOptions *opts, + Error **errp) +{ + const BlockJobDriver *drv = block_job_driver(job); + + GLOBAL_STATE_CODE(); + + if (job_apply_verb_locked(&job->job, JOB_VERB_CHANGE, errp)) { + return; + } + + if (drv->change) { + job_unlock(); + drv->change(job, opts, errp); + job_lock(); + } else { + error_setg(errp, "Job type does not support change"); + } +} + +void block_job_ratelimit_processed_bytes(BlockJob *job, uint64_t n) { IO_CODE(); - return ratelimit_calculate_delay(&job->limit, n); + ratelimit_calculate_delay(&job->limit, n); +} + +void block_job_ratelimit_sleep(BlockJob *job) +{ + uint64_t delay_ns; + + /* + * Sleep at least once. If the job is reentered early, keep waiting until + * we've waited for the full time that is necessary to keep the job at the + * right speed. + * + * Make sure to recalculate the delay after each (possibly interrupted) + * sleep because the speed can change while the job has yielded. + */ + do { + delay_ns = ratelimit_calculate_delay(&job->limit, 0); + job_sleep_ns(&job->job, delay_ns); + } while (delay_ns && !job_is_cancelled(&job->job)); } BlockJobInfo *block_job_query_locked(BlockJob *job, Error **errp) { BlockJobInfo *info; uint64_t progress_current, progress_total; + const BlockJobDriver *drv = block_job_driver(job); GLOBAL_STATE_CODE(); @@ -336,9 +391,9 @@ BlockJobInfo *block_job_query_locked(BlockJob *job, Error **errp) &progress_total); info = g_new0(BlockJobInfo, 1); - info->type = g_strdup(job_type_str(&job->job)); + info->type = job_type(&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; @@ -349,20 +404,18 @@ BlockJobInfo *block_job_query_locked(BlockJob *job, Error **errp) 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)); } + if (drv->query) { + job_unlock(); + drv->query(job, info); + job_lock(); + } return info; } -BlockJobInfo *block_job_query(BlockJob *job, Error **errp) -{ - JOB_LOCK_GUARD(); - return block_job_query_locked(job, errp); -} - /* Called with job lock held */ static void block_job_iostatus_set_err_locked(BlockJob *job, int error) { @@ -415,7 +468,6 @@ static void block_job_event_completed_locked(Notifier *n, void *opaque) progress_total, progress_current, job->speed, - !!msg, msg); } @@ -462,6 +514,8 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, int ret; GLOBAL_STATE_CODE(); + bdrv_graph_wrlock(bs); + if (job_id == NULL && !(flags & JOB_INTERNAL)) { job_id = bdrv_get_device_name(bs); } @@ -469,6 +523,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, job = job_create(job_id, &driver->job_driver, txn, bdrv_get_aio_context(bs), flags, cb, opaque, errp); if (job == NULL) { + bdrv_graph_wrunlock(bs); return NULL; } @@ -508,9 +563,11 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, goto fail; } + bdrv_graph_wrunlock(bs); return job; fail: + bdrv_graph_wrunlock(bs); job_early_fail(&job->job); return NULL; } @@ -525,7 +582,7 @@ void block_job_iostatus_reset_locked(BlockJob *job) 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);