cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

throttle.c (8945B)


      1/*
      2 * QEMU block throttling filter driver infrastructure
      3 *
      4 * Copyright (c) 2017 Manos Pitsidianakis
      5 *
      6 * This program is free software; you can redistribute it and/or
      7 * modify it under the terms of the GNU General Public License as
      8 * published by the Free Software Foundation; either version 2 or
      9 * (at your option) version 3 of the License.
     10 *
     11 * This program is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 * GNU General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU General Public License
     17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
     18 */
     19
     20#include "qemu/osdep.h"
     21#include "block/throttle-groups.h"
     22#include "qemu/module.h"
     23#include "qemu/option.h"
     24#include "qemu/throttle-options.h"
     25#include "qapi/error.h"
     26
     27static QemuOptsList throttle_opts = {
     28    .name = "throttle",
     29    .head = QTAILQ_HEAD_INITIALIZER(throttle_opts.head),
     30    .desc = {
     31        {
     32            .name = QEMU_OPT_THROTTLE_GROUP_NAME,
     33            .type = QEMU_OPT_STRING,
     34            .help = "Name of the throttle group",
     35        },
     36        { /* end of list */ }
     37    },
     38};
     39
     40/*
     41 * If this function succeeds then the throttle group name is stored in
     42 * @group and must be freed by the caller.
     43 * If there's an error then @group remains unmodified.
     44 */
     45static int throttle_parse_options(QDict *options, char **group, Error **errp)
     46{
     47    int ret;
     48    const char *group_name;
     49    QemuOpts *opts = qemu_opts_create(&throttle_opts, NULL, 0, &error_abort);
     50
     51    if (!qemu_opts_absorb_qdict(opts, options, errp)) {
     52        ret = -EINVAL;
     53        goto fin;
     54    }
     55
     56    group_name = qemu_opt_get(opts, QEMU_OPT_THROTTLE_GROUP_NAME);
     57    if (!group_name) {
     58        error_setg(errp, "Please specify a throttle group");
     59        ret = -EINVAL;
     60        goto fin;
     61    } else if (!throttle_group_exists(group_name)) {
     62        error_setg(errp, "Throttle group '%s' does not exist", group_name);
     63        ret = -EINVAL;
     64        goto fin;
     65    }
     66
     67    *group = g_strdup(group_name);
     68    ret = 0;
     69fin:
     70    qemu_opts_del(opts);
     71    return ret;
     72}
     73
     74static int throttle_open(BlockDriverState *bs, QDict *options,
     75                         int flags, Error **errp)
     76{
     77    ThrottleGroupMember *tgm = bs->opaque;
     78    char *group;
     79    int ret;
     80
     81    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
     82                               BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
     83                               false, errp);
     84    if (!bs->file) {
     85        return -EINVAL;
     86    }
     87    bs->supported_write_flags = bs->file->bs->supported_write_flags |
     88                                BDRV_REQ_WRITE_UNCHANGED;
     89    bs->supported_zero_flags = bs->file->bs->supported_zero_flags |
     90                               BDRV_REQ_WRITE_UNCHANGED;
     91
     92    ret = throttle_parse_options(options, &group, errp);
     93    if (ret == 0) {
     94        /* Register membership to group with name group_name */
     95        throttle_group_register_tgm(tgm, group, bdrv_get_aio_context(bs));
     96        g_free(group);
     97    }
     98
     99    return ret;
    100}
    101
    102static void throttle_close(BlockDriverState *bs)
    103{
    104    ThrottleGroupMember *tgm = bs->opaque;
    105    throttle_group_unregister_tgm(tgm);
    106}
    107
    108
    109static int64_t throttle_getlength(BlockDriverState *bs)
    110{
    111    return bdrv_getlength(bs->file->bs);
    112}
    113
    114static int coroutine_fn throttle_co_preadv(BlockDriverState *bs,
    115                                           int64_t offset, int64_t bytes,
    116                                           QEMUIOVector *qiov,
    117                                           BdrvRequestFlags flags)
    118{
    119
    120    ThrottleGroupMember *tgm = bs->opaque;
    121    throttle_group_co_io_limits_intercept(tgm, bytes, false);
    122
    123    return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
    124}
    125
    126static int coroutine_fn throttle_co_pwritev(BlockDriverState *bs,
    127                                            int64_t offset, int64_t bytes,
    128                                            QEMUIOVector *qiov,
    129                                            BdrvRequestFlags flags)
    130{
    131    ThrottleGroupMember *tgm = bs->opaque;
    132    throttle_group_co_io_limits_intercept(tgm, bytes, true);
    133
    134    return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
    135}
    136
    137static int coroutine_fn throttle_co_pwrite_zeroes(BlockDriverState *bs,
    138                                                  int64_t offset, int64_t bytes,
    139                                                  BdrvRequestFlags flags)
    140{
    141    ThrottleGroupMember *tgm = bs->opaque;
    142    throttle_group_co_io_limits_intercept(tgm, bytes, true);
    143
    144    return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
    145}
    146
    147static int coroutine_fn throttle_co_pdiscard(BlockDriverState *bs,
    148                                             int64_t offset, int64_t bytes)
    149{
    150    ThrottleGroupMember *tgm = bs->opaque;
    151    throttle_group_co_io_limits_intercept(tgm, bytes, true);
    152
    153    return bdrv_co_pdiscard(bs->file, offset, bytes);
    154}
    155
    156static int coroutine_fn throttle_co_pwritev_compressed(BlockDriverState *bs,
    157                                                       int64_t offset,
    158                                                       int64_t bytes,
    159                                                       QEMUIOVector *qiov)
    160{
    161    return throttle_co_pwritev(bs, offset, bytes, qiov,
    162                               BDRV_REQ_WRITE_COMPRESSED);
    163}
    164
    165static int throttle_co_flush(BlockDriverState *bs)
    166{
    167    return bdrv_co_flush(bs->file->bs);
    168}
    169
    170static void throttle_detach_aio_context(BlockDriverState *bs)
    171{
    172    ThrottleGroupMember *tgm = bs->opaque;
    173    throttle_group_detach_aio_context(tgm);
    174}
    175
    176static void throttle_attach_aio_context(BlockDriverState *bs,
    177                                        AioContext *new_context)
    178{
    179    ThrottleGroupMember *tgm = bs->opaque;
    180    throttle_group_attach_aio_context(tgm, new_context);
    181}
    182
    183static int throttle_reopen_prepare(BDRVReopenState *reopen_state,
    184                                   BlockReopenQueue *queue, Error **errp)
    185{
    186    int ret;
    187    char *group = NULL;
    188
    189    assert(reopen_state != NULL);
    190    assert(reopen_state->bs != NULL);
    191
    192    ret = throttle_parse_options(reopen_state->options, &group, errp);
    193    reopen_state->opaque = group;
    194    return ret;
    195}
    196
    197static void throttle_reopen_commit(BDRVReopenState *reopen_state)
    198{
    199    BlockDriverState *bs = reopen_state->bs;
    200    ThrottleGroupMember *tgm = bs->opaque;
    201    char *group = reopen_state->opaque;
    202
    203    assert(group);
    204
    205    if (strcmp(group, throttle_group_get_name(tgm))) {
    206        throttle_group_unregister_tgm(tgm);
    207        throttle_group_register_tgm(tgm, group, bdrv_get_aio_context(bs));
    208    }
    209    g_free(reopen_state->opaque);
    210    reopen_state->opaque = NULL;
    211}
    212
    213static void throttle_reopen_abort(BDRVReopenState *reopen_state)
    214{
    215    g_free(reopen_state->opaque);
    216    reopen_state->opaque = NULL;
    217}
    218
    219static void coroutine_fn throttle_co_drain_begin(BlockDriverState *bs)
    220{
    221    ThrottleGroupMember *tgm = bs->opaque;
    222    if (qatomic_fetch_inc(&tgm->io_limits_disabled) == 0) {
    223        throttle_group_restart_tgm(tgm);
    224    }
    225}
    226
    227static void coroutine_fn throttle_co_drain_end(BlockDriverState *bs)
    228{
    229    ThrottleGroupMember *tgm = bs->opaque;
    230    assert(tgm->io_limits_disabled);
    231    qatomic_dec(&tgm->io_limits_disabled);
    232}
    233
    234static const char *const throttle_strong_runtime_opts[] = {
    235    QEMU_OPT_THROTTLE_GROUP_NAME,
    236
    237    NULL
    238};
    239
    240static BlockDriver bdrv_throttle = {
    241    .format_name                        =   "throttle",
    242    .instance_size                      =   sizeof(ThrottleGroupMember),
    243
    244    .bdrv_open                          =   throttle_open,
    245    .bdrv_close                         =   throttle_close,
    246    .bdrv_co_flush                      =   throttle_co_flush,
    247
    248    .bdrv_child_perm                    =   bdrv_default_perms,
    249
    250    .bdrv_getlength                     =   throttle_getlength,
    251
    252    .bdrv_co_preadv                     =   throttle_co_preadv,
    253    .bdrv_co_pwritev                    =   throttle_co_pwritev,
    254
    255    .bdrv_co_pwrite_zeroes              =   throttle_co_pwrite_zeroes,
    256    .bdrv_co_pdiscard                   =   throttle_co_pdiscard,
    257    .bdrv_co_pwritev_compressed         =   throttle_co_pwritev_compressed,
    258
    259    .bdrv_attach_aio_context            =   throttle_attach_aio_context,
    260    .bdrv_detach_aio_context            =   throttle_detach_aio_context,
    261
    262    .bdrv_reopen_prepare                =   throttle_reopen_prepare,
    263    .bdrv_reopen_commit                 =   throttle_reopen_commit,
    264    .bdrv_reopen_abort                  =   throttle_reopen_abort,
    265
    266    .bdrv_co_drain_begin                =   throttle_co_drain_begin,
    267    .bdrv_co_drain_end                  =   throttle_co_drain_end,
    268
    269    .is_filter                          =   true,
    270    .strong_runtime_opts                =   throttle_strong_runtime_opts,
    271};
    272
    273static void bdrv_throttle_init(void)
    274{
    275    bdrv_register(&bdrv_throttle);
    276}
    277
    278block_init(bdrv_throttle_init);