mirror of
https://github.com/qemu/qemu.git
synced 2024-12-02 16:23:35 +08:00
922a01a013
qemu-common.h includes qemu/option.h, but most places that include the
former don't actually need the latter. Drop the include, and add it
to the places that actually need it.
While there, drop superfluous includes of both headers, and
separate #include from file comment with a blank line.
This cleanup makes the number of objects depending on qemu/option.h
drop from 4545 (out of 4743) to 284 in my "build everything" tree.
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20180201111846.21846-20-armbru@redhat.com>
[Semantic conflict with commit bdd6a90a9e
in block/nvme.c resolved]
257 lines
8.1 KiB
C
257 lines
8.1 KiB
C
/*
|
|
* QEMU block throttling filter driver infrastructure
|
|
*
|
|
* Copyright (c) 2017 Manos Pitsidianakis
|
|
*
|
|
* 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; either version 2 or
|
|
* (at your option) version 3 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "block/throttle-groups.h"
|
|
#include "qemu/option.h"
|
|
#include "qemu/throttle-options.h"
|
|
#include "qapi/error.h"
|
|
|
|
static QemuOptsList throttle_opts = {
|
|
.name = "throttle",
|
|
.head = QTAILQ_HEAD_INITIALIZER(throttle_opts.head),
|
|
.desc = {
|
|
{
|
|
.name = QEMU_OPT_THROTTLE_GROUP_NAME,
|
|
.type = QEMU_OPT_STRING,
|
|
.help = "Name of the throttle group",
|
|
},
|
|
{ /* end of list */ }
|
|
},
|
|
};
|
|
|
|
static int throttle_configure_tgm(BlockDriverState *bs,
|
|
ThrottleGroupMember *tgm,
|
|
QDict *options, Error **errp)
|
|
{
|
|
int ret;
|
|
const char *group_name;
|
|
Error *local_err = NULL;
|
|
QemuOpts *opts = qemu_opts_create(&throttle_opts, NULL, 0, &error_abort);
|
|
|
|
qemu_opts_absorb_qdict(opts, options, &local_err);
|
|
if (local_err) {
|
|
error_propagate(errp, local_err);
|
|
ret = -EINVAL;
|
|
goto fin;
|
|
}
|
|
|
|
group_name = qemu_opt_get(opts, QEMU_OPT_THROTTLE_GROUP_NAME);
|
|
if (!group_name) {
|
|
error_setg(errp, "Please specify a throttle group");
|
|
ret = -EINVAL;
|
|
goto fin;
|
|
} else if (!throttle_group_exists(group_name)) {
|
|
error_setg(errp, "Throttle group '%s' does not exist", group_name);
|
|
ret = -EINVAL;
|
|
goto fin;
|
|
}
|
|
|
|
/* Register membership to group with name group_name */
|
|
throttle_group_register_tgm(tgm, group_name, bdrv_get_aio_context(bs));
|
|
ret = 0;
|
|
fin:
|
|
qemu_opts_del(opts);
|
|
return ret;
|
|
}
|
|
|
|
static int throttle_open(BlockDriverState *bs, QDict *options,
|
|
int flags, Error **errp)
|
|
{
|
|
ThrottleGroupMember *tgm = bs->opaque;
|
|
|
|
bs->file = bdrv_open_child(NULL, options, "file", bs,
|
|
&child_file, false, errp);
|
|
if (!bs->file) {
|
|
return -EINVAL;
|
|
}
|
|
bs->supported_write_flags = bs->file->bs->supported_write_flags;
|
|
bs->supported_zero_flags = bs->file->bs->supported_zero_flags;
|
|
|
|
return throttle_configure_tgm(bs, tgm, options, errp);
|
|
}
|
|
|
|
static void throttle_close(BlockDriverState *bs)
|
|
{
|
|
ThrottleGroupMember *tgm = bs->opaque;
|
|
throttle_group_unregister_tgm(tgm);
|
|
}
|
|
|
|
|
|
static int64_t throttle_getlength(BlockDriverState *bs)
|
|
{
|
|
return bdrv_getlength(bs->file->bs);
|
|
}
|
|
|
|
static int coroutine_fn throttle_co_preadv(BlockDriverState *bs,
|
|
uint64_t offset, uint64_t bytes,
|
|
QEMUIOVector *qiov, int flags)
|
|
{
|
|
|
|
ThrottleGroupMember *tgm = bs->opaque;
|
|
throttle_group_co_io_limits_intercept(tgm, bytes, false);
|
|
|
|
return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
|
|
}
|
|
|
|
static int coroutine_fn throttle_co_pwritev(BlockDriverState *bs,
|
|
uint64_t offset, uint64_t bytes,
|
|
QEMUIOVector *qiov, int flags)
|
|
{
|
|
ThrottleGroupMember *tgm = bs->opaque;
|
|
throttle_group_co_io_limits_intercept(tgm, bytes, true);
|
|
|
|
return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
|
|
}
|
|
|
|
static int coroutine_fn throttle_co_pwrite_zeroes(BlockDriverState *bs,
|
|
int64_t offset, int bytes,
|
|
BdrvRequestFlags flags)
|
|
{
|
|
ThrottleGroupMember *tgm = bs->opaque;
|
|
throttle_group_co_io_limits_intercept(tgm, bytes, true);
|
|
|
|
return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
|
|
}
|
|
|
|
static int coroutine_fn throttle_co_pdiscard(BlockDriverState *bs,
|
|
int64_t offset, int bytes)
|
|
{
|
|
ThrottleGroupMember *tgm = bs->opaque;
|
|
throttle_group_co_io_limits_intercept(tgm, bytes, true);
|
|
|
|
return bdrv_co_pdiscard(bs->file->bs, offset, bytes);
|
|
}
|
|
|
|
static int throttle_co_flush(BlockDriverState *bs)
|
|
{
|
|
return bdrv_co_flush(bs->file->bs);
|
|
}
|
|
|
|
static void throttle_detach_aio_context(BlockDriverState *bs)
|
|
{
|
|
ThrottleGroupMember *tgm = bs->opaque;
|
|
throttle_group_detach_aio_context(tgm);
|
|
}
|
|
|
|
static void throttle_attach_aio_context(BlockDriverState *bs,
|
|
AioContext *new_context)
|
|
{
|
|
ThrottleGroupMember *tgm = bs->opaque;
|
|
throttle_group_attach_aio_context(tgm, new_context);
|
|
}
|
|
|
|
static int throttle_reopen_prepare(BDRVReopenState *reopen_state,
|
|
BlockReopenQueue *queue, Error **errp)
|
|
{
|
|
ThrottleGroupMember *tgm;
|
|
|
|
assert(reopen_state != NULL);
|
|
assert(reopen_state->bs != NULL);
|
|
|
|
reopen_state->opaque = g_new0(ThrottleGroupMember, 1);
|
|
tgm = reopen_state->opaque;
|
|
|
|
return throttle_configure_tgm(reopen_state->bs, tgm, reopen_state->options,
|
|
errp);
|
|
}
|
|
|
|
static void throttle_reopen_commit(BDRVReopenState *reopen_state)
|
|
{
|
|
ThrottleGroupMember *old_tgm = reopen_state->bs->opaque;
|
|
ThrottleGroupMember *new_tgm = reopen_state->opaque;
|
|
|
|
throttle_group_unregister_tgm(old_tgm);
|
|
g_free(old_tgm);
|
|
reopen_state->bs->opaque = new_tgm;
|
|
reopen_state->opaque = NULL;
|
|
}
|
|
|
|
static void throttle_reopen_abort(BDRVReopenState *reopen_state)
|
|
{
|
|
ThrottleGroupMember *tgm = reopen_state->opaque;
|
|
|
|
throttle_group_unregister_tgm(tgm);
|
|
g_free(tgm);
|
|
reopen_state->opaque = NULL;
|
|
}
|
|
|
|
static bool throttle_recurse_is_first_non_filter(BlockDriverState *bs,
|
|
BlockDriverState *candidate)
|
|
{
|
|
return bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
|
|
}
|
|
|
|
static void coroutine_fn throttle_co_drain_begin(BlockDriverState *bs)
|
|
{
|
|
ThrottleGroupMember *tgm = bs->opaque;
|
|
if (atomic_fetch_inc(&tgm->io_limits_disabled) == 0) {
|
|
throttle_group_restart_tgm(tgm);
|
|
}
|
|
}
|
|
|
|
static void coroutine_fn throttle_co_drain_end(BlockDriverState *bs)
|
|
{
|
|
ThrottleGroupMember *tgm = bs->opaque;
|
|
assert(tgm->io_limits_disabled);
|
|
atomic_dec(&tgm->io_limits_disabled);
|
|
}
|
|
|
|
static BlockDriver bdrv_throttle = {
|
|
.format_name = "throttle",
|
|
.protocol_name = "throttle",
|
|
.instance_size = sizeof(ThrottleGroupMember),
|
|
|
|
.bdrv_file_open = throttle_open,
|
|
.bdrv_close = throttle_close,
|
|
.bdrv_co_flush = throttle_co_flush,
|
|
|
|
.bdrv_child_perm = bdrv_filter_default_perms,
|
|
|
|
.bdrv_getlength = throttle_getlength,
|
|
|
|
.bdrv_co_preadv = throttle_co_preadv,
|
|
.bdrv_co_pwritev = throttle_co_pwritev,
|
|
|
|
.bdrv_co_pwrite_zeroes = throttle_co_pwrite_zeroes,
|
|
.bdrv_co_pdiscard = throttle_co_pdiscard,
|
|
|
|
.bdrv_recurse_is_first_non_filter = throttle_recurse_is_first_non_filter,
|
|
|
|
.bdrv_attach_aio_context = throttle_attach_aio_context,
|
|
.bdrv_detach_aio_context = throttle_detach_aio_context,
|
|
|
|
.bdrv_reopen_prepare = throttle_reopen_prepare,
|
|
.bdrv_reopen_commit = throttle_reopen_commit,
|
|
.bdrv_reopen_abort = throttle_reopen_abort,
|
|
.bdrv_co_get_block_status = bdrv_co_get_block_status_from_file,
|
|
|
|
.bdrv_co_drain_begin = throttle_co_drain_begin,
|
|
.bdrv_co_drain_end = throttle_co_drain_end,
|
|
|
|
.is_filter = true,
|
|
};
|
|
|
|
static void bdrv_throttle_init(void)
|
|
{
|
|
bdrv_register(&bdrv_throttle);
|
|
}
|
|
|
|
block_init(bdrv_throttle_init);
|