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

block-hmp-cmds.c (31656B)


      1/*
      2 * Blockdev HMP commands
      3 *
      4 *  Authors:
      5 *  Anthony Liguori   <aliguori@us.ibm.com>
      6 *
      7 * Copyright (c) 2003-2008 Fabrice Bellard
      8 *
      9 * This work is licensed under the terms of the GNU GPL, version 2.
     10 * See the COPYING file in the top-level directory.
     11 * Contributions after 2012-01-13 are licensed under the terms of the
     12 * GNU GPL, version 2 or (at your option) any later version.
     13 *
     14 * This file incorporates work covered by the following copyright and
     15 * permission notice:
     16 *
     17 * Copyright (c) 2003-2008 Fabrice Bellard
     18 *
     19 * Permission is hereby granted, free of charge, to any person obtaining a copy
     20 * of this software and associated documentation files (the "Software"), to deal
     21 * in the Software without restriction, including without limitation the rights
     22 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     23 * copies of the Software, and to permit persons to whom the Software is
     24 * furnished to do so, subject to the following conditions:
     25 *
     26 * The above copyright notice and this permission notice shall be included in
     27 * all copies or substantial portions of the Software.
     28 *
     29 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     30 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     31 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     32 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     33 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     34 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     35 * THE SOFTWARE.
     36 */
     37
     38#include "qemu/osdep.h"
     39#include "hw/boards.h"
     40#include "sysemu/block-backend.h"
     41#include "sysemu/blockdev.h"
     42#include "qapi/qapi-commands-block.h"
     43#include "qapi/qapi-commands-block-export.h"
     44#include "qapi/qmp/qdict.h"
     45#include "qapi/error.h"
     46#include "qapi/qmp/qerror.h"
     47#include "qemu/config-file.h"
     48#include "qemu/option.h"
     49#include "qemu/sockets.h"
     50#include "qemu/cutils.h"
     51#include "sysemu/sysemu.h"
     52#include "monitor/monitor.h"
     53#include "monitor/hmp.h"
     54#include "block/nbd.h"
     55#include "block/qapi.h"
     56#include "block/block_int.h"
     57#include "block/block-hmp-cmds.h"
     58#include "qemu-io.h"
     59
     60static void hmp_drive_add_node(Monitor *mon, const char *optstr)
     61{
     62    QemuOpts *opts;
     63    QDict *qdict;
     64    Error *local_err = NULL;
     65
     66    opts = qemu_opts_parse_noisily(&qemu_drive_opts, optstr, false);
     67    if (!opts) {
     68        return;
     69    }
     70
     71    qdict = qemu_opts_to_qdict(opts, NULL);
     72
     73    if (!qdict_get_try_str(qdict, "node-name")) {
     74        qobject_unref(qdict);
     75        error_report("'node-name' needs to be specified");
     76        goto out;
     77    }
     78
     79    BlockDriverState *bs = bds_tree_init(qdict, &local_err);
     80    if (!bs) {
     81        error_report_err(local_err);
     82        goto out;
     83    }
     84
     85    bdrv_set_monitor_owned(bs);
     86out:
     87    qemu_opts_del(opts);
     88}
     89
     90void hmp_drive_add(Monitor *mon, const QDict *qdict)
     91{
     92    Error *err = NULL;
     93    DriveInfo *dinfo;
     94    QemuOpts *opts;
     95    MachineClass *mc;
     96    const char *optstr = qdict_get_str(qdict, "opts");
     97    bool node = qdict_get_try_bool(qdict, "node", false);
     98
     99    if (node) {
    100        hmp_drive_add_node(mon, optstr);
    101        return;
    102    }
    103
    104    opts = drive_def(optstr);
    105    if (!opts)
    106        return;
    107
    108    mc = MACHINE_GET_CLASS(current_machine);
    109    dinfo = drive_new(opts, mc->block_default_type, &err);
    110    if (err) {
    111        error_report_err(err);
    112        qemu_opts_del(opts);
    113        goto err;
    114    }
    115
    116    if (!dinfo) {
    117        return;
    118    }
    119
    120    switch (dinfo->type) {
    121    case IF_NONE:
    122        monitor_printf(mon, "OK\n");
    123        break;
    124    default:
    125        monitor_printf(mon, "Can't hot-add drive to type %d\n", dinfo->type);
    126        goto err;
    127    }
    128    return;
    129
    130err:
    131    if (dinfo) {
    132        BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
    133        monitor_remove_blk(blk);
    134        blk_unref(blk);
    135    }
    136}
    137
    138void hmp_drive_del(Monitor *mon, const QDict *qdict)
    139{
    140    const char *id = qdict_get_str(qdict, "id");
    141    BlockBackend *blk;
    142    BlockDriverState *bs;
    143    AioContext *aio_context;
    144    Error *local_err = NULL;
    145
    146    bs = bdrv_find_node(id);
    147    if (bs) {
    148        qmp_blockdev_del(id, &local_err);
    149        if (local_err) {
    150            error_report_err(local_err);
    151        }
    152        return;
    153    }
    154
    155    blk = blk_by_name(id);
    156    if (!blk) {
    157        error_report("Device '%s' not found", id);
    158        return;
    159    }
    160
    161    if (!blk_legacy_dinfo(blk)) {
    162        error_report("Deleting device added with blockdev-add"
    163                     " is not supported");
    164        return;
    165    }
    166
    167    aio_context = blk_get_aio_context(blk);
    168    aio_context_acquire(aio_context);
    169
    170    bs = blk_bs(blk);
    171    if (bs) {
    172        if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &local_err)) {
    173            error_report_err(local_err);
    174            aio_context_release(aio_context);
    175            return;
    176        }
    177
    178        blk_remove_bs(blk);
    179    }
    180
    181    /* Make the BlockBackend and the attached BlockDriverState anonymous */
    182    monitor_remove_blk(blk);
    183
    184    /*
    185     * If this BlockBackend has a device attached to it, its refcount will be
    186     * decremented when the device is removed; otherwise we have to do so here.
    187     */
    188    if (blk_get_attached_dev(blk)) {
    189        /* Further I/O must not pause the guest */
    190        blk_set_on_error(blk, BLOCKDEV_ON_ERROR_REPORT,
    191                         BLOCKDEV_ON_ERROR_REPORT);
    192    } else {
    193        blk_unref(blk);
    194    }
    195
    196    aio_context_release(aio_context);
    197}
    198
    199void hmp_commit(Monitor *mon, const QDict *qdict)
    200{
    201    const char *device = qdict_get_str(qdict, "device");
    202    BlockBackend *blk;
    203    int ret;
    204
    205    if (!strcmp(device, "all")) {
    206        ret = blk_commit_all();
    207    } else {
    208        BlockDriverState *bs;
    209        AioContext *aio_context;
    210
    211        blk = blk_by_name(device);
    212        if (!blk) {
    213            error_report("Device '%s' not found", device);
    214            return;
    215        }
    216        if (!blk_is_available(blk)) {
    217            error_report("Device '%s' has no medium", device);
    218            return;
    219        }
    220
    221        bs = bdrv_skip_implicit_filters(blk_bs(blk));
    222        aio_context = bdrv_get_aio_context(bs);
    223        aio_context_acquire(aio_context);
    224
    225        ret = bdrv_commit(bs);
    226
    227        aio_context_release(aio_context);
    228    }
    229    if (ret < 0) {
    230        error_report("'commit' error for '%s': %s", device, strerror(-ret));
    231    }
    232}
    233
    234void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
    235{
    236    const char *filename = qdict_get_str(qdict, "target");
    237    const char *format = qdict_get_try_str(qdict, "format");
    238    bool reuse = qdict_get_try_bool(qdict, "reuse", false);
    239    bool full = qdict_get_try_bool(qdict, "full", false);
    240    Error *err = NULL;
    241    DriveMirror mirror = {
    242        .device = (char *)qdict_get_str(qdict, "device"),
    243        .target = (char *)filename,
    244        .has_format = !!format,
    245        .format = (char *)format,
    246        .sync = full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
    247        .has_mode = true,
    248        .mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS,
    249        .unmap = true,
    250    };
    251
    252    if (!filename) {
    253        error_setg(&err, QERR_MISSING_PARAMETER, "target");
    254        goto end;
    255    }
    256    qmp_drive_mirror(&mirror, &err);
    257end:
    258    hmp_handle_error(mon, err);
    259}
    260
    261void hmp_drive_backup(Monitor *mon, const QDict *qdict)
    262{
    263    const char *device = qdict_get_str(qdict, "device");
    264    const char *filename = qdict_get_str(qdict, "target");
    265    const char *format = qdict_get_try_str(qdict, "format");
    266    bool reuse = qdict_get_try_bool(qdict, "reuse", false);
    267    bool full = qdict_get_try_bool(qdict, "full", false);
    268    bool compress = qdict_get_try_bool(qdict, "compress", false);
    269    Error *err = NULL;
    270    DriveBackup backup = {
    271        .device = (char *)device,
    272        .target = (char *)filename,
    273        .has_format = !!format,
    274        .format = (char *)format,
    275        .sync = full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
    276        .has_mode = true,
    277        .mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS,
    278        .has_compress = !!compress,
    279        .compress = compress,
    280    };
    281
    282    if (!filename) {
    283        error_setg(&err, QERR_MISSING_PARAMETER, "target");
    284        goto end;
    285    }
    286
    287    qmp_drive_backup(&backup, &err);
    288end:
    289    hmp_handle_error(mon, err);
    290}
    291
    292void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict)
    293{
    294    Error *error = NULL;
    295    const char *device = qdict_get_str(qdict, "device");
    296    int64_t value = qdict_get_int(qdict, "speed");
    297
    298    qmp_block_job_set_speed(device, value, &error);
    299
    300    hmp_handle_error(mon, error);
    301}
    302
    303void hmp_block_job_cancel(Monitor *mon, const QDict *qdict)
    304{
    305    Error *error = NULL;
    306    const char *device = qdict_get_str(qdict, "device");
    307    bool force = qdict_get_try_bool(qdict, "force", false);
    308
    309    qmp_block_job_cancel(device, true, force, &error);
    310
    311    hmp_handle_error(mon, error);
    312}
    313
    314void hmp_block_job_pause(Monitor *mon, const QDict *qdict)
    315{
    316    Error *error = NULL;
    317    const char *device = qdict_get_str(qdict, "device");
    318
    319    qmp_block_job_pause(device, &error);
    320
    321    hmp_handle_error(mon, error);
    322}
    323
    324void hmp_block_job_resume(Monitor *mon, const QDict *qdict)
    325{
    326    Error *error = NULL;
    327    const char *device = qdict_get_str(qdict, "device");
    328
    329    qmp_block_job_resume(device, &error);
    330
    331    hmp_handle_error(mon, error);
    332}
    333
    334void hmp_block_job_complete(Monitor *mon, const QDict *qdict)
    335{
    336    Error *error = NULL;
    337    const char *device = qdict_get_str(qdict, "device");
    338
    339    qmp_block_job_complete(device, &error);
    340
    341    hmp_handle_error(mon, error);
    342}
    343
    344void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
    345{
    346    const char *device = qdict_get_str(qdict, "device");
    347    const char *filename = qdict_get_try_str(qdict, "snapshot-file");
    348    const char *format = qdict_get_try_str(qdict, "format");
    349    bool reuse = qdict_get_try_bool(qdict, "reuse", false);
    350    enum NewImageMode mode;
    351    Error *err = NULL;
    352
    353    if (!filename) {
    354        /*
    355         * In the future, if 'snapshot-file' is not specified, the snapshot
    356         * will be taken internally. Today it's actually required.
    357         */
    358        error_setg(&err, QERR_MISSING_PARAMETER, "snapshot-file");
    359        goto end;
    360    }
    361
    362    mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS;
    363    qmp_blockdev_snapshot_sync(true, device, false, NULL,
    364                               filename, false, NULL,
    365                               !!format, format,
    366                               true, mode, &err);
    367end:
    368    hmp_handle_error(mon, err);
    369}
    370
    371void hmp_snapshot_blkdev_internal(Monitor *mon, const QDict *qdict)
    372{
    373    const char *device = qdict_get_str(qdict, "device");
    374    const char *name = qdict_get_str(qdict, "name");
    375    Error *err = NULL;
    376
    377    qmp_blockdev_snapshot_internal_sync(device, name, &err);
    378    hmp_handle_error(mon, err);
    379}
    380
    381void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict)
    382{
    383    const char *device = qdict_get_str(qdict, "device");
    384    const char *name = qdict_get_str(qdict, "name");
    385    const char *id = qdict_get_try_str(qdict, "id");
    386    Error *err = NULL;
    387
    388    qmp_blockdev_snapshot_delete_internal_sync(device, !!id, id,
    389                                               true, name, &err);
    390    hmp_handle_error(mon, err);
    391}
    392
    393void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
    394{
    395    const char *uri = qdict_get_str(qdict, "uri");
    396    bool writable = qdict_get_try_bool(qdict, "writable", false);
    397    bool all = qdict_get_try_bool(qdict, "all", false);
    398    Error *local_err = NULL;
    399    BlockInfoList *block_list, *info;
    400    SocketAddress *addr;
    401    NbdServerAddOptions export;
    402
    403    if (writable && !all) {
    404        error_setg(&local_err, "-w only valid together with -a");
    405        goto exit;
    406    }
    407
    408    /* First check if the address is valid and start the server.  */
    409    addr = socket_parse(uri, &local_err);
    410    if (local_err != NULL) {
    411        goto exit;
    412    }
    413
    414    nbd_server_start(addr, NULL, NULL, 0, &local_err);
    415    qapi_free_SocketAddress(addr);
    416    if (local_err != NULL) {
    417        goto exit;
    418    }
    419
    420    if (!all) {
    421        return;
    422    }
    423
    424    /* Then try adding all block devices.  If one fails, close all and
    425     * exit.
    426     */
    427    block_list = qmp_query_block(NULL);
    428
    429    for (info = block_list; info; info = info->next) {
    430        if (!info->value->has_inserted) {
    431            continue;
    432        }
    433
    434        export = (NbdServerAddOptions) {
    435            .device         = info->value->device,
    436            .has_writable   = true,
    437            .writable       = writable,
    438        };
    439
    440        qmp_nbd_server_add(&export, &local_err);
    441
    442        if (local_err != NULL) {
    443            qmp_nbd_server_stop(NULL);
    444            break;
    445        }
    446    }
    447
    448    qapi_free_BlockInfoList(block_list);
    449
    450exit:
    451    hmp_handle_error(mon, local_err);
    452}
    453
    454void hmp_nbd_server_add(Monitor *mon, const QDict *qdict)
    455{
    456    const char *device = qdict_get_str(qdict, "device");
    457    const char *name = qdict_get_try_str(qdict, "name");
    458    bool writable = qdict_get_try_bool(qdict, "writable", false);
    459    Error *local_err = NULL;
    460
    461    NbdServerAddOptions export = {
    462        .device         = (char *) device,
    463        .has_name       = !!name,
    464        .name           = (char *) name,
    465        .has_writable   = true,
    466        .writable       = writable,
    467    };
    468
    469    qmp_nbd_server_add(&export, &local_err);
    470    hmp_handle_error(mon, local_err);
    471}
    472
    473void hmp_nbd_server_remove(Monitor *mon, const QDict *qdict)
    474{
    475    const char *name = qdict_get_str(qdict, "name");
    476    bool force = qdict_get_try_bool(qdict, "force", false);
    477    Error *err = NULL;
    478
    479    /* Rely on BLOCK_EXPORT_REMOVE_MODE_SAFE being the default */
    480    qmp_nbd_server_remove(name, force, BLOCK_EXPORT_REMOVE_MODE_HARD, &err);
    481    hmp_handle_error(mon, err);
    482}
    483
    484void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict)
    485{
    486    Error *err = NULL;
    487
    488    qmp_nbd_server_stop(&err);
    489    hmp_handle_error(mon, err);
    490}
    491
    492void hmp_block_resize(Monitor *mon, const QDict *qdict)
    493{
    494    const char *device = qdict_get_str(qdict, "device");
    495    int64_t size = qdict_get_int(qdict, "size");
    496    Error *err = NULL;
    497
    498    qmp_block_resize(true, device, false, NULL, size, &err);
    499    hmp_handle_error(mon, err);
    500}
    501
    502void hmp_block_stream(Monitor *mon, const QDict *qdict)
    503{
    504    Error *error = NULL;
    505    const char *device = qdict_get_str(qdict, "device");
    506    const char *base = qdict_get_try_str(qdict, "base");
    507    int64_t speed = qdict_get_try_int(qdict, "speed", 0);
    508
    509    qmp_block_stream(true, device, device, base != NULL, base, false, NULL,
    510                     false, NULL, false, NULL,
    511                     qdict_haskey(qdict, "speed"), speed, true,
    512                     BLOCKDEV_ON_ERROR_REPORT, false, NULL, false, false, false,
    513                     false, &error);
    514
    515    hmp_handle_error(mon, error);
    516}
    517
    518void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
    519{
    520    Error *err = NULL;
    521    char *device = (char *) qdict_get_str(qdict, "device");
    522    BlockIOThrottle throttle = {
    523        .bps = qdict_get_int(qdict, "bps"),
    524        .bps_rd = qdict_get_int(qdict, "bps_rd"),
    525        .bps_wr = qdict_get_int(qdict, "bps_wr"),
    526        .iops = qdict_get_int(qdict, "iops"),
    527        .iops_rd = qdict_get_int(qdict, "iops_rd"),
    528        .iops_wr = qdict_get_int(qdict, "iops_wr"),
    529    };
    530
    531    /*
    532     * qmp_block_set_io_throttle has separate parameters for the
    533     * (deprecated) block device name and the qdev ID but the HMP
    534     * version has only one, so we must decide which one to pass.
    535     */
    536    if (blk_by_name(device)) {
    537        throttle.has_device = true;
    538        throttle.device = device;
    539    } else {
    540        throttle.has_id = true;
    541        throttle.id = device;
    542    }
    543
    544    qmp_block_set_io_throttle(&throttle, &err);
    545    hmp_handle_error(mon, err);
    546}
    547
    548void hmp_eject(Monitor *mon, const QDict *qdict)
    549{
    550    bool force = qdict_get_try_bool(qdict, "force", false);
    551    const char *device = qdict_get_str(qdict, "device");
    552    Error *err = NULL;
    553
    554    qmp_eject(true, device, false, NULL, true, force, &err);
    555    hmp_handle_error(mon, err);
    556}
    557
    558void hmp_qemu_io(Monitor *mon, const QDict *qdict)
    559{
    560    BlockBackend *blk = NULL;
    561    BlockDriverState *bs = NULL;
    562    BlockBackend *local_blk = NULL;
    563    AioContext *ctx = NULL;
    564    bool qdev = qdict_get_try_bool(qdict, "qdev", false);
    565    const char *device = qdict_get_str(qdict, "device");
    566    const char *command = qdict_get_str(qdict, "command");
    567    Error *err = NULL;
    568    int ret;
    569
    570    if (qdev) {
    571        blk = blk_by_qdev_id(device, &err);
    572        if (!blk) {
    573            goto fail;
    574        }
    575    } else {
    576        blk = blk_by_name(device);
    577        if (!blk) {
    578            bs = bdrv_lookup_bs(NULL, device, &err);
    579            if (!bs) {
    580                goto fail;
    581            }
    582        }
    583    }
    584
    585    ctx = blk ? blk_get_aio_context(blk) : bdrv_get_aio_context(bs);
    586    aio_context_acquire(ctx);
    587
    588    if (bs) {
    589        blk = local_blk = blk_new(bdrv_get_aio_context(bs), 0, BLK_PERM_ALL);
    590        ret = blk_insert_bs(blk, bs, &err);
    591        if (ret < 0) {
    592            goto fail;
    593        }
    594    }
    595
    596    /*
    597     * Notably absent: Proper permission management. This is sad, but it seems
    598     * almost impossible to achieve without changing the semantics and thereby
    599     * limiting the use cases of the qemu-io HMP command.
    600     *
    601     * In an ideal world we would unconditionally create a new BlockBackend for
    602     * qemuio_command(), but we have commands like 'reopen' and want them to
    603     * take effect on the exact BlockBackend whose name the user passed instead
    604     * of just on a temporary copy of it.
    605     *
    606     * Another problem is that deleting the temporary BlockBackend involves
    607     * draining all requests on it first, but some qemu-iotests cases want to
    608     * issue multiple aio_read/write requests and expect them to complete in
    609     * the background while the monitor has already returned.
    610     *
    611     * This is also what prevents us from saving the original permissions and
    612     * restoring them later: We can't revoke permissions until all requests
    613     * have completed, and we don't know when that is nor can we really let
    614     * anything else run before we have revoken them to avoid race conditions.
    615     *
    616     * What happens now is that command() in qemu-io-cmds.c can extend the
    617     * permissions if necessary for the qemu-io command. And they simply stay
    618     * extended, possibly resulting in a read-only guest device keeping write
    619     * permissions. Ugly, but it appears to be the lesser evil.
    620     */
    621    qemuio_command(blk, command);
    622
    623fail:
    624    blk_unref(local_blk);
    625
    626    if (ctx) {
    627        aio_context_release(ctx);
    628    }
    629
    630    hmp_handle_error(mon, err);
    631}
    632
    633static void print_block_info(Monitor *mon, BlockInfo *info,
    634                             BlockDeviceInfo *inserted, bool verbose)
    635{
    636    ImageInfo *image_info;
    637
    638    assert(!info || !info->has_inserted || info->inserted == inserted);
    639
    640    if (info && *info->device) {
    641        monitor_printf(mon, "%s", info->device);
    642        if (inserted && inserted->has_node_name) {
    643            monitor_printf(mon, " (%s)", inserted->node_name);
    644        }
    645    } else {
    646        assert(info || inserted);
    647        monitor_printf(mon, "%s",
    648                       inserted && inserted->has_node_name ? inserted->node_name
    649                       : info && info->has_qdev ? info->qdev
    650                       : "<anonymous>");
    651    }
    652
    653    if (inserted) {
    654        monitor_printf(mon, ": %s (%s%s%s)\n",
    655                       inserted->file,
    656                       inserted->drv,
    657                       inserted->ro ? ", read-only" : "",
    658                       inserted->encrypted ? ", encrypted" : "");
    659    } else {
    660        monitor_printf(mon, ": [not inserted]\n");
    661    }
    662
    663    if (info) {
    664        if (info->has_qdev) {
    665            monitor_printf(mon, "    Attached to:      %s\n", info->qdev);
    666        }
    667        if (info->has_io_status && info->io_status != BLOCK_DEVICE_IO_STATUS_OK) {
    668            monitor_printf(mon, "    I/O status:       %s\n",
    669                           BlockDeviceIoStatus_str(info->io_status));
    670        }
    671
    672        if (info->removable) {
    673            monitor_printf(mon, "    Removable device: %slocked, tray %s\n",
    674                           info->locked ? "" : "not ",
    675                           info->tray_open ? "open" : "closed");
    676        }
    677    }
    678
    679
    680    if (!inserted) {
    681        return;
    682    }
    683
    684    monitor_printf(mon, "    Cache mode:       %s%s%s\n",
    685                   inserted->cache->writeback ? "writeback" : "writethrough",
    686                   inserted->cache->direct ? ", direct" : "",
    687                   inserted->cache->no_flush ? ", ignore flushes" : "");
    688
    689    if (inserted->has_backing_file) {
    690        monitor_printf(mon,
    691                       "    Backing file:     %s "
    692                       "(chain depth: %" PRId64 ")\n",
    693                       inserted->backing_file,
    694                       inserted->backing_file_depth);
    695    }
    696
    697    if (inserted->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF) {
    698        monitor_printf(mon, "    Detect zeroes:    %s\n",
    699                BlockdevDetectZeroesOptions_str(inserted->detect_zeroes));
    700    }
    701
    702    if (inserted->bps  || inserted->bps_rd  || inserted->bps_wr  ||
    703        inserted->iops || inserted->iops_rd || inserted->iops_wr)
    704    {
    705        monitor_printf(mon, "    I/O throttling:   bps=%" PRId64
    706                        " bps_rd=%" PRId64  " bps_wr=%" PRId64
    707                        " bps_max=%" PRId64
    708                        " bps_rd_max=%" PRId64
    709                        " bps_wr_max=%" PRId64
    710                        " iops=%" PRId64 " iops_rd=%" PRId64
    711                        " iops_wr=%" PRId64
    712                        " iops_max=%" PRId64
    713                        " iops_rd_max=%" PRId64
    714                        " iops_wr_max=%" PRId64
    715                        " iops_size=%" PRId64
    716                        " group=%s\n",
    717                        inserted->bps,
    718                        inserted->bps_rd,
    719                        inserted->bps_wr,
    720                        inserted->bps_max,
    721                        inserted->bps_rd_max,
    722                        inserted->bps_wr_max,
    723                        inserted->iops,
    724                        inserted->iops_rd,
    725                        inserted->iops_wr,
    726                        inserted->iops_max,
    727                        inserted->iops_rd_max,
    728                        inserted->iops_wr_max,
    729                        inserted->iops_size,
    730                        inserted->group);
    731    }
    732
    733    if (verbose) {
    734        monitor_printf(mon, "\nImages:\n");
    735        image_info = inserted->image;
    736        while (1) {
    737                bdrv_image_info_dump(image_info);
    738            if (image_info->has_backing_image) {
    739                image_info = image_info->backing_image;
    740            } else {
    741                break;
    742            }
    743        }
    744    }
    745}
    746
    747void hmp_info_block(Monitor *mon, const QDict *qdict)
    748{
    749    BlockInfoList *block_list, *info;
    750    BlockDeviceInfoList *blockdev_list, *blockdev;
    751    const char *device = qdict_get_try_str(qdict, "device");
    752    bool verbose = qdict_get_try_bool(qdict, "verbose", false);
    753    bool nodes = qdict_get_try_bool(qdict, "nodes", false);
    754    bool printed = false;
    755
    756    /* Print BlockBackend information */
    757    if (!nodes) {
    758        block_list = qmp_query_block(NULL);
    759    } else {
    760        block_list = NULL;
    761    }
    762
    763    for (info = block_list; info; info = info->next) {
    764        if (device && strcmp(device, info->value->device)) {
    765            continue;
    766        }
    767
    768        if (info != block_list) {
    769            monitor_printf(mon, "\n");
    770        }
    771
    772        print_block_info(mon, info->value, info->value->has_inserted
    773                                           ? info->value->inserted : NULL,
    774                         verbose);
    775        printed = true;
    776    }
    777
    778    qapi_free_BlockInfoList(block_list);
    779
    780    if ((!device && !nodes) || printed) {
    781        return;
    782    }
    783
    784    /* Print node information */
    785    blockdev_list = qmp_query_named_block_nodes(false, false, NULL);
    786    for (blockdev = blockdev_list; blockdev; blockdev = blockdev->next) {
    787        assert(blockdev->value->has_node_name);
    788        if (device && strcmp(device, blockdev->value->node_name)) {
    789            continue;
    790        }
    791
    792        if (blockdev != blockdev_list) {
    793            monitor_printf(mon, "\n");
    794        }
    795
    796        print_block_info(mon, NULL, blockdev->value, verbose);
    797    }
    798    qapi_free_BlockDeviceInfoList(blockdev_list);
    799}
    800
    801void hmp_info_blockstats(Monitor *mon, const QDict *qdict)
    802{
    803    BlockStatsList *stats_list, *stats;
    804
    805    stats_list = qmp_query_blockstats(false, false, NULL);
    806
    807    for (stats = stats_list; stats; stats = stats->next) {
    808        if (!stats->value->has_device) {
    809            continue;
    810        }
    811
    812        monitor_printf(mon, "%s:", stats->value->device);
    813        monitor_printf(mon, " rd_bytes=%" PRId64
    814                       " wr_bytes=%" PRId64
    815                       " rd_operations=%" PRId64
    816                       " wr_operations=%" PRId64
    817                       " flush_operations=%" PRId64
    818                       " wr_total_time_ns=%" PRId64
    819                       " rd_total_time_ns=%" PRId64
    820                       " flush_total_time_ns=%" PRId64
    821                       " rd_merged=%" PRId64
    822                       " wr_merged=%" PRId64
    823                       " idle_time_ns=%" PRId64
    824                       "\n",
    825                       stats->value->stats->rd_bytes,
    826                       stats->value->stats->wr_bytes,
    827                       stats->value->stats->rd_operations,
    828                       stats->value->stats->wr_operations,
    829                       stats->value->stats->flush_operations,
    830                       stats->value->stats->wr_total_time_ns,
    831                       stats->value->stats->rd_total_time_ns,
    832                       stats->value->stats->flush_total_time_ns,
    833                       stats->value->stats->rd_merged,
    834                       stats->value->stats->wr_merged,
    835                       stats->value->stats->idle_time_ns);
    836    }
    837
    838    qapi_free_BlockStatsList(stats_list);
    839}
    840
    841void hmp_info_block_jobs(Monitor *mon, const QDict *qdict)
    842{
    843    BlockJobInfoList *list;
    844
    845    list = qmp_query_block_jobs(&error_abort);
    846
    847    if (!list) {
    848        monitor_printf(mon, "No active jobs\n");
    849        return;
    850    }
    851
    852    while (list) {
    853        if (strcmp(list->value->type, "stream") == 0) {
    854            monitor_printf(mon, "Streaming device %s: Completed %" PRId64
    855                           " of %" PRId64 " bytes, speed limit %" PRId64
    856                           " bytes/s\n",
    857                           list->value->device,
    858                           list->value->offset,
    859                           list->value->len,
    860                           list->value->speed);
    861        } else {
    862            monitor_printf(mon, "Type %s, device %s: Completed %" PRId64
    863                           " of %" PRId64 " bytes, speed limit %" PRId64
    864                           " bytes/s\n",
    865                           list->value->type,
    866                           list->value->device,
    867                           list->value->offset,
    868                           list->value->len,
    869                           list->value->speed);
    870        }
    871        list = list->next;
    872    }
    873
    874    qapi_free_BlockJobInfoList(list);
    875}
    876
    877void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
    878{
    879    BlockDriverState *bs, *bs1;
    880    BdrvNextIterator it1;
    881    QEMUSnapshotInfo *sn_tab, *sn;
    882    bool no_snapshot = true;
    883    int nb_sns, i;
    884    int total;
    885    int *global_snapshots;
    886    AioContext *aio_context;
    887
    888    typedef struct SnapshotEntry {
    889        QEMUSnapshotInfo sn;
    890        QTAILQ_ENTRY(SnapshotEntry) next;
    891    } SnapshotEntry;
    892
    893    typedef struct ImageEntry {
    894        const char *imagename;
    895        QTAILQ_ENTRY(ImageEntry) next;
    896        QTAILQ_HEAD(, SnapshotEntry) snapshots;
    897    } ImageEntry;
    898
    899    QTAILQ_HEAD(, ImageEntry) image_list =
    900        QTAILQ_HEAD_INITIALIZER(image_list);
    901
    902    ImageEntry *image_entry, *next_ie;
    903    SnapshotEntry *snapshot_entry;
    904    Error *err = NULL;
    905
    906    bs = bdrv_all_find_vmstate_bs(NULL, false, NULL, &err);
    907    if (!bs) {
    908        error_report_err(err);
    909        return;
    910    }
    911    aio_context = bdrv_get_aio_context(bs);
    912
    913    aio_context_acquire(aio_context);
    914    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
    915    aio_context_release(aio_context);
    916
    917    if (nb_sns < 0) {
    918        monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);
    919        return;
    920    }
    921
    922    for (bs1 = bdrv_first(&it1); bs1; bs1 = bdrv_next(&it1)) {
    923        int bs1_nb_sns = 0;
    924        ImageEntry *ie;
    925        SnapshotEntry *se;
    926        AioContext *ctx = bdrv_get_aio_context(bs1);
    927
    928        aio_context_acquire(ctx);
    929        if (bdrv_can_snapshot(bs1)) {
    930            sn = NULL;
    931            bs1_nb_sns = bdrv_snapshot_list(bs1, &sn);
    932            if (bs1_nb_sns > 0) {
    933                no_snapshot = false;
    934                ie = g_new0(ImageEntry, 1);
    935                ie->imagename = bdrv_get_device_name(bs1);
    936                QTAILQ_INIT(&ie->snapshots);
    937                QTAILQ_INSERT_TAIL(&image_list, ie, next);
    938                for (i = 0; i < bs1_nb_sns; i++) {
    939                    se = g_new0(SnapshotEntry, 1);
    940                    se->sn = sn[i];
    941                    QTAILQ_INSERT_TAIL(&ie->snapshots, se, next);
    942                }
    943            }
    944            g_free(sn);
    945        }
    946        aio_context_release(ctx);
    947    }
    948
    949    if (no_snapshot) {
    950        monitor_printf(mon, "There is no snapshot available.\n");
    951        return;
    952    }
    953
    954    global_snapshots = g_new0(int, nb_sns);
    955    total = 0;
    956    for (i = 0; i < nb_sns; i++) {
    957        SnapshotEntry *next_sn;
    958        if (bdrv_all_has_snapshot(sn_tab[i].name, false, NULL, NULL) == 1) {
    959            global_snapshots[total] = i;
    960            total++;
    961            QTAILQ_FOREACH(image_entry, &image_list, next) {
    962                QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots,
    963                                    next, next_sn) {
    964                    if (!strcmp(sn_tab[i].name, snapshot_entry->sn.name)) {
    965                        QTAILQ_REMOVE(&image_entry->snapshots, snapshot_entry,
    966                                      next);
    967                        g_free(snapshot_entry);
    968                    }
    969                }
    970            }
    971        }
    972    }
    973    monitor_printf(mon, "List of snapshots present on all disks:\n");
    974
    975    if (total > 0) {
    976        bdrv_snapshot_dump(NULL);
    977        monitor_printf(mon, "\n");
    978        for (i = 0; i < total; i++) {
    979            sn = &sn_tab[global_snapshots[i]];
    980            /*
    981             * The ID is not guaranteed to be the same on all images, so
    982             * overwrite it.
    983             */
    984            pstrcpy(sn->id_str, sizeof(sn->id_str), "--");
    985            bdrv_snapshot_dump(sn);
    986            monitor_printf(mon, "\n");
    987        }
    988    } else {
    989        monitor_printf(mon, "None\n");
    990    }
    991
    992    QTAILQ_FOREACH(image_entry, &image_list, next) {
    993        if (QTAILQ_EMPTY(&image_entry->snapshots)) {
    994            continue;
    995        }
    996        monitor_printf(mon,
    997                       "\nList of partial (non-loadable) snapshots on '%s':\n",
    998                       image_entry->imagename);
    999        bdrv_snapshot_dump(NULL);
   1000        monitor_printf(mon, "\n");
   1001        QTAILQ_FOREACH(snapshot_entry, &image_entry->snapshots, next) {
   1002            bdrv_snapshot_dump(&snapshot_entry->sn);
   1003            monitor_printf(mon, "\n");
   1004        }
   1005    }
   1006
   1007    QTAILQ_FOREACH_SAFE(image_entry, &image_list, next, next_ie) {
   1008        SnapshotEntry *next_sn;
   1009        QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots, next,
   1010                            next_sn) {
   1011            g_free(snapshot_entry);
   1012        }
   1013        g_free(image_entry);
   1014    }
   1015    g_free(sn_tab);
   1016    g_free(global_snapshots);
   1017}