#include "qemu/osdep.h"
#include "block/throttle-groups.h"
+#include "qemu/option.h"
#include "qemu/throttle-options.h"
#include "qapi/error.h"
},
};
-static int throttle_configure_tgm(BlockDriverState *bs,
- ThrottleGroupMember *tgm,
- QDict *options, Error **errp)
+/*
+ * If this function succeeds then the throttle group name is stored in
+ * @group and must be freed by the caller.
+ * If there's an error then @group remains unmodified.
+ */
+static int throttle_parse_options(QDict *options, char **group, Error **errp)
{
int ret;
const char *group_name;
goto fin;
}
- /* Register membership to group with name group_name */
- throttle_group_register_tgm(tgm, group_name, bdrv_get_aio_context(bs));
+ *group = g_strdup(group_name);
ret = 0;
fin:
qemu_opts_del(opts);
int flags, Error **errp)
{
ThrottleGroupMember *tgm = bs->opaque;
+ char *group;
+ int ret;
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;
+ bs->supported_write_flags = bs->file->bs->supported_write_flags |
+ BDRV_REQ_WRITE_UNCHANGED;
+ bs->supported_zero_flags = bs->file->bs->supported_zero_flags |
+ BDRV_REQ_WRITE_UNCHANGED;
+
+ ret = throttle_parse_options(options, &group, errp);
+ if (ret == 0) {
+ /* Register membership to group with name group_name */
+ throttle_group_register_tgm(tgm, group, bdrv_get_aio_context(bs));
+ g_free(group);
+ }
- return throttle_configure_tgm(bs, tgm, options, errp);
+ return ret;
}
static void throttle_close(BlockDriverState *bs)
ThrottleGroupMember *tgm = bs->opaque;
throttle_group_co_io_limits_intercept(tgm, bytes, true);
- return bdrv_co_pdiscard(bs->file->bs, offset, bytes);
+ return bdrv_co_pdiscard(bs->file, offset, bytes);
}
static int throttle_co_flush(BlockDriverState *bs)
static int throttle_reopen_prepare(BDRVReopenState *reopen_state,
BlockReopenQueue *queue, Error **errp)
{
- ThrottleGroupMember *tgm;
+ int ret;
+ char *group = NULL;
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);
+ ret = throttle_parse_options(reopen_state->options, &group, errp);
+ reopen_state->opaque = group;
+ return ret;
}
static void throttle_reopen_commit(BDRVReopenState *reopen_state)
{
- ThrottleGroupMember *old_tgm = reopen_state->bs->opaque;
- ThrottleGroupMember *new_tgm = reopen_state->opaque;
+ BlockDriverState *bs = reopen_state->bs;
+ ThrottleGroupMember *tgm = bs->opaque;
+ char *group = reopen_state->opaque;
- throttle_group_unregister_tgm(old_tgm);
- g_free(old_tgm);
- reopen_state->bs->opaque = new_tgm;
+ assert(group);
+
+ if (strcmp(group, throttle_group_get_name(tgm))) {
+ throttle_group_unregister_tgm(tgm);
+ throttle_group_register_tgm(tgm, group, bdrv_get_aio_context(bs));
+ }
+ g_free(reopen_state->opaque);
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);
+ g_free(reopen_state->opaque);
reopen_state->opaque = NULL;
}
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_open = throttle_open,
.bdrv_close = throttle_close,
.bdrv_co_flush = throttle_co_flush,
.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_block_status = bdrv_co_block_status_from_file,
+
+ .bdrv_co_drain_begin = throttle_co_drain_begin,
+ .bdrv_co_drain_end = throttle_co_drain_end,
.is_filter = true,
};