From 747ff602636fd83daae7ee4b1dd6e8d257a89fea Mon Sep 17 00:00:00 2001 From: Jeff Cody Date: Thu, 27 Sep 2012 13:29:13 -0400 Subject: block: add live block commit functionality This adds the live commit coroutine. This iteration focuses on the commit only below the active layer, and not the active layer itself. The behaviour is similar to block streaming; the sectors are walked through, and anything that exists above 'base' is committed back down into base. At the end, intermediate images are deleted, and the chain stitched together. Images are restored to their original open flags upon completion. Signed-off-by: Jeff Cody Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/commit.c | 267 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 block/commit.c (limited to 'block/commit.c') diff --git a/block/commit.c b/block/commit.c new file mode 100644 index 0000000000..624ec5f62a --- /dev/null +++ b/block/commit.c @@ -0,0 +1,267 @@ +/* + * Live block commit + * + * Copyright Red Hat, Inc. 2012 + * + * Authors: + * Jeff Cody + * Based on stream.c by Stefan Hajnoczi + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "trace.h" +#include "block_int.h" +#include "qemu/ratelimit.h" + +enum { + /* + * Size of data buffer for populating the image file. This should be large + * enough to process multiple clusters in a single call, so that populating + * contiguous regions of the image is efficient. + */ + COMMIT_BUFFER_SIZE = 512 * 1024, /* in bytes */ +}; + +#define SLICE_TIME 100000000ULL /* ns */ + +typedef struct CommitBlockJob { + BlockJob common; + RateLimit limit; + BlockDriverState *active; + BlockDriverState *top; + BlockDriverState *base; + BlockErrorAction on_error; + int base_flags; + int orig_overlay_flags; +} CommitBlockJob; + +static int coroutine_fn commit_populate(BlockDriverState *bs, + BlockDriverState *base, + int64_t sector_num, int nb_sectors, + void *buf) +{ + int ret = 0; + + ret = bdrv_read(bs, sector_num, buf, nb_sectors); + if (ret) { + return ret; + } + + ret = bdrv_write(base, sector_num, buf, nb_sectors); + if (ret) { + return ret; + } + + return 0; +} + +static void coroutine_fn commit_run(void *opaque) +{ + CommitBlockJob *s = opaque; + BlockDriverState *active = s->active; + BlockDriverState *top = s->top; + BlockDriverState *base = s->base; + BlockDriverState *overlay_bs = NULL; + int64_t sector_num, end; + int ret = 0; + int n = 0; + void *buf; + int bytes_written = 0; + int64_t base_len; + + ret = s->common.len = bdrv_getlength(top); + + + if (s->common.len < 0) { + goto exit_restore_reopen; + } + + ret = base_len = bdrv_getlength(base); + if (base_len < 0) { + goto exit_restore_reopen; + } + + if (base_len < s->common.len) { + ret = bdrv_truncate(base, s->common.len); + if (ret) { + goto exit_restore_reopen; + } + } + + overlay_bs = bdrv_find_overlay(active, top); + + end = s->common.len >> BDRV_SECTOR_BITS; + buf = qemu_blockalign(top, COMMIT_BUFFER_SIZE); + + for (sector_num = 0; sector_num < end; sector_num += n) { + uint64_t delay_ns = 0; + bool copy; + +wait: + /* Note that even when no rate limit is applied we need to yield + * with no pending I/O here so that qemu_aio_flush() returns. + */ + block_job_sleep_ns(&s->common, rt_clock, delay_ns); + if (block_job_is_cancelled(&s->common)) { + break; + } + /* Copy if allocated above the base */ + ret = bdrv_co_is_allocated_above(top, base, sector_num, + COMMIT_BUFFER_SIZE / BDRV_SECTOR_SIZE, + &n); + copy = (ret == 1); + trace_commit_one_iteration(s, sector_num, n, ret); + if (copy) { + if (s->common.speed) { + delay_ns = ratelimit_calculate_delay(&s->limit, n); + if (delay_ns > 0) { + goto wait; + } + } + ret = commit_populate(top, base, sector_num, n, buf); + bytes_written += n * BDRV_SECTOR_SIZE; + } + if (ret < 0) { + if (s->on_error == BLOCK_ERR_STOP_ANY || + s->on_error == BLOCK_ERR_REPORT || + (s->on_error == BLOCK_ERR_STOP_ENOSPC && ret == -ENOSPC)) { + goto exit_free_buf; + } else { + n = 0; + continue; + } + } + /* Publish progress */ + s->common.offset += n * BDRV_SECTOR_SIZE; + } + + ret = 0; + + if (!block_job_is_cancelled(&s->common) && sector_num == end) { + /* success */ + ret = bdrv_drop_intermediate(active, top, base); + } + +exit_free_buf: + qemu_vfree(buf); + +exit_restore_reopen: + /* restore base open flags here if appropriate (e.g., change the base back + * to r/o). These reopens do not need to be atomic, since we won't abort + * even on failure here */ + if (s->base_flags != bdrv_get_flags(base)) { + bdrv_reopen(base, s->base_flags, NULL); + } + if (s->orig_overlay_flags != bdrv_get_flags(overlay_bs)) { + bdrv_reopen(overlay_bs, s->orig_overlay_flags, NULL); + } + + block_job_complete(&s->common, ret); +} + +static void commit_set_speed(BlockJob *job, int64_t speed, Error **errp) +{ + CommitBlockJob *s = container_of(job, CommitBlockJob, common); + + if (speed < 0) { + error_set(errp, QERR_INVALID_PARAMETER, "speed"); + return; + } + ratelimit_set_speed(&s->limit, speed / BDRV_SECTOR_SIZE, SLICE_TIME); +} + +static BlockJobType commit_job_type = { + .instance_size = sizeof(CommitBlockJob), + .job_type = "commit", + .set_speed = commit_set_speed, +}; + +void commit_start(BlockDriverState *bs, BlockDriverState *base, + BlockDriverState *top, int64_t speed, + BlockErrorAction on_error, BlockDriverCompletionFunc *cb, + void *opaque, Error **errp) +{ + CommitBlockJob *s; + BlockReopenQueue *reopen_queue = NULL; + int orig_overlay_flags; + int orig_base_flags; + BlockDriverState *overlay_bs; + Error *local_err = NULL; + + if ((on_error == BLOCK_ERR_STOP_ANY || + on_error == BLOCK_ERR_STOP_ENOSPC) && + !bdrv_iostatus_is_enabled(bs)) { + error_set(errp, QERR_INVALID_PARAMETER_COMBINATION); + return; + } + + /* Once we support top == active layer, remove this check */ + if (top == bs) { + error_setg(errp, + "Top image as the active layer is currently unsupported"); + return; + } + + if (top == base) { + error_setg(errp, "Invalid files for merge: top and base are the same"); + return; + } + + /* top and base may be valid, but let's make sure that base is reachable + * from top */ + if (bdrv_find_backing_image(top, base->filename) != base) { + error_setg(errp, + "Base (%s) is not reachable from top (%s)", + base->filename, top->filename); + return; + } + + overlay_bs = bdrv_find_overlay(bs, top); + + if (overlay_bs == NULL) { + error_setg(errp, "Could not find overlay image for %s:", top->filename); + return; + } + + orig_base_flags = bdrv_get_flags(base); + orig_overlay_flags = bdrv_get_flags(overlay_bs); + + /* convert base & overlay_bs to r/w, if necessary */ + if (!(orig_base_flags & BDRV_O_RDWR)) { + reopen_queue = bdrv_reopen_queue(reopen_queue, base, + orig_base_flags | BDRV_O_RDWR); + } + if (!(orig_overlay_flags & BDRV_O_RDWR)) { + reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs, + orig_overlay_flags | BDRV_O_RDWR); + } + if (reopen_queue) { + bdrv_reopen_multiple(reopen_queue, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } + } + + + s = block_job_create(&commit_job_type, bs, speed, cb, opaque, errp); + if (!s) { + return; + } + + s->base = base; + s->top = top; + s->active = bs; + + s->base_flags = orig_base_flags; + s->orig_overlay_flags = orig_overlay_flags; + + s->on_error = on_error; + s->common.co = qemu_coroutine_create(commit_run); + + trace_commit_start(bs, base, top, s, s->common.co, opaque); + qemu_coroutine_enter(s->common.co, s); +} -- cgit v1.2.3-55-g7522 From 2f0c9fe64c6a2887047b7eab05cd85b2643234c8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 28 Sep 2012 17:22:47 +0200 Subject: block: move job APIs to separate files Signed-off-by: Paolo Bonzini Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- Makefile.objs | 5 +- block.c | 128 +------------------------------------ block.h | 2 + block/Makefile.objs | 5 +- block/commit.c | 1 + block/stream.c | 1 + block_int.h | 151 -------------------------------------------- blockdev.c | 1 + blockjob.c | 163 +++++++++++++++++++++++++++++++++++++++++++++++ blockjob.h | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 354 insertions(+), 282 deletions(-) create mode 100644 blockjob.c create mode 100644 blockjob.h (limited to 'block/commit.c') diff --git a/Makefile.objs b/Makefile.objs index 7c1c68206b..b1f3e22547 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -42,7 +42,8 @@ coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.o # block-obj-y is code used by both qemu system emulation and qemu-img block-obj-y = cutils.o iov.o cache-utils.o qemu-option.o module.o async.o -block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o qemu-progress.o qemu-sockets.o uri.o +block-obj-y += nbd.o block.o blockjob.o aio.o aes.o qemu-config.o +block-obj-y += qemu-progress.o qemu-sockets.o uri.o block-obj-y += $(coroutine-obj-y) $(qobject-obj-y) $(version-obj-y) block-obj-$(CONFIG_POSIX) += posix-aio-compat.o block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o @@ -59,7 +60,7 @@ endif # suppress *all* target specific code in case of system emulation, i.e. a # single QEMU executable should support all CPUs and machines. -common-obj-y = $(block-obj-y) blockdev.o +common-obj-y = $(block-obj-y) blockdev.o block/ common-obj-y += net.o net/ common-obj-y += qom/ common-obj-y += readline.o console.o cursor.o diff --git a/block.c b/block.c index d7a6d14a98..8202f27167 100644 --- a/block.c +++ b/block.c @@ -26,6 +26,7 @@ #include "trace.h" #include "monitor.h" #include "block_int.h" +#include "blockjob.h" #include "module.h" #include "qjson.h" #include "qemu-coroutine.h" @@ -4406,130 +4407,3 @@ out: return ret; } - -void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs, - int64_t speed, BlockDriverCompletionFunc *cb, - void *opaque, Error **errp) -{ - BlockJob *job; - - if (bs->job || bdrv_in_use(bs)) { - error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs)); - return NULL; - } - bdrv_set_in_use(bs, 1); - - job = g_malloc0(job_type->instance_size); - job->job_type = job_type; - job->bs = bs; - job->cb = cb; - job->opaque = opaque; - job->busy = true; - bs->job = job; - - /* Only set speed when necessary to avoid NotSupported error */ - if (speed != 0) { - Error *local_err = NULL; - - block_job_set_speed(job, speed, &local_err); - if (error_is_set(&local_err)) { - bs->job = NULL; - g_free(job); - bdrv_set_in_use(bs, 0); - error_propagate(errp, local_err); - return NULL; - } - } - return job; -} - -void block_job_complete(BlockJob *job, int ret) -{ - BlockDriverState *bs = job->bs; - - assert(bs->job == job); - job->cb(job->opaque, ret); - bs->job = NULL; - 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->job_type->set_speed) { - error_set(errp, QERR_NOT_SUPPORTED); - return; - } - job->job_type->set_speed(job, speed, &local_err); - if (error_is_set(&local_err)) { - error_propagate(errp, local_err); - return; - } - - job->speed = speed; -} - -void block_job_cancel(BlockJob *job) -{ - job->cancelled = true; - if (job->co && !job->busy) { - qemu_coroutine_enter(job->co, NULL); - } -} - -bool block_job_is_cancelled(BlockJob *job) -{ - return job->cancelled; -} - -struct BlockCancelData { - BlockJob *job; - BlockDriverCompletionFunc *cb; - void *opaque; - bool cancelled; - int ret; -}; - -static void block_job_cancel_cb(void *opaque, int ret) -{ - struct BlockCancelData *data = opaque; - - data->cancelled = block_job_is_cancelled(data->job); - data->ret = ret; - data->cb(data->opaque, ret); -} - -int block_job_cancel_sync(BlockJob *job) -{ - struct BlockCancelData data; - BlockDriverState *bs = job->bs; - - assert(bs->job == job); - - /* Set up our own callback to store the result and chain to - * the original callback. - */ - data.job = job; - data.cb = job->cb; - data.opaque = job->opaque; - data.ret = -EINPROGRESS; - job->cb = block_job_cancel_cb; - job->opaque = &data; - block_job_cancel(job); - while (data.ret == -EINPROGRESS) { - qemu_aio_wait(); - } - return (data.cancelled && data.ret == 0) ? -ECANCELED : data.ret; -} - -void block_job_sleep_ns(BlockJob *job, QEMUClock *clock, int64_t ns) -{ - /* Check cancellation *before* setting busy = false, too! */ - if (!block_job_is_cancelled(job)) { - job->busy = false; - co_sleep_ns(clock, ns); - job->busy = true; - } -} diff --git a/block.h b/block.h index e9249c44e6..bd002d573e 100644 --- a/block.h +++ b/block.h @@ -6,9 +6,11 @@ #include "qemu-option.h" #include "qemu-coroutine.h" #include "qobject.h" +#include "qapi-types.h" /* block.c */ typedef struct BlockDriver BlockDriver; +typedef struct BlockJob BlockJob; typedef struct BlockDriverInfo { /* in bytes, 0 if irrelevant */ diff --git a/block/Makefile.objs b/block/Makefile.objs index 81fd43cefb..554f429d05 100644 --- a/block/Makefile.objs +++ b/block/Makefile.objs @@ -3,11 +3,12 @@ block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-c block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o block-obj-y += qed-check.o block-obj-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o -block-obj-y += stream.o -block-obj-y += commit.o block-obj-$(CONFIG_WIN32) += raw-win32.o block-obj-$(CONFIG_POSIX) += raw-posix.o block-obj-$(CONFIG_LIBISCSI) += iscsi.o block-obj-$(CONFIG_CURL) += curl.o block-obj-$(CONFIG_RBD) += rbd.o block-obj-$(CONFIG_GLUSTERFS) += gluster.o + +common-obj-y += stream.o +common-obj-y += commit.o diff --git a/block/commit.c b/block/commit.c index 624ec5f62a..cabb470b5b 100644 --- a/block/commit.c +++ b/block/commit.c @@ -14,6 +14,7 @@ #include "trace.h" #include "block_int.h" +#include "blockjob.h" #include "qemu/ratelimit.h" enum { diff --git a/block/stream.c b/block/stream.c index c4f87dd5b6..57e4be7c64 100644 --- a/block/stream.c +++ b/block/stream.c @@ -13,6 +13,7 @@ #include "trace.h" #include "block_int.h" +#include "blockjob.h" #include "qemu/ratelimit.h" enum { diff --git a/block_int.h b/block_int.h index 6b6b3ab639..61dc73b0e4 100644 --- a/block_int.h +++ b/block_int.h @@ -67,73 +67,6 @@ typedef struct BlockIOBaseValue { uint64_t ios[2]; } BlockIOBaseValue; -typedef struct BlockJob BlockJob; - -/** - * BlockJobType: - * - * A class type for block job objects. - */ -typedef struct BlockJobType { - /** Derived BlockJob struct size */ - size_t instance_size; - - /** String describing the operation, part of query-block-jobs QMP API */ - const char *job_type; - - /** Optional callback for job types that support setting a speed limit */ - void (*set_speed)(BlockJob *job, int64_t speed, Error **errp); -} BlockJobType; - -/** - * BlockJob: - * - * Long-running operation on a BlockDriverState. - */ -struct BlockJob { - /** The job type, including the job vtable. */ - const BlockJobType *job_type; - - /** The block device on which the job is operating. */ - BlockDriverState *bs; - - /** - * The coroutine that executes the job. If not NULL, it is - * reentered when busy is false and the job is cancelled. - */ - Coroutine *co; - - /** - * Set to true if the job should cancel itself. The flag must - * always be tested just before toggling the busy flag from false - * to true. After a job has been cancelled, it should only yield - * if #qemu_aio_wait will ("sooner or later") reenter the coroutine. - */ - bool cancelled; - - /** - * Set to false by the job while it is in a quiescent state, where - * no I/O is pending and the job has yielded on any condition - * that is not detected by #qemu_aio_wait, such as a timer. - */ - bool busy; - - /** Offset that is published by the query-block-jobs QMP API */ - int64_t offset; - - /** Length that is published by the query-block-jobs QMP API */ - int64_t len; - - /** Speed that was set with @block_job_set_speed. */ - int64_t speed; - - /** The completion function that will be called when the job completes. */ - BlockDriverCompletionFunc *cb; - - /** The opaque value that is passed to the completion function. */ - void *opaque; -}; - struct BlockDriver { const char *format_name; int instance_size; @@ -354,90 +287,6 @@ void bdrv_set_io_limits(BlockDriverState *bs, int is_windows_drive(const char *filename); #endif -/** - * block_job_create: - * @job_type: The class object for the newly-created job. - * @bs: The block - * @speed: The maximum speed, in bytes per second, or 0 for unlimited. - * @cb: Completion function for the job. - * @opaque: Opaque pointer value passed to @cb. - * @errp: Error object. - * - * Create a new long-running block device job and return it. The job - * will call @cb asynchronously when the job completes. Note that - * @bs may have been closed at the time the @cb it is called. If - * this is the case, the job may be reported as either cancelled or - * completed. - * - * This function is not part of the public job interface; it should be - * called from a wrapper that is specific to the job type. - */ -void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs, - int64_t speed, BlockDriverCompletionFunc *cb, - void *opaque, Error **errp); - -/** - * block_job_sleep_ns: - * @job: The job that calls the function. - * @clock: The clock to sleep on. - * @ns: How many nanoseconds to stop for. - * - * Put the job to sleep (assuming that it wasn't canceled) for @ns - * nanoseconds. Canceling the job will interrupt the wait immediately. - */ -void block_job_sleep_ns(BlockJob *job, QEMUClock *clock, int64_t ns); - -/** - * block_job_complete: - * @job: The job being completed. - * @ret: The status code. - * - * Call the completion function that was registered at creation time, and - * free @job. - */ -void block_job_complete(BlockJob *job, int ret); - -/** - * block_job_set_speed: - * @job: The job to set the speed for. - * @speed: The new value - * @errp: Error object. - * - * Set a rate-limiting parameter for the job; the actual meaning may - * vary depending on the job type. - */ -void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp); - -/** - * block_job_cancel: - * @job: The job to be canceled. - * - * Asynchronously cancel the specified job. - */ -void block_job_cancel(BlockJob *job); - -/** - * block_job_is_cancelled: - * @job: The job being queried. - * - * Returns whether the job is scheduled for cancellation. - */ -bool block_job_is_cancelled(BlockJob *job); - -/** - * block_job_cancel_sync: - * @job: The job to be canceled. - * - * Synchronously cancel the job. The completion callback is called - * before the function returns. The job may actually complete - * instead of canceling itself; the circumstances under which this - * happens depend on the kind of job that is active. - * - * Returns the return value from the job if the job actually completed - * during the call, or -ECANCELED if it was canceled. - */ -int block_job_cancel_sync(BlockJob *job); - /** * stream_start: * @bs: Block device to operate on. diff --git a/blockdev.c b/blockdev.c index d824612089..d3f91c0aea 100644 --- a/blockdev.c +++ b/blockdev.c @@ -9,6 +9,7 @@ #include "blockdev.h" #include "hw/block-common.h" +#include "blockjob.h" #include "monitor.h" #include "qerror.h" #include "qemu-option.h" diff --git a/blockjob.c b/blockjob.c new file mode 100644 index 0000000000..9737a43b27 --- /dev/null +++ b/blockjob.c @@ -0,0 +1,163 @@ +/* + * QEMU System Emulator block driver + * + * Copyright (c) 2011 IBM Corp. + * Copyright (c) 2012 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "config-host.h" +#include "qemu-common.h" +#include "trace.h" +#include "monitor.h" +#include "block.h" +#include "blockjob.h" +#include "block_int.h" +#include "qjson.h" +#include "qemu-coroutine.h" +#include "qmp-commands.h" +#include "qemu-timer.h" + +void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs, + int64_t speed, BlockDriverCompletionFunc *cb, + void *opaque, Error **errp) +{ + BlockJob *job; + + if (bs->job || bdrv_in_use(bs)) { + error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs)); + return NULL; + } + bdrv_set_in_use(bs, 1); + + job = g_malloc0(job_type->instance_size); + job->job_type = job_type; + job->bs = bs; + job->cb = cb; + job->opaque = opaque; + job->busy = true; + bs->job = job; + + /* Only set speed when necessary to avoid NotSupported error */ + if (speed != 0) { + Error *local_err = NULL; + + block_job_set_speed(job, speed, &local_err); + if (error_is_set(&local_err)) { + bs->job = NULL; + g_free(job); + bdrv_set_in_use(bs, 0); + error_propagate(errp, local_err); + return NULL; + } + } + return job; +} + +void block_job_complete(BlockJob *job, int ret) +{ + BlockDriverState *bs = job->bs; + + assert(bs->job == job); + job->cb(job->opaque, ret); + bs->job = NULL; + 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->job_type->set_speed) { + error_set(errp, QERR_NOT_SUPPORTED); + return; + } + job->job_type->set_speed(job, speed, &local_err); + if (error_is_set(&local_err)) { + error_propagate(errp, local_err); + return; + } + + job->speed = speed; +} + +void block_job_cancel(BlockJob *job) +{ + job->cancelled = true; + if (job->co && !job->busy) { + qemu_coroutine_enter(job->co, NULL); + } +} + +bool block_job_is_cancelled(BlockJob *job) +{ + return job->cancelled; +} + +struct BlockCancelData { + BlockJob *job; + BlockDriverCompletionFunc *cb; + void *opaque; + bool cancelled; + int ret; +}; + +static void block_job_cancel_cb(void *opaque, int ret) +{ + struct BlockCancelData *data = opaque; + + data->cancelled = block_job_is_cancelled(data->job); + data->ret = ret; + data->cb(data->opaque, ret); +} + +int block_job_cancel_sync(BlockJob *job) +{ + struct BlockCancelData data; + BlockDriverState *bs = job->bs; + + assert(bs->job == job); + + /* Set up our own callback to store the result and chain to + * the original callback. + */ + data.job = job; + data.cb = job->cb; + data.opaque = job->opaque; + data.ret = -EINPROGRESS; + job->cb = block_job_cancel_cb; + job->opaque = &data; + block_job_cancel(job); + while (data.ret == -EINPROGRESS) { + qemu_aio_wait(); + } + return (data.cancelled && data.ret == 0) ? -ECANCELED : data.ret; +} + +void block_job_sleep_ns(BlockJob *job, QEMUClock *clock, int64_t ns) +{ + /* Check cancellation *before* setting busy = false, too! */ + if (!block_job_is_cancelled(job)) { + job->busy = false; + co_sleep_ns(clock, ns); + job->busy = true; + } +} diff --git a/blockjob.h b/blockjob.h new file mode 100644 index 0000000000..753f5bcd17 --- /dev/null +++ b/blockjob.h @@ -0,0 +1,179 @@ +/* + * Declarations for long-running block device operations + * + * Copyright (c) 2011 IBM Corp. + * Copyright (c) 2012 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef BLOCKJOB_H +#define BLOCKJOB_H 1 + +#include "block.h" + +/** + * BlockJobType: + * + * A class type for block job objects. + */ +typedef struct BlockJobType { + /** Derived BlockJob struct size */ + size_t instance_size; + + /** String describing the operation, part of query-block-jobs QMP API */ + const char *job_type; + + /** Optional callback for job types that support setting a speed limit */ + void (*set_speed)(BlockJob *job, int64_t speed, Error **errp); +} BlockJobType; + +/** + * BlockJob: + * + * Long-running operation on a BlockDriverState. + */ +struct BlockJob { + /** The job type, including the job vtable. */ + const BlockJobType *job_type; + + /** The block device on which the job is operating. */ + BlockDriverState *bs; + + /** + * The coroutine that executes the job. If not NULL, it is + * reentered when busy is false and the job is cancelled. + */ + Coroutine *co; + + /** + * Set to true if the job should cancel itself. The flag must + * always be tested just before toggling the busy flag from false + * to true. After a job has been cancelled, it should only yield + * if #qemu_aio_wait will ("sooner or later") reenter the coroutine. + */ + bool cancelled; + + /** + * Set to false by the job while it is in a quiescent state, where + * no I/O is pending and the job has yielded on any condition + * that is not detected by #qemu_aio_wait, such as a timer. + */ + bool busy; + + /** Offset that is published by the query-block-jobs QMP API */ + int64_t offset; + + /** Length that is published by the query-block-jobs QMP API */ + int64_t len; + + /** Speed that was set with @block_job_set_speed. */ + int64_t speed; + + /** The completion function that will be called when the job completes. */ + BlockDriverCompletionFunc *cb; + + /** The opaque value that is passed to the completion function. */ + void *opaque; +}; + +/** + * block_job_create: + * @job_type: The class object for the newly-created job. + * @bs: The block + * @speed: The maximum speed, in bytes per second, or 0 for unlimited. + * @cb: Completion function for the job. + * @opaque: Opaque pointer value passed to @cb. + * @errp: Error object. + * + * Create a new long-running block device job and return it. The job + * will call @cb asynchronously when the job completes. Note that + * @bs may have been closed at the time the @cb it is called. If + * this is the case, the job may be reported as either cancelled or + * completed. + * + * This function is not part of the public job interface; it should be + * called from a wrapper that is specific to the job type. + */ +void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs, + int64_t speed, BlockDriverCompletionFunc *cb, + void *opaque, Error **errp); + +/** + * block_job_sleep_ns: + * @job: The job that calls the function. + * @clock: The clock to sleep on. + * @ns: How many nanoseconds to stop for. + * + * Put the job to sleep (assuming that it wasn't canceled) for @ns + * nanoseconds. Canceling the job will interrupt the wait immediately. + */ +void block_job_sleep_ns(BlockJob *job, QEMUClock *clock, int64_t ns); + +/** + * block_job_complete: + * @job: The job being completed. + * @ret: The status code. + * + * Call the completion function that was registered at creation time, and + * free @job. + */ +void block_job_complete(BlockJob *job, int ret); + +/** + * block_job_set_speed: + * @job: The job to set the speed for. + * @speed: The new value + * @errp: Error object. + * + * Set a rate-limiting parameter for the job; the actual meaning may + * vary depending on the job type. + */ +void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp); + +/** + * block_job_cancel: + * @job: The job to be canceled. + * + * Asynchronously cancel the specified job. + */ +void block_job_cancel(BlockJob *job); + +/** + * block_job_is_cancelled: + * @job: The job being queried. + * + * Returns whether the job is scheduled for cancellation. + */ +bool block_job_is_cancelled(BlockJob *job); + +/** + * block_job_cancel_sync: + * @job: The job to be canceled. + * + * Synchronously cancel the job. The completion callback is called + * before the function returns. The job may actually complete + * instead of canceling itself; the circumstances under which this + * happens depend on the kind of job that is active. + * + * Returns the return value from the job if the job actually completed + * during the call, or -ECANCELED if it was canceled. + */ +int block_job_cancel_sync(BlockJob *job); + +#endif -- cgit v1.2.3-55-g7522 From 92aa5c6d77ac29574c1717bcf57827fa1e586f31 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 28 Sep 2012 17:22:55 +0200 Subject: iostatus: move BlockdevOnError declaration to QAPI This will let block-stream reuse the enum. Places that used the enums are renamed accordingly. Signed-off-by: Paolo Bonzini Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block.c | 6 +++--- block.h | 5 ----- block/commit.c | 14 +++++++------- block_int.h | 2 +- blockdev.c | 14 +++++++------- hw/fdc.c | 4 ++-- hw/ide/core.c | 6 +++--- hw/scsi-disk.c | 6 +++--- hw/scsi-generic.c | 4 ++-- hw/virtio-blk.c | 6 +++--- qapi-schema.json | 23 +++++++++++++++++++++++ 11 files changed, 54 insertions(+), 36 deletions(-) (limited to 'block/commit.c') diff --git a/block.c b/block.c index 7b4508295c..1c3ebd7858 100644 --- a/block.c +++ b/block.c @@ -4209,9 +4209,9 @@ void bdrv_iostatus_enable(BlockDriverState *bs) bool bdrv_iostatus_is_enabled(const BlockDriverState *bs) { return (bs->iostatus_enabled && - (bs->on_write_error == BLOCK_ERR_STOP_ENOSPC || - bs->on_write_error == BLOCK_ERR_STOP_ANY || - bs->on_read_error == BLOCK_ERR_STOP_ANY)); + (bs->on_write_error == BLOCKDEV_ON_ERROR_ENOSPC || + bs->on_write_error == BLOCKDEV_ON_ERROR_STOP || + bs->on_read_error == BLOCKDEV_ON_ERROR_STOP)); } void bdrv_iostatus_disable(BlockDriverState *bs) diff --git a/block.h b/block.h index 038621f426..ee81129456 100644 --- a/block.h +++ b/block.h @@ -90,11 +90,6 @@ typedef struct BlockDevOps { #define BDRV_SECTOR_SIZE (1ULL << BDRV_SECTOR_BITS) #define BDRV_SECTOR_MASK ~(BDRV_SECTOR_SIZE - 1) -typedef enum { - BLOCK_ERR_REPORT, BLOCK_ERR_IGNORE, BLOCK_ERR_STOP_ENOSPC, - BLOCK_ERR_STOP_ANY -} BlockdevOnError; - typedef enum { BDRV_ACTION_REPORT, BDRV_ACTION_IGNORE, BDRV_ACTION_STOP } BlockErrorAction; diff --git a/block/commit.c b/block/commit.c index cabb470b5b..733c91403c 100644 --- a/block/commit.c +++ b/block/commit.c @@ -34,7 +34,7 @@ typedef struct CommitBlockJob { BlockDriverState *active; BlockDriverState *top; BlockDriverState *base; - BlockErrorAction on_error; + BlockdevOnError on_error; int base_flags; int orig_overlay_flags; } CommitBlockJob; @@ -126,9 +126,9 @@ wait: bytes_written += n * BDRV_SECTOR_SIZE; } if (ret < 0) { - if (s->on_error == BLOCK_ERR_STOP_ANY || - s->on_error == BLOCK_ERR_REPORT || - (s->on_error == BLOCK_ERR_STOP_ENOSPC && ret == -ENOSPC)) { + if (s->on_error == BLOCKDEV_ON_ERROR_STOP || + s->on_error == BLOCKDEV_ON_ERROR_REPORT|| + (s->on_error == BLOCKDEV_ON_ERROR_ENOSPC && ret == -ENOSPC)) { goto exit_free_buf; } else { n = 0; @@ -182,7 +182,7 @@ static BlockJobType commit_job_type = { void commit_start(BlockDriverState *bs, BlockDriverState *base, BlockDriverState *top, int64_t speed, - BlockErrorAction on_error, BlockDriverCompletionFunc *cb, + BlockdevOnError on_error, BlockDriverCompletionFunc *cb, void *opaque, Error **errp) { CommitBlockJob *s; @@ -192,8 +192,8 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base, BlockDriverState *overlay_bs; Error *local_err = NULL; - if ((on_error == BLOCK_ERR_STOP_ANY || - on_error == BLOCK_ERR_STOP_ENOSPC) && + if ((on_error == BLOCKDEV_ON_ERROR_STOP || + on_error == BLOCKDEV_ON_ERROR_ENOSPC) && !bdrv_iostatus_is_enabled(bs)) { error_set(errp, QERR_INVALID_PARAMETER_COMBINATION); return; diff --git a/block_int.h b/block_int.h index b98c770b96..615aafca8e 100644 --- a/block_int.h +++ b/block_int.h @@ -323,7 +323,7 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base, */ void commit_start(BlockDriverState *bs, BlockDriverState *base, BlockDriverState *top, int64_t speed, - BlockErrorAction on_error, BlockDriverCompletionFunc *cb, + BlockdevOnError on_error, BlockDriverCompletionFunc *cb, void *opaque, Error **errp); #endif /* BLOCK_INT_H */ diff --git a/blockdev.c b/blockdev.c index f097e5743a..63307154b0 100644 --- a/blockdev.c +++ b/blockdev.c @@ -241,13 +241,13 @@ static void drive_put_ref_bh_schedule(DriveInfo *dinfo) static int parse_block_error_action(const char *buf, int is_read) { if (!strcmp(buf, "ignore")) { - return BLOCK_ERR_IGNORE; + return BLOCKDEV_ON_ERROR_IGNORE; } else if (!is_read && !strcmp(buf, "enospc")) { - return BLOCK_ERR_STOP_ENOSPC; + return BLOCKDEV_ON_ERROR_ENOSPC; } else if (!strcmp(buf, "stop")) { - return BLOCK_ERR_STOP_ANY; + return BLOCKDEV_ON_ERROR_STOP; } else if (!strcmp(buf, "report")) { - return BLOCK_ERR_REPORT; + return BLOCKDEV_ON_ERROR_REPORT; } else { error_report("'%s' invalid %s error action", buf, is_read ? "read" : "write"); @@ -433,7 +433,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi) return NULL; } - on_write_error = BLOCK_ERR_STOP_ENOSPC; + on_write_error = BLOCKDEV_ON_ERROR_ENOSPC; if ((buf = qemu_opt_get(opts, "werror")) != NULL) { if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) { error_report("werror is not supported by this bus type"); @@ -446,7 +446,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi) } } - on_read_error = BLOCK_ERR_REPORT; + on_read_error = BLOCKDEV_ON_ERROR_REPORT; if ((buf = qemu_opt_get(opts, "rerror")) != NULL) { if (type != IF_IDE && type != IF_VIRTIO && type != IF_SCSI && type != IF_NONE) { error_report("rerror is not supported by this bus type"); @@ -1143,7 +1143,7 @@ void qmp_block_commit(const char *device, /* This will be part of the QMP command, if/when the * BlockdevOnError change for blkmirror makes it in */ - BlockErrorAction on_error = BLOCK_ERR_REPORT; + BlockdevOnError on_error = BLOCKDEV_ON_ERROR_REPORT; /* drain all i/o before commits */ bdrv_drain_all(); diff --git a/hw/fdc.c b/hw/fdc.c index 08830c1ba2..43b0f20503 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -1994,11 +1994,11 @@ static int fdctrl_connect_drives(FDCtrl *fdctrl) drive->fdctrl = fdctrl; if (drive->bs) { - if (bdrv_get_on_error(drive->bs, 0) != BLOCK_ERR_STOP_ENOSPC) { + if (bdrv_get_on_error(drive->bs, 0) != BLOCKDEV_ON_ERROR_ENOSPC) { error_report("fdc doesn't support drive option werror"); return -1; } - if (bdrv_get_on_error(drive->bs, 1) != BLOCK_ERR_REPORT) { + if (bdrv_get_on_error(drive->bs, 1) != BLOCKDEV_ON_ERROR_REPORT) { error_report("fdc doesn't support drive option rerror"); return -1; } diff --git a/hw/ide/core.c b/hw/ide/core.c index 57b9fa458d..2620e87ae4 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -559,13 +559,13 @@ static int ide_handle_rw_error(IDEState *s, int error, int op) int is_read = (op & BM_STATUS_RETRY_READ); BlockdevOnError action = bdrv_get_on_error(s->bs, is_read); - if (action == BLOCK_ERR_IGNORE) { + if (action == BLOCKDEV_ON_ERROR_IGNORE) { bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_IGNORE, is_read); return 0; } - if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC) - || action == BLOCK_ERR_STOP_ANY) { + if ((error == ENOSPC && action == BLOCKDEV_ON_ERROR_ENOSPC) + || action == BLOCKDEV_ON_ERROR_STOP) { s->bus->dma->ops->set_unit(s->bus->dma, s->unit); s->bus->error_status = op; bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_STOP, is_read); diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index fef83a3606..c295326e99 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -390,13 +390,13 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error) SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); BlockdevOnError action = bdrv_get_on_error(s->qdev.conf.bs, is_read); - if (action == BLOCK_ERR_IGNORE) { + if (action == BLOCKDEV_ON_ERROR_IGNORE) { bdrv_emit_qmp_error_event(s->qdev.conf.bs, BDRV_ACTION_IGNORE, is_read); return 0; } - if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC) - || action == BLOCK_ERR_STOP_ANY) { + if ((error == ENOSPC && action == BLOCKDEV_ON_ERROR_ENOSPC) + || action == BLOCKDEV_ON_ERROR_STOP) { bdrv_emit_qmp_error_event(s->qdev.conf.bs, BDRV_ACTION_STOP, is_read); vm_stop(RUN_STATE_IO_ERROR); diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index a5eb663ecf..d9045341ba 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -400,11 +400,11 @@ static int scsi_generic_initfn(SCSIDevice *s) return -1; } - if (bdrv_get_on_error(s->conf.bs, 0) != BLOCK_ERR_STOP_ENOSPC) { + if (bdrv_get_on_error(s->conf.bs, 0) != BLOCKDEV_ON_ERROR_ENOSPC) { error_report("Device doesn't support drive option werror"); return -1; } - if (bdrv_get_on_error(s->conf.bs, 1) != BLOCK_ERR_REPORT) { + if (bdrv_get_on_error(s->conf.bs, 1) != BLOCKDEV_ON_ERROR_REPORT) { error_report("Device doesn't support drive option rerror"); return -1; } diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 01e537dc9b..f178fa86c7 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -69,13 +69,13 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error, BlockdevOnError action = bdrv_get_on_error(req->dev->bs, is_read); VirtIOBlock *s = req->dev; - if (action == BLOCK_ERR_IGNORE) { + if (action == BLOCKDEV_ON_ERROR_IGNORE) { bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_IGNORE, is_read); return 0; } - if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC) - || action == BLOCK_ERR_STOP_ANY) { + if ((error == ENOSPC && action == BLOCKDEV_ON_ERROR_ENOSPC) + || action == BLOCKDEV_ON_ERROR_STOP) { req->next = s->rq; s->rq = req; bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_STOP, is_read); diff --git a/qapi-schema.json b/qapi-schema.json index 0f2b1a0a1d..a7264135a1 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1087,6 +1087,29 @@ ## { 'command': 'query-pci', 'returns': ['PciInfo'] } +## +# @BlockdevOnError: +# +# An enumeration of possible behaviors for errors on I/O operations. +# The exact meaning depends on whether the I/O was initiated by a guest +# or by a block job +# +# @report: for guest operations, report the error to the guest; +# for jobs, cancel the job +# +# @ignore: ignore the error, only report a QMP event (BLOCK_IO_ERROR +# or BLOCK_JOB_ERROR) +# +# @enospc: same as @stop on ENOSPC, same as @report otherwise. +# +# @stop: for guest operations, stop the virtual machine; +# for jobs, pause the job +# +# Since: 1.3 +## +{ 'enum': 'BlockdevOnError', + 'data': ['report', 'ignore', 'enospc', 'stop'] } + ## # @BlockJobInfo: # -- cgit v1.2.3-55-g7522 From d5208c45be38ab858db6ec5a5097aa1c1a8ebbc9 Mon Sep 17 00:00:00 2001 From: Jeff Cody Date: Tue, 16 Oct 2012 15:49:10 -0400 Subject: block: in commit, determine base image from the top image This simplifies some code and error checking, and also fixes a bug. bdrv_find_backing_image() should only be passed absolute filenames, or filenames relative to the chain. In the QMP message handler for block commit, when looking up the base do so from the determined top image, so we know it is reachable from top. Some of the error messages put out by block-commit have changed slightly, which causes 2 tests cases for block-commit to fail. This patch updates the test cases to look for the correct error output. Signed-off-by: Jeff Cody Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/commit.c | 9 --------- blockdev.c | 21 +++++++++++---------- tests/qemu-iotests/040 | 4 ++-- 3 files changed, 13 insertions(+), 21 deletions(-) (limited to 'block/commit.c') diff --git a/block/commit.c b/block/commit.c index 733c91403c..13d9e82471 100644 --- a/block/commit.c +++ b/block/commit.c @@ -211,15 +211,6 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base, return; } - /* top and base may be valid, but let's make sure that base is reachable - * from top */ - if (bdrv_find_backing_image(top, base->filename) != base) { - error_setg(errp, - "Base (%s) is not reachable from top (%s)", - base->filename, top->filename); - return; - } - overlay_bs = bdrv_find_overlay(bs, top); if (overlay_bs == NULL) { diff --git a/blockdev.c b/blockdev.c index 99828ad2bd..46e4bbd8d9 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1157,16 +1157,6 @@ void qmp_block_commit(const char *device, error_set(errp, QERR_DEVICE_NOT_FOUND, device); return; } - if (base && has_base) { - base_bs = bdrv_find_backing_image(bs, base); - } else { - base_bs = bdrv_find_base(bs); - } - - if (base_bs == NULL) { - error_set(errp, QERR_BASE_NOT_FOUND, base ? base : "NULL"); - return; - } /* default top_bs is the active layer */ top_bs = bs; @@ -1182,6 +1172,17 @@ void qmp_block_commit(const char *device, return; } + if (has_base && base) { + base_bs = bdrv_find_backing_image(top_bs, base); + } else { + base_bs = bdrv_find_base(top_bs); + } + + if (base_bs == NULL) { + error_set(errp, QERR_BASE_NOT_FOUND, base ? base : "NULL"); + return; + } + commit_start(bs, base_bs, top_bs, speed, on_error, block_job_cb, bs, &local_err); if (local_err != NULL) { diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040 index 258e7eae38..0fa6441a53 100755 --- a/tests/qemu-iotests/040 +++ b/tests/qemu-iotests/040 @@ -111,7 +111,7 @@ class TestSingleDrive(ImageCommitTestCase): self.assert_no_active_commit() result = self.vm.qmp('block-commit', device='drive0', top='%s' % backing_img, base='%s' % backing_img) self.assert_qmp(result, 'error/class', 'GenericError') - self.assert_qmp(result, 'error/desc', 'Invalid files for merge: top and base are the same') + self.assert_qmp(result, 'error/desc', 'Base \'%s\' not found' % backing_img) def test_top_invalid(self): self.assert_no_active_commit() @@ -135,7 +135,7 @@ class TestSingleDrive(ImageCommitTestCase): self.assert_no_active_commit() result = self.vm.qmp('block-commit', device='drive0', top='%s' % backing_img, base='%s' % mid_img) self.assert_qmp(result, 'error/class', 'GenericError') - self.assert_qmp(result, 'error/desc', 'Base (%(1)s) is not reachable from top (%(2)s)' % {"1" : mid_img, "2" : backing_img}) + self.assert_qmp(result, 'error/desc', 'Base \'%s\' not found' % mid_img) def test_top_omitted(self): self.assert_no_active_commit() -- cgit v1.2.3-55-g7522 From 65f4632243f526958aa1f6b3911add98329c3796 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 18 Oct 2012 16:49:20 +0200 Subject: block: rename block_job_complete to block_job_completed The imperative will be used for the QMP command. Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block/commit.c | 2 +- block/stream.c | 4 ++-- blockjob.c | 2 +- blockjob.h | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'block/commit.c') diff --git a/block/commit.c b/block/commit.c index 13d9e82471..fae79582d4 100644 --- a/block/commit.c +++ b/block/commit.c @@ -160,7 +160,7 @@ exit_restore_reopen: bdrv_reopen(overlay_bs, s->orig_overlay_flags, NULL); } - block_job_complete(&s->common, ret); + block_job_completed(&s->common, ret); } static void commit_set_speed(BlockJob *job, int64_t speed, Error **errp) diff --git a/block/stream.c b/block/stream.c index 792665276e..0c0fc7a13b 100644 --- a/block/stream.c +++ b/block/stream.c @@ -86,7 +86,7 @@ static void coroutine_fn stream_run(void *opaque) s->common.len = bdrv_getlength(bs); if (s->common.len < 0) { - block_job_complete(&s->common, s->common.len); + block_job_completed(&s->common, s->common.len); return; } @@ -184,7 +184,7 @@ wait: } qemu_vfree(buf); - block_job_complete(&s->common, ret); + block_job_completed(&s->common, ret); } static void stream_set_speed(BlockJob *job, int64_t speed, Error **errp) diff --git a/blockjob.c b/blockjob.c index f55f55a193..b5c16f3766 100644 --- a/blockjob.c +++ b/blockjob.c @@ -71,7 +71,7 @@ void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs, return job; } -void block_job_complete(BlockJob *job, int ret) +void block_job_completed(BlockJob *job, int ret) { BlockDriverState *bs = job->bs; diff --git a/blockjob.h b/blockjob.h index 930cc3c46a..c2261a91f4 100644 --- a/blockjob.h +++ b/blockjob.h @@ -135,14 +135,14 @@ void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs, void block_job_sleep_ns(BlockJob *job, QEMUClock *clock, int64_t ns); /** - * block_job_complete: + * block_job_completed: * @job: The job being completed. * @ret: The status code. * * Call the completion function that was registered at creation time, and * free @job. */ -void block_job_complete(BlockJob *job, int ret); +void block_job_completed(BlockJob *job, int ret); /** * block_job_set_speed: -- cgit v1.2.3-55-g7522 From c57b6656c3168bccca7f78b3f740e9149893b3da Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 13 Nov 2012 16:35:13 +0100 Subject: aio: Get rid of qemu_aio_flush() There are no remaining users, and new users should probably be using bdrv_drain_all() in the first place. Signed-off-by: Kevin Wolf --- async.c | 5 ----- block/commit.c | 2 +- block/mirror.c | 2 +- block/stream.c | 2 +- main-loop.c | 5 ----- qemu-aio.h | 9 ++------- 6 files changed, 5 insertions(+), 20 deletions(-) (limited to 'block/commit.c') diff --git a/async.c b/async.c index 3f0e8f367c..41ae0c1195 100644 --- a/async.c +++ b/async.c @@ -215,8 +215,3 @@ void aio_context_unref(AioContext *ctx) { g_source_unref(&ctx->source); } - -void aio_flush(AioContext *ctx) -{ - while (aio_poll(ctx, true)); -} diff --git a/block/commit.c b/block/commit.c index fae79582d4..e2bb1e241b 100644 --- a/block/commit.c +++ b/block/commit.c @@ -103,7 +103,7 @@ static void coroutine_fn commit_run(void *opaque) wait: /* Note that even when no rate limit is applied we need to yield - * with no pending I/O here so that qemu_aio_flush() returns. + * with no pending I/O here so that bdrv_drain_all() returns. */ block_job_sleep_ns(&s->common, rt_clock, delay_ns); if (block_job_is_cancelled(&s->common)) { diff --git a/block/mirror.c b/block/mirror.c index d6618a4b34..b1f5d4fa22 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -205,7 +205,7 @@ static void coroutine_fn mirror_run(void *opaque) } /* Note that even when no rate limit is applied we need to yield - * with no pending I/O here so that qemu_aio_flush() returns. + * with no pending I/O here so that bdrv_drain_all() returns. */ block_job_sleep_ns(&s->common, rt_clock, delay_ns); if (block_job_is_cancelled(&s->common)) { diff --git a/block/stream.c b/block/stream.c index 0c0fc7a13b..0dcd286035 100644 --- a/block/stream.c +++ b/block/stream.c @@ -108,7 +108,7 @@ static void coroutine_fn stream_run(void *opaque) wait: /* Note that even when no rate limit is applied we need to yield - * with no pending I/O here so that qemu_aio_flush() returns. + * with no pending I/O here so that bdrv_drain_all() returns. */ block_job_sleep_ns(&s->common, rt_clock, delay_ns); if (block_job_is_cancelled(&s->common)) { diff --git a/main-loop.c b/main-loop.c index c87624e621..7dba6f6e35 100644 --- a/main-loop.c +++ b/main-loop.c @@ -432,11 +432,6 @@ QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque) return aio_bh_new(qemu_aio_context, cb, opaque); } -void qemu_aio_flush(void) -{ - aio_flush(qemu_aio_context); -} - bool qemu_aio_wait(void) { return aio_poll(qemu_aio_context, true); diff --git a/qemu-aio.h b/qemu-aio.h index 3889fe97a4..31884a8f16 100644 --- a/qemu-aio.h +++ b/qemu-aio.h @@ -162,10 +162,6 @@ void qemu_bh_cancel(QEMUBH *bh); */ void qemu_bh_delete(QEMUBH *bh); -/* Flush any pending AIO operation. This function will block until all - * outstanding AIO operations have been completed or cancelled. */ -void aio_flush(AioContext *ctx); - /* Return whether there are any pending callbacks from the GSource * attached to the AioContext. * @@ -196,7 +192,7 @@ typedef int (AioFlushHandler)(void *opaque); /* Register a file descriptor and associated callbacks. Behaves very similarly * to qemu_set_fd_handler2. Unlike qemu_set_fd_handler2, these callbacks will - * be invoked when using either qemu_aio_wait() or qemu_aio_flush(). + * be invoked when using qemu_aio_wait(). * * Code that invokes AIO completion functions should rely on this function * instead of qemu_set_fd_handler[2]. @@ -211,7 +207,7 @@ void aio_set_fd_handler(AioContext *ctx, /* Register an event notifier and associated callbacks. Behaves very similarly * to event_notifier_set_handler. Unlike event_notifier_set_handler, these callbacks - * will be invoked when using either qemu_aio_wait() or qemu_aio_flush(). + * will be invoked when using qemu_aio_wait(). * * Code that invokes AIO completion functions should rely on this function * instead of event_notifier_set_handler. @@ -228,7 +224,6 @@ GSource *aio_get_g_source(AioContext *ctx); /* Functions to operate on the main QEMU AioContext. */ -void qemu_aio_flush(void); bool qemu_aio_wait(void); void qemu_aio_set_event_notifier(EventNotifier *notifier, EventNotifierHandler *io_read, -- cgit v1.2.3-55-g7522 From 737e150e89c44c6b33691a627e24bac7fb58f349 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 17 Dec 2012 18:19:44 +0100 Subject: block: move include files to include/block/ Signed-off-by: Paolo Bonzini --- aes.c | 2 +- aes.h | 26 --- aio-posix.c | 2 +- aio-win32.c | 2 +- async.c | 2 +- block-migration.c | 2 +- block.c | 6 +- block.h | 439 ------------------------------------------ block/blkdebug.c | 2 +- block/blkverify.c | 2 +- block/bochs.c | 2 +- block/cloop.c | 2 +- block/commit.c | 4 +- block/cow.c | 2 +- block/curl.c | 2 +- block/dmg.c | 2 +- block/gluster.c | 2 +- block/iscsi.c | 2 +- block/linux-aio.c | 2 +- block/mirror.c | 4 +- block/nbd.c | 4 +- block/parallels.c | 2 +- block/qcow.c | 4 +- block/qcow2-cache.c | 2 +- block/qcow2-cluster.c | 2 +- block/qcow2-refcount.c | 2 +- block/qcow2-snapshot.c | 2 +- block/qcow2.c | 4 +- block/qcow2.h | 4 +- block/qed.h | 2 +- block/raw-posix.c | 4 +- block/raw-win32.c | 4 +- block/raw.c | 2 +- block/rbd.c | 2 +- block/sheepdog.c | 2 +- block/stream.c | 4 +- block/vdi.c | 2 +- block/vmdk.c | 2 +- block/vpc.c | 2 +- block/vvfat.c | 2 +- block/win32-aio.c | 4 +- block_int.h | 366 ----------------------------------- blockdev-nbd.c | 2 +- blockdev.c | 4 +- blockdev.h | 2 +- blockjob.c | 8 +- blockjob.h | 278 -------------------------- cmd.c | 2 +- coroutine-gthread.c | 2 +- coroutine-sigaltstack.c | 2 +- coroutine-ucontext.c | 2 +- coroutine-win32.c | 2 +- dma.h | 2 +- hw/9pfs/codir.c | 2 +- hw/9pfs/cofile.c | 2 +- hw/9pfs/cofs.c | 2 +- hw/9pfs/coxattr.c | 2 +- hw/9pfs/virtio-9p-coth.c | 2 +- hw/9pfs/virtio-9p-coth.h | 2 +- hw/9pfs/virtio-9p.h | 2 +- hw/hd-geometry.c | 2 +- hw/hw.h | 2 +- hw/ide/cmd646.c | 2 +- hw/ide/ich.c | 2 +- hw/ide/isa.c | 2 +- hw/ide/macio.c | 2 +- hw/ide/microdrive.c | 2 +- hw/ide/mmio.c | 2 +- hw/ide/pci.c | 2 +- hw/ide/via.c | 2 +- hw/mips_fulong2e.c | 2 +- hw/mips_malta.c | 2 +- hw/musicpal.c | 2 +- hw/pflash_cfi01.c | 2 +- hw/pflash_cfi02.c | 2 +- hw/ppc405_boards.c | 2 +- hw/s390-virtio-bus.c | 2 +- hw/s390-virtio.c | 2 +- hw/scsi.h | 2 +- hw/sd.c | 2 +- hw/spitz.c | 2 +- hw/tosa.c | 2 +- include/block/aes.h | 26 +++ include/block/aio.h | 240 +++++++++++++++++++++++ include/block/block.h | 439 ++++++++++++++++++++++++++++++++++++++++++ include/block/block_int.h | 366 +++++++++++++++++++++++++++++++++++ include/block/blockjob.h | 278 ++++++++++++++++++++++++++ include/block/coroutine.h | 211 ++++++++++++++++++++ include/block/coroutine_int.h | 49 +++++ include/block/nbd.h | 100 ++++++++++ include/block/thread-pool.h | 34 ++++ iohandler.c | 2 +- main-loop.c | 2 +- main-loop.h | 2 +- migration-exec.c | 2 +- migration-fd.c | 2 +- migration-tcp.c | 2 +- migration-unix.c | 2 +- migration.c | 2 +- monitor.h | 2 +- nbd.c | 6 +- nbd.h | 100 ---------- qemu-aio.h | 240 ----------------------- qemu-char.h | 2 +- qemu-coroutine-int.h | 49 ----- qemu-coroutine-io.c | 2 +- qemu-coroutine-lock.c | 6 +- qemu-coroutine-sleep.c | 2 +- qemu-coroutine.c | 4 +- qemu-coroutine.h | 211 -------------------- qemu-img.c | 2 +- qemu-io.c | 2 +- qemu-nbd.c | 4 +- tests/test-aio.c | 2 +- tests/test-coroutine.c | 2 +- tests/test-thread-pool.c | 6 +- thread-pool.c | 6 +- thread-pool.h | 34 ---- 118 files changed, 1869 insertions(+), 1869 deletions(-) delete mode 100644 aes.h delete mode 100644 block.h delete mode 100644 block_int.h delete mode 100644 blockjob.h create mode 100644 include/block/aes.h create mode 100644 include/block/aio.h create mode 100644 include/block/block.h create mode 100644 include/block/block_int.h create mode 100644 include/block/blockjob.h create mode 100644 include/block/coroutine.h create mode 100644 include/block/coroutine_int.h create mode 100644 include/block/nbd.h create mode 100644 include/block/thread-pool.h delete mode 100644 nbd.h delete mode 100644 qemu-aio.h delete mode 100644 qemu-coroutine-int.h delete mode 100644 qemu-coroutine.h delete mode 100644 thread-pool.h (limited to 'block/commit.c') diff --git a/aes.c b/aes.c index eb37adbed8..1da7bff1c9 100644 --- a/aes.c +++ b/aes.c @@ -28,7 +28,7 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "qemu-common.h" -#include "aes.h" +#include "block/aes.h" #ifndef NDEBUG #define NDEBUG diff --git a/aes.h b/aes.h deleted file mode 100644 index a0167eb7d5..0000000000 --- a/aes.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef QEMU_AES_H -#define QEMU_AES_H - -#define AES_MAXNR 14 -#define AES_BLOCK_SIZE 16 - -struct aes_key_st { - uint32_t rd_key[4 *(AES_MAXNR + 1)]; - int rounds; -}; -typedef struct aes_key_st AES_KEY; - -int AES_set_encrypt_key(const unsigned char *userKey, const int bits, - AES_KEY *key); -int AES_set_decrypt_key(const unsigned char *userKey, const int bits, - AES_KEY *key); - -void AES_encrypt(const unsigned char *in, unsigned char *out, - const AES_KEY *key); -void AES_decrypt(const unsigned char *in, unsigned char *out, - const AES_KEY *key); -void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, - const unsigned long length, const AES_KEY *key, - unsigned char *ivec, const int enc); - -#endif diff --git a/aio-posix.c b/aio-posix.c index 05cc84e121..d1e1bc2c75 100644 --- a/aio-posix.c +++ b/aio-posix.c @@ -14,7 +14,7 @@ */ #include "qemu-common.h" -#include "block.h" +#include "block/block.h" #include "qemu-queue.h" #include "qemu_socket.h" diff --git a/aio-win32.c b/aio-win32.c index cec4646635..9a26f9c3d9 100644 --- a/aio-win32.c +++ b/aio-win32.c @@ -16,7 +16,7 @@ */ #include "qemu-common.h" -#include "block.h" +#include "block/block.h" #include "qemu-queue.h" #include "qemu_socket.h" diff --git a/async.c b/async.c index 41ae0c1195..6df4caf68a 100644 --- a/async.c +++ b/async.c @@ -23,7 +23,7 @@ */ #include "qemu-common.h" -#include "qemu-aio.h" +#include "block/aio.h" #include "main-loop.h" /***********************************************************/ diff --git a/block-migration.c b/block-migration.c index 71b9601e00..c15de9f750 100644 --- a/block-migration.c +++ b/block-migration.c @@ -14,7 +14,7 @@ */ #include "qemu-common.h" -#include "block_int.h" +#include "block/block_int.h" #include "hw/hw.h" #include "qemu-queue.h" #include "qemu-timer.h" diff --git a/block.c b/block.c index e962a5afe9..5eab9e2519 100644 --- a/block.c +++ b/block.c @@ -25,13 +25,13 @@ #include "qemu-common.h" #include "trace.h" #include "monitor.h" -#include "block_int.h" -#include "blockjob.h" +#include "block/block_int.h" +#include "block/blockjob.h" #include "module.h" #include "qapi/qmp/qjson.h" #include "sysemu.h" #include "notify.h" -#include "qemu-coroutine.h" +#include "block/coroutine.h" #include "qmp-commands.h" #include "qemu-timer.h" diff --git a/block.h b/block.h deleted file mode 100644 index 0b22892d61..0000000000 --- a/block.h +++ /dev/null @@ -1,439 +0,0 @@ -#ifndef BLOCK_H -#define BLOCK_H - -#include "qemu-aio.h" -#include "qemu-common.h" -#include "qemu-option.h" -#include "qemu-coroutine.h" -#include "qapi/qmp/qobject.h" -#include "qapi-types.h" - -/* block.c */ -typedef struct BlockDriver BlockDriver; -typedef struct BlockJob BlockJob; - -typedef struct BlockDriverInfo { - /* in bytes, 0 if irrelevant */ - int cluster_size; - /* offset at which the VM state can be saved (0 if not possible) */ - int64_t vm_state_offset; - bool is_dirty; -} BlockDriverInfo; - -typedef struct BlockFragInfo { - uint64_t allocated_clusters; - uint64_t total_clusters; - uint64_t fragmented_clusters; -} BlockFragInfo; - -typedef struct QEMUSnapshotInfo { - char id_str[128]; /* unique snapshot id */ - /* the following fields are informative. They are not needed for - the consistency of the snapshot */ - char name[256]; /* user chosen name */ - uint64_t vm_state_size; /* VM state info size */ - uint32_t date_sec; /* UTC date of the snapshot */ - uint32_t date_nsec; - uint64_t vm_clock_nsec; /* VM clock relative to boot */ -} QEMUSnapshotInfo; - -/* Callbacks for block device models */ -typedef struct BlockDevOps { - /* - * Runs when virtual media changed (monitor commands eject, change) - * Argument load is true on load and false on eject. - * Beware: doesn't run when a host device's physical media - * changes. Sure would be useful if it did. - * Device models with removable media must implement this callback. - */ - void (*change_media_cb)(void *opaque, bool load); - /* - * Runs when an eject request is issued from the monitor, the tray - * is closed, and the medium is locked. - * Device models that do not implement is_medium_locked will not need - * this callback. Device models that can lock the medium or tray might - * want to implement the callback and unlock the tray when "force" is - * true, even if they do not support eject requests. - */ - void (*eject_request_cb)(void *opaque, bool force); - /* - * Is the virtual tray open? - * Device models implement this only when the device has a tray. - */ - bool (*is_tray_open)(void *opaque); - /* - * Is the virtual medium locked into the device? - * Device models implement this only when device has such a lock. - */ - bool (*is_medium_locked)(void *opaque); - /* - * Runs when the size changed (e.g. monitor command block_resize) - */ - void (*resize_cb)(void *opaque); -} BlockDevOps; - -#define BDRV_O_RDWR 0x0002 -#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */ -#define BDRV_O_NOCACHE 0x0020 /* do not use the host page cache */ -#define BDRV_O_CACHE_WB 0x0040 /* use write-back caching */ -#define BDRV_O_NATIVE_AIO 0x0080 /* use native AIO instead of the thread pool */ -#define BDRV_O_NO_BACKING 0x0100 /* don't open the backing file */ -#define BDRV_O_NO_FLUSH 0x0200 /* disable flushing on this disk */ -#define BDRV_O_COPY_ON_READ 0x0400 /* copy read backing sectors into image */ -#define BDRV_O_INCOMING 0x0800 /* consistency hint for incoming migration */ -#define BDRV_O_CHECK 0x1000 /* open solely for consistency check */ -#define BDRV_O_ALLOW_RDWR 0x2000 /* allow reopen to change from r/o to r/w */ - -#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH) - -#define BDRV_SECTOR_BITS 9 -#define BDRV_SECTOR_SIZE (1ULL << BDRV_SECTOR_BITS) -#define BDRV_SECTOR_MASK ~(BDRV_SECTOR_SIZE - 1) - -typedef enum { - BDRV_ACTION_REPORT, BDRV_ACTION_IGNORE, BDRV_ACTION_STOP -} BlockErrorAction; - -typedef QSIMPLEQ_HEAD(BlockReopenQueue, BlockReopenQueueEntry) BlockReopenQueue; - -typedef struct BDRVReopenState { - BlockDriverState *bs; - int flags; - void *opaque; -} BDRVReopenState; - - -void bdrv_iostatus_enable(BlockDriverState *bs); -void bdrv_iostatus_reset(BlockDriverState *bs); -void bdrv_iostatus_disable(BlockDriverState *bs); -bool bdrv_iostatus_is_enabled(const BlockDriverState *bs); -void bdrv_iostatus_set_err(BlockDriverState *bs, int error); -void bdrv_info_print(Monitor *mon, const QObject *data); -void bdrv_info(Monitor *mon, QObject **ret_data); -void bdrv_stats_print(Monitor *mon, const QObject *data); -void bdrv_info_stats(Monitor *mon, QObject **ret_data); - -/* disk I/O throttling */ -void bdrv_io_limits_enable(BlockDriverState *bs); -void bdrv_io_limits_disable(BlockDriverState *bs); -bool bdrv_io_limits_enabled(BlockDriverState *bs); - -void bdrv_init(void); -void bdrv_init_with_whitelist(void); -BlockDriver *bdrv_find_protocol(const char *filename); -BlockDriver *bdrv_find_format(const char *format_name); -BlockDriver *bdrv_find_whitelisted_format(const char *format_name); -int bdrv_create(BlockDriver *drv, const char* filename, - QEMUOptionParameter *options); -int bdrv_create_file(const char* filename, QEMUOptionParameter *options); -BlockDriverState *bdrv_new(const char *device_name); -void bdrv_make_anon(BlockDriverState *bs); -void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old); -void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top); -void bdrv_delete(BlockDriverState *bs); -int bdrv_parse_cache_flags(const char *mode, int *flags); -int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags); -int bdrv_open_backing_file(BlockDriverState *bs); -int bdrv_open(BlockDriverState *bs, const char *filename, int flags, - BlockDriver *drv); -BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, - BlockDriverState *bs, int flags); -int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp); -int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp); -int bdrv_reopen_prepare(BDRVReopenState *reopen_state, - BlockReopenQueue *queue, Error **errp); -void bdrv_reopen_commit(BDRVReopenState *reopen_state); -void bdrv_reopen_abort(BDRVReopenState *reopen_state); -void bdrv_close(BlockDriverState *bs); -void bdrv_add_close_notifier(BlockDriverState *bs, Notifier *notify); -int bdrv_attach_dev(BlockDriverState *bs, void *dev); -void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev); -void bdrv_detach_dev(BlockDriverState *bs, void *dev); -void *bdrv_get_attached_dev(BlockDriverState *bs); -void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops, - void *opaque); -void bdrv_dev_eject_request(BlockDriverState *bs, bool force); -bool bdrv_dev_has_removable_media(BlockDriverState *bs); -bool bdrv_dev_is_tray_open(BlockDriverState *bs); -bool bdrv_dev_is_medium_locked(BlockDriverState *bs); -int bdrv_read(BlockDriverState *bs, int64_t sector_num, - uint8_t *buf, int nb_sectors); -int bdrv_read_unthrottled(BlockDriverState *bs, int64_t sector_num, - uint8_t *buf, int nb_sectors); -int bdrv_write(BlockDriverState *bs, int64_t sector_num, - const uint8_t *buf, int nb_sectors); -int bdrv_pread(BlockDriverState *bs, int64_t offset, - void *buf, int count); -int bdrv_pwrite(BlockDriverState *bs, int64_t offset, - const void *buf, int count); -int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset, - const void *buf, int count); -int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num, - int nb_sectors, QEMUIOVector *qiov); -int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs, - int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); -int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num, - int nb_sectors, QEMUIOVector *qiov); -/* - * Efficiently zero a region of the disk image. Note that this is a regular - * I/O request like read or write and should have a reasonable size. This - * function is not suitable for zeroing the entire image in a single request - * because it may allocate memory for the entire region. - */ -int coroutine_fn bdrv_co_write_zeroes(BlockDriverState *bs, int64_t sector_num, - int nb_sectors); -int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t sector_num, - int nb_sectors, int *pnum); -int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top, - BlockDriverState *base, - int64_t sector_num, - int nb_sectors, int *pnum); -BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, - const char *backing_file); -int bdrv_get_backing_file_depth(BlockDriverState *bs); -int bdrv_truncate(BlockDriverState *bs, int64_t offset); -int64_t bdrv_getlength(BlockDriverState *bs); -int64_t bdrv_get_allocated_file_size(BlockDriverState *bs); -void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); -int bdrv_commit(BlockDriverState *bs); -int bdrv_commit_all(void); -int bdrv_change_backing_file(BlockDriverState *bs, - const char *backing_file, const char *backing_fmt); -void bdrv_register(BlockDriver *bdrv); -int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top, - BlockDriverState *base); -BlockDriverState *bdrv_find_overlay(BlockDriverState *active, - BlockDriverState *bs); -BlockDriverState *bdrv_find_base(BlockDriverState *bs); - - -typedef struct BdrvCheckResult { - int corruptions; - int leaks; - int check_errors; - int corruptions_fixed; - int leaks_fixed; - BlockFragInfo bfi; -} BdrvCheckResult; - -typedef enum { - BDRV_FIX_LEAKS = 1, - BDRV_FIX_ERRORS = 2, -} BdrvCheckMode; - -int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix); - -/* async block I/O */ -typedef void BlockDriverDirtyHandler(BlockDriverState *bs, int64_t sector, - int sector_num); -BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num, - QEMUIOVector *iov, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque); -BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num, - QEMUIOVector *iov, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque); -BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs, - BlockDriverCompletionFunc *cb, void *opaque); -BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs, - int64_t sector_num, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque); -void bdrv_aio_cancel(BlockDriverAIOCB *acb); - -typedef struct BlockRequest { - /* Fields to be filled by multiwrite caller */ - int64_t sector; - int nb_sectors; - QEMUIOVector *qiov; - BlockDriverCompletionFunc *cb; - void *opaque; - - /* Filled by multiwrite implementation */ - int error; -} BlockRequest; - -int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, - int num_reqs); - -/* sg packet commands */ -int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf); -BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs, - unsigned long int req, void *buf, - BlockDriverCompletionFunc *cb, void *opaque); - -/* Invalidate any cached metadata used by image formats */ -void bdrv_invalidate_cache(BlockDriverState *bs); -void bdrv_invalidate_cache_all(void); - -void bdrv_clear_incoming_migration_all(void); - -/* Ensure contents are flushed to disk. */ -int bdrv_flush(BlockDriverState *bs); -int coroutine_fn bdrv_co_flush(BlockDriverState *bs); -void bdrv_flush_all(void); -void bdrv_close_all(void); -void bdrv_drain_all(void); - -int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors); -int bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors); -int bdrv_has_zero_init(BlockDriverState *bs); -int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, - int *pnum); - -void bdrv_set_on_error(BlockDriverState *bs, BlockdevOnError on_read_error, - BlockdevOnError on_write_error); -BlockdevOnError bdrv_get_on_error(BlockDriverState *bs, bool is_read); -BlockErrorAction bdrv_get_error_action(BlockDriverState *bs, bool is_read, int error); -void bdrv_error_action(BlockDriverState *bs, BlockErrorAction action, - bool is_read, int error); -int bdrv_is_read_only(BlockDriverState *bs); -int bdrv_is_sg(BlockDriverState *bs); -int bdrv_enable_write_cache(BlockDriverState *bs); -void bdrv_set_enable_write_cache(BlockDriverState *bs, bool wce); -int bdrv_is_inserted(BlockDriverState *bs); -int bdrv_media_changed(BlockDriverState *bs); -void bdrv_lock_medium(BlockDriverState *bs, bool locked); -void bdrv_eject(BlockDriverState *bs, bool eject_flag); -const char *bdrv_get_format_name(BlockDriverState *bs); -BlockDriverState *bdrv_find(const char *name); -BlockDriverState *bdrv_next(BlockDriverState *bs); -void bdrv_iterate(void (*it)(void *opaque, BlockDriverState *bs), - void *opaque); -int bdrv_is_encrypted(BlockDriverState *bs); -int bdrv_key_required(BlockDriverState *bs); -int bdrv_set_key(BlockDriverState *bs, const char *key); -int bdrv_query_missing_keys(void); -void bdrv_iterate_format(void (*it)(void *opaque, const char *name), - void *opaque); -const char *bdrv_get_device_name(BlockDriverState *bs); -int bdrv_get_flags(BlockDriverState *bs); -int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, - const uint8_t *buf, int nb_sectors); -int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); - -const char *bdrv_get_encrypted_filename(BlockDriverState *bs); -void bdrv_get_backing_filename(BlockDriverState *bs, - char *filename, int filename_size); -void bdrv_get_full_backing_filename(BlockDriverState *bs, - char *dest, size_t sz); -BlockInfo *bdrv_query_info(BlockDriverState *s); -BlockStats *bdrv_query_stats(const BlockDriverState *bs); -int bdrv_can_snapshot(BlockDriverState *bs); -int bdrv_is_snapshot(BlockDriverState *bs); -BlockDriverState *bdrv_snapshots(void); -int bdrv_snapshot_create(BlockDriverState *bs, - QEMUSnapshotInfo *sn_info); -int bdrv_snapshot_goto(BlockDriverState *bs, - const char *snapshot_id); -int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id); -int bdrv_snapshot_list(BlockDriverState *bs, - QEMUSnapshotInfo **psn_info); -int bdrv_snapshot_load_tmp(BlockDriverState *bs, - const char *snapshot_name); -char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn); - -char *get_human_readable_size(char *buf, int buf_size, int64_t size); -int path_is_absolute(const char *path); -void path_combine(char *dest, int dest_size, - const char *base_path, - const char *filename); - -int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf, - int64_t pos, int size); - -int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf, - int64_t pos, int size); - -void bdrv_img_create(const char *filename, const char *fmt, - const char *base_filename, const char *base_fmt, - char *options, uint64_t img_size, int flags, Error **errp); - -void bdrv_set_buffer_alignment(BlockDriverState *bs, int align); -void *qemu_blockalign(BlockDriverState *bs, size_t size); - -#define BDRV_SECTORS_PER_DIRTY_CHUNK 2048 - -void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable); -int bdrv_get_dirty(BlockDriverState *bs, int64_t sector); -void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors); -void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors); -int64_t bdrv_get_next_dirty(BlockDriverState *bs, int64_t sector); -int64_t bdrv_get_dirty_count(BlockDriverState *bs); - -void bdrv_enable_copy_on_read(BlockDriverState *bs); -void bdrv_disable_copy_on_read(BlockDriverState *bs); - -void bdrv_set_in_use(BlockDriverState *bs, int in_use); -int bdrv_in_use(BlockDriverState *bs); - -enum BlockAcctType { - BDRV_ACCT_READ, - BDRV_ACCT_WRITE, - BDRV_ACCT_FLUSH, - BDRV_MAX_IOTYPE, -}; - -typedef struct BlockAcctCookie { - int64_t bytes; - int64_t start_time_ns; - enum BlockAcctType type; -} BlockAcctCookie; - -void bdrv_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie, - int64_t bytes, enum BlockAcctType type); -void bdrv_acct_done(BlockDriverState *bs, BlockAcctCookie *cookie); - -typedef enum { - BLKDBG_L1_UPDATE, - - BLKDBG_L1_GROW_ALLOC_TABLE, - BLKDBG_L1_GROW_WRITE_TABLE, - BLKDBG_L1_GROW_ACTIVATE_TABLE, - - BLKDBG_L2_LOAD, - BLKDBG_L2_UPDATE, - BLKDBG_L2_UPDATE_COMPRESSED, - BLKDBG_L2_ALLOC_COW_READ, - BLKDBG_L2_ALLOC_WRITE, - - BLKDBG_READ_AIO, - BLKDBG_READ_BACKING_AIO, - BLKDBG_READ_COMPRESSED, - - BLKDBG_WRITE_AIO, - BLKDBG_WRITE_COMPRESSED, - - BLKDBG_VMSTATE_LOAD, - BLKDBG_VMSTATE_SAVE, - - BLKDBG_COW_READ, - BLKDBG_COW_WRITE, - - BLKDBG_REFTABLE_LOAD, - BLKDBG_REFTABLE_GROW, - - BLKDBG_REFBLOCK_LOAD, - BLKDBG_REFBLOCK_UPDATE, - BLKDBG_REFBLOCK_UPDATE_PART, - BLKDBG_REFBLOCK_ALLOC, - BLKDBG_REFBLOCK_ALLOC_HOOKUP, - BLKDBG_REFBLOCK_ALLOC_WRITE, - BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS, - BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE, - BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE, - - BLKDBG_CLUSTER_ALLOC, - BLKDBG_CLUSTER_ALLOC_BYTES, - BLKDBG_CLUSTER_FREE, - - BLKDBG_EVENT_MAX, -} BlkDebugEvent; - -#define BLKDBG_EVENT(bs, evt) bdrv_debug_event(bs, evt) -void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event); - -int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event, - const char *tag); -int bdrv_debug_resume(BlockDriverState *bs, const char *tag); -bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag); - -#endif diff --git a/block/blkdebug.c b/block/blkdebug.c index 65556e73e5..cd2866e7bd 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -24,7 +24,7 @@ #include "qemu-common.h" #include "qemu-config.h" -#include "block_int.h" +#include "block/block_int.h" #include "module.h" typedef struct BDRVBlkdebugState { diff --git a/block/blkverify.c b/block/blkverify.c index 4beede77ab..cde5098e5a 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -9,7 +9,7 @@ #include #include "qemu_socket.h" /* for EINPROGRESS on Windows */ -#include "block_int.h" +#include "block/block_int.h" typedef struct { BlockDriverState *test_file; diff --git a/block/bochs.c b/block/bochs.c index ab7944dc43..2cc7524782 100644 --- a/block/bochs.c +++ b/block/bochs.c @@ -23,7 +23,7 @@ * THE SOFTWARE. */ #include "qemu-common.h" -#include "block_int.h" +#include "block/block_int.h" #include "module.h" /**************************************************************/ diff --git a/block/cloop.c b/block/cloop.c index 7570eb8e74..da29ff379c 100644 --- a/block/cloop.c +++ b/block/cloop.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ #include "qemu-common.h" -#include "block_int.h" +#include "block/block_int.h" #include "module.h" #include diff --git a/block/commit.c b/block/commit.c index e2bb1e241b..61ebdba54f 100644 --- a/block/commit.c +++ b/block/commit.c @@ -13,8 +13,8 @@ */ #include "trace.h" -#include "block_int.h" -#include "blockjob.h" +#include "block/block_int.h" +#include "block/blockjob.h" #include "qemu/ratelimit.h" enum { diff --git a/block/cow.c b/block/cow.c index a5a00eb9ca..1438ae1e3b 100644 --- a/block/cow.c +++ b/block/cow.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ #include "qemu-common.h" -#include "block_int.h" +#include "block/block_int.h" #include "module.h" /**************************************************************/ diff --git a/block/curl.c b/block/curl.c index 1179484de0..47df9524ea 100644 --- a/block/curl.c +++ b/block/curl.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ #include "qemu-common.h" -#include "block_int.h" +#include "block/block_int.h" #include // #define DEBUG diff --git a/block/dmg.c b/block/dmg.c index 37902a4347..6ee505a9f5 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ #include "qemu-common.h" -#include "block_int.h" +#include "block/block_int.h" #include "bswap.h" #include "module.h" #include diff --git a/block/gluster.c b/block/gluster.c index 1c90174b13..4cb4e60227 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -16,7 +16,7 @@ * GNU GPL, version 2 or (at your option) any later version. */ #include -#include "block_int.h" +#include "block/block_int.h" #include "qemu_socket.h" #include "uri.h" diff --git a/block/iscsi.c b/block/iscsi.c index 33b93d8000..77e619a1fd 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -29,7 +29,7 @@ #include "qemu-common.h" #include "qemu-config.h" #include "qemu-error.h" -#include "block_int.h" +#include "block/block_int.h" #include "trace.h" #include "hw/scsi-defs.h" diff --git a/block/linux-aio.c b/block/linux-aio.c index 91ef863241..28e5a04e12 100644 --- a/block/linux-aio.c +++ b/block/linux-aio.c @@ -8,7 +8,7 @@ * See the COPYING file in the top-level directory. */ #include "qemu-common.h" -#include "qemu-aio.h" +#include "block/aio.h" #include "qemu-queue.h" #include "block/raw-aio.h" #include "event_notifier.h" diff --git a/block/mirror.c b/block/mirror.c index b1f5d4fa22..8aeacbf12c 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -12,8 +12,8 @@ */ #include "trace.h" -#include "blockjob.h" -#include "block_int.h" +#include "block/blockjob.h" +#include "block/block_int.h" #include "qemu/ratelimit.h" enum { diff --git a/block/nbd.c b/block/nbd.c index e87c248175..38d6b90ab2 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -27,9 +27,9 @@ */ #include "qemu-common.h" -#include "nbd.h" +#include "block/nbd.h" #include "uri.h" -#include "block_int.h" +#include "block/block_int.h" #include "module.h" #include "qemu_socket.h" diff --git a/block/parallels.c b/block/parallels.c index d30f0ecf77..ae88cd6359 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ #include "qemu-common.h" -#include "block_int.h" +#include "block/block_int.h" #include "module.h" /**************************************************************/ diff --git a/block/qcow.c b/block/qcow.c index b239c82ae0..d13bd400f0 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -22,10 +22,10 @@ * THE SOFTWARE. */ #include "qemu-common.h" -#include "block_int.h" +#include "block/block_int.h" #include "module.h" #include -#include "aes.h" +#include "block/aes.h" #include "migration.h" /**************************************************************/ diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c index 2d4322a8dd..2f3114ecc2 100644 --- a/block/qcow2-cache.c +++ b/block/qcow2-cache.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -#include "block_int.h" +#include "block/block_int.h" #include "qemu-common.h" #include "qcow2.h" #include "trace.h" diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 468ef1be56..56fccf9487 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -25,7 +25,7 @@ #include #include "qemu-common.h" -#include "block_int.h" +#include "block/block_int.h" #include "block/qcow2.h" #include "trace.h" diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 96224d1af2..6a95aa6c92 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -23,7 +23,7 @@ */ #include "qemu-common.h" -#include "block_int.h" +#include "block/block_int.h" #include "block/qcow2.h" static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size); diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index 4e7c93b8b3..eb8fcd5549 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -23,7 +23,7 @@ */ #include "qemu-common.h" -#include "block_int.h" +#include "block/block_int.h" #include "block/qcow2.h" typedef struct QEMU_PACKED QCowSnapshotHeader { diff --git a/block/qcow2.c b/block/qcow2.c index 217b4e422f..205d910a52 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -22,10 +22,10 @@ * THE SOFTWARE. */ #include "qemu-common.h" -#include "block_int.h" +#include "block/block_int.h" #include "module.h" #include -#include "aes.h" +#include "block/aes.h" #include "block/qcow2.h" #include "qemu-error.h" #include "qapi/qmp/qerror.h" diff --git a/block/qcow2.h b/block/qcow2.h index a60fcb429a..718b52baca 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -25,8 +25,8 @@ #ifndef BLOCK_QCOW2_H #define BLOCK_QCOW2_H -#include "aes.h" -#include "qemu-coroutine.h" +#include "block/aes.h" +#include "block/coroutine.h" //#define DEBUG_ALLOC //#define DEBUG_ALLOC2 diff --git a/block/qed.h b/block/qed.h index a063bf70af..2b4ddedf31 100644 --- a/block/qed.h +++ b/block/qed.h @@ -15,7 +15,7 @@ #ifndef BLOCK_QED_H #define BLOCK_QED_H -#include "block_int.h" +#include "block/block_int.h" /* The layout of a QED file is as follows: * diff --git a/block/raw-posix.c b/block/raw-posix.c index 48eff2fd83..4e73885269 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -24,10 +24,10 @@ #include "qemu-common.h" #include "qemu-timer.h" #include "qemu-log.h" -#include "block_int.h" +#include "block/block_int.h" #include "module.h" #include "trace.h" -#include "thread-pool.h" +#include "block/thread-pool.h" #include "iov.h" #include "raw-aio.h" diff --git a/block/raw-win32.c b/block/raw-win32.c index ce207a3109..9269fe84c0 100644 --- a/block/raw-win32.c +++ b/block/raw-win32.c @@ -23,11 +23,11 @@ */ #include "qemu-common.h" #include "qemu-timer.h" -#include "block_int.h" +#include "block/block_int.h" #include "module.h" #include "raw-aio.h" #include "trace.h" -#include "thread-pool.h" +#include "block/thread-pool.h" #include "iov.h" #include #include diff --git a/block/raw.c b/block/raw.c index 253e949b8c..6aec93dadb 100644 --- a/block/raw.c +++ b/block/raw.c @@ -1,6 +1,6 @@ #include "qemu-common.h" -#include "block_int.h" +#include "block/block_int.h" #include "module.h" static int raw_open(BlockDriverState *bs, int flags) diff --git a/block/rbd.c b/block/rbd.c index 737bab16cc..8def2f174c 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -15,7 +15,7 @@ #include "qemu-common.h" #include "qemu-error.h" -#include "block_int.h" +#include "block/block_int.h" #include diff --git a/block/sheepdog.c b/block/sheepdog.c index a48f58cfe8..da70df2d00 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -15,7 +15,7 @@ #include "qemu-common.h" #include "qemu-error.h" #include "qemu_socket.h" -#include "block_int.h" +#include "block/block_int.h" #include "bitops.h" #define SD_PROTO_VER 0x01 diff --git a/block/stream.c b/block/stream.c index 0dcd286035..d6df06f35a 100644 --- a/block/stream.c +++ b/block/stream.c @@ -12,8 +12,8 @@ */ #include "trace.h" -#include "block_int.h" -#include "blockjob.h" +#include "block/block_int.h" +#include "block/blockjob.h" #include "qemu/ratelimit.h" enum { diff --git a/block/vdi.c b/block/vdi.c index c8330b7eae..dab9cac76e 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -50,7 +50,7 @@ */ #include "qemu-common.h" -#include "block_int.h" +#include "block/block_int.h" #include "module.h" #include "migration.h" diff --git a/block/vmdk.c b/block/vmdk.c index 51398c0c08..68e50e1a3e 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -24,7 +24,7 @@ */ #include "qemu-common.h" -#include "block_int.h" +#include "block/block_int.h" #include "module.h" #include "migration.h" #include diff --git a/block/vpc.c b/block/vpc.c index 566e9a3b37..aabd71201c 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -23,7 +23,7 @@ * THE SOFTWARE. */ #include "qemu-common.h" -#include "block_int.h" +#include "block/block_int.h" #include "module.h" #include "migration.h" #if defined(CONFIG_UUID) diff --git a/block/vvfat.c b/block/vvfat.c index 59d3c5b8ac..fbabafca76 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -25,7 +25,7 @@ #include #include #include "qemu-common.h" -#include "block_int.h" +#include "block/block_int.h" #include "module.h" #include "migration.h" diff --git a/block/win32-aio.c b/block/win32-aio.c index 4704ee06c2..606e4d6925 100644 --- a/block/win32-aio.c +++ b/block/win32-aio.c @@ -23,10 +23,10 @@ */ #include "qemu-common.h" #include "qemu-timer.h" -#include "block_int.h" +#include "block/block_int.h" #include "module.h" #include "qemu-common.h" -#include "qemu-aio.h" +#include "block/aio.h" #include "raw-aio.h" #include "event_notifier.h" #include diff --git a/block_int.h b/block_int.h deleted file mode 100644 index a748b6c571..0000000000 --- a/block_int.h +++ /dev/null @@ -1,366 +0,0 @@ -/* - * QEMU System Emulator block driver - * - * Copyright (c) 2003 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef BLOCK_INT_H -#define BLOCK_INT_H - -#include "block.h" -#include "qemu-option.h" -#include "qemu-queue.h" -#include "qemu-coroutine.h" -#include "qemu-timer.h" -#include "qapi-types.h" -#include "qapi/qmp/qerror.h" -#include "monitor.h" - -#define BLOCK_FLAG_ENCRYPT 1 -#define BLOCK_FLAG_COMPAT6 4 -#define BLOCK_FLAG_LAZY_REFCOUNTS 8 - -#define BLOCK_IO_LIMIT_READ 0 -#define BLOCK_IO_LIMIT_WRITE 1 -#define BLOCK_IO_LIMIT_TOTAL 2 - -#define BLOCK_IO_SLICE_TIME 100000000 -#define NANOSECONDS_PER_SECOND 1000000000.0 - -#define BLOCK_OPT_SIZE "size" -#define BLOCK_OPT_ENCRYPT "encryption" -#define BLOCK_OPT_COMPAT6 "compat6" -#define BLOCK_OPT_BACKING_FILE "backing_file" -#define BLOCK_OPT_BACKING_FMT "backing_fmt" -#define BLOCK_OPT_CLUSTER_SIZE "cluster_size" -#define BLOCK_OPT_TABLE_SIZE "table_size" -#define BLOCK_OPT_PREALLOC "preallocation" -#define BLOCK_OPT_SUBFMT "subformat" -#define BLOCK_OPT_COMPAT_LEVEL "compat" -#define BLOCK_OPT_LAZY_REFCOUNTS "lazy_refcounts" - -typedef struct BdrvTrackedRequest BdrvTrackedRequest; - -typedef struct BlockIOLimit { - int64_t bps[3]; - int64_t iops[3]; -} BlockIOLimit; - -typedef struct BlockIOBaseValue { - uint64_t bytes[2]; - uint64_t ios[2]; -} BlockIOBaseValue; - -struct BlockDriver { - const char *format_name; - int instance_size; - int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename); - int (*bdrv_probe_device)(const char *filename); - - /* For handling image reopen for split or non-split files */ - int (*bdrv_reopen_prepare)(BDRVReopenState *reopen_state, - BlockReopenQueue *queue, Error **errp); - void (*bdrv_reopen_commit)(BDRVReopenState *reopen_state); - void (*bdrv_reopen_abort)(BDRVReopenState *reopen_state); - - int (*bdrv_open)(BlockDriverState *bs, int flags); - int (*bdrv_file_open)(BlockDriverState *bs, const char *filename, int flags); - int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num, - uint8_t *buf, int nb_sectors); - int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num, - const uint8_t *buf, int nb_sectors); - void (*bdrv_close)(BlockDriverState *bs); - void (*bdrv_rebind)(BlockDriverState *bs); - int (*bdrv_create)(const char *filename, QEMUOptionParameter *options); - int (*bdrv_set_key)(BlockDriverState *bs, const char *key); - int (*bdrv_make_empty)(BlockDriverState *bs); - /* aio */ - BlockDriverAIOCB *(*bdrv_aio_readv)(BlockDriverState *bs, - int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque); - BlockDriverAIOCB *(*bdrv_aio_writev)(BlockDriverState *bs, - int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque); - BlockDriverAIOCB *(*bdrv_aio_flush)(BlockDriverState *bs, - BlockDriverCompletionFunc *cb, void *opaque); - BlockDriverAIOCB *(*bdrv_aio_discard)(BlockDriverState *bs, - int64_t sector_num, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque); - - int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs, - int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); - int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs, - int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); - /* - * Efficiently zero a region of the disk image. Typically an image format - * would use a compact metadata representation to implement this. This - * function pointer may be NULL and .bdrv_co_writev() will be called - * instead. - */ - int coroutine_fn (*bdrv_co_write_zeroes)(BlockDriverState *bs, - int64_t sector_num, int nb_sectors); - int coroutine_fn (*bdrv_co_discard)(BlockDriverState *bs, - int64_t sector_num, int nb_sectors); - int coroutine_fn (*bdrv_co_is_allocated)(BlockDriverState *bs, - int64_t sector_num, int nb_sectors, int *pnum); - - /* - * Invalidate any cached meta-data. - */ - void (*bdrv_invalidate_cache)(BlockDriverState *bs); - - /* - * Flushes all data that was already written to the OS all the way down to - * the disk (for example raw-posix calls fsync()). - */ - int coroutine_fn (*bdrv_co_flush_to_disk)(BlockDriverState *bs); - - /* - * Flushes all internal caches to the OS. The data may still sit in a - * writeback cache of the host OS, but it will survive a crash of the qemu - * process. - */ - int coroutine_fn (*bdrv_co_flush_to_os)(BlockDriverState *bs); - - const char *protocol_name; - int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset); - int64_t (*bdrv_getlength)(BlockDriverState *bs); - int64_t (*bdrv_get_allocated_file_size)(BlockDriverState *bs); - int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num, - const uint8_t *buf, int nb_sectors); - - int (*bdrv_snapshot_create)(BlockDriverState *bs, - QEMUSnapshotInfo *sn_info); - int (*bdrv_snapshot_goto)(BlockDriverState *bs, - const char *snapshot_id); - int (*bdrv_snapshot_delete)(BlockDriverState *bs, const char *snapshot_id); - int (*bdrv_snapshot_list)(BlockDriverState *bs, - QEMUSnapshotInfo **psn_info); - int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs, - const char *snapshot_name); - int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi); - - int (*bdrv_save_vmstate)(BlockDriverState *bs, const uint8_t *buf, - int64_t pos, int size); - int (*bdrv_load_vmstate)(BlockDriverState *bs, uint8_t *buf, - int64_t pos, int size); - - int (*bdrv_change_backing_file)(BlockDriverState *bs, - const char *backing_file, const char *backing_fmt); - - /* removable device specific */ - int (*bdrv_is_inserted)(BlockDriverState *bs); - int (*bdrv_media_changed)(BlockDriverState *bs); - void (*bdrv_eject)(BlockDriverState *bs, bool eject_flag); - void (*bdrv_lock_medium)(BlockDriverState *bs, bool locked); - - /* to control generic scsi devices */ - int (*bdrv_ioctl)(BlockDriverState *bs, unsigned long int req, void *buf); - BlockDriverAIOCB *(*bdrv_aio_ioctl)(BlockDriverState *bs, - unsigned long int req, void *buf, - BlockDriverCompletionFunc *cb, void *opaque); - - /* List of options for creating images, terminated by name == NULL */ - QEMUOptionParameter *create_options; - - - /* - * Returns 0 for completed check, -errno for internal errors. - * The check results are stored in result. - */ - int (*bdrv_check)(BlockDriverState* bs, BdrvCheckResult *result, - BdrvCheckMode fix); - - void (*bdrv_debug_event)(BlockDriverState *bs, BlkDebugEvent event); - - /* TODO Better pass a option string/QDict/QemuOpts to add any rule? */ - int (*bdrv_debug_breakpoint)(BlockDriverState *bs, const char *event, - const char *tag); - int (*bdrv_debug_resume)(BlockDriverState *bs, const char *tag); - bool (*bdrv_debug_is_suspended)(BlockDriverState *bs, const char *tag); - - /* - * Returns 1 if newly created images are guaranteed to contain only - * zeros, 0 otherwise. - */ - int (*bdrv_has_zero_init)(BlockDriverState *bs); - - QLIST_ENTRY(BlockDriver) list; -}; - -/* - * Note: the function bdrv_append() copies and swaps contents of - * BlockDriverStates, so if you add new fields to this struct, please - * inspect bdrv_append() to determine if the new fields need to be - * copied as well. - */ -struct BlockDriverState { - int64_t total_sectors; /* if we are reading a disk image, give its - size in sectors */ - int read_only; /* if true, the media is read only */ - int open_flags; /* flags used to open the file, re-used for re-open */ - int encrypted; /* if true, the media is encrypted */ - int valid_key; /* if true, a valid encryption key has been set */ - int sg; /* if true, the device is a /dev/sg* */ - int copy_on_read; /* if true, copy read backing sectors into image - note this is a reference count */ - - BlockDriver *drv; /* NULL means no media */ - void *opaque; - - void *dev; /* attached device model, if any */ - /* TODO change to DeviceState when all users are qdevified */ - const BlockDevOps *dev_ops; - void *dev_opaque; - - char filename[1024]; - char backing_file[1024]; /* if non zero, the image is a diff of - this file image */ - char backing_format[16]; /* if non-zero and backing_file exists */ - int is_temporary; - - BlockDriverState *backing_hd; - BlockDriverState *file; - - NotifierList close_notifiers; - - /* number of in-flight copy-on-read requests */ - unsigned int copy_on_read_in_flight; - - /* the time for latest disk I/O */ - int64_t slice_time; - int64_t slice_start; - int64_t slice_end; - BlockIOLimit io_limits; - BlockIOBaseValue io_base; - CoQueue throttled_reqs; - QEMUTimer *block_timer; - bool io_limits_enabled; - - /* I/O stats (display with "info blockstats"). */ - uint64_t nr_bytes[BDRV_MAX_IOTYPE]; - uint64_t nr_ops[BDRV_MAX_IOTYPE]; - uint64_t total_time_ns[BDRV_MAX_IOTYPE]; - uint64_t wr_highest_sector; - - /* Whether the disk can expand beyond total_sectors */ - int growable; - - /* the memory alignment required for the buffers handled by this driver */ - int buffer_alignment; - - /* do we need to tell the quest if we have a volatile write cache? */ - int enable_write_cache; - - /* NOTE: the following infos are only hints for real hardware - drivers. They are not used by the block driver */ - BlockdevOnError on_read_error, on_write_error; - bool iostatus_enabled; - BlockDeviceIoStatus iostatus; - char device_name[32]; - unsigned long *dirty_bitmap; - int64_t dirty_count; - int in_use; /* users other than guest access, eg. block migration */ - QTAILQ_ENTRY(BlockDriverState) list; - - QLIST_HEAD(, BdrvTrackedRequest) tracked_requests; - - /* long-running background operation */ - BlockJob *job; - -}; - -int get_tmp_filename(char *filename, int size); - -void bdrv_set_io_limits(BlockDriverState *bs, - BlockIOLimit *io_limits); - -#ifdef _WIN32 -int is_windows_drive(const char *filename); -#endif -void bdrv_emit_qmp_error_event(const BlockDriverState *bdrv, - enum MonitorEvent ev, - BlockErrorAction action, bool is_read); - -/** - * stream_start: - * @bs: Block device to operate on. - * @base: Block device that will become the new base, or %NULL to - * flatten the whole backing file chain onto @bs. - * @base_id: The file name that will be written to @bs as the new - * backing file if the job completes. Ignored if @base is %NULL. - * @speed: The maximum speed, in bytes per second, or 0 for unlimited. - * @on_error: The action to take upon error. - * @cb: Completion function for the job. - * @opaque: Opaque pointer value passed to @cb. - * @errp: Error object. - * - * Start a streaming operation on @bs. Clusters that are unallocated - * in @bs, but allocated in any image between @base and @bs (both - * exclusive) will be written to @bs. At the end of a successful - * streaming job, the backing file of @bs will be changed to - * @base_id in the written image and to @base in the live BlockDriverState. - */ -void stream_start(BlockDriverState *bs, BlockDriverState *base, - const char *base_id, int64_t speed, BlockdevOnError on_error, - BlockDriverCompletionFunc *cb, - void *opaque, Error **errp); - -/** - * commit_start: - * @bs: Top Block device - * @base: Block device that will be written into, and become the new top - * @speed: The maximum speed, in bytes per second, or 0 for unlimited. - * @on_error: The action to take upon error. - * @cb: Completion function for the job. - * @opaque: Opaque pointer value passed to @cb. - * @errp: Error object. - * - */ -void commit_start(BlockDriverState *bs, BlockDriverState *base, - BlockDriverState *top, int64_t speed, - BlockdevOnError on_error, BlockDriverCompletionFunc *cb, - void *opaque, Error **errp); - -/* - * mirror_start: - * @bs: Block device to operate on. - * @target: Block device to write to. - * @speed: The maximum speed, in bytes per second, or 0 for unlimited. - * @mode: Whether to collapse all images in the chain to the target. - * @on_source_error: The action to take upon error reading from the source. - * @on_target_error: The action to take upon error writing to the target. - * @cb: Completion function for the job. - * @opaque: Opaque pointer value passed to @cb. - * @errp: Error object. - * - * Start a mirroring operation on @bs. Clusters that are allocated - * in @bs will be written to @bs until the job is cancelled or - * manually completed. At the end of a successful mirroring job, - * @bs will be switched to read from @target. - */ -void mirror_start(BlockDriverState *bs, BlockDriverState *target, - int64_t speed, MirrorSyncMode mode, - BlockdevOnError on_source_error, - BlockdevOnError on_target_error, - BlockDriverCompletionFunc *cb, - void *opaque, Error **errp); - -#endif /* BLOCK_INT_H */ diff --git a/blockdev-nbd.c b/blockdev-nbd.c index a194ecd392..81aa1d34ef 100644 --- a/blockdev-nbd.c +++ b/blockdev-nbd.c @@ -16,7 +16,7 @@ #include "sysemu.h" #include "qmp-commands.h" #include "trace.h" -#include "nbd.h" +#include "block/nbd.h" #include "qemu_socket.h" static int server_fd = -1; diff --git a/blockdev.c b/blockdev.c index c85c614577..ff6b333f69 100644 --- a/blockdev.c +++ b/blockdev.c @@ -9,14 +9,14 @@ #include "blockdev.h" #include "hw/block-common.h" -#include "blockjob.h" +#include "block/blockjob.h" #include "monitor.h" #include "qapi/qmp/qerror.h" #include "qemu-option.h" #include "qemu-config.h" #include "qapi/qmp/types.h" #include "sysemu.h" -#include "block_int.h" +#include "block/block_int.h" #include "qmp-commands.h" #include "trace.h" #include "arch_init.h" diff --git a/blockdev.h b/blockdev.h index 6e36d9f2c2..4134864758 100644 --- a/blockdev.h +++ b/blockdev.h @@ -10,7 +10,7 @@ #ifndef BLOCKDEV_H #define BLOCKDEV_H -#include "block.h" +#include "block/block.h" #include "qapi/error.h" #include "qemu-queue.h" diff --git a/blockjob.c b/blockjob.c index 8c0a286a77..004480d714 100644 --- a/blockjob.c +++ b/blockjob.c @@ -27,11 +27,11 @@ #include "qemu-common.h" #include "trace.h" #include "monitor.h" -#include "block.h" -#include "blockjob.h" -#include "block_int.h" +#include "block/block.h" +#include "block/blockjob.h" +#include "block/block_int.h" #include "qapi/qmp/qjson.h" -#include "qemu-coroutine.h" +#include "block/coroutine.h" #include "qmp-commands.h" #include "qemu-timer.h" diff --git a/blockjob.h b/blockjob.h deleted file mode 100644 index 3792b73e52..0000000000 --- a/blockjob.h +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Declarations for long-running block device operations - * - * Copyright (c) 2011 IBM Corp. - * Copyright (c) 2012 Red Hat, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef BLOCKJOB_H -#define BLOCKJOB_H 1 - -#include "block.h" - -/** - * BlockJobType: - * - * A class type for block job objects. - */ -typedef struct BlockJobType { - /** Derived BlockJob struct size */ - size_t instance_size; - - /** String describing the operation, part of query-block-jobs QMP API */ - const char *job_type; - - /** Optional callback for job types that support setting a speed limit */ - void (*set_speed)(BlockJob *job, int64_t speed, Error **errp); - - /** Optional callback for job types that need to forward I/O status reset */ - void (*iostatus_reset)(BlockJob *job); - - /** - * Optional callback for job types whose completion must be triggered - * manually. - */ - void (*complete)(BlockJob *job, Error **errp); -} BlockJobType; - -/** - * BlockJob: - * - * Long-running operation on a BlockDriverState. - */ -struct BlockJob { - /** The job type, including the job vtable. */ - const BlockJobType *job_type; - - /** The block device on which the job is operating. */ - BlockDriverState *bs; - - /** - * The coroutine that executes the job. If not NULL, it is - * reentered when busy is false and the job is cancelled. - */ - Coroutine *co; - - /** - * Set to true if the job should cancel itself. The flag must - * always be tested just before toggling the busy flag from false - * to true. After a job has been cancelled, it should only yield - * if #qemu_aio_wait will ("sooner or later") reenter the coroutine. - */ - bool cancelled; - - /** - * Set to true if the job is either paused, or will pause itself - * as soon as possible (if busy == true). - */ - bool paused; - - /** - * Set to false by the job while it is in a quiescent state, where - * no I/O is pending and the job has yielded on any condition - * that is not detected by #qemu_aio_wait, such as a timer. - */ - bool busy; - - /** Status that is published by the query-block-jobs QMP API */ - BlockDeviceIoStatus iostatus; - - /** Offset that is published by the query-block-jobs QMP API */ - int64_t offset; - - /** Length that is published by the query-block-jobs QMP API */ - int64_t len; - - /** Speed that was set with @block_job_set_speed. */ - int64_t speed; - - /** The completion function that will be called when the job completes. */ - BlockDriverCompletionFunc *cb; - - /** The opaque value that is passed to the completion function. */ - void *opaque; -}; - -/** - * block_job_create: - * @job_type: The class object for the newly-created job. - * @bs: The block - * @speed: The maximum speed, in bytes per second, or 0 for unlimited. - * @cb: Completion function for the job. - * @opaque: Opaque pointer value passed to @cb. - * @errp: Error object. - * - * Create a new long-running block device job and return it. The job - * will call @cb asynchronously when the job completes. Note that - * @bs may have been closed at the time the @cb it is called. If - * this is the case, the job may be reported as either cancelled or - * completed. - * - * This function is not part of the public job interface; it should be - * called from a wrapper that is specific to the job type. - */ -void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs, - int64_t speed, BlockDriverCompletionFunc *cb, - void *opaque, Error **errp); - -/** - * block_job_sleep_ns: - * @job: The job that calls the function. - * @clock: The clock to sleep on. - * @ns: How many nanoseconds to stop for. - * - * Put the job to sleep (assuming that it wasn't canceled) for @ns - * nanoseconds. Canceling the job will interrupt the wait immediately. - */ -void block_job_sleep_ns(BlockJob *job, QEMUClock *clock, int64_t ns); - -/** - * block_job_completed: - * @job: The job being completed. - * @ret: The status code. - * - * Call the completion function that was registered at creation time, and - * free @job. - */ -void block_job_completed(BlockJob *job, int ret); - -/** - * block_job_set_speed: - * @job: The job to set the speed for. - * @speed: The new value - * @errp: Error object. - * - * Set a rate-limiting parameter for the job; the actual meaning may - * vary depending on the job type. - */ -void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp); - -/** - * block_job_cancel: - * @job: The job to be canceled. - * - * Asynchronously cancel the specified job. - */ -void block_job_cancel(BlockJob *job); - -/** - * block_job_complete: - * @job: The job to be completed. - * @errp: Error object. - * - * Asynchronously complete the specified job. - */ -void block_job_complete(BlockJob *job, Error **errp); - -/** - * block_job_is_cancelled: - * @job: The job being queried. - * - * Returns whether the job is scheduled for cancellation. - */ -bool block_job_is_cancelled(BlockJob *job); - -/** - * block_job_query: - * @job: The job to get information about. - * - * Return information about a job. - */ -BlockJobInfo *block_job_query(BlockJob *job); - -/** - * block_job_pause: - * @job: The job to be paused. - * - * Asynchronously pause the specified job. - */ -void block_job_pause(BlockJob *job); - -/** - * block_job_resume: - * @job: The job to be resumed. - * - * Resume the specified job. - */ -void block_job_resume(BlockJob *job); - -/** - * qobject_from_block_job: - * @job: The job whose information is requested. - * - * Return a QDict corresponding to @job's query-block-jobs entry. - */ -QObject *qobject_from_block_job(BlockJob *job); - -/** - * block_job_ready: - * @job: The job which is now ready to complete. - * - * Send a BLOCK_JOB_READY event for the specified job. - */ -void block_job_ready(BlockJob *job); - -/** - * block_job_is_paused: - * @job: The job being queried. - * - * Returns whether the job is currently paused, or will pause - * as soon as it reaches a sleeping point. - */ -bool block_job_is_paused(BlockJob *job); - -/** - * block_job_cancel_sync: - * @job: The job to be canceled. - * - * Synchronously cancel the job. The completion callback is called - * before the function returns. The job may actually complete - * instead of canceling itself; the circumstances under which this - * happens depend on the kind of job that is active. - * - * Returns the return value from the job if the job actually completed - * during the call, or -ECANCELED if it was canceled. - */ -int block_job_cancel_sync(BlockJob *job); - -/** - * block_job_iostatus_reset: - * @job: The job whose I/O status should be reset. - * - * Reset I/O status on @job and on BlockDriverState objects it uses, - * other than job->bs. - */ -void block_job_iostatus_reset(BlockJob *job); - -/** - * block_job_error_action: - * @job: The job to signal an error for. - * @bs: The block device on which to set an I/O error. - * @on_err: The error action setting. - * @is_read: Whether the operation was a read. - * @error: The error that was reported. - * - * Report an I/O error for a block job and possibly stop the VM. Return the - * action that was selected based on @on_err and @error. - */ -BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs, - BlockdevOnError on_err, - int is_read, int error); -#endif diff --git a/cmd.c b/cmd.c index f40f09bbb7..01a8c3a299 100644 --- a/cmd.c +++ b/cmd.c @@ -24,7 +24,7 @@ #include #include "cmd.h" -#include "qemu-aio.h" +#include "block/aio.h" #include "main-loop.h" #define _(x) x /* not gettext support yet */ diff --git a/coroutine-gthread.c b/coroutine-gthread.c index 30c24c94b8..d3e5b991f7 100644 --- a/coroutine-gthread.c +++ b/coroutine-gthread.c @@ -20,7 +20,7 @@ #include #include "qemu-common.h" -#include "qemu-coroutine-int.h" +#include "block/coroutine_int.h" typedef struct { Coroutine base; diff --git a/coroutine-sigaltstack.c b/coroutine-sigaltstack.c index 39dbaa5da1..e37ebac9c4 100644 --- a/coroutine-sigaltstack.c +++ b/coroutine-sigaltstack.c @@ -31,7 +31,7 @@ #include #include #include "qemu-common.h" -#include "qemu-coroutine-int.h" +#include "block/coroutine_int.h" enum { /* Maximum free pool size prevents holding too many freed coroutines */ diff --git a/coroutine-ucontext.c b/coroutine-ucontext.c index 784081ab18..2ed703a3ed 100644 --- a/coroutine-ucontext.c +++ b/coroutine-ucontext.c @@ -28,7 +28,7 @@ #include #include #include "qemu-common.h" -#include "qemu-coroutine-int.h" +#include "block/coroutine_int.h" #ifdef CONFIG_VALGRIND_H #include diff --git a/coroutine-win32.c b/coroutine-win32.c index 4179609eec..edc1f72c18 100644 --- a/coroutine-win32.c +++ b/coroutine-win32.c @@ -23,7 +23,7 @@ */ #include "qemu-common.h" -#include "qemu-coroutine-int.h" +#include "block/coroutine_int.h" typedef struct { diff --git a/dma.h b/dma.h index eedf878383..40280365ce 100644 --- a/dma.h +++ b/dma.h @@ -13,7 +13,7 @@ #include #include "memory.h" #include "hw/hw.h" -#include "block.h" +#include "block/block.h" #include "kvm.h" typedef struct DMAContext DMAContext; diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c index 3d188284ba..cd137330b9 100644 --- a/hw/9pfs/codir.c +++ b/hw/9pfs/codir.c @@ -14,7 +14,7 @@ #include "fsdev/qemu-fsdev.h" #include "qemu-thread.h" -#include "qemu-coroutine.h" +#include "block/coroutine.h" #include "virtio-9p-coth.h" int v9fs_co_readdir_r(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent *dent, diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c index 9345aaeb2e..6d6dac7abf 100644 --- a/hw/9pfs/cofile.c +++ b/hw/9pfs/cofile.c @@ -14,7 +14,7 @@ #include "fsdev/qemu-fsdev.h" #include "qemu-thread.h" -#include "qemu-coroutine.h" +#include "block/coroutine.h" #include "virtio-9p-coth.h" int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode, diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c index 83f125bd47..4b9ba30157 100644 --- a/hw/9pfs/cofs.c +++ b/hw/9pfs/cofs.c @@ -14,7 +14,7 @@ #include "fsdev/qemu-fsdev.h" #include "qemu-thread.h" -#include "qemu-coroutine.h" +#include "block/coroutine.h" #include "virtio-9p-coth.h" int v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf) diff --git a/hw/9pfs/coxattr.c b/hw/9pfs/coxattr.c index 8a48228702..08365a697e 100644 --- a/hw/9pfs/coxattr.c +++ b/hw/9pfs/coxattr.c @@ -14,7 +14,7 @@ #include "fsdev/qemu-fsdev.h" #include "qemu-thread.h" -#include "qemu-coroutine.h" +#include "block/coroutine.h" #include "virtio-9p-coth.h" int v9fs_co_llistxattr(V9fsPDU *pdu, V9fsPath *path, void *value, size_t size) diff --git a/hw/9pfs/virtio-9p-coth.c b/hw/9pfs/virtio-9p-coth.c index 9368df7610..958725e5cc 100644 --- a/hw/9pfs/virtio-9p-coth.c +++ b/hw/9pfs/virtio-9p-coth.c @@ -14,7 +14,7 @@ #include "fsdev/qemu-fsdev.h" #include "qemu-thread.h" -#include "qemu-coroutine.h" +#include "block/coroutine.h" #include "virtio-9p-coth.h" /* v9fs glib thread pool */ diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h index c31c96578b..8c48a16c10 100644 --- a/hw/9pfs/virtio-9p-coth.h +++ b/hw/9pfs/virtio-9p-coth.h @@ -16,7 +16,7 @@ #define _QEMU_VIRTIO_9P_COTH_H #include "qemu-thread.h" -#include "qemu-coroutine.h" +#include "block/coroutine.h" #include "virtio-9p.h" #include diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h index 579794404b..2c0c3baad4 100644 --- a/hw/9pfs/virtio-9p.h +++ b/hw/9pfs/virtio-9p.h @@ -10,7 +10,7 @@ #include "fsdev/file-op-9p.h" #include "fsdev/virtio-9p-marshal.h" #include "qemu-thread.h" -#include "qemu-coroutine.h" +#include "block/coroutine.h" /* The feature bitmap for virtio 9P */ diff --git a/hw/hd-geometry.c b/hw/hd-geometry.c index 1cdb9fb753..c30514364f 100644 --- a/hw/hd-geometry.c +++ b/hw/hd-geometry.c @@ -30,7 +30,7 @@ * THE SOFTWARE. */ -#include "block.h" +#include "block/block.h" #include "hw/block-common.h" #include "trace.h" diff --git a/hw/hw.h b/hw/hw.h index f530f6f41a..003d974866 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -10,7 +10,7 @@ #include "ioport.h" #include "irq.h" -#include "qemu-aio.h" +#include "block/aio.h" #include "qemu-file.h" #include "vmstate.h" #include "qemu-log.h" diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index 88210eabc8..f6d15b9f2a 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -26,7 +26,7 @@ #include #include #include -#include "block.h" +#include "block/block.h" #include "sysemu.h" #include "dma.h" diff --git a/hw/ide/ich.c b/hw/ide/ich.c index 8e1a48e257..3457b98cc1 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -65,7 +65,7 @@ #include #include #include -#include "block.h" +#include "block/block.h" #include "dma.h" #include diff --git a/hw/ide/isa.c b/hw/ide/isa.c index 8ab2718eea..39df87c608 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -25,7 +25,7 @@ #include #include #include -#include "block.h" +#include "block/block.h" #include "dma.h" #include diff --git a/hw/ide/macio.c b/hw/ide/macio.c index d2edcc0850..87cbb0c31e 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -25,7 +25,7 @@ #include #include #include -#include "block.h" +#include "block/block.h" #include "dma.h" #include diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c index 9eee5b50ba..6cce5230c5 100644 --- a/hw/ide/microdrive.c +++ b/hw/ide/microdrive.c @@ -25,7 +25,7 @@ #include #include #include -#include "block.h" +#include "block/block.h" #include "dma.h" #include diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c index bcb26c8b64..40443513be 100644 --- a/hw/ide/mmio.c +++ b/hw/ide/mmio.c @@ -23,7 +23,7 @@ * THE SOFTWARE. */ #include -#include "block.h" +#include "block/block.h" #include "dma.h" #include diff --git a/hw/ide/pci.c b/hw/ide/pci.c index 23a0e237fb..8821d5cceb 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -26,7 +26,7 @@ #include #include #include -#include "block.h" +#include "block/block.h" #include "dma.h" #include diff --git a/hw/ide/via.c b/hw/ide/via.c index 8b4a24e5c2..880f61cc8e 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -27,7 +27,7 @@ #include #include #include -#include "block.h" +#include "block/block.h" #include "sysemu.h" #include "dma.h" diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c index bab96b27c1..b46f7fdcb1 100644 --- a/hw/mips_fulong2e.c +++ b/hw/mips_fulong2e.c @@ -25,7 +25,7 @@ #include "net/net.h" #include "boards.h" #include "smbus.h" -#include "block.h" +#include "block/block.h" #include "flash.h" #include "mips.h" #include "mips_cpudevs.h" diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 3f9f171385..60f237987f 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -29,7 +29,7 @@ #include "net/net.h" #include "boards.h" #include "smbus.h" -#include "block.h" +#include "block/block.h" #include "flash.h" #include "mips.h" #include "mips_cpudevs.h" diff --git a/hw/musicpal.c b/hw/musicpal.c index d16cd141a2..d7672e92a5 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -18,7 +18,7 @@ #include "serial.h" #include "qemu-timer.h" #include "ptimer.h" -#include "block.h" +#include "block/block.h" #include "flash.h" #include "ui/console.h" #include "i2c.h" diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c index 7d040b508a..a2f6360838 100644 --- a/hw/pflash_cfi01.c +++ b/hw/pflash_cfi01.c @@ -38,7 +38,7 @@ #include "hw.h" #include "flash.h" -#include "block.h" +#include "block/block.h" #include "qemu-timer.h" #include "exec-memory.h" #include "host-utils.h" diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index f918e36580..beab67fc87 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -38,7 +38,7 @@ #include "hw.h" #include "flash.h" #include "qemu-timer.h" -#include "block.h" +#include "block/block.h" #include "exec-memory.h" #include "host-utils.h" #include "sysbus.h" diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c index 8dc693f050..b875e3b615 100644 --- a/hw/ppc405_boards.c +++ b/hw/ppc405_boards.c @@ -27,7 +27,7 @@ #include "nvram.h" #include "flash.h" #include "sysemu.h" -#include "block.h" +#include "block/block.h" #include "boards.h" #include "qemu-log.h" #include "loader.h" diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index 169dd4683d..f7e1939288 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -18,7 +18,7 @@ */ #include "hw.h" -#include "block.h" +#include "block/block.h" #include "sysemu.h" #include "boards.h" #include "monitor.h" diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index 8c724b942c..b732bccef8 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -18,7 +18,7 @@ */ #include "hw.h" -#include "block.h" +#include "block/block.h" #include "blockdev.h" #include "sysemu.h" #include "net/net.h" diff --git a/hw/scsi.h b/hw/scsi.h index b8f73577d3..24ed522722 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -2,7 +2,7 @@ #define QEMU_HW_SCSI_H #include "qdev.h" -#include "block.h" +#include "block/block.h" #include "hw/block-common.h" #include "sysemu.h" diff --git a/hw/sd.c b/hw/sd.c index 607edba9c8..2e54eea981 100644 --- a/hw/sd.c +++ b/hw/sd.c @@ -30,7 +30,7 @@ */ #include "hw.h" -#include "block.h" +#include "block/block.h" #include "sd.h" #include "bitmap.h" diff --git a/hw/spitz.c b/hw/spitz.c index d4575d20bf..1500161d44 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -22,7 +22,7 @@ #include "devices.h" #include "sharpsl.h" #include "ui/console.h" -#include "block.h" +#include "block/block.h" #include "audio/audio.h" #include "boards.h" #include "blockdev.h" diff --git a/hw/tosa.c b/hw/tosa.c index 512278c241..3991a909b5 100644 --- a/hw/tosa.c +++ b/hw/tosa.c @@ -17,7 +17,7 @@ #include "devices.h" #include "sharpsl.h" #include "pcmcia.h" -#include "block.h" +#include "block/block.h" #include "boards.h" #include "i2c.h" #include "ssi.h" diff --git a/include/block/aes.h b/include/block/aes.h new file mode 100644 index 0000000000..a0167eb7d5 --- /dev/null +++ b/include/block/aes.h @@ -0,0 +1,26 @@ +#ifndef QEMU_AES_H +#define QEMU_AES_H + +#define AES_MAXNR 14 +#define AES_BLOCK_SIZE 16 + +struct aes_key_st { + uint32_t rd_key[4 *(AES_MAXNR + 1)]; + int rounds; +}; +typedef struct aes_key_st AES_KEY; + +int AES_set_encrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key); +int AES_set_decrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key); + +void AES_encrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); +void AES_decrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); +void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, + const unsigned long length, const AES_KEY *key, + unsigned char *ivec, const int enc); + +#endif diff --git a/include/block/aio.h b/include/block/aio.h new file mode 100644 index 0000000000..31884a8f16 --- /dev/null +++ b/include/block/aio.h @@ -0,0 +1,240 @@ +/* + * QEMU aio implementation + * + * Copyright IBM, Corp. 2008 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_AIO_H +#define QEMU_AIO_H + +#include "qemu-common.h" +#include "qemu-queue.h" +#include "event_notifier.h" + +typedef struct BlockDriverAIOCB BlockDriverAIOCB; +typedef void BlockDriverCompletionFunc(void *opaque, int ret); + +typedef struct AIOCBInfo { + void (*cancel)(BlockDriverAIOCB *acb); + size_t aiocb_size; +} AIOCBInfo; + +struct BlockDriverAIOCB { + const AIOCBInfo *aiocb_info; + BlockDriverState *bs; + BlockDriverCompletionFunc *cb; + void *opaque; +}; + +void *qemu_aio_get(const AIOCBInfo *aiocb_info, BlockDriverState *bs, + BlockDriverCompletionFunc *cb, void *opaque); +void qemu_aio_release(void *p); + +typedef struct AioHandler AioHandler; +typedef void QEMUBHFunc(void *opaque); +typedef void IOHandler(void *opaque); + +typedef struct AioContext { + GSource source; + + /* The list of registered AIO handlers */ + QLIST_HEAD(, AioHandler) aio_handlers; + + /* This is a simple lock used to protect the aio_handlers list. + * Specifically, it's used to ensure that no callbacks are removed while + * we're walking and dispatching callbacks. + */ + int walking_handlers; + + /* Anchor of the list of Bottom Halves belonging to the context */ + struct QEMUBH *first_bh; + + /* A simple lock used to protect the first_bh list, and ensure that + * no callbacks are removed while we're walking and dispatching callbacks. + */ + int walking_bh; + + /* Used for aio_notify. */ + EventNotifier notifier; +} AioContext; + +/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */ +typedef int (AioFlushEventNotifierHandler)(EventNotifier *e); + +/** + * aio_context_new: Allocate a new AioContext. + * + * AioContext provide a mini event-loop that can be waited on synchronously. + * They also provide bottom halves, a service to execute a piece of code + * as soon as possible. + */ +AioContext *aio_context_new(void); + +/** + * aio_context_ref: + * @ctx: The AioContext to operate on. + * + * Add a reference to an AioContext. + */ +void aio_context_ref(AioContext *ctx); + +/** + * aio_context_unref: + * @ctx: The AioContext to operate on. + * + * Drop a reference to an AioContext. + */ +void aio_context_unref(AioContext *ctx); + +/** + * aio_bh_new: Allocate a new bottom half structure. + * + * Bottom halves are lightweight callbacks whose invocation is guaranteed + * to be wait-free, thread-safe and signal-safe. The #QEMUBH structure + * is opaque and must be allocated prior to its use. + */ +QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque); + +/** + * aio_notify: Force processing of pending events. + * + * Similar to signaling a condition variable, aio_notify forces + * aio_wait to exit, so that the next call will re-examine pending events. + * The caller of aio_notify will usually call aio_wait again very soon, + * or go through another iteration of the GLib main loop. Hence, aio_notify + * also has the side effect of recalculating the sets of file descriptors + * that the main loop waits for. + * + * Calling aio_notify is rarely necessary, because for example scheduling + * a bottom half calls it already. + */ +void aio_notify(AioContext *ctx); + +/** + * aio_bh_poll: Poll bottom halves for an AioContext. + * + * These are internal functions used by the QEMU main loop. + */ +int aio_bh_poll(AioContext *ctx); + +/** + * qemu_bh_schedule: Schedule a bottom half. + * + * Scheduling a bottom half interrupts the main loop and causes the + * execution of the callback that was passed to qemu_bh_new. + * + * Bottom halves that are scheduled from a bottom half handler are instantly + * invoked. This can create an infinite loop if a bottom half handler + * schedules itself. + * + * @bh: The bottom half to be scheduled. + */ +void qemu_bh_schedule(QEMUBH *bh); + +/** + * qemu_bh_cancel: Cancel execution of a bottom half. + * + * Canceling execution of a bottom half undoes the effect of calls to + * qemu_bh_schedule without freeing its resources yet. While cancellation + * itself is also wait-free and thread-safe, it can of course race with the + * loop that executes bottom halves unless you are holding the iothread + * mutex. This makes it mostly useless if you are not holding the mutex. + * + * @bh: The bottom half to be canceled. + */ +void qemu_bh_cancel(QEMUBH *bh); + +/** + *qemu_bh_delete: Cancel execution of a bottom half and free its resources. + * + * Deleting a bottom half frees the memory that was allocated for it by + * qemu_bh_new. It also implies canceling the bottom half if it was + * scheduled. + * + * @bh: The bottom half to be deleted. + */ +void qemu_bh_delete(QEMUBH *bh); + +/* Return whether there are any pending callbacks from the GSource + * attached to the AioContext. + * + * This is used internally in the implementation of the GSource. + */ +bool aio_pending(AioContext *ctx); + +/* Progress in completing AIO work to occur. This can issue new pending + * aio as a result of executing I/O completion or bh callbacks. + * + * If there is no pending AIO operation or completion (bottom half), + * return false. If there are pending bottom halves, return true. + * + * If there are no pending bottom halves, but there are pending AIO + * operations, it may not be possible to make any progress without + * blocking. If @blocking is true, this function will wait until one + * or more AIO events have completed, to ensure something has moved + * before returning. + * + * If @blocking is false, this function will also return false if the + * function cannot make any progress without blocking. + */ +bool aio_poll(AioContext *ctx, bool blocking); + +#ifdef CONFIG_POSIX +/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */ +typedef int (AioFlushHandler)(void *opaque); + +/* Register a file descriptor and associated callbacks. Behaves very similarly + * to qemu_set_fd_handler2. Unlike qemu_set_fd_handler2, these callbacks will + * be invoked when using qemu_aio_wait(). + * + * Code that invokes AIO completion functions should rely on this function + * instead of qemu_set_fd_handler[2]. + */ +void aio_set_fd_handler(AioContext *ctx, + int fd, + IOHandler *io_read, + IOHandler *io_write, + AioFlushHandler *io_flush, + void *opaque); +#endif + +/* Register an event notifier and associated callbacks. Behaves very similarly + * to event_notifier_set_handler. Unlike event_notifier_set_handler, these callbacks + * will be invoked when using qemu_aio_wait(). + * + * Code that invokes AIO completion functions should rely on this function + * instead of event_notifier_set_handler. + */ +void aio_set_event_notifier(AioContext *ctx, + EventNotifier *notifier, + EventNotifierHandler *io_read, + AioFlushEventNotifierHandler *io_flush); + +/* Return a GSource that lets the main loop poll the file descriptors attached + * to this AioContext. + */ +GSource *aio_get_g_source(AioContext *ctx); + +/* Functions to operate on the main QEMU AioContext. */ + +bool qemu_aio_wait(void); +void qemu_aio_set_event_notifier(EventNotifier *notifier, + EventNotifierHandler *io_read, + AioFlushEventNotifierHandler *io_flush); + +#ifdef CONFIG_POSIX +void qemu_aio_set_fd_handler(int fd, + IOHandler *io_read, + IOHandler *io_write, + AioFlushHandler *io_flush, + void *opaque); +#endif + +#endif diff --git a/include/block/block.h b/include/block/block.h new file mode 100644 index 0000000000..d49ce4dbc5 --- /dev/null +++ b/include/block/block.h @@ -0,0 +1,439 @@ +#ifndef BLOCK_H +#define BLOCK_H + +#include "block/aio.h" +#include "qemu-common.h" +#include "qemu-option.h" +#include "block/coroutine.h" +#include "qapi/qmp/qobject.h" +#include "qapi-types.h" + +/* block.c */ +typedef struct BlockDriver BlockDriver; +typedef struct BlockJob BlockJob; + +typedef struct BlockDriverInfo { + /* in bytes, 0 if irrelevant */ + int cluster_size; + /* offset at which the VM state can be saved (0 if not possible) */ + int64_t vm_state_offset; + bool is_dirty; +} BlockDriverInfo; + +typedef struct BlockFragInfo { + uint64_t allocated_clusters; + uint64_t total_clusters; + uint64_t fragmented_clusters; +} BlockFragInfo; + +typedef struct QEMUSnapshotInfo { + char id_str[128]; /* unique snapshot id */ + /* the following fields are informative. They are not needed for + the consistency of the snapshot */ + char name[256]; /* user chosen name */ + uint64_t vm_state_size; /* VM state info size */ + uint32_t date_sec; /* UTC date of the snapshot */ + uint32_t date_nsec; + uint64_t vm_clock_nsec; /* VM clock relative to boot */ +} QEMUSnapshotInfo; + +/* Callbacks for block device models */ +typedef struct BlockDevOps { + /* + * Runs when virtual media changed (monitor commands eject, change) + * Argument load is true on load and false on eject. + * Beware: doesn't run when a host device's physical media + * changes. Sure would be useful if it did. + * Device models with removable media must implement this callback. + */ + void (*change_media_cb)(void *opaque, bool load); + /* + * Runs when an eject request is issued from the monitor, the tray + * is closed, and the medium is locked. + * Device models that do not implement is_medium_locked will not need + * this callback. Device models that can lock the medium or tray might + * want to implement the callback and unlock the tray when "force" is + * true, even if they do not support eject requests. + */ + void (*eject_request_cb)(void *opaque, bool force); + /* + * Is the virtual tray open? + * Device models implement this only when the device has a tray. + */ + bool (*is_tray_open)(void *opaque); + /* + * Is the virtual medium locked into the device? + * Device models implement this only when device has such a lock. + */ + bool (*is_medium_locked)(void *opaque); + /* + * Runs when the size changed (e.g. monitor command block_resize) + */ + void (*resize_cb)(void *opaque); +} BlockDevOps; + +#define BDRV_O_RDWR 0x0002 +#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */ +#define BDRV_O_NOCACHE 0x0020 /* do not use the host page cache */ +#define BDRV_O_CACHE_WB 0x0040 /* use write-back caching */ +#define BDRV_O_NATIVE_AIO 0x0080 /* use native AIO instead of the thread pool */ +#define BDRV_O_NO_BACKING 0x0100 /* don't open the backing file */ +#define BDRV_O_NO_FLUSH 0x0200 /* disable flushing on this disk */ +#define BDRV_O_COPY_ON_READ 0x0400 /* copy read backing sectors into image */ +#define BDRV_O_INCOMING 0x0800 /* consistency hint for incoming migration */ +#define BDRV_O_CHECK 0x1000 /* open solely for consistency check */ +#define BDRV_O_ALLOW_RDWR 0x2000 /* allow reopen to change from r/o to r/w */ + +#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH) + +#define BDRV_SECTOR_BITS 9 +#define BDRV_SECTOR_SIZE (1ULL << BDRV_SECTOR_BITS) +#define BDRV_SECTOR_MASK ~(BDRV_SECTOR_SIZE - 1) + +typedef enum { + BDRV_ACTION_REPORT, BDRV_ACTION_IGNORE, BDRV_ACTION_STOP +} BlockErrorAction; + +typedef QSIMPLEQ_HEAD(BlockReopenQueue, BlockReopenQueueEntry) BlockReopenQueue; + +typedef struct BDRVReopenState { + BlockDriverState *bs; + int flags; + void *opaque; +} BDRVReopenState; + + +void bdrv_iostatus_enable(BlockDriverState *bs); +void bdrv_iostatus_reset(BlockDriverState *bs); +void bdrv_iostatus_disable(BlockDriverState *bs); +bool bdrv_iostatus_is_enabled(const BlockDriverState *bs); +void bdrv_iostatus_set_err(BlockDriverState *bs, int error); +void bdrv_info_print(Monitor *mon, const QObject *data); +void bdrv_info(Monitor *mon, QObject **ret_data); +void bdrv_stats_print(Monitor *mon, const QObject *data); +void bdrv_info_stats(Monitor *mon, QObject **ret_data); + +/* disk I/O throttling */ +void bdrv_io_limits_enable(BlockDriverState *bs); +void bdrv_io_limits_disable(BlockDriverState *bs); +bool bdrv_io_limits_enabled(BlockDriverState *bs); + +void bdrv_init(void); +void bdrv_init_with_whitelist(void); +BlockDriver *bdrv_find_protocol(const char *filename); +BlockDriver *bdrv_find_format(const char *format_name); +BlockDriver *bdrv_find_whitelisted_format(const char *format_name); +int bdrv_create(BlockDriver *drv, const char* filename, + QEMUOptionParameter *options); +int bdrv_create_file(const char* filename, QEMUOptionParameter *options); +BlockDriverState *bdrv_new(const char *device_name); +void bdrv_make_anon(BlockDriverState *bs); +void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old); +void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top); +void bdrv_delete(BlockDriverState *bs); +int bdrv_parse_cache_flags(const char *mode, int *flags); +int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags); +int bdrv_open_backing_file(BlockDriverState *bs); +int bdrv_open(BlockDriverState *bs, const char *filename, int flags, + BlockDriver *drv); +BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, + BlockDriverState *bs, int flags); +int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp); +int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp); +int bdrv_reopen_prepare(BDRVReopenState *reopen_state, + BlockReopenQueue *queue, Error **errp); +void bdrv_reopen_commit(BDRVReopenState *reopen_state); +void bdrv_reopen_abort(BDRVReopenState *reopen_state); +void bdrv_close(BlockDriverState *bs); +void bdrv_add_close_notifier(BlockDriverState *bs, Notifier *notify); +int bdrv_attach_dev(BlockDriverState *bs, void *dev); +void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev); +void bdrv_detach_dev(BlockDriverState *bs, void *dev); +void *bdrv_get_attached_dev(BlockDriverState *bs); +void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops, + void *opaque); +void bdrv_dev_eject_request(BlockDriverState *bs, bool force); +bool bdrv_dev_has_removable_media(BlockDriverState *bs); +bool bdrv_dev_is_tray_open(BlockDriverState *bs); +bool bdrv_dev_is_medium_locked(BlockDriverState *bs); +int bdrv_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors); +int bdrv_read_unthrottled(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors); +int bdrv_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors); +int bdrv_pread(BlockDriverState *bs, int64_t offset, + void *buf, int count); +int bdrv_pwrite(BlockDriverState *bs, int64_t offset, + const void *buf, int count); +int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset, + const void *buf, int count); +int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num, + int nb_sectors, QEMUIOVector *qiov); +int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); +int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num, + int nb_sectors, QEMUIOVector *qiov); +/* + * Efficiently zero a region of the disk image. Note that this is a regular + * I/O request like read or write and should have a reasonable size. This + * function is not suitable for zeroing the entire image in a single request + * because it may allocate memory for the entire region. + */ +int coroutine_fn bdrv_co_write_zeroes(BlockDriverState *bs, int64_t sector_num, + int nb_sectors); +int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t sector_num, + int nb_sectors, int *pnum); +int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top, + BlockDriverState *base, + int64_t sector_num, + int nb_sectors, int *pnum); +BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, + const char *backing_file); +int bdrv_get_backing_file_depth(BlockDriverState *bs); +int bdrv_truncate(BlockDriverState *bs, int64_t offset); +int64_t bdrv_getlength(BlockDriverState *bs); +int64_t bdrv_get_allocated_file_size(BlockDriverState *bs); +void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); +int bdrv_commit(BlockDriverState *bs); +int bdrv_commit_all(void); +int bdrv_change_backing_file(BlockDriverState *bs, + const char *backing_file, const char *backing_fmt); +void bdrv_register(BlockDriver *bdrv); +int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top, + BlockDriverState *base); +BlockDriverState *bdrv_find_overlay(BlockDriverState *active, + BlockDriverState *bs); +BlockDriverState *bdrv_find_base(BlockDriverState *bs); + + +typedef struct BdrvCheckResult { + int corruptions; + int leaks; + int check_errors; + int corruptions_fixed; + int leaks_fixed; + BlockFragInfo bfi; +} BdrvCheckResult; + +typedef enum { + BDRV_FIX_LEAKS = 1, + BDRV_FIX_ERRORS = 2, +} BdrvCheckMode; + +int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix); + +/* async block I/O */ +typedef void BlockDriverDirtyHandler(BlockDriverState *bs, int64_t sector, + int sector_num); +BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num, + QEMUIOVector *iov, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque); +BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num, + QEMUIOVector *iov, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque); +BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs, + BlockDriverCompletionFunc *cb, void *opaque); +BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque); +void bdrv_aio_cancel(BlockDriverAIOCB *acb); + +typedef struct BlockRequest { + /* Fields to be filled by multiwrite caller */ + int64_t sector; + int nb_sectors; + QEMUIOVector *qiov; + BlockDriverCompletionFunc *cb; + void *opaque; + + /* Filled by multiwrite implementation */ + int error; +} BlockRequest; + +int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, + int num_reqs); + +/* sg packet commands */ +int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf); +BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs, + unsigned long int req, void *buf, + BlockDriverCompletionFunc *cb, void *opaque); + +/* Invalidate any cached metadata used by image formats */ +void bdrv_invalidate_cache(BlockDriverState *bs); +void bdrv_invalidate_cache_all(void); + +void bdrv_clear_incoming_migration_all(void); + +/* Ensure contents are flushed to disk. */ +int bdrv_flush(BlockDriverState *bs); +int coroutine_fn bdrv_co_flush(BlockDriverState *bs); +void bdrv_flush_all(void); +void bdrv_close_all(void); +void bdrv_drain_all(void); + +int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors); +int bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors); +int bdrv_has_zero_init(BlockDriverState *bs); +int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, + int *pnum); + +void bdrv_set_on_error(BlockDriverState *bs, BlockdevOnError on_read_error, + BlockdevOnError on_write_error); +BlockdevOnError bdrv_get_on_error(BlockDriverState *bs, bool is_read); +BlockErrorAction bdrv_get_error_action(BlockDriverState *bs, bool is_read, int error); +void bdrv_error_action(BlockDriverState *bs, BlockErrorAction action, + bool is_read, int error); +int bdrv_is_read_only(BlockDriverState *bs); +int bdrv_is_sg(BlockDriverState *bs); +int bdrv_enable_write_cache(BlockDriverState *bs); +void bdrv_set_enable_write_cache(BlockDriverState *bs, bool wce); +int bdrv_is_inserted(BlockDriverState *bs); +int bdrv_media_changed(BlockDriverState *bs); +void bdrv_lock_medium(BlockDriverState *bs, bool locked); +void bdrv_eject(BlockDriverState *bs, bool eject_flag); +const char *bdrv_get_format_name(BlockDriverState *bs); +BlockDriverState *bdrv_find(const char *name); +BlockDriverState *bdrv_next(BlockDriverState *bs); +void bdrv_iterate(void (*it)(void *opaque, BlockDriverState *bs), + void *opaque); +int bdrv_is_encrypted(BlockDriverState *bs); +int bdrv_key_required(BlockDriverState *bs); +int bdrv_set_key(BlockDriverState *bs, const char *key); +int bdrv_query_missing_keys(void); +void bdrv_iterate_format(void (*it)(void *opaque, const char *name), + void *opaque); +const char *bdrv_get_device_name(BlockDriverState *bs); +int bdrv_get_flags(BlockDriverState *bs); +int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors); +int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); + +const char *bdrv_get_encrypted_filename(BlockDriverState *bs); +void bdrv_get_backing_filename(BlockDriverState *bs, + char *filename, int filename_size); +void bdrv_get_full_backing_filename(BlockDriverState *bs, + char *dest, size_t sz); +BlockInfo *bdrv_query_info(BlockDriverState *s); +BlockStats *bdrv_query_stats(const BlockDriverState *bs); +int bdrv_can_snapshot(BlockDriverState *bs); +int bdrv_is_snapshot(BlockDriverState *bs); +BlockDriverState *bdrv_snapshots(void); +int bdrv_snapshot_create(BlockDriverState *bs, + QEMUSnapshotInfo *sn_info); +int bdrv_snapshot_goto(BlockDriverState *bs, + const char *snapshot_id); +int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id); +int bdrv_snapshot_list(BlockDriverState *bs, + QEMUSnapshotInfo **psn_info); +int bdrv_snapshot_load_tmp(BlockDriverState *bs, + const char *snapshot_name); +char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn); + +char *get_human_readable_size(char *buf, int buf_size, int64_t size); +int path_is_absolute(const char *path); +void path_combine(char *dest, int dest_size, + const char *base_path, + const char *filename); + +int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf, + int64_t pos, int size); + +int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf, + int64_t pos, int size); + +void bdrv_img_create(const char *filename, const char *fmt, + const char *base_filename, const char *base_fmt, + char *options, uint64_t img_size, int flags, Error **errp); + +void bdrv_set_buffer_alignment(BlockDriverState *bs, int align); +void *qemu_blockalign(BlockDriverState *bs, size_t size); + +#define BDRV_SECTORS_PER_DIRTY_CHUNK 2048 + +void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable); +int bdrv_get_dirty(BlockDriverState *bs, int64_t sector); +void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors); +void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors); +int64_t bdrv_get_next_dirty(BlockDriverState *bs, int64_t sector); +int64_t bdrv_get_dirty_count(BlockDriverState *bs); + +void bdrv_enable_copy_on_read(BlockDriverState *bs); +void bdrv_disable_copy_on_read(BlockDriverState *bs); + +void bdrv_set_in_use(BlockDriverState *bs, int in_use); +int bdrv_in_use(BlockDriverState *bs); + +enum BlockAcctType { + BDRV_ACCT_READ, + BDRV_ACCT_WRITE, + BDRV_ACCT_FLUSH, + BDRV_MAX_IOTYPE, +}; + +typedef struct BlockAcctCookie { + int64_t bytes; + int64_t start_time_ns; + enum BlockAcctType type; +} BlockAcctCookie; + +void bdrv_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie, + int64_t bytes, enum BlockAcctType type); +void bdrv_acct_done(BlockDriverState *bs, BlockAcctCookie *cookie); + +typedef enum { + BLKDBG_L1_UPDATE, + + BLKDBG_L1_GROW_ALLOC_TABLE, + BLKDBG_L1_GROW_WRITE_TABLE, + BLKDBG_L1_GROW_ACTIVATE_TABLE, + + BLKDBG_L2_LOAD, + BLKDBG_L2_UPDATE, + BLKDBG_L2_UPDATE_COMPRESSED, + BLKDBG_L2_ALLOC_COW_READ, + BLKDBG_L2_ALLOC_WRITE, + + BLKDBG_READ_AIO, + BLKDBG_READ_BACKING_AIO, + BLKDBG_READ_COMPRESSED, + + BLKDBG_WRITE_AIO, + BLKDBG_WRITE_COMPRESSED, + + BLKDBG_VMSTATE_LOAD, + BLKDBG_VMSTATE_SAVE, + + BLKDBG_COW_READ, + BLKDBG_COW_WRITE, + + BLKDBG_REFTABLE_LOAD, + BLKDBG_REFTABLE_GROW, + + BLKDBG_REFBLOCK_LOAD, + BLKDBG_REFBLOCK_UPDATE, + BLKDBG_REFBLOCK_UPDATE_PART, + BLKDBG_REFBLOCK_ALLOC, + BLKDBG_REFBLOCK_ALLOC_HOOKUP, + BLKDBG_REFBLOCK_ALLOC_WRITE, + BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS, + BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE, + BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE, + + BLKDBG_CLUSTER_ALLOC, + BLKDBG_CLUSTER_ALLOC_BYTES, + BLKDBG_CLUSTER_FREE, + + BLKDBG_EVENT_MAX, +} BlkDebugEvent; + +#define BLKDBG_EVENT(bs, evt) bdrv_debug_event(bs, evt) +void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event); + +int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event, + const char *tag); +int bdrv_debug_resume(BlockDriverState *bs, const char *tag); +bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag); + +#endif diff --git a/include/block/block_int.h b/include/block/block_int.h new file mode 100644 index 0000000000..d06de2637b --- /dev/null +++ b/include/block/block_int.h @@ -0,0 +1,366 @@ +/* + * QEMU System Emulator block driver + * + * Copyright (c) 2003 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef BLOCK_INT_H +#define BLOCK_INT_H + +#include "block/block.h" +#include "qemu-option.h" +#include "qemu-queue.h" +#include "block/coroutine.h" +#include "qemu-timer.h" +#include "qapi-types.h" +#include "qapi/qmp/qerror.h" +#include "monitor.h" + +#define BLOCK_FLAG_ENCRYPT 1 +#define BLOCK_FLAG_COMPAT6 4 +#define BLOCK_FLAG_LAZY_REFCOUNTS 8 + +#define BLOCK_IO_LIMIT_READ 0 +#define BLOCK_IO_LIMIT_WRITE 1 +#define BLOCK_IO_LIMIT_TOTAL 2 + +#define BLOCK_IO_SLICE_TIME 100000000 +#define NANOSECONDS_PER_SECOND 1000000000.0 + +#define BLOCK_OPT_SIZE "size" +#define BLOCK_OPT_ENCRYPT "encryption" +#define BLOCK_OPT_COMPAT6 "compat6" +#define BLOCK_OPT_BACKING_FILE "backing_file" +#define BLOCK_OPT_BACKING_FMT "backing_fmt" +#define BLOCK_OPT_CLUSTER_SIZE "cluster_size" +#define BLOCK_OPT_TABLE_SIZE "table_size" +#define BLOCK_OPT_PREALLOC "preallocation" +#define BLOCK_OPT_SUBFMT "subformat" +#define BLOCK_OPT_COMPAT_LEVEL "compat" +#define BLOCK_OPT_LAZY_REFCOUNTS "lazy_refcounts" + +typedef struct BdrvTrackedRequest BdrvTrackedRequest; + +typedef struct BlockIOLimit { + int64_t bps[3]; + int64_t iops[3]; +} BlockIOLimit; + +typedef struct BlockIOBaseValue { + uint64_t bytes[2]; + uint64_t ios[2]; +} BlockIOBaseValue; + +struct BlockDriver { + const char *format_name; + int instance_size; + int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename); + int (*bdrv_probe_device)(const char *filename); + + /* For handling image reopen for split or non-split files */ + int (*bdrv_reopen_prepare)(BDRVReopenState *reopen_state, + BlockReopenQueue *queue, Error **errp); + void (*bdrv_reopen_commit)(BDRVReopenState *reopen_state); + void (*bdrv_reopen_abort)(BDRVReopenState *reopen_state); + + int (*bdrv_open)(BlockDriverState *bs, int flags); + int (*bdrv_file_open)(BlockDriverState *bs, const char *filename, int flags); + int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors); + int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors); + void (*bdrv_close)(BlockDriverState *bs); + void (*bdrv_rebind)(BlockDriverState *bs); + int (*bdrv_create)(const char *filename, QEMUOptionParameter *options); + int (*bdrv_set_key)(BlockDriverState *bs, const char *key); + int (*bdrv_make_empty)(BlockDriverState *bs); + /* aio */ + BlockDriverAIOCB *(*bdrv_aio_readv)(BlockDriverState *bs, + int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque); + BlockDriverAIOCB *(*bdrv_aio_writev)(BlockDriverState *bs, + int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque); + BlockDriverAIOCB *(*bdrv_aio_flush)(BlockDriverState *bs, + BlockDriverCompletionFunc *cb, void *opaque); + BlockDriverAIOCB *(*bdrv_aio_discard)(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque); + + int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); + int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); + /* + * Efficiently zero a region of the disk image. Typically an image format + * would use a compact metadata representation to implement this. This + * function pointer may be NULL and .bdrv_co_writev() will be called + * instead. + */ + int coroutine_fn (*bdrv_co_write_zeroes)(BlockDriverState *bs, + int64_t sector_num, int nb_sectors); + int coroutine_fn (*bdrv_co_discard)(BlockDriverState *bs, + int64_t sector_num, int nb_sectors); + int coroutine_fn (*bdrv_co_is_allocated)(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, int *pnum); + + /* + * Invalidate any cached meta-data. + */ + void (*bdrv_invalidate_cache)(BlockDriverState *bs); + + /* + * Flushes all data that was already written to the OS all the way down to + * the disk (for example raw-posix calls fsync()). + */ + int coroutine_fn (*bdrv_co_flush_to_disk)(BlockDriverState *bs); + + /* + * Flushes all internal caches to the OS. The data may still sit in a + * writeback cache of the host OS, but it will survive a crash of the qemu + * process. + */ + int coroutine_fn (*bdrv_co_flush_to_os)(BlockDriverState *bs); + + const char *protocol_name; + int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset); + int64_t (*bdrv_getlength)(BlockDriverState *bs); + int64_t (*bdrv_get_allocated_file_size)(BlockDriverState *bs); + int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors); + + int (*bdrv_snapshot_create)(BlockDriverState *bs, + QEMUSnapshotInfo *sn_info); + int (*bdrv_snapshot_goto)(BlockDriverState *bs, + const char *snapshot_id); + int (*bdrv_snapshot_delete)(BlockDriverState *bs, const char *snapshot_id); + int (*bdrv_snapshot_list)(BlockDriverState *bs, + QEMUSnapshotInfo **psn_info); + int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs, + const char *snapshot_name); + int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi); + + int (*bdrv_save_vmstate)(BlockDriverState *bs, const uint8_t *buf, + int64_t pos, int size); + int (*bdrv_load_vmstate)(BlockDriverState *bs, uint8_t *buf, + int64_t pos, int size); + + int (*bdrv_change_backing_file)(BlockDriverState *bs, + const char *backing_file, const char *backing_fmt); + + /* removable device specific */ + int (*bdrv_is_inserted)(BlockDriverState *bs); + int (*bdrv_media_changed)(BlockDriverState *bs); + void (*bdrv_eject)(BlockDriverState *bs, bool eject_flag); + void (*bdrv_lock_medium)(BlockDriverState *bs, bool locked); + + /* to control generic scsi devices */ + int (*bdrv_ioctl)(BlockDriverState *bs, unsigned long int req, void *buf); + BlockDriverAIOCB *(*bdrv_aio_ioctl)(BlockDriverState *bs, + unsigned long int req, void *buf, + BlockDriverCompletionFunc *cb, void *opaque); + + /* List of options for creating images, terminated by name == NULL */ + QEMUOptionParameter *create_options; + + + /* + * Returns 0 for completed check, -errno for internal errors. + * The check results are stored in result. + */ + int (*bdrv_check)(BlockDriverState* bs, BdrvCheckResult *result, + BdrvCheckMode fix); + + void (*bdrv_debug_event)(BlockDriverState *bs, BlkDebugEvent event); + + /* TODO Better pass a option string/QDict/QemuOpts to add any rule? */ + int (*bdrv_debug_breakpoint)(BlockDriverState *bs, const char *event, + const char *tag); + int (*bdrv_debug_resume)(BlockDriverState *bs, const char *tag); + bool (*bdrv_debug_is_suspended)(BlockDriverState *bs, const char *tag); + + /* + * Returns 1 if newly created images are guaranteed to contain only + * zeros, 0 otherwise. + */ + int (*bdrv_has_zero_init)(BlockDriverState *bs); + + QLIST_ENTRY(BlockDriver) list; +}; + +/* + * Note: the function bdrv_append() copies and swaps contents of + * BlockDriverStates, so if you add new fields to this struct, please + * inspect bdrv_append() to determine if the new fields need to be + * copied as well. + */ +struct BlockDriverState { + int64_t total_sectors; /* if we are reading a disk image, give its + size in sectors */ + int read_only; /* if true, the media is read only */ + int open_flags; /* flags used to open the file, re-used for re-open */ + int encrypted; /* if true, the media is encrypted */ + int valid_key; /* if true, a valid encryption key has been set */ + int sg; /* if true, the device is a /dev/sg* */ + int copy_on_read; /* if true, copy read backing sectors into image + note this is a reference count */ + + BlockDriver *drv; /* NULL means no media */ + void *opaque; + + void *dev; /* attached device model, if any */ + /* TODO change to DeviceState when all users are qdevified */ + const BlockDevOps *dev_ops; + void *dev_opaque; + + char filename[1024]; + char backing_file[1024]; /* if non zero, the image is a diff of + this file image */ + char backing_format[16]; /* if non-zero and backing_file exists */ + int is_temporary; + + BlockDriverState *backing_hd; + BlockDriverState *file; + + NotifierList close_notifiers; + + /* number of in-flight copy-on-read requests */ + unsigned int copy_on_read_in_flight; + + /* the time for latest disk I/O */ + int64_t slice_time; + int64_t slice_start; + int64_t slice_end; + BlockIOLimit io_limits; + BlockIOBaseValue io_base; + CoQueue throttled_reqs; + QEMUTimer *block_timer; + bool io_limits_enabled; + + /* I/O stats (display with "info blockstats"). */ + uint64_t nr_bytes[BDRV_MAX_IOTYPE]; + uint64_t nr_ops[BDRV_MAX_IOTYPE]; + uint64_t total_time_ns[BDRV_MAX_IOTYPE]; + uint64_t wr_highest_sector; + + /* Whether the disk can expand beyond total_sectors */ + int growable; + + /* the memory alignment required for the buffers handled by this driver */ + int buffer_alignment; + + /* do we need to tell the quest if we have a volatile write cache? */ + int enable_write_cache; + + /* NOTE: the following infos are only hints for real hardware + drivers. They are not used by the block driver */ + BlockdevOnError on_read_error, on_write_error; + bool iostatus_enabled; + BlockDeviceIoStatus iostatus; + char device_name[32]; + unsigned long *dirty_bitmap; + int64_t dirty_count; + int in_use; /* users other than guest access, eg. block migration */ + QTAILQ_ENTRY(BlockDriverState) list; + + QLIST_HEAD(, BdrvTrackedRequest) tracked_requests; + + /* long-running background operation */ + BlockJob *job; + +}; + +int get_tmp_filename(char *filename, int size); + +void bdrv_set_io_limits(BlockDriverState *bs, + BlockIOLimit *io_limits); + +#ifdef _WIN32 +int is_windows_drive(const char *filename); +#endif +void bdrv_emit_qmp_error_event(const BlockDriverState *bdrv, + enum MonitorEvent ev, + BlockErrorAction action, bool is_read); + +/** + * stream_start: + * @bs: Block device to operate on. + * @base: Block device that will become the new base, or %NULL to + * flatten the whole backing file chain onto @bs. + * @base_id: The file name that will be written to @bs as the new + * backing file if the job completes. Ignored if @base is %NULL. + * @speed: The maximum speed, in bytes per second, or 0 for unlimited. + * @on_error: The action to take upon error. + * @cb: Completion function for the job. + * @opaque: Opaque pointer value passed to @cb. + * @errp: Error object. + * + * Start a streaming operation on @bs. Clusters that are unallocated + * in @bs, but allocated in any image between @base and @bs (both + * exclusive) will be written to @bs. At the end of a successful + * streaming job, the backing file of @bs will be changed to + * @base_id in the written image and to @base in the live BlockDriverState. + */ +void stream_start(BlockDriverState *bs, BlockDriverState *base, + const char *base_id, int64_t speed, BlockdevOnError on_error, + BlockDriverCompletionFunc *cb, + void *opaque, Error **errp); + +/** + * commit_start: + * @bs: Top Block device + * @base: Block device that will be written into, and become the new top + * @speed: The maximum speed, in bytes per second, or 0 for unlimited. + * @on_error: The action to take upon error. + * @cb: Completion function for the job. + * @opaque: Opaque pointer value passed to @cb. + * @errp: Error object. + * + */ +void commit_start(BlockDriverState *bs, BlockDriverState *base, + BlockDriverState *top, int64_t speed, + BlockdevOnError on_error, BlockDriverCompletionFunc *cb, + void *opaque, Error **errp); + +/* + * mirror_start: + * @bs: Block device to operate on. + * @target: Block device to write to. + * @speed: The maximum speed, in bytes per second, or 0 for unlimited. + * @mode: Whether to collapse all images in the chain to the target. + * @on_source_error: The action to take upon error reading from the source. + * @on_target_error: The action to take upon error writing to the target. + * @cb: Completion function for the job. + * @opaque: Opaque pointer value passed to @cb. + * @errp: Error object. + * + * Start a mirroring operation on @bs. Clusters that are allocated + * in @bs will be written to @bs until the job is cancelled or + * manually completed. At the end of a successful mirroring job, + * @bs will be switched to read from @target. + */ +void mirror_start(BlockDriverState *bs, BlockDriverState *target, + int64_t speed, MirrorSyncMode mode, + BlockdevOnError on_source_error, + BlockdevOnError on_target_error, + BlockDriverCompletionFunc *cb, + void *opaque, Error **errp); + +#endif /* BLOCK_INT_H */ diff --git a/include/block/blockjob.h b/include/block/blockjob.h new file mode 100644 index 0000000000..c290d07bba --- /dev/null +++ b/include/block/blockjob.h @@ -0,0 +1,278 @@ +/* + * Declarations for long-running block device operations + * + * Copyright (c) 2011 IBM Corp. + * Copyright (c) 2012 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef BLOCKJOB_H +#define BLOCKJOB_H 1 + +#include "block/block.h" + +/** + * BlockJobType: + * + * A class type for block job objects. + */ +typedef struct BlockJobType { + /** Derived BlockJob struct size */ + size_t instance_size; + + /** String describing the operation, part of query-block-jobs QMP API */ + const char *job_type; + + /** Optional callback for job types that support setting a speed limit */ + void (*set_speed)(BlockJob *job, int64_t speed, Error **errp); + + /** Optional callback for job types that need to forward I/O status reset */ + void (*iostatus_reset)(BlockJob *job); + + /** + * Optional callback for job types whose completion must be triggered + * manually. + */ + void (*complete)(BlockJob *job, Error **errp); +} BlockJobType; + +/** + * BlockJob: + * + * Long-running operation on a BlockDriverState. + */ +struct BlockJob { + /** The job type, including the job vtable. */ + const BlockJobType *job_type; + + /** The block device on which the job is operating. */ + BlockDriverState *bs; + + /** + * The coroutine that executes the job. If not NULL, it is + * reentered when busy is false and the job is cancelled. + */ + Coroutine *co; + + /** + * Set to true if the job should cancel itself. The flag must + * always be tested just before toggling the busy flag from false + * to true. After a job has been cancelled, it should only yield + * if #qemu_aio_wait will ("sooner or later") reenter the coroutine. + */ + bool cancelled; + + /** + * Set to true if the job is either paused, or will pause itself + * as soon as possible (if busy == true). + */ + bool paused; + + /** + * Set to false by the job while it is in a quiescent state, where + * no I/O is pending and the job has yielded on any condition + * that is not detected by #qemu_aio_wait, such as a timer. + */ + bool busy; + + /** Status that is published by the query-block-jobs QMP API */ + BlockDeviceIoStatus iostatus; + + /** Offset that is published by the query-block-jobs QMP API */ + int64_t offset; + + /** Length that is published by the query-block-jobs QMP API */ + int64_t len; + + /** Speed that was set with @block_job_set_speed. */ + int64_t speed; + + /** The completion function that will be called when the job completes. */ + BlockDriverCompletionFunc *cb; + + /** The opaque value that is passed to the completion function. */ + void *opaque; +}; + +/** + * block_job_create: + * @job_type: The class object for the newly-created job. + * @bs: The block + * @speed: The maximum speed, in bytes per second, or 0 for unlimited. + * @cb: Completion function for the job. + * @opaque: Opaque pointer value passed to @cb. + * @errp: Error object. + * + * Create a new long-running block device job and return it. The job + * will call @cb asynchronously when the job completes. Note that + * @bs may have been closed at the time the @cb it is called. If + * this is the case, the job may be reported as either cancelled or + * completed. + * + * This function is not part of the public job interface; it should be + * called from a wrapper that is specific to the job type. + */ +void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs, + int64_t speed, BlockDriverCompletionFunc *cb, + void *opaque, Error **errp); + +/** + * block_job_sleep_ns: + * @job: The job that calls the function. + * @clock: The clock to sleep on. + * @ns: How many nanoseconds to stop for. + * + * Put the job to sleep (assuming that it wasn't canceled) for @ns + * nanoseconds. Canceling the job will interrupt the wait immediately. + */ +void block_job_sleep_ns(BlockJob *job, QEMUClock *clock, int64_t ns); + +/** + * block_job_completed: + * @job: The job being completed. + * @ret: The status code. + * + * Call the completion function that was registered at creation time, and + * free @job. + */ +void block_job_completed(BlockJob *job, int ret); + +/** + * block_job_set_speed: + * @job: The job to set the speed for. + * @speed: The new value + * @errp: Error object. + * + * Set a rate-limiting parameter for the job; the actual meaning may + * vary depending on the job type. + */ +void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp); + +/** + * block_job_cancel: + * @job: The job to be canceled. + * + * Asynchronously cancel the specified job. + */ +void block_job_cancel(BlockJob *job); + +/** + * block_job_complete: + * @job: The job to be completed. + * @errp: Error object. + * + * Asynchronously complete the specified job. + */ +void block_job_complete(BlockJob *job, Error **errp); + +/** + * block_job_is_cancelled: + * @job: The job being queried. + * + * Returns whether the job is scheduled for cancellation. + */ +bool block_job_is_cancelled(BlockJob *job); + +/** + * block_job_query: + * @job: The job to get information about. + * + * Return information about a job. + */ +BlockJobInfo *block_job_query(BlockJob *job); + +/** + * block_job_pause: + * @job: The job to be paused. + * + * Asynchronously pause the specified job. + */ +void block_job_pause(BlockJob *job); + +/** + * block_job_resume: + * @job: The job to be resumed. + * + * Resume the specified job. + */ +void block_job_resume(BlockJob *job); + +/** + * qobject_from_block_job: + * @job: The job whose information is requested. + * + * Return a QDict corresponding to @job's query-block-jobs entry. + */ +QObject *qobject_from_block_job(BlockJob *job); + +/** + * block_job_ready: + * @job: The job which is now ready to complete. + * + * Send a BLOCK_JOB_READY event for the specified job. + */ +void block_job_ready(BlockJob *job); + +/** + * block_job_is_paused: + * @job: The job being queried. + * + * Returns whether the job is currently paused, or will pause + * as soon as it reaches a sleeping point. + */ +bool block_job_is_paused(BlockJob *job); + +/** + * block_job_cancel_sync: + * @job: The job to be canceled. + * + * Synchronously cancel the job. The completion callback is called + * before the function returns. The job may actually complete + * instead of canceling itself; the circumstances under which this + * happens depend on the kind of job that is active. + * + * Returns the return value from the job if the job actually completed + * during the call, or -ECANCELED if it was canceled. + */ +int block_job_cancel_sync(BlockJob *job); + +/** + * block_job_iostatus_reset: + * @job: The job whose I/O status should be reset. + * + * Reset I/O status on @job and on BlockDriverState objects it uses, + * other than job->bs. + */ +void block_job_iostatus_reset(BlockJob *job); + +/** + * block_job_error_action: + * @job: The job to signal an error for. + * @bs: The block device on which to set an I/O error. + * @on_err: The error action setting. + * @is_read: Whether the operation was a read. + * @error: The error that was reported. + * + * Report an I/O error for a block job and possibly stop the VM. Return the + * action that was selected based on @on_err and @error. + */ +BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs, + BlockdevOnError on_err, + int is_read, int error); +#endif diff --git a/include/block/coroutine.h b/include/block/coroutine.h new file mode 100644 index 0000000000..34c15d4116 --- /dev/null +++ b/include/block/coroutine.h @@ -0,0 +1,211 @@ +/* + * QEMU coroutine implementation + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Stefan Hajnoczi + * Kevin Wolf + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#ifndef QEMU_COROUTINE_H +#define QEMU_COROUTINE_H + +#include +#include "qemu-queue.h" +#include "qemu-timer.h" + +/** + * Coroutines are a mechanism for stack switching and can be used for + * cooperative userspace threading. These functions provide a simple but + * useful flavor of coroutines that is suitable for writing sequential code, + * rather than callbacks, for operations that need to give up control while + * waiting for events to complete. + * + * These functions are re-entrant and may be used outside the global mutex. + */ + +/** + * Mark a function that executes in coroutine context + * + * Functions that execute in coroutine context cannot be called directly from + * normal functions. In the future it would be nice to enable compiler or + * static checker support for catching such errors. This annotation might make + * it possible and in the meantime it serves as documentation. + * + * For example: + * + * static void coroutine_fn foo(void) { + * .... + * } + */ +#define coroutine_fn + +typedef struct Coroutine Coroutine; + +/** + * Coroutine entry point + * + * When the coroutine is entered for the first time, opaque is passed in as an + * argument. + * + * When this function returns, the coroutine is destroyed automatically and + * execution continues in the caller who last entered the coroutine. + */ +typedef void coroutine_fn CoroutineEntry(void *opaque); + +/** + * Create a new coroutine + * + * Use qemu_coroutine_enter() to actually transfer control to the coroutine. + */ +Coroutine *qemu_coroutine_create(CoroutineEntry *entry); + +/** + * Transfer control to a coroutine + * + * The opaque argument is passed as the argument to the entry point when + * entering the coroutine for the first time. It is subsequently ignored. + */ +void qemu_coroutine_enter(Coroutine *coroutine, void *opaque); + +/** + * Transfer control back to a coroutine's caller + * + * This function does not return until the coroutine is re-entered using + * qemu_coroutine_enter(). + */ +void coroutine_fn qemu_coroutine_yield(void); + +/** + * Get the currently executing coroutine + */ +Coroutine *coroutine_fn qemu_coroutine_self(void); + +/** + * Return whether or not currently inside a coroutine + * + * This can be used to write functions that work both when in coroutine context + * and when not in coroutine context. Note that such functions cannot use the + * coroutine_fn annotation since they work outside coroutine context. + */ +bool qemu_in_coroutine(void); + + + +/** + * CoQueues are a mechanism to queue coroutines in order to continue executing + * them later. They provide the fundamental primitives on which coroutine locks + * are built. + */ +typedef struct CoQueue { + QTAILQ_HEAD(, Coroutine) entries; +} CoQueue; + +/** + * Initialise a CoQueue. This must be called before any other operation is used + * on the CoQueue. + */ +void qemu_co_queue_init(CoQueue *queue); + +/** + * Adds the current coroutine to the CoQueue and transfers control to the + * caller of the coroutine. + */ +void coroutine_fn qemu_co_queue_wait(CoQueue *queue); + +/** + * Adds the current coroutine to the head of the CoQueue and transfers control to the + * caller of the coroutine. + */ +void coroutine_fn qemu_co_queue_wait_insert_head(CoQueue *queue); + +/** + * Restarts the next coroutine in the CoQueue and removes it from the queue. + * + * Returns true if a coroutine was restarted, false if the queue is empty. + */ +bool qemu_co_queue_next(CoQueue *queue); + +/** + * Restarts all coroutines in the CoQueue and leaves the queue empty. + */ +void qemu_co_queue_restart_all(CoQueue *queue); + +/** + * Checks if the CoQueue is empty. + */ +bool qemu_co_queue_empty(CoQueue *queue); + + +/** + * Provides a mutex that can be used to synchronise coroutines + */ +typedef struct CoMutex { + bool locked; + CoQueue queue; +} CoMutex; + +/** + * Initialises a CoMutex. This must be called before any other operation is used + * on the CoMutex. + */ +void qemu_co_mutex_init(CoMutex *mutex); + +/** + * Locks the mutex. If the lock cannot be taken immediately, control is + * transferred to the caller of the current coroutine. + */ +void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex); + +/** + * Unlocks the mutex and schedules the next coroutine that was waiting for this + * lock to be run. + */ +void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex); + +typedef struct CoRwlock { + bool writer; + int reader; + CoQueue queue; +} CoRwlock; + +/** + * Initialises a CoRwlock. This must be called before any other operation + * is used on the CoRwlock + */ +void qemu_co_rwlock_init(CoRwlock *lock); + +/** + * Read locks the CoRwlock. If the lock cannot be taken immediately because + * of a parallel writer, control is transferred to the caller of the current + * coroutine. + */ +void qemu_co_rwlock_rdlock(CoRwlock *lock); + +/** + * Write Locks the mutex. If the lock cannot be taken immediately because + * of a parallel reader, control is transferred to the caller of the current + * coroutine. + */ +void qemu_co_rwlock_wrlock(CoRwlock *lock); + +/** + * Unlocks the read/write lock and schedules the next coroutine that was + * waiting for this lock to be run. + */ +void qemu_co_rwlock_unlock(CoRwlock *lock); + +/** + * Yield the coroutine for a given duration + * + * Note this function uses timers and hence only works when a main loop is in + * use. See main-loop.h and do not use from qemu-tool programs. + */ +void coroutine_fn co_sleep_ns(QEMUClock *clock, int64_t ns); + +#endif /* QEMU_COROUTINE_H */ diff --git a/include/block/coroutine_int.h b/include/block/coroutine_int.h new file mode 100644 index 0000000000..282a3ceda6 --- /dev/null +++ b/include/block/coroutine_int.h @@ -0,0 +1,49 @@ +/* + * Coroutine internals + * + * Copyright (c) 2011 Kevin Wolf + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef QEMU_COROUTINE_INT_H +#define QEMU_COROUTINE_INT_H + +#include "qemu-queue.h" +#include "block/coroutine.h" + +typedef enum { + COROUTINE_YIELD = 1, + COROUTINE_TERMINATE = 2, +} CoroutineAction; + +struct Coroutine { + CoroutineEntry *entry; + void *entry_arg; + Coroutine *caller; + QSLIST_ENTRY(Coroutine) pool_next; + QTAILQ_ENTRY(Coroutine) co_queue_next; +}; + +Coroutine *qemu_coroutine_new(void); +void qemu_coroutine_delete(Coroutine *co); +CoroutineAction qemu_coroutine_switch(Coroutine *from, Coroutine *to, + CoroutineAction action); + +#endif diff --git a/include/block/nbd.h b/include/block/nbd.h new file mode 100644 index 0000000000..344f05b794 --- /dev/null +++ b/include/block/nbd.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2005 Anthony Liguori + * + * Network Block Device + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef NBD_H +#define NBD_H + +#include + +#include "qemu-common.h" + +struct nbd_request { + uint32_t magic; + uint32_t type; + uint64_t handle; + uint64_t from; + uint32_t len; +} QEMU_PACKED; + +struct nbd_reply { + uint32_t magic; + uint32_t error; + uint64_t handle; +} QEMU_PACKED; + +#define NBD_FLAG_HAS_FLAGS (1 << 0) /* Flags are there */ +#define NBD_FLAG_READ_ONLY (1 << 1) /* Device is read-only */ +#define NBD_FLAG_SEND_FLUSH (1 << 2) /* Send FLUSH */ +#define NBD_FLAG_SEND_FUA (1 << 3) /* Send FUA (Force Unit Access) */ +#define NBD_FLAG_ROTATIONAL (1 << 4) /* Use elevator algorithm - rotational media */ +#define NBD_FLAG_SEND_TRIM (1 << 5) /* Send TRIM (discard) */ + +#define NBD_CMD_MASK_COMMAND 0x0000ffff +#define NBD_CMD_FLAG_FUA (1 << 16) + +enum { + NBD_CMD_READ = 0, + NBD_CMD_WRITE = 1, + NBD_CMD_DISC = 2, + NBD_CMD_FLUSH = 3, + NBD_CMD_TRIM = 4 +}; + +#define NBD_DEFAULT_PORT 10809 + +#define NBD_BUFFER_SIZE (1024*1024) + +ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read); +int tcp_socket_outgoing(const char *address, uint16_t port); +int tcp_socket_incoming(const char *address, uint16_t port); +int tcp_socket_outgoing_spec(const char *address_and_port); +int tcp_socket_incoming_spec(const char *address_and_port); +int unix_socket_outgoing(const char *path); +int unix_socket_incoming(const char *path); + +int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags, + off_t *size, size_t *blocksize); +int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize); +ssize_t nbd_send_request(int csock, struct nbd_request *request); +ssize_t nbd_receive_reply(int csock, struct nbd_reply *reply); +int nbd_client(int fd); +int nbd_disconnect(int fd); + +typedef struct NBDExport NBDExport; +typedef struct NBDClient NBDClient; + +NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, + off_t size, uint32_t nbdflags, + void (*close)(NBDExport *)); +void nbd_export_close(NBDExport *exp); +void nbd_export_get(NBDExport *exp); +void nbd_export_put(NBDExport *exp); + +BlockDriverState *nbd_export_get_blockdev(NBDExport *exp); + +NBDExport *nbd_export_find(const char *name); +void nbd_export_set_name(NBDExport *exp, const char *name); +void nbd_export_close_all(void); + +NBDClient *nbd_client_new(NBDExport *exp, int csock, + void (*close)(NBDClient *)); +void nbd_client_close(NBDClient *client); +void nbd_client_get(NBDClient *client); +void nbd_client_put(NBDClient *client); + +#endif diff --git a/include/block/thread-pool.h b/include/block/thread-pool.h new file mode 100644 index 0000000000..a87b287081 --- /dev/null +++ b/include/block/thread-pool.h @@ -0,0 +1,34 @@ +/* + * QEMU block layer thread pool + * + * Copyright IBM, Corp. 2008 + * Copyright Red Hat, Inc. 2012 + * + * Authors: + * Anthony Liguori + * Paolo Bonzini + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#ifndef QEMU_THREAD_POOL_H +#define QEMU_THREAD_POOL_H 1 + +#include "qemu-common.h" +#include "qemu-queue.h" +#include "qemu-thread.h" +#include "block/coroutine.h" +#include "block/block_int.h" + +typedef int ThreadPoolFunc(void *opaque); + +BlockDriverAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg, + BlockDriverCompletionFunc *cb, void *opaque); +int coroutine_fn thread_pool_submit_co(ThreadPoolFunc *func, void *arg); +void thread_pool_submit(ThreadPoolFunc *func, void *arg); + +#endif diff --git a/iohandler.c b/iohandler.c index 258f42d8d2..cf8276dffc 100644 --- a/iohandler.c +++ b/iohandler.c @@ -25,7 +25,7 @@ #include "config-host.h" #include "qemu-common.h" #include "qemu-queue.h" -#include "qemu-aio.h" +#include "block/aio.h" #include "main-loop.h" #ifndef _WIN32 diff --git a/main-loop.c b/main-loop.c index 7dba6f6e35..f9006118ad 100644 --- a/main-loop.c +++ b/main-loop.c @@ -26,7 +26,7 @@ #include "qemu-timer.h" #include "slirp/slirp.h" #include "main-loop.h" -#include "qemu-aio.h" +#include "block/aio.h" #ifndef _WIN32 diff --git a/main-loop.h b/main-loop.h index 326c74269c..e8059c3d0a 100644 --- a/main-loop.h +++ b/main-loop.h @@ -25,7 +25,7 @@ #ifndef QEMU_MAIN_LOOP_H #define QEMU_MAIN_LOOP_H 1 -#include "qemu-aio.h" +#include "block/aio.h" #define SIG_IPI SIGUSR1 diff --git a/migration-exec.c b/migration-exec.c index b4a3ca3921..3e55b7792d 100644 --- a/migration-exec.c +++ b/migration-exec.c @@ -19,7 +19,7 @@ #include "qemu_socket.h" #include "migration.h" #include "buffered_file.h" -#include "block.h" +#include "block/block.h" #include #include diff --git a/migration-fd.c b/migration-fd.c index 6d42287913..e86228823f 100644 --- a/migration-fd.c +++ b/migration-fd.c @@ -18,7 +18,7 @@ #include "migration.h" #include "monitor.h" #include "buffered_file.h" -#include "block.h" +#include "block/block.h" #include "qemu_socket.h" //#define DEBUG_MIGRATION_FD diff --git a/migration-tcp.c b/migration-tcp.c index a9bb817d99..07f51f2aef 100644 --- a/migration-tcp.c +++ b/migration-tcp.c @@ -17,7 +17,7 @@ #include "qemu_socket.h" #include "migration.h" #include "buffered_file.h" -#include "block.h" +#include "block/block.h" //#define DEBUG_MIGRATION_TCP diff --git a/migration-unix.c b/migration-unix.c index e58e8bc15b..1b9c461083 100644 --- a/migration-unix.c +++ b/migration-unix.c @@ -17,7 +17,7 @@ #include "qemu_socket.h" #include "migration.h" #include "buffered_file.h" -#include "block.h" +#include "block/block.h" //#define DEBUG_MIGRATION_UNIX diff --git a/migration.c b/migration.c index 73ce170ddf..1fce152548 100644 --- a/migration.c +++ b/migration.c @@ -18,7 +18,7 @@ #include "monitor.h" #include "buffered_file.h" #include "sysemu.h" -#include "block.h" +#include "block/block.h" #include "qemu_socket.h" #include "block-migration.h" #include "qmp-commands.h" diff --git a/monitor.h b/monitor.h index 7c29d9db34..9e96e83f5f 100644 --- a/monitor.h +++ b/monitor.h @@ -4,7 +4,7 @@ #include "qemu-common.h" #include "qapi/qmp/qerror.h" #include "qapi/qmp/qdict.h" -#include "block.h" +#include "block/block.h" #include "readline.h" extern Monitor *cur_mon; diff --git a/nbd.c b/nbd.c index 01976e8e33..04ff0a1d44 100644 --- a/nbd.c +++ b/nbd.c @@ -16,10 +16,10 @@ * along with this program; if not, see . */ -#include "nbd.h" -#include "block.h" +#include "block/nbd.h" +#include "block/block.h" -#include "qemu-coroutine.h" +#include "block/coroutine.h" #include #include diff --git a/nbd.h b/nbd.h deleted file mode 100644 index 344f05b794..0000000000 --- a/nbd.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2005 Anthony Liguori - * - * Network Block Device - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -#ifndef NBD_H -#define NBD_H - -#include - -#include "qemu-common.h" - -struct nbd_request { - uint32_t magic; - uint32_t type; - uint64_t handle; - uint64_t from; - uint32_t len; -} QEMU_PACKED; - -struct nbd_reply { - uint32_t magic; - uint32_t error; - uint64_t handle; -} QEMU_PACKED; - -#define NBD_FLAG_HAS_FLAGS (1 << 0) /* Flags are there */ -#define NBD_FLAG_READ_ONLY (1 << 1) /* Device is read-only */ -#define NBD_FLAG_SEND_FLUSH (1 << 2) /* Send FLUSH */ -#define NBD_FLAG_SEND_FUA (1 << 3) /* Send FUA (Force Unit Access) */ -#define NBD_FLAG_ROTATIONAL (1 << 4) /* Use elevator algorithm - rotational media */ -#define NBD_FLAG_SEND_TRIM (1 << 5) /* Send TRIM (discard) */ - -#define NBD_CMD_MASK_COMMAND 0x0000ffff -#define NBD_CMD_FLAG_FUA (1 << 16) - -enum { - NBD_CMD_READ = 0, - NBD_CMD_WRITE = 1, - NBD_CMD_DISC = 2, - NBD_CMD_FLUSH = 3, - NBD_CMD_TRIM = 4 -}; - -#define NBD_DEFAULT_PORT 10809 - -#define NBD_BUFFER_SIZE (1024*1024) - -ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read); -int tcp_socket_outgoing(const char *address, uint16_t port); -int tcp_socket_incoming(const char *address, uint16_t port); -int tcp_socket_outgoing_spec(const char *address_and_port); -int tcp_socket_incoming_spec(const char *address_and_port); -int unix_socket_outgoing(const char *path); -int unix_socket_incoming(const char *path); - -int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags, - off_t *size, size_t *blocksize); -int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize); -ssize_t nbd_send_request(int csock, struct nbd_request *request); -ssize_t nbd_receive_reply(int csock, struct nbd_reply *reply); -int nbd_client(int fd); -int nbd_disconnect(int fd); - -typedef struct NBDExport NBDExport; -typedef struct NBDClient NBDClient; - -NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, - off_t size, uint32_t nbdflags, - void (*close)(NBDExport *)); -void nbd_export_close(NBDExport *exp); -void nbd_export_get(NBDExport *exp); -void nbd_export_put(NBDExport *exp); - -BlockDriverState *nbd_export_get_blockdev(NBDExport *exp); - -NBDExport *nbd_export_find(const char *name); -void nbd_export_set_name(NBDExport *exp, const char *name); -void nbd_export_close_all(void); - -NBDClient *nbd_client_new(NBDExport *exp, int csock, - void (*close)(NBDClient *)); -void nbd_client_close(NBDClient *client); -void nbd_client_get(NBDClient *client); -void nbd_client_put(NBDClient *client); - -#endif diff --git a/qemu-aio.h b/qemu-aio.h deleted file mode 100644 index 31884a8f16..0000000000 --- a/qemu-aio.h +++ /dev/null @@ -1,240 +0,0 @@ -/* - * QEMU aio implementation - * - * Copyright IBM, Corp. 2008 - * - * Authors: - * Anthony Liguori - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - */ - -#ifndef QEMU_AIO_H -#define QEMU_AIO_H - -#include "qemu-common.h" -#include "qemu-queue.h" -#include "event_notifier.h" - -typedef struct BlockDriverAIOCB BlockDriverAIOCB; -typedef void BlockDriverCompletionFunc(void *opaque, int ret); - -typedef struct AIOCBInfo { - void (*cancel)(BlockDriverAIOCB *acb); - size_t aiocb_size; -} AIOCBInfo; - -struct BlockDriverAIOCB { - const AIOCBInfo *aiocb_info; - BlockDriverState *bs; - BlockDriverCompletionFunc *cb; - void *opaque; -}; - -void *qemu_aio_get(const AIOCBInfo *aiocb_info, BlockDriverState *bs, - BlockDriverCompletionFunc *cb, void *opaque); -void qemu_aio_release(void *p); - -typedef struct AioHandler AioHandler; -typedef void QEMUBHFunc(void *opaque); -typedef void IOHandler(void *opaque); - -typedef struct AioContext { - GSource source; - - /* The list of registered AIO handlers */ - QLIST_HEAD(, AioHandler) aio_handlers; - - /* This is a simple lock used to protect the aio_handlers list. - * Specifically, it's used to ensure that no callbacks are removed while - * we're walking and dispatching callbacks. - */ - int walking_handlers; - - /* Anchor of the list of Bottom Halves belonging to the context */ - struct QEMUBH *first_bh; - - /* A simple lock used to protect the first_bh list, and ensure that - * no callbacks are removed while we're walking and dispatching callbacks. - */ - int walking_bh; - - /* Used for aio_notify. */ - EventNotifier notifier; -} AioContext; - -/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */ -typedef int (AioFlushEventNotifierHandler)(EventNotifier *e); - -/** - * aio_context_new: Allocate a new AioContext. - * - * AioContext provide a mini event-loop that can be waited on synchronously. - * They also provide bottom halves, a service to execute a piece of code - * as soon as possible. - */ -AioContext *aio_context_new(void); - -/** - * aio_context_ref: - * @ctx: The AioContext to operate on. - * - * Add a reference to an AioContext. - */ -void aio_context_ref(AioContext *ctx); - -/** - * aio_context_unref: - * @ctx: The AioContext to operate on. - * - * Drop a reference to an AioContext. - */ -void aio_context_unref(AioContext *ctx); - -/** - * aio_bh_new: Allocate a new bottom half structure. - * - * Bottom halves are lightweight callbacks whose invocation is guaranteed - * to be wait-free, thread-safe and signal-safe. The #QEMUBH structure - * is opaque and must be allocated prior to its use. - */ -QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque); - -/** - * aio_notify: Force processing of pending events. - * - * Similar to signaling a condition variable, aio_notify forces - * aio_wait to exit, so that the next call will re-examine pending events. - * The caller of aio_notify will usually call aio_wait again very soon, - * or go through another iteration of the GLib main loop. Hence, aio_notify - * also has the side effect of recalculating the sets of file descriptors - * that the main loop waits for. - * - * Calling aio_notify is rarely necessary, because for example scheduling - * a bottom half calls it already. - */ -void aio_notify(AioContext *ctx); - -/** - * aio_bh_poll: Poll bottom halves for an AioContext. - * - * These are internal functions used by the QEMU main loop. - */ -int aio_bh_poll(AioContext *ctx); - -/** - * qemu_bh_schedule: Schedule a bottom half. - * - * Scheduling a bottom half interrupts the main loop and causes the - * execution of the callback that was passed to qemu_bh_new. - * - * Bottom halves that are scheduled from a bottom half handler are instantly - * invoked. This can create an infinite loop if a bottom half handler - * schedules itself. - * - * @bh: The bottom half to be scheduled. - */ -void qemu_bh_schedule(QEMUBH *bh); - -/** - * qemu_bh_cancel: Cancel execution of a bottom half. - * - * Canceling execution of a bottom half undoes the effect of calls to - * qemu_bh_schedule without freeing its resources yet. While cancellation - * itself is also wait-free and thread-safe, it can of course race with the - * loop that executes bottom halves unless you are holding the iothread - * mutex. This makes it mostly useless if you are not holding the mutex. - * - * @bh: The bottom half to be canceled. - */ -void qemu_bh_cancel(QEMUBH *bh); - -/** - *qemu_bh_delete: Cancel execution of a bottom half and free its resources. - * - * Deleting a bottom half frees the memory that was allocated for it by - * qemu_bh_new. It also implies canceling the bottom half if it was - * scheduled. - * - * @bh: The bottom half to be deleted. - */ -void qemu_bh_delete(QEMUBH *bh); - -/* Return whether there are any pending callbacks from the GSource - * attached to the AioContext. - * - * This is used internally in the implementation of the GSource. - */ -bool aio_pending(AioContext *ctx); - -/* Progress in completing AIO work to occur. This can issue new pending - * aio as a result of executing I/O completion or bh callbacks. - * - * If there is no pending AIO operation or completion (bottom half), - * return false. If there are pending bottom halves, return true. - * - * If there are no pending bottom halves, but there are pending AIO - * operations, it may not be possible to make any progress without - * blocking. If @blocking is true, this function will wait until one - * or more AIO events have completed, to ensure something has moved - * before returning. - * - * If @blocking is false, this function will also return false if the - * function cannot make any progress without blocking. - */ -bool aio_poll(AioContext *ctx, bool blocking); - -#ifdef CONFIG_POSIX -/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */ -typedef int (AioFlushHandler)(void *opaque); - -/* Register a file descriptor and associated callbacks. Behaves very similarly - * to qemu_set_fd_handler2. Unlike qemu_set_fd_handler2, these callbacks will - * be invoked when using qemu_aio_wait(). - * - * Code that invokes AIO completion functions should rely on this function - * instead of qemu_set_fd_handler[2]. - */ -void aio_set_fd_handler(AioContext *ctx, - int fd, - IOHandler *io_read, - IOHandler *io_write, - AioFlushHandler *io_flush, - void *opaque); -#endif - -/* Register an event notifier and associated callbacks. Behaves very similarly - * to event_notifier_set_handler. Unlike event_notifier_set_handler, these callbacks - * will be invoked when using qemu_aio_wait(). - * - * Code that invokes AIO completion functions should rely on this function - * instead of event_notifier_set_handler. - */ -void aio_set_event_notifier(AioContext *ctx, - EventNotifier *notifier, - EventNotifierHandler *io_read, - AioFlushEventNotifierHandler *io_flush); - -/* Return a GSource that lets the main loop poll the file descriptors attached - * to this AioContext. - */ -GSource *aio_get_g_source(AioContext *ctx); - -/* Functions to operate on the main QEMU AioContext. */ - -bool qemu_aio_wait(void); -void qemu_aio_set_event_notifier(EventNotifier *notifier, - EventNotifierHandler *io_read, - AioFlushEventNotifierHandler *io_flush); - -#ifdef CONFIG_POSIX -void qemu_aio_set_fd_handler(int fd, - IOHandler *io_read, - IOHandler *io_write, - AioFlushHandler *io_flush, - void *opaque); -#endif - -#endif diff --git a/qemu-char.h b/qemu-char.h index 3e230a1319..5ff1b2ba91 100644 --- a/qemu-char.h +++ b/qemu-char.h @@ -5,7 +5,7 @@ #include "qemu-queue.h" #include "qemu-option.h" #include "qemu-config.h" -#include "qemu-aio.h" +#include "block/aio.h" #include "qapi/qmp/qobject.h" #include "qapi/qmp/qstring.h" #include "main-loop.h" diff --git a/qemu-coroutine-int.h b/qemu-coroutine-int.h deleted file mode 100644 index 0f1bd80a8d..0000000000 --- a/qemu-coroutine-int.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Coroutine internals - * - * Copyright (c) 2011 Kevin Wolf - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef QEMU_COROUTINE_INT_H -#define QEMU_COROUTINE_INT_H - -#include "qemu-queue.h" -#include "qemu-coroutine.h" - -typedef enum { - COROUTINE_YIELD = 1, - COROUTINE_TERMINATE = 2, -} CoroutineAction; - -struct Coroutine { - CoroutineEntry *entry; - void *entry_arg; - Coroutine *caller; - QSLIST_ENTRY(Coroutine) pool_next; - QTAILQ_ENTRY(Coroutine) co_queue_next; -}; - -Coroutine *qemu_coroutine_new(void); -void qemu_coroutine_delete(Coroutine *co); -CoroutineAction qemu_coroutine_switch(Coroutine *from, Coroutine *to, - CoroutineAction action); - -#endif diff --git a/qemu-coroutine-io.c b/qemu-coroutine-io.c index 5734965003..5fae9c7d47 100644 --- a/qemu-coroutine-io.c +++ b/qemu-coroutine-io.c @@ -24,7 +24,7 @@ */ #include "qemu-common.h" #include "qemu_socket.h" -#include "qemu-coroutine.h" +#include "block/coroutine.h" #include "iov.h" ssize_t coroutine_fn diff --git a/qemu-coroutine-lock.c b/qemu-coroutine-lock.c index 9dda3f86c9..c3939ac6ef 100644 --- a/qemu-coroutine-lock.c +++ b/qemu-coroutine-lock.c @@ -23,10 +23,10 @@ */ #include "qemu-common.h" -#include "qemu-coroutine.h" -#include "qemu-coroutine-int.h" +#include "block/coroutine.h" +#include "block/coroutine_int.h" #include "qemu-queue.h" -#include "qemu-aio.h" +#include "block/aio.h" #include "trace.h" static QTAILQ_HEAD(, Coroutine) unlock_bh_queue = diff --git a/qemu-coroutine-sleep.c b/qemu-coroutine-sleep.c index d7083ee41a..26e6dac2eb 100644 --- a/qemu-coroutine-sleep.c +++ b/qemu-coroutine-sleep.c @@ -11,7 +11,7 @@ * */ -#include "qemu-coroutine.h" +#include "block/coroutine.h" #include "qemu-timer.h" typedef struct CoSleepCB { diff --git a/qemu-coroutine.c b/qemu-coroutine.c index 600be2643c..0f6e268574 100644 --- a/qemu-coroutine.c +++ b/qemu-coroutine.c @@ -14,8 +14,8 @@ #include "trace.h" #include "qemu-common.h" -#include "qemu-coroutine.h" -#include "qemu-coroutine-int.h" +#include "block/coroutine.h" +#include "block/coroutine_int.h" Coroutine *qemu_coroutine_create(CoroutineEntry *entry) { diff --git a/qemu-coroutine.h b/qemu-coroutine.h deleted file mode 100644 index 34c15d4116..0000000000 --- a/qemu-coroutine.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * QEMU coroutine implementation - * - * Copyright IBM, Corp. 2011 - * - * Authors: - * Stefan Hajnoczi - * Kevin Wolf - * - * This work is licensed under the terms of the GNU LGPL, version 2 or later. - * See the COPYING.LIB file in the top-level directory. - * - */ - -#ifndef QEMU_COROUTINE_H -#define QEMU_COROUTINE_H - -#include -#include "qemu-queue.h" -#include "qemu-timer.h" - -/** - * Coroutines are a mechanism for stack switching and can be used for - * cooperative userspace threading. These functions provide a simple but - * useful flavor of coroutines that is suitable for writing sequential code, - * rather than callbacks, for operations that need to give up control while - * waiting for events to complete. - * - * These functions are re-entrant and may be used outside the global mutex. - */ - -/** - * Mark a function that executes in coroutine context - * - * Functions that execute in coroutine context cannot be called directly from - * normal functions. In the future it would be nice to enable compiler or - * static checker support for catching such errors. This annotation might make - * it possible and in the meantime it serves as documentation. - * - * For example: - * - * static void coroutine_fn foo(void) { - * .... - * } - */ -#define coroutine_fn - -typedef struct Coroutine Coroutine; - -/** - * Coroutine entry point - * - * When the coroutine is entered for the first time, opaque is passed in as an - * argument. - * - * When this function returns, the coroutine is destroyed automatically and - * execution continues in the caller who last entered the coroutine. - */ -typedef void coroutine_fn CoroutineEntry(void *opaque); - -/** - * Create a new coroutine - * - * Use qemu_coroutine_enter() to actually transfer control to the coroutine. - */ -Coroutine *qemu_coroutine_create(CoroutineEntry *entry); - -/** - * Transfer control to a coroutine - * - * The opaque argument is passed as the argument to the entry point when - * entering the coroutine for the first time. It is subsequently ignored. - */ -void qemu_coroutine_enter(Coroutine *coroutine, void *opaque); - -/** - * Transfer control back to a coroutine's caller - * - * This function does not return until the coroutine is re-entered using - * qemu_coroutine_enter(). - */ -void coroutine_fn qemu_coroutine_yield(void); - -/** - * Get the currently executing coroutine - */ -Coroutine *coroutine_fn qemu_coroutine_self(void); - -/** - * Return whether or not currently inside a coroutine - * - * This can be used to write functions that work both when in coroutine context - * and when not in coroutine context. Note that such functions cannot use the - * coroutine_fn annotation since they work outside coroutine context. - */ -bool qemu_in_coroutine(void); - - - -/** - * CoQueues are a mechanism to queue coroutines in order to continue executing - * them later. They provide the fundamental primitives on which coroutine locks - * are built. - */ -typedef struct CoQueue { - QTAILQ_HEAD(, Coroutine) entries; -} CoQueue; - -/** - * Initialise a CoQueue. This must be called before any other operation is used - * on the CoQueue. - */ -void qemu_co_queue_init(CoQueue *queue); - -/** - * Adds the current coroutine to the CoQueue and transfers control to the - * caller of the coroutine. - */ -void coroutine_fn qemu_co_queue_wait(CoQueue *queue); - -/** - * Adds the current coroutine to the head of the CoQueue and transfers control to the - * caller of the coroutine. - */ -void coroutine_fn qemu_co_queue_wait_insert_head(CoQueue *queue); - -/** - * Restarts the next coroutine in the CoQueue and removes it from the queue. - * - * Returns true if a coroutine was restarted, false if the queue is empty. - */ -bool qemu_co_queue_next(CoQueue *queue); - -/** - * Restarts all coroutines in the CoQueue and leaves the queue empty. - */ -void qemu_co_queue_restart_all(CoQueue *queue); - -/** - * Checks if the CoQueue is empty. - */ -bool qemu_co_queue_empty(CoQueue *queue); - - -/** - * Provides a mutex that can be used to synchronise coroutines - */ -typedef struct CoMutex { - bool locked; - CoQueue queue; -} CoMutex; - -/** - * Initialises a CoMutex. This must be called before any other operation is used - * on the CoMutex. - */ -void qemu_co_mutex_init(CoMutex *mutex); - -/** - * Locks the mutex. If the lock cannot be taken immediately, control is - * transferred to the caller of the current coroutine. - */ -void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex); - -/** - * Unlocks the mutex and schedules the next coroutine that was waiting for this - * lock to be run. - */ -void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex); - -typedef struct CoRwlock { - bool writer; - int reader; - CoQueue queue; -} CoRwlock; - -/** - * Initialises a CoRwlock. This must be called before any other operation - * is used on the CoRwlock - */ -void qemu_co_rwlock_init(CoRwlock *lock); - -/** - * Read locks the CoRwlock. If the lock cannot be taken immediately because - * of a parallel writer, control is transferred to the caller of the current - * coroutine. - */ -void qemu_co_rwlock_rdlock(CoRwlock *lock); - -/** - * Write Locks the mutex. If the lock cannot be taken immediately because - * of a parallel reader, control is transferred to the caller of the current - * coroutine. - */ -void qemu_co_rwlock_wrlock(CoRwlock *lock); - -/** - * Unlocks the read/write lock and schedules the next coroutine that was - * waiting for this lock to be run. - */ -void qemu_co_rwlock_unlock(CoRwlock *lock); - -/** - * Yield the coroutine for a given duration - * - * Note this function uses timers and hence only works when a main loop is in - * use. See main-loop.h and do not use from qemu-tool programs. - */ -void coroutine_fn co_sleep_ns(QEMUClock *clock, int64_t ns); - -#endif /* QEMU_COROUTINE_H */ diff --git a/qemu-img.c b/qemu-img.c index a13bc788cf..2e5ca5c964 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -29,7 +29,7 @@ #include "qemu-error.h" #include "osdep.h" #include "sysemu.h" -#include "block_int.h" +#include "block/block_int.h" #include #include diff --git a/qemu-io.c b/qemu-io.c index 1637773302..e0e47423d7 100644 --- a/qemu-io.c +++ b/qemu-io.c @@ -16,7 +16,7 @@ #include "qemu-common.h" #include "main-loop.h" -#include "block_int.h" +#include "block/block_int.h" #include "cmd.h" #include "trace/control.h" diff --git a/qemu-nbd.c b/qemu-nbd.c index 80f08d8464..0a6091b6a8 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -17,8 +17,8 @@ */ #include "qemu-common.h" -#include "block.h" -#include "nbd.h" +#include "block/block.h" +#include "block/nbd.h" #include #include diff --git a/tests/test-aio.c b/tests/test-aio.c index a8a4f0c6a5..e4ebef76b9 100644 --- a/tests/test-aio.c +++ b/tests/test-aio.c @@ -11,7 +11,7 @@ */ #include -#include "qemu-aio.h" +#include "block/aio.h" AioContext *ctx; diff --git a/tests/test-coroutine.c b/tests/test-coroutine.c index e5d14eb696..4c6cc81fb9 100644 --- a/tests/test-coroutine.c +++ b/tests/test-coroutine.c @@ -12,7 +12,7 @@ */ #include -#include "qemu-coroutine.h" +#include "block/coroutine.h" /* * Check that qemu_in_coroutine() works diff --git a/tests/test-thread-pool.c b/tests/test-thread-pool.c index ea8e676b0c..9998e031f2 100644 --- a/tests/test-thread-pool.c +++ b/tests/test-thread-pool.c @@ -1,8 +1,8 @@ #include #include "qemu-common.h" -#include "qemu-aio.h" -#include "thread-pool.h" -#include "block.h" +#include "block/aio.h" +#include "block/thread-pool.h" +#include "block/block.h" static int active; diff --git a/thread-pool.c b/thread-pool.c index 204f70b7b5..4c73a7db97 100644 --- a/thread-pool.c +++ b/thread-pool.c @@ -18,11 +18,11 @@ #include "qemu-queue.h" #include "qemu-thread.h" #include "osdep.h" -#include "qemu-coroutine.h" +#include "block/coroutine.h" #include "trace.h" -#include "block_int.h" +#include "block/block_int.h" #include "event_notifier.h" -#include "thread-pool.h" +#include "block/thread-pool.h" static void do_spawn_thread(void); diff --git a/thread-pool.h b/thread-pool.h deleted file mode 100644 index 378a4ac9f9..0000000000 --- a/thread-pool.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * QEMU block layer thread pool - * - * Copyright IBM, Corp. 2008 - * Copyright Red Hat, Inc. 2012 - * - * Authors: - * Anthony Liguori - * Paolo Bonzini - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#ifndef QEMU_THREAD_POOL_H -#define QEMU_THREAD_POOL_H 1 - -#include "qemu-common.h" -#include "qemu-queue.h" -#include "qemu-thread.h" -#include "qemu-coroutine.h" -#include "block_int.h" - -typedef int ThreadPoolFunc(void *opaque); - -BlockDriverAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg, - BlockDriverCompletionFunc *cb, void *opaque); -int coroutine_fn thread_pool_submit_co(ThreadPoolFunc *func, void *arg); -void thread_pool_submit(ThreadPoolFunc *func, void *arg); - -#endif -- cgit v1.2.3-55-g7522