* THE SOFTWARE.
*/
-#include "config-host.h"
+#include "qemu/osdep.h"
#include "qemu-common.h"
#include "trace.h"
#include "block/block.h"
int refcnt;
};
+static QLIST_HEAD(, BlockJob) block_jobs = QLIST_HEAD_INITIALIZER(block_jobs);
+
+BlockJob *block_job_next(BlockJob *job)
+{
+ if (!job) {
+ return QLIST_FIRST(&block_jobs);
+ }
+ return QLIST_NEXT(job, job_list);
+}
+
void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
int64_t speed, BlockCompletionFunc *cb,
void *opaque, Error **errp)
{
+ BlockBackend *blk;
BlockJob *job;
if (bs->job) {
error_setg(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
return NULL;
}
- bdrv_ref(bs);
+
+ blk = blk_new();
+ blk_insert_bs(blk, bs);
+
job = g_malloc0(driver->instance_size);
error_setg(&job->blocker, "block device is in use by block job: %s",
BlockJobType_lookup[driver->job_type]);
job->driver = driver;
job->id = g_strdup(bdrv_get_device_name(bs));
- job->bs = bs;
+ job->blk = blk;
job->cb = cb;
job->opaque = opaque;
job->busy = true;
job->refcnt = 1;
bs->job = job;
+ QLIST_INSERT_HEAD(&block_jobs, job, job_list);
+
/* Only set speed when necessary to avoid NotSupported error */
if (speed != 0) {
Error *local_err = NULL;
void block_job_unref(BlockJob *job)
{
if (--job->refcnt == 0) {
- job->bs->job = NULL;
- bdrv_op_unblock_all(job->bs, job->blocker);
- bdrv_unref(job->bs);
+ BlockDriverState *bs = blk_bs(job->blk);
+ bs->job = NULL;
+ bdrv_op_unblock_all(bs, job->blocker);
+ blk_unref(job->blk);
error_free(job->blocker);
g_free(job->id);
+ QLIST_REMOVE(job, job_list);
g_free(job);
}
}
txn->aborting = true;
/* We are the first failed job. Cancel other jobs. */
QLIST_FOREACH(other_job, &txn->jobs, txn_list) {
- ctx = bdrv_get_aio_context(other_job->bs);
+ ctx = blk_get_aio_context(other_job->blk);
aio_context_acquire(ctx);
}
QLIST_FOREACH(other_job, &txn->jobs, txn_list) {
assert(other_job->completed);
}
QLIST_FOREACH_SAFE(other_job, &txn->jobs, txn_list, next) {
- ctx = bdrv_get_aio_context(other_job->bs);
+ ctx = blk_get_aio_context(other_job->blk);
block_job_completed_single(other_job);
aio_context_release(ctx);
}
}
/* We are the last completed job, commit the transaction. */
QLIST_FOREACH_SAFE(other_job, &txn->jobs, txn_list, next) {
- ctx = bdrv_get_aio_context(other_job->bs);
+ ctx = blk_get_aio_context(other_job->blk);
aio_context_acquire(ctx);
assert(other_job->ret == 0);
block_job_completed_single(other_job);
void block_job_completed(BlockJob *job, int ret)
{
- BlockDriverState *bs = job->bs;
-
- assert(bs->job == job);
+ assert(blk_bs(job->blk)->job == job);
assert(!job->completed);
job->completed = true;
job->ret = ret;
}
}
-struct BlockFinishData {
- BlockJob *job;
- BlockCompletionFunc *cb;
- void *opaque;
- bool cancelled;
- int ret;
-};
-
static int block_job_finish_sync(BlockJob *job,
void (*finish)(BlockJob *, Error **errp),
Error **errp)
{
- BlockDriverState *bs = job->bs;
Error *local_err = NULL;
int ret;
- assert(bs->job == job);
+ assert(blk_bs(job->blk)->job == job);
block_job_ref(job);
finish(job, &local_err);
return -EBUSY;
}
while (!job->completed) {
- aio_poll(bdrv_get_aio_context(bs), true);
+ aio_poll(job->deferred_to_main_loop ? qemu_get_aio_context() :
+ blk_get_aio_context(job->blk),
+ true);
}
ret = (job->cancelled && job->ret == 0) ? -ECANCELED : job->ret;
block_job_unref(job);
return block_job_finish_sync(job, &block_job_cancel_err, NULL);
}
+void block_job_cancel_sync_all(void)
+{
+ BlockJob *job;
+ AioContext *aio_context;
+
+ while ((job = QLIST_FIRST(&block_jobs))) {
+ aio_context = blk_get_aio_context(job->blk);
+ aio_context_acquire(aio_context);
+ block_job_cancel_sync(job);
+ aio_context_release(aio_context);
+ }
+}
+
int block_job_complete_sync(BlockJob *job, Error **errp)
{
return block_job_finish_sync(job, &block_job_complete, errp);
}
job->busy = false;
+ if (!block_job_is_paused(job)) {
+ co_aio_sleep_ns(blk_get_aio_context(job->blk), type, ns);
+ }
+ /* The job can be paused while sleeping, so check this again */
if (block_job_is_paused(job)) {
qemu_coroutine_yield();
- } else {
- co_aio_sleep_ns(bdrv_get_aio_context(job->bs), type, ns);
}
job->busy = true;
}
job->speed, &error_abort);
}
-BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs,
- BlockdevOnError on_err,
+BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err,
int is_read, int error)
{
BlockErrorAction action;
job->user_paused = true;
block_job_pause(job);
block_job_iostatus_set_err(job, error);
- if (bs->blk && bs != job->bs) {
- blk_iostatus_set_err(bs->blk, error);
- }
}
return action;
}
aio_context_acquire(data->aio_context);
/* Fetch BDS AioContext again, in case it has changed */
- aio_context = bdrv_get_aio_context(data->job->bs);
+ aio_context = blk_get_aio_context(data->job->blk);
aio_context_acquire(aio_context);
+ data->job->deferred_to_main_loop = false;
data->fn(data->job, data->opaque);
aio_context_release(aio_context);
BlockJobDeferToMainLoopData *data = g_malloc(sizeof(*data));
data->job = job;
data->bh = qemu_bh_new(block_job_defer_to_main_loop_bh, data);
- data->aio_context = bdrv_get_aio_context(job->bs);
+ data->aio_context = blk_get_aio_context(job->blk);
data->fn = fn;
data->opaque = opaque;
+ job->deferred_to_main_loop = true;
qemu_bh_schedule(data->bh);
}