20
#include "qemu/osdep.h"
21
#include "block/block-io.h"
22
#include "block/block_int.h"
23
#include "block/throttle-groups.h"
24
#include "qemu/module.h"
25
#include "qemu/option.h"
26
#include "qemu/throttle-options.h"
27
#include "qapi/error.h"
29
static QemuOptsList throttle_opts = {
31
.head = QTAILQ_HEAD_INITIALIZER(throttle_opts.head),
34
.name = QEMU_OPT_THROTTLE_GROUP_NAME,
35
.type = QEMU_OPT_STRING,
36
.help = "Name of the throttle group",
47
static int throttle_parse_options(QDict *options, char **group, Error **errp)
50
const char *group_name;
51
QemuOpts *opts = qemu_opts_create(&throttle_opts, NULL, 0, &error_abort);
53
if (!qemu_opts_absorb_qdict(opts, options, errp)) {
58
group_name = qemu_opt_get(opts, QEMU_OPT_THROTTLE_GROUP_NAME);
60
error_setg(errp, "Please specify a throttle group");
63
} else if (!throttle_group_exists(group_name)) {
64
error_setg(errp, "Throttle group '%s' does not exist", group_name);
69
*group = g_strdup(group_name);
76
static int throttle_open(BlockDriverState *bs, QDict *options,
77
int flags, Error **errp)
79
ThrottleGroupMember *tgm = bs->opaque;
83
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
88
GRAPH_RDLOCK_GUARD_MAINLOOP();
90
bs->supported_write_flags = bs->file->bs->supported_write_flags |
91
BDRV_REQ_WRITE_UNCHANGED;
92
bs->supported_zero_flags = bs->file->bs->supported_zero_flags |
93
BDRV_REQ_WRITE_UNCHANGED;
95
ret = throttle_parse_options(options, &group, errp);
98
throttle_group_register_tgm(tgm, group, bdrv_get_aio_context(bs));
105
static void throttle_close(BlockDriverState *bs)
107
ThrottleGroupMember *tgm = bs->opaque;
108
throttle_group_unregister_tgm(tgm);
112
static int64_t coroutine_fn GRAPH_RDLOCK
113
throttle_co_getlength(BlockDriverState *bs)
115
return bdrv_co_getlength(bs->file->bs);
118
static int coroutine_fn GRAPH_RDLOCK
119
throttle_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
120
QEMUIOVector *qiov, BdrvRequestFlags flags)
123
ThrottleGroupMember *tgm = bs->opaque;
124
throttle_group_co_io_limits_intercept(tgm, bytes, THROTTLE_READ);
126
return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
129
static int coroutine_fn GRAPH_RDLOCK
130
throttle_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
131
QEMUIOVector *qiov, BdrvRequestFlags flags)
133
ThrottleGroupMember *tgm = bs->opaque;
134
throttle_group_co_io_limits_intercept(tgm, bytes, THROTTLE_WRITE);
136
return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
139
static int coroutine_fn GRAPH_RDLOCK
140
throttle_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
141
BdrvRequestFlags flags)
143
ThrottleGroupMember *tgm = bs->opaque;
144
throttle_group_co_io_limits_intercept(tgm, bytes, THROTTLE_WRITE);
146
return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
149
static int coroutine_fn GRAPH_RDLOCK
150
throttle_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
152
ThrottleGroupMember *tgm = bs->opaque;
153
throttle_group_co_io_limits_intercept(tgm, bytes, THROTTLE_WRITE);
155
return bdrv_co_pdiscard(bs->file, offset, bytes);
158
static int coroutine_fn GRAPH_RDLOCK
159
throttle_co_pwritev_compressed(BlockDriverState *bs, int64_t offset,
160
int64_t bytes, QEMUIOVector *qiov)
162
return throttle_co_pwritev(bs, offset, bytes, qiov,
163
BDRV_REQ_WRITE_COMPRESSED);
166
static int coroutine_fn GRAPH_RDLOCK throttle_co_flush(BlockDriverState *bs)
168
return bdrv_co_flush(bs->file->bs);
171
static void throttle_detach_aio_context(BlockDriverState *bs)
173
ThrottleGroupMember *tgm = bs->opaque;
174
throttle_group_detach_aio_context(tgm);
177
static void throttle_attach_aio_context(BlockDriverState *bs,
178
AioContext *new_context)
180
ThrottleGroupMember *tgm = bs->opaque;
181
throttle_group_attach_aio_context(tgm, new_context);
184
static int throttle_reopen_prepare(BDRVReopenState *reopen_state,
185
BlockReopenQueue *queue, Error **errp)
190
assert(reopen_state != NULL);
191
assert(reopen_state->bs != NULL);
193
ret = throttle_parse_options(reopen_state->options, &group, errp);
194
reopen_state->opaque = group;
198
static void throttle_reopen_commit(BDRVReopenState *reopen_state)
200
BlockDriverState *bs = reopen_state->bs;
201
ThrottleGroupMember *tgm = bs->opaque;
202
char *group = reopen_state->opaque;
206
if (strcmp(group, throttle_group_get_name(tgm))) {
207
throttle_group_unregister_tgm(tgm);
208
throttle_group_register_tgm(tgm, group, bdrv_get_aio_context(bs));
210
g_free(reopen_state->opaque);
211
reopen_state->opaque = NULL;
214
static void throttle_reopen_abort(BDRVReopenState *reopen_state)
216
g_free(reopen_state->opaque);
217
reopen_state->opaque = NULL;
220
static void throttle_drain_begin(BlockDriverState *bs)
222
ThrottleGroupMember *tgm = bs->opaque;
223
if (qatomic_fetch_inc(&tgm->io_limits_disabled) == 0) {
224
throttle_group_restart_tgm(tgm);
228
static void throttle_drain_end(BlockDriverState *bs)
230
ThrottleGroupMember *tgm = bs->opaque;
231
assert(tgm->io_limits_disabled);
232
qatomic_dec(&tgm->io_limits_disabled);
235
static const char *const throttle_strong_runtime_opts[] = {
236
QEMU_OPT_THROTTLE_GROUP_NAME,
241
static BlockDriver bdrv_throttle = {
242
.format_name = "throttle",
243
.instance_size = sizeof(ThrottleGroupMember),
245
.bdrv_open = throttle_open,
246
.bdrv_close = throttle_close,
247
.bdrv_co_flush = throttle_co_flush,
249
.bdrv_child_perm = bdrv_default_perms,
251
.bdrv_co_getlength = throttle_co_getlength,
253
.bdrv_co_preadv = throttle_co_preadv,
254
.bdrv_co_pwritev = throttle_co_pwritev,
256
.bdrv_co_pwrite_zeroes = throttle_co_pwrite_zeroes,
257
.bdrv_co_pdiscard = throttle_co_pdiscard,
258
.bdrv_co_pwritev_compressed = throttle_co_pwritev_compressed,
260
.bdrv_attach_aio_context = throttle_attach_aio_context,
261
.bdrv_detach_aio_context = throttle_detach_aio_context,
263
.bdrv_reopen_prepare = throttle_reopen_prepare,
264
.bdrv_reopen_commit = throttle_reopen_commit,
265
.bdrv_reopen_abort = throttle_reopen_abort,
267
.bdrv_drain_begin = throttle_drain_begin,
268
.bdrv_drain_end = throttle_drain_end,
271
.strong_runtime_opts = throttle_strong_runtime_opts,
274
static void bdrv_throttle_init(void)
276
bdrv_register(&bdrv_throttle);
279
block_init(bdrv_throttle_init);