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

qapi-sysemu.c (17247B)


      1/*
      2 * QMP command handlers specific to the system emulators
      3 *
      4 * Copyright (c) 2003-2008 Fabrice Bellard
      5 *
      6 * This work is licensed under the terms of the GNU GPL, version 2 or
      7 * later.  See the COPYING file in the top-level directory.
      8 *
      9 * This file incorporates work covered by the following copyright and
     10 * permission notice:
     11 *
     12 * Copyright (c) 2003-2008 Fabrice Bellard
     13 *
     14 * Permission is hereby granted, free of charge, to any person obtaining a copy
     15 * of this software and associated documentation files (the "Software"), to deal
     16 * in the Software without restriction, including without limitation the rights
     17 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     18 * copies of the Software, and to permit persons to whom the Software is
     19 * furnished to do so, subject to the following conditions:
     20 *
     21 * The above copyright notice and this permission notice shall be included in
     22 * all copies or substantial portions of the Software.
     23 *
     24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     27 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     29 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     30 * THE SOFTWARE.
     31 */
     32
     33#include "qemu/osdep.h"
     34
     35#include "qapi/error.h"
     36#include "qapi/qapi-commands-block.h"
     37#include "qapi/qmp/qdict.h"
     38#include "sysemu/block-backend.h"
     39#include "sysemu/blockdev.h"
     40
     41static BlockBackend *qmp_get_blk(const char *blk_name, const char *qdev_id,
     42                                 Error **errp)
     43{
     44    BlockBackend *blk;
     45
     46    if (!blk_name == !qdev_id) {
     47        error_setg(errp, "Need exactly one of 'device' and 'id'");
     48        return NULL;
     49    }
     50
     51    if (qdev_id) {
     52        blk = blk_by_qdev_id(qdev_id, errp);
     53    } else {
     54        blk = blk_by_name(blk_name);
     55        if (blk == NULL) {
     56            error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
     57                      "Device '%s' not found", blk_name);
     58        }
     59    }
     60
     61    return blk;
     62}
     63
     64/*
     65 * Attempt to open the tray of @device.
     66 * If @force, ignore its tray lock.
     67 * Else, if the tray is locked, don't open it, but ask the guest to open it.
     68 * On error, store an error through @errp and return -errno.
     69 * If @device does not exist, return -ENODEV.
     70 * If it has no removable media, return -ENOTSUP.
     71 * If it has no tray, return -ENOSYS.
     72 * If the guest was asked to open the tray, return -EINPROGRESS.
     73 * Else, return 0.
     74 */
     75static int do_open_tray(const char *blk_name, const char *qdev_id,
     76                        bool force, Error **errp)
     77{
     78    BlockBackend *blk;
     79    const char *device = qdev_id ?: blk_name;
     80    bool locked;
     81
     82    blk = qmp_get_blk(blk_name, qdev_id, errp);
     83    if (!blk) {
     84        return -ENODEV;
     85    }
     86
     87    if (!blk_dev_has_removable_media(blk)) {
     88        error_setg(errp, "Device '%s' is not removable", device);
     89        return -ENOTSUP;
     90    }
     91
     92    if (!blk_dev_has_tray(blk)) {
     93        error_setg(errp, "Device '%s' does not have a tray", device);
     94        return -ENOSYS;
     95    }
     96
     97    if (blk_dev_is_tray_open(blk)) {
     98        return 0;
     99    }
    100
    101    locked = blk_dev_is_medium_locked(blk);
    102    if (locked) {
    103        blk_dev_eject_request(blk, force);
    104    }
    105
    106    if (!locked || force) {
    107        blk_dev_change_media_cb(blk, false, &error_abort);
    108    }
    109
    110    if (locked && !force) {
    111        error_setg(errp, "Device '%s' is locked and force was not specified, "
    112                   "wait for tray to open and try again", device);
    113        return -EINPROGRESS;
    114    }
    115
    116    return 0;
    117}
    118
    119void qmp_blockdev_open_tray(bool has_device, const char *device,
    120                            bool has_id, const char *id,
    121                            bool has_force, bool force,
    122                            Error **errp)
    123{
    124    Error *local_err = NULL;
    125    int rc;
    126
    127    if (!has_force) {
    128        force = false;
    129    }
    130    rc = do_open_tray(has_device ? device : NULL,
    131                      has_id ? id : NULL,
    132                      force, &local_err);
    133    if (rc && rc != -ENOSYS && rc != -EINPROGRESS) {
    134        error_propagate(errp, local_err);
    135        return;
    136    }
    137    error_free(local_err);
    138}
    139
    140void qmp_blockdev_close_tray(bool has_device, const char *device,
    141                             bool has_id, const char *id,
    142                             Error **errp)
    143{
    144    BlockBackend *blk;
    145    Error *local_err = NULL;
    146
    147    device = has_device ? device : NULL;
    148    id = has_id ? id : NULL;
    149
    150    blk = qmp_get_blk(device, id, errp);
    151    if (!blk) {
    152        return;
    153    }
    154
    155    if (!blk_dev_has_removable_media(blk)) {
    156        error_setg(errp, "Device '%s' is not removable", device ?: id);
    157        return;
    158    }
    159
    160    if (!blk_dev_has_tray(blk)) {
    161        /* Ignore this command on tray-less devices */
    162        return;
    163    }
    164
    165    if (!blk_dev_is_tray_open(blk)) {
    166        return;
    167    }
    168
    169    blk_dev_change_media_cb(blk, true, &local_err);
    170    if (local_err) {
    171        error_propagate(errp, local_err);
    172        return;
    173    }
    174}
    175
    176static void blockdev_remove_medium(bool has_device, const char *device,
    177                                   bool has_id, const char *id, Error **errp)
    178{
    179    BlockBackend *blk;
    180    BlockDriverState *bs;
    181    AioContext *aio_context;
    182    bool has_attached_device;
    183
    184    device = has_device ? device : NULL;
    185    id = has_id ? id : NULL;
    186
    187    blk = qmp_get_blk(device, id, errp);
    188    if (!blk) {
    189        return;
    190    }
    191
    192    /* For BBs without a device, we can exchange the BDS tree at will */
    193    has_attached_device = blk_get_attached_dev(blk);
    194
    195    if (has_attached_device && !blk_dev_has_removable_media(blk)) {
    196        error_setg(errp, "Device '%s' is not removable", device ?: id);
    197        return;
    198    }
    199
    200    if (has_attached_device && blk_dev_has_tray(blk) &&
    201        !blk_dev_is_tray_open(blk))
    202    {
    203        error_setg(errp, "Tray of device '%s' is not open", device ?: id);
    204        return;
    205    }
    206
    207    bs = blk_bs(blk);
    208    if (!bs) {
    209        return;
    210    }
    211
    212    aio_context = bdrv_get_aio_context(bs);
    213    aio_context_acquire(aio_context);
    214
    215    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
    216        goto out;
    217    }
    218
    219    blk_remove_bs(blk);
    220
    221    if (!blk_dev_has_tray(blk)) {
    222        /* For tray-less devices, blockdev-open-tray is a no-op (or may not be
    223         * called at all); therefore, the medium needs to be ejected here.
    224         * Do it after blk_remove_bs() so blk_is_inserted(blk) returns the @load
    225         * value passed here (i.e. false). */
    226        blk_dev_change_media_cb(blk, false, &error_abort);
    227    }
    228
    229out:
    230    aio_context_release(aio_context);
    231}
    232
    233void qmp_blockdev_remove_medium(const char *id, Error **errp)
    234{
    235    blockdev_remove_medium(false, NULL, true, id, errp);
    236}
    237
    238static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
    239                                            BlockDriverState *bs, Error **errp)
    240{
    241    Error *local_err = NULL;
    242    bool has_device;
    243    int ret;
    244
    245    /* For BBs without a device, we can exchange the BDS tree at will */
    246    has_device = blk_get_attached_dev(blk);
    247
    248    if (has_device && !blk_dev_has_removable_media(blk)) {
    249        error_setg(errp, "Device is not removable");
    250        return;
    251    }
    252
    253    if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) {
    254        error_setg(errp, "Tray of the device is not open");
    255        return;
    256    }
    257
    258    if (blk_bs(blk)) {
    259        error_setg(errp, "There already is a medium in the device");
    260        return;
    261    }
    262
    263    ret = blk_insert_bs(blk, bs, errp);
    264    if (ret < 0) {
    265        return;
    266    }
    267
    268    if (!blk_dev_has_tray(blk)) {
    269        /* For tray-less devices, blockdev-close-tray is a no-op (or may not be
    270         * called at all); therefore, the medium needs to be pushed into the
    271         * slot here.
    272         * Do it after blk_insert_bs() so blk_is_inserted(blk) returns the @load
    273         * value passed here (i.e. true). */
    274        blk_dev_change_media_cb(blk, true, &local_err);
    275        if (local_err) {
    276            error_propagate(errp, local_err);
    277            blk_remove_bs(blk);
    278            return;
    279        }
    280    }
    281}
    282
    283static void blockdev_insert_medium(bool has_device, const char *device,
    284                                   bool has_id, const char *id,
    285                                   const char *node_name, Error **errp)
    286{
    287    BlockBackend *blk;
    288    BlockDriverState *bs;
    289
    290    blk = qmp_get_blk(has_device ? device : NULL,
    291                      has_id ? id : NULL,
    292                      errp);
    293    if (!blk) {
    294        return;
    295    }
    296
    297    bs = bdrv_find_node(node_name);
    298    if (!bs) {
    299        error_setg(errp, "Node '%s' not found", node_name);
    300        return;
    301    }
    302
    303    if (bdrv_has_blk(bs)) {
    304        error_setg(errp, "Node '%s' is already in use", node_name);
    305        return;
    306    }
    307
    308    qmp_blockdev_insert_anon_medium(blk, bs, errp);
    309}
    310
    311void qmp_blockdev_insert_medium(const char *id, const char *node_name,
    312                                Error **errp)
    313{
    314    blockdev_insert_medium(false, NULL, true, id, node_name, errp);
    315}
    316
    317void qmp_blockdev_change_medium(bool has_device, const char *device,
    318                                bool has_id, const char *id,
    319                                const char *filename,
    320                                bool has_format, const char *format,
    321                                bool has_read_only,
    322                                BlockdevChangeReadOnlyMode read_only,
    323                                Error **errp)
    324{
    325    BlockBackend *blk;
    326    BlockDriverState *medium_bs = NULL;
    327    int bdrv_flags;
    328    bool detect_zeroes;
    329    int rc;
    330    QDict *options = NULL;
    331    Error *err = NULL;
    332
    333    blk = qmp_get_blk(has_device ? device : NULL,
    334                      has_id ? id : NULL,
    335                      errp);
    336    if (!blk) {
    337        goto fail;
    338    }
    339
    340    if (blk_bs(blk)) {
    341        blk_update_root_state(blk);
    342    }
    343
    344    bdrv_flags = blk_get_open_flags_from_root_state(blk);
    345    bdrv_flags &= ~(BDRV_O_TEMPORARY | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING |
    346        BDRV_O_PROTOCOL | BDRV_O_AUTO_RDONLY);
    347
    348    if (!has_read_only) {
    349        read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN;
    350    }
    351
    352    switch (read_only) {
    353    case BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN:
    354        break;
    355
    356    case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_ONLY:
    357        bdrv_flags &= ~BDRV_O_RDWR;
    358        break;
    359
    360    case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_WRITE:
    361        bdrv_flags |= BDRV_O_RDWR;
    362        break;
    363
    364    default:
    365        abort();
    366    }
    367
    368    options = qdict_new();
    369    detect_zeroes = blk_get_detect_zeroes_from_root_state(blk);
    370    qdict_put_str(options, "detect-zeroes", detect_zeroes ? "on" : "off");
    371
    372    if (has_format) {
    373        qdict_put_str(options, "driver", format);
    374    }
    375
    376    medium_bs = bdrv_open(filename, NULL, options, bdrv_flags, errp);
    377    if (!medium_bs) {
    378        goto fail;
    379    }
    380
    381    rc = do_open_tray(has_device ? device : NULL,
    382                      has_id ? id : NULL,
    383                      false, &err);
    384    if (rc && rc != -ENOSYS) {
    385        error_propagate(errp, err);
    386        goto fail;
    387    }
    388    error_free(err);
    389    err = NULL;
    390
    391    blockdev_remove_medium(has_device, device, has_id, id, &err);
    392    if (err) {
    393        error_propagate(errp, err);
    394        goto fail;
    395    }
    396
    397    qmp_blockdev_insert_anon_medium(blk, medium_bs, &err);
    398    if (err) {
    399        error_propagate(errp, err);
    400        goto fail;
    401    }
    402
    403    qmp_blockdev_close_tray(has_device, device, has_id, id, errp);
    404
    405fail:
    406    /* If the medium has been inserted, the device has its own reference, so
    407     * ours must be relinquished; and if it has not been inserted successfully,
    408     * the reference must be relinquished anyway */
    409    bdrv_unref(medium_bs);
    410}
    411
    412void qmp_eject(bool has_device, const char *device,
    413               bool has_id, const char *id,
    414               bool has_force, bool force, Error **errp)
    415{
    416    Error *local_err = NULL;
    417    int rc;
    418
    419    if (!has_force) {
    420        force = false;
    421    }
    422
    423    rc = do_open_tray(has_device ? device : NULL,
    424                      has_id ? id : NULL,
    425                      force, &local_err);
    426    if (rc && rc != -ENOSYS) {
    427        error_propagate(errp, local_err);
    428        return;
    429    }
    430    error_free(local_err);
    431
    432    blockdev_remove_medium(has_device, device, has_id, id, errp);
    433}
    434
    435/* throttling disk I/O limits */
    436void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp)
    437{
    438    ThrottleConfig cfg;
    439    BlockDriverState *bs;
    440    BlockBackend *blk;
    441    AioContext *aio_context;
    442
    443    blk = qmp_get_blk(arg->has_device ? arg->device : NULL,
    444                      arg->has_id ? arg->id : NULL,
    445                      errp);
    446    if (!blk) {
    447        return;
    448    }
    449
    450    aio_context = blk_get_aio_context(blk);
    451    aio_context_acquire(aio_context);
    452
    453    bs = blk_bs(blk);
    454    if (!bs) {
    455        error_setg(errp, "Device has no medium");
    456        goto out;
    457    }
    458
    459    throttle_config_init(&cfg);
    460    cfg.buckets[THROTTLE_BPS_TOTAL].avg = arg->bps;
    461    cfg.buckets[THROTTLE_BPS_READ].avg  = arg->bps_rd;
    462    cfg.buckets[THROTTLE_BPS_WRITE].avg = arg->bps_wr;
    463
    464    cfg.buckets[THROTTLE_OPS_TOTAL].avg = arg->iops;
    465    cfg.buckets[THROTTLE_OPS_READ].avg  = arg->iops_rd;
    466    cfg.buckets[THROTTLE_OPS_WRITE].avg = arg->iops_wr;
    467
    468    if (arg->has_bps_max) {
    469        cfg.buckets[THROTTLE_BPS_TOTAL].max = arg->bps_max;
    470    }
    471    if (arg->has_bps_rd_max) {
    472        cfg.buckets[THROTTLE_BPS_READ].max = arg->bps_rd_max;
    473    }
    474    if (arg->has_bps_wr_max) {
    475        cfg.buckets[THROTTLE_BPS_WRITE].max = arg->bps_wr_max;
    476    }
    477    if (arg->has_iops_max) {
    478        cfg.buckets[THROTTLE_OPS_TOTAL].max = arg->iops_max;
    479    }
    480    if (arg->has_iops_rd_max) {
    481        cfg.buckets[THROTTLE_OPS_READ].max = arg->iops_rd_max;
    482    }
    483    if (arg->has_iops_wr_max) {
    484        cfg.buckets[THROTTLE_OPS_WRITE].max = arg->iops_wr_max;
    485    }
    486
    487    if (arg->has_bps_max_length) {
    488        cfg.buckets[THROTTLE_BPS_TOTAL].burst_length = arg->bps_max_length;
    489    }
    490    if (arg->has_bps_rd_max_length) {
    491        cfg.buckets[THROTTLE_BPS_READ].burst_length = arg->bps_rd_max_length;
    492    }
    493    if (arg->has_bps_wr_max_length) {
    494        cfg.buckets[THROTTLE_BPS_WRITE].burst_length = arg->bps_wr_max_length;
    495    }
    496    if (arg->has_iops_max_length) {
    497        cfg.buckets[THROTTLE_OPS_TOTAL].burst_length = arg->iops_max_length;
    498    }
    499    if (arg->has_iops_rd_max_length) {
    500        cfg.buckets[THROTTLE_OPS_READ].burst_length = arg->iops_rd_max_length;
    501    }
    502    if (arg->has_iops_wr_max_length) {
    503        cfg.buckets[THROTTLE_OPS_WRITE].burst_length = arg->iops_wr_max_length;
    504    }
    505
    506    if (arg->has_iops_size) {
    507        cfg.op_size = arg->iops_size;
    508    }
    509
    510    if (!throttle_is_valid(&cfg, errp)) {
    511        goto out;
    512    }
    513
    514    if (throttle_enabled(&cfg)) {
    515        /* Enable I/O limits if they're not enabled yet, otherwise
    516         * just update the throttling group. */
    517        if (!blk_get_public(blk)->throttle_group_member.throttle_state) {
    518            blk_io_limits_enable(blk,
    519                                 arg->has_group ? arg->group :
    520                                 arg->has_device ? arg->device :
    521                                 arg->id);
    522        } else if (arg->has_group) {
    523            blk_io_limits_update_group(blk, arg->group);
    524        }
    525        /* Set the new throttling configuration */
    526        blk_set_io_limits(blk, &cfg);
    527    } else if (blk_get_public(blk)->throttle_group_member.throttle_state) {
    528        /* If all throttling settings are set to 0, disable I/O limits */
    529        blk_io_limits_disable(blk);
    530    }
    531
    532out:
    533    aio_context_release(aio_context);
    534}
    535
    536void qmp_block_latency_histogram_set(
    537    const char *id,
    538    bool has_boundaries, uint64List *boundaries,
    539    bool has_boundaries_read, uint64List *boundaries_read,
    540    bool has_boundaries_write, uint64List *boundaries_write,
    541    bool has_boundaries_flush, uint64List *boundaries_flush,
    542    Error **errp)
    543{
    544    BlockBackend *blk = qmp_get_blk(NULL, id, errp);
    545    BlockAcctStats *stats;
    546    int ret;
    547
    548    if (!blk) {
    549        return;
    550    }
    551
    552    stats = blk_get_stats(blk);
    553
    554    if (!has_boundaries && !has_boundaries_read && !has_boundaries_write &&
    555        !has_boundaries_flush)
    556    {
    557        block_latency_histograms_clear(stats);
    558        return;
    559    }
    560
    561    if (has_boundaries || has_boundaries_read) {
    562        ret = block_latency_histogram_set(
    563            stats, BLOCK_ACCT_READ,
    564            has_boundaries_read ? boundaries_read : boundaries);
    565        if (ret) {
    566            error_setg(errp, "Device '%s' set read boundaries fail", id);
    567            return;
    568        }
    569    }
    570
    571    if (has_boundaries || has_boundaries_write) {
    572        ret = block_latency_histogram_set(
    573            stats, BLOCK_ACCT_WRITE,
    574            has_boundaries_write ? boundaries_write : boundaries);
    575        if (ret) {
    576            error_setg(errp, "Device '%s' set write boundaries fail", id);
    577            return;
    578        }
    579    }
    580
    581    if (has_boundaries || has_boundaries_flush) {
    582        ret = block_latency_histogram_set(
    583            stats, BLOCK_ACCT_FLUSH,
    584            has_boundaries_flush ? boundaries_flush : boundaries);
    585        if (ret) {
    586            error_setg(errp, "Device '%s' set flush boundaries fail", id);
    587            return;
    588        }
    589    }
    590}