2 * Blockdev HMP commands
5 * Anthony Liguori <aliguori@us.ibm.com>
7 * Copyright (c) 2003-2008 Fabrice Bellard
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.
14 * This file incorporates work covered by the following copyright and
17 * Copyright (c) 2003-2008 Fabrice Bellard
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:
26 * The above copyright notice and this permission notice shall be included in
27 * all copies or substantial portions of the Software.
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
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 "qemu/error-report.h"
52 #include "sysemu/sysemu.h"
53 #include "monitor/monitor.h"
54 #include "monitor/hmp.h"
55 #include "block/nbd.h"
56 #include "block/qapi.h"
57 #include "block/block_int.h"
58 #include "block/block-hmp-cmds.h"
61 static void hmp_drive_add_node(Monitor
*mon
, const char *optstr
)
65 Error
*local_err
= NULL
;
67 opts
= qemu_opts_parse_noisily(&qemu_drive_opts
, optstr
, false);
72 qdict
= qemu_opts_to_qdict(opts
, NULL
);
74 if (!qdict_get_try_str(qdict
, "node-name")) {
76 error_report("'node-name' needs to be specified");
80 BlockDriverState
*bs
= bds_tree_init(qdict
, &local_err
);
82 error_report_err(local_err
);
86 bdrv_set_monitor_owned(bs
);
91 void hmp_drive_add(Monitor
*mon
, const QDict
*qdict
)
97 const char *optstr
= qdict_get_str(qdict
, "opts");
98 bool node
= qdict_get_try_bool(qdict
, "node", false);
101 hmp_drive_add_node(mon
, optstr
);
105 opts
= qemu_opts_parse_noisily(qemu_find_opts("drive"), optstr
, false);
109 mc
= MACHINE_GET_CLASS(current_machine
);
110 dinfo
= drive_new(opts
, mc
->block_default_type
, &err
);
112 error_report_err(err
);
121 switch (dinfo
->type
) {
123 monitor_printf(mon
, "OK\n");
126 monitor_printf(mon
, "Can't hot-add drive to type %d\n", dinfo
->type
);
133 BlockBackend
*blk
= blk_by_legacy_dinfo(dinfo
);
134 monitor_remove_blk(blk
);
139 void hmp_drive_del(Monitor
*mon
, const QDict
*qdict
)
141 const char *id
= qdict_get_str(qdict
, "id");
143 BlockDriverState
*bs
;
144 AioContext
*aio_context
;
145 Error
*local_err
= NULL
;
148 GRAPH_RDLOCK_GUARD_MAINLOOP();
150 bs
= bdrv_find_node(id
);
152 qmp_blockdev_del(id
, &local_err
);
154 error_report_err(local_err
);
159 blk
= blk_by_name(id
);
161 error_report("Device '%s' not found", id
);
165 if (!blk_legacy_dinfo(blk
)) {
166 error_report("Deleting device added with blockdev-add"
167 " is not supported");
171 aio_context
= blk_get_aio_context(blk
);
172 aio_context_acquire(aio_context
);
176 if (bdrv_op_is_blocked(bs
, BLOCK_OP_TYPE_DRIVE_DEL
, &local_err
)) {
177 error_report_err(local_err
);
178 aio_context_release(aio_context
);
185 /* Make the BlockBackend and the attached BlockDriverState anonymous */
186 monitor_remove_blk(blk
);
189 * If this BlockBackend has a device attached to it, its refcount will be
190 * decremented when the device is removed; otherwise we have to do so here.
192 if (blk_get_attached_dev(blk
)) {
193 /* Further I/O must not pause the guest */
194 blk_set_on_error(blk
, BLOCKDEV_ON_ERROR_REPORT
,
195 BLOCKDEV_ON_ERROR_REPORT
);
200 aio_context_release(aio_context
);
203 void hmp_commit(Monitor
*mon
, const QDict
*qdict
)
205 const char *device
= qdict_get_str(qdict
, "device");
210 GRAPH_RDLOCK_GUARD_MAINLOOP();
212 if (!strcmp(device
, "all")) {
213 ret
= blk_commit_all();
215 BlockDriverState
*bs
;
216 AioContext
*aio_context
;
218 blk
= blk_by_name(device
);
220 error_report("Device '%s' not found", device
);
224 bs
= bdrv_skip_implicit_filters(blk_bs(blk
));
225 aio_context
= bdrv_get_aio_context(bs
);
226 aio_context_acquire(aio_context
);
228 if (!blk_is_available(blk
)) {
229 error_report("Device '%s' has no medium", device
);
230 aio_context_release(aio_context
);
234 ret
= bdrv_commit(bs
);
236 aio_context_release(aio_context
);
239 error_report("'commit' error for '%s': %s", device
, strerror(-ret
));
243 void hmp_drive_mirror(Monitor
*mon
, const QDict
*qdict
)
245 const char *filename
= qdict_get_str(qdict
, "target");
246 const char *format
= qdict_get_try_str(qdict
, "format");
247 bool reuse
= qdict_get_try_bool(qdict
, "reuse", false);
248 bool full
= qdict_get_try_bool(qdict
, "full", false);
250 DriveMirror mirror
= {
251 .device
= (char *)qdict_get_str(qdict
, "device"),
252 .target
= (char *)filename
,
253 .format
= (char *)format
,
254 .sync
= full
? MIRROR_SYNC_MODE_FULL
: MIRROR_SYNC_MODE_TOP
,
256 .mode
= reuse
? NEW_IMAGE_MODE_EXISTING
: NEW_IMAGE_MODE_ABSOLUTE_PATHS
,
261 error_setg(&err
, QERR_MISSING_PARAMETER
, "target");
264 qmp_drive_mirror(&mirror
, &err
);
266 hmp_handle_error(mon
, err
);
269 void hmp_drive_backup(Monitor
*mon
, const QDict
*qdict
)
271 const char *device
= qdict_get_str(qdict
, "device");
272 const char *filename
= qdict_get_str(qdict
, "target");
273 const char *format
= qdict_get_try_str(qdict
, "format");
274 bool reuse
= qdict_get_try_bool(qdict
, "reuse", false);
275 bool full
= qdict_get_try_bool(qdict
, "full", false);
276 bool compress
= qdict_get_try_bool(qdict
, "compress", false);
278 DriveBackup backup
= {
279 .device
= (char *)device
,
280 .target
= (char *)filename
,
281 .format
= (char *)format
,
282 .sync
= full
? MIRROR_SYNC_MODE_FULL
: MIRROR_SYNC_MODE_TOP
,
284 .mode
= reuse
? NEW_IMAGE_MODE_EXISTING
: NEW_IMAGE_MODE_ABSOLUTE_PATHS
,
285 .has_compress
= !!compress
,
286 .compress
= compress
,
290 error_setg(&err
, QERR_MISSING_PARAMETER
, "target");
294 qmp_drive_backup(&backup
, &err
);
296 hmp_handle_error(mon
, err
);
299 void hmp_block_job_set_speed(Monitor
*mon
, const QDict
*qdict
)
302 const char *device
= qdict_get_str(qdict
, "device");
303 int64_t value
= qdict_get_int(qdict
, "speed");
305 qmp_block_job_set_speed(device
, value
, &error
);
307 hmp_handle_error(mon
, error
);
310 void hmp_block_job_cancel(Monitor
*mon
, const QDict
*qdict
)
313 const char *device
= qdict_get_str(qdict
, "device");
314 bool force
= qdict_get_try_bool(qdict
, "force", false);
316 qmp_block_job_cancel(device
, true, force
, &error
);
318 hmp_handle_error(mon
, error
);
321 void hmp_block_job_pause(Monitor
*mon
, const QDict
*qdict
)
324 const char *device
= qdict_get_str(qdict
, "device");
326 qmp_block_job_pause(device
, &error
);
328 hmp_handle_error(mon
, error
);
331 void hmp_block_job_resume(Monitor
*mon
, const QDict
*qdict
)
334 const char *device
= qdict_get_str(qdict
, "device");
336 qmp_block_job_resume(device
, &error
);
338 hmp_handle_error(mon
, error
);
341 void hmp_block_job_complete(Monitor
*mon
, const QDict
*qdict
)
344 const char *device
= qdict_get_str(qdict
, "device");
346 qmp_block_job_complete(device
, &error
);
348 hmp_handle_error(mon
, error
);
351 void hmp_snapshot_blkdev(Monitor
*mon
, const QDict
*qdict
)
353 const char *device
= qdict_get_str(qdict
, "device");
354 const char *filename
= qdict_get_try_str(qdict
, "snapshot-file");
355 const char *format
= qdict_get_try_str(qdict
, "format");
356 bool reuse
= qdict_get_try_bool(qdict
, "reuse", false);
357 enum NewImageMode mode
;
362 * In the future, if 'snapshot-file' is not specified, the snapshot
363 * will be taken internally. Today it's actually required.
365 error_setg(&err
, QERR_MISSING_PARAMETER
, "snapshot-file");
369 mode
= reuse
? NEW_IMAGE_MODE_EXISTING
: NEW_IMAGE_MODE_ABSOLUTE_PATHS
;
370 qmp_blockdev_snapshot_sync(device
, NULL
, filename
, NULL
, format
,
373 hmp_handle_error(mon
, err
);
376 void hmp_snapshot_blkdev_internal(Monitor
*mon
, const QDict
*qdict
)
378 const char *device
= qdict_get_str(qdict
, "device");
379 const char *name
= qdict_get_str(qdict
, "name");
382 qmp_blockdev_snapshot_internal_sync(device
, name
, &err
);
383 hmp_handle_error(mon
, err
);
386 void hmp_snapshot_delete_blkdev_internal(Monitor
*mon
, const QDict
*qdict
)
388 const char *device
= qdict_get_str(qdict
, "device");
389 const char *name
= qdict_get_str(qdict
, "name");
390 const char *id
= qdict_get_try_str(qdict
, "id");
393 qmp_blockdev_snapshot_delete_internal_sync(device
, id
, name
, &err
);
394 hmp_handle_error(mon
, err
);
397 void hmp_nbd_server_start(Monitor
*mon
, const QDict
*qdict
)
399 const char *uri
= qdict_get_str(qdict
, "uri");
400 bool writable
= qdict_get_try_bool(qdict
, "writable", false);
401 bool all
= qdict_get_try_bool(qdict
, "all", false);
402 Error
*local_err
= NULL
;
403 BlockInfoList
*block_list
, *info
;
405 NbdServerAddOptions export
;
407 if (writable
&& !all
) {
408 error_setg(&local_err
, "-w only valid together with -a");
412 /* First check if the address is valid and start the server. */
413 addr
= socket_parse(uri
, &local_err
);
414 if (local_err
!= NULL
) {
418 nbd_server_start(addr
, NULL
, NULL
, 0, &local_err
);
419 qapi_free_SocketAddress(addr
);
420 if (local_err
!= NULL
) {
428 /* Then try adding all block devices. If one fails, close all and
431 block_list
= qmp_query_block(NULL
);
433 for (info
= block_list
; info
; info
= info
->next
) {
434 if (!info
->value
->inserted
) {
438 export
= (NbdServerAddOptions
) {
439 .device
= info
->value
->device
,
440 .has_writable
= true,
441 .writable
= writable
,
444 qmp_nbd_server_add(&export
, &local_err
);
446 if (local_err
!= NULL
) {
447 qmp_nbd_server_stop(NULL
);
452 qapi_free_BlockInfoList(block_list
);
455 hmp_handle_error(mon
, local_err
);
458 void hmp_nbd_server_add(Monitor
*mon
, const QDict
*qdict
)
460 const char *device
= qdict_get_str(qdict
, "device");
461 const char *name
= qdict_get_try_str(qdict
, "name");
462 bool writable
= qdict_get_try_bool(qdict
, "writable", false);
463 Error
*local_err
= NULL
;
465 NbdServerAddOptions export
= {
466 .device
= (char *) device
,
467 .name
= (char *) name
,
468 .has_writable
= true,
469 .writable
= writable
,
472 qmp_nbd_server_add(&export
, &local_err
);
473 hmp_handle_error(mon
, local_err
);
476 void hmp_nbd_server_remove(Monitor
*mon
, const QDict
*qdict
)
478 const char *name
= qdict_get_str(qdict
, "name");
479 bool force
= qdict_get_try_bool(qdict
, "force", false);
482 /* Rely on BLOCK_EXPORT_REMOVE_MODE_SAFE being the default */
483 qmp_nbd_server_remove(name
, force
, BLOCK_EXPORT_REMOVE_MODE_HARD
, &err
);
484 hmp_handle_error(mon
, err
);
487 void hmp_nbd_server_stop(Monitor
*mon
, const QDict
*qdict
)
491 qmp_nbd_server_stop(&err
);
492 hmp_handle_error(mon
, err
);
495 void coroutine_fn
hmp_block_resize(Monitor
*mon
, const QDict
*qdict
)
497 const char *device
= qdict_get_str(qdict
, "device");
498 int64_t size
= qdict_get_int(qdict
, "size");
501 qmp_block_resize(device
, NULL
, size
, &err
);
502 hmp_handle_error(mon
, err
);
505 void hmp_block_stream(Monitor
*mon
, const QDict
*qdict
)
508 const char *device
= qdict_get_str(qdict
, "device");
509 const char *base
= qdict_get_try_str(qdict
, "base");
510 int64_t speed
= qdict_get_try_int(qdict
, "speed", 0);
512 qmp_block_stream(device
, device
, base
, NULL
, NULL
, NULL
,
513 qdict_haskey(qdict
, "speed"), speed
,
514 true, BLOCKDEV_ON_ERROR_REPORT
, NULL
,
515 false, false, false, false, &error
);
517 hmp_handle_error(mon
, error
);
520 void hmp_block_set_io_throttle(Monitor
*mon
, const QDict
*qdict
)
523 char *device
= (char *) qdict_get_str(qdict
, "device");
524 BlockIOThrottle throttle
= {
525 .bps
= qdict_get_int(qdict
, "bps"),
526 .bps_rd
= qdict_get_int(qdict
, "bps_rd"),
527 .bps_wr
= qdict_get_int(qdict
, "bps_wr"),
528 .iops
= qdict_get_int(qdict
, "iops"),
529 .iops_rd
= qdict_get_int(qdict
, "iops_rd"),
530 .iops_wr
= qdict_get_int(qdict
, "iops_wr"),
534 * qmp_block_set_io_throttle has separate parameters for the
535 * (deprecated) block device name and the qdev ID but the HMP
536 * version has only one, so we must decide which one to pass.
538 if (blk_by_name(device
)) {
539 throttle
.device
= device
;
541 throttle
.id
= device
;
544 qmp_block_set_io_throttle(&throttle
, &err
);
545 hmp_handle_error(mon
, err
);
548 void hmp_eject(Monitor
*mon
, const QDict
*qdict
)
550 bool force
= qdict_get_try_bool(qdict
, "force", false);
551 const char *device
= qdict_get_str(qdict
, "device");
554 qmp_eject(device
, NULL
, true, force
, &err
);
555 hmp_handle_error(mon
, err
);
558 void hmp_qemu_io(Monitor
*mon
, const QDict
*qdict
)
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");
571 blk
= blk_by_qdev_id(device
, &err
);
576 blk
= blk_by_name(device
);
578 bs
= bdrv_lookup_bs(NULL
, device
, &err
);
585 ctx
= blk
? blk_get_aio_context(blk
) : bdrv_get_aio_context(bs
);
586 aio_context_acquire(ctx
);
589 blk
= local_blk
= blk_new(bdrv_get_aio_context(bs
), 0, BLK_PERM_ALL
);
590 ret
= blk_insert_bs(blk
, bs
, &err
);
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.
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.
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.
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.
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.
621 qemuio_command(blk
, command
);
624 blk_unref(local_blk
);
627 aio_context_release(ctx
);
630 hmp_handle_error(mon
, err
);
633 static void print_block_info(Monitor
*mon
, BlockInfo
*info
,
634 BlockDeviceInfo
*inserted
, bool verbose
)
636 ImageInfo
*image_info
;
638 assert(!info
|| !info
->inserted
|| info
->inserted
== inserted
);
640 if (info
&& *info
->device
) {
641 monitor_puts(mon
, info
->device
);
642 if (inserted
&& inserted
->node_name
) {
643 monitor_printf(mon
, " (%s)", inserted
->node_name
);
646 assert(info
|| inserted
);
648 inserted
&& inserted
->node_name
? inserted
->node_name
649 : info
&& info
->qdev
? info
->qdev
654 monitor_printf(mon
, ": %s (%s%s%s)\n",
657 inserted
->ro
? ", read-only" : "",
658 inserted
->encrypted
? ", encrypted" : "");
660 monitor_printf(mon
, ": [not inserted]\n");
665 monitor_printf(mon
, " Attached to: %s\n", info
->qdev
);
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
));
672 if (info
->removable
) {
673 monitor_printf(mon
, " Removable device: %slocked, tray %s\n",
674 info
->locked
? "" : "not ",
675 info
->tray_open
? "open" : "closed");
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" : "");
689 if (inserted
->backing_file
) {
692 "(chain depth: %" PRId64
")\n",
693 inserted
->backing_file
,
694 inserted
->backing_file_depth
);
697 if (inserted
->detect_zeroes
!= BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF
) {
698 monitor_printf(mon
, " Detect zeroes: %s\n",
699 BlockdevDetectZeroesOptions_str(inserted
->detect_zeroes
));
702 if (inserted
->bps
|| inserted
->bps_rd
|| inserted
->bps_wr
||
703 inserted
->iops
|| inserted
->iops_rd
|| inserted
->iops_wr
)
705 monitor_printf(mon
, " I/O throttling: bps=%" PRId64
706 " bps_rd=%" PRId64
" bps_wr=%" PRId64
708 " bps_rd_max=%" PRId64
709 " bps_wr_max=%" PRId64
710 " iops=%" PRId64
" iops_rd=%" PRId64
713 " iops_rd_max=%" PRId64
714 " iops_wr_max=%" PRId64
715 " iops_size=%" PRId64
721 inserted
->bps_rd_max
,
722 inserted
->bps_wr_max
,
727 inserted
->iops_rd_max
,
728 inserted
->iops_wr_max
,
734 monitor_printf(mon
, "\nImages:\n");
735 image_info
= inserted
->image
;
737 bdrv_node_info_dump(qapi_ImageInfo_base(image_info
), 0, false);
738 if (image_info
->backing_image
) {
739 image_info
= image_info
->backing_image
;
747 void hmp_info_block(Monitor
*mon
, const QDict
*qdict
)
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;
756 /* Print BlockBackend information */
758 block_list
= qmp_query_block(NULL
);
763 for (info
= block_list
; info
; info
= info
->next
) {
764 if (device
&& strcmp(device
, info
->value
->device
)) {
768 if (info
!= block_list
) {
769 monitor_printf(mon
, "\n");
772 print_block_info(mon
, info
->value
, info
->value
->inserted
,
777 qapi_free_BlockInfoList(block_list
);
779 if ((!device
&& !nodes
) || printed
) {
783 /* Print node information */
784 blockdev_list
= qmp_query_named_block_nodes(false, false, NULL
);
785 for (blockdev
= blockdev_list
; blockdev
; blockdev
= blockdev
->next
) {
786 assert(blockdev
->value
->node_name
);
787 if (device
&& strcmp(device
, blockdev
->value
->node_name
)) {
791 if (blockdev
!= blockdev_list
) {
792 monitor_printf(mon
, "\n");
795 print_block_info(mon
, NULL
, blockdev
->value
, verbose
);
797 qapi_free_BlockDeviceInfoList(blockdev_list
);
800 void hmp_info_blockstats(Monitor
*mon
, const QDict
*qdict
)
802 BlockStatsList
*stats_list
, *stats
;
804 stats_list
= qmp_query_blockstats(false, false, NULL
);
806 for (stats
= stats_list
; stats
; stats
= stats
->next
) {
807 if (!stats
->value
->device
) {
811 monitor_printf(mon
, "%s:", stats
->value
->device
);
812 monitor_printf(mon
, " rd_bytes=%" PRId64
814 " rd_operations=%" PRId64
815 " wr_operations=%" PRId64
816 " flush_operations=%" PRId64
817 " wr_total_time_ns=%" PRId64
818 " rd_total_time_ns=%" PRId64
819 " flush_total_time_ns=%" PRId64
820 " rd_merged=%" PRId64
821 " wr_merged=%" PRId64
822 " idle_time_ns=%" PRId64
824 stats
->value
->stats
->rd_bytes
,
825 stats
->value
->stats
->wr_bytes
,
826 stats
->value
->stats
->rd_operations
,
827 stats
->value
->stats
->wr_operations
,
828 stats
->value
->stats
->flush_operations
,
829 stats
->value
->stats
->wr_total_time_ns
,
830 stats
->value
->stats
->rd_total_time_ns
,
831 stats
->value
->stats
->flush_total_time_ns
,
832 stats
->value
->stats
->rd_merged
,
833 stats
->value
->stats
->wr_merged
,
834 stats
->value
->stats
->idle_time_ns
);
837 qapi_free_BlockStatsList(stats_list
);
840 void hmp_info_block_jobs(Monitor
*mon
, const QDict
*qdict
)
842 BlockJobInfoList
*list
;
844 list
= qmp_query_block_jobs(&error_abort
);
847 monitor_printf(mon
, "No active jobs\n");
852 if (list
->value
->type
== JOB_TYPE_STREAM
) {
853 monitor_printf(mon
, "Streaming device %s: Completed %" PRId64
854 " of %" PRId64
" bytes, speed limit %" PRId64
861 monitor_printf(mon
, "Type %s, device %s: Completed %" PRId64
862 " of %" PRId64
" bytes, speed limit %" PRId64
864 JobType_str(list
->value
->type
),
873 qapi_free_BlockJobInfoList(list
);
876 void hmp_info_snapshots(Monitor
*mon
, const QDict
*qdict
)
878 BlockDriverState
*bs
, *bs1
;
879 BdrvNextIterator it1
;
880 QEMUSnapshotInfo
*sn_tab
, *sn
;
881 bool no_snapshot
= true;
884 int *global_snapshots
;
885 AioContext
*aio_context
;
887 typedef struct SnapshotEntry
{
889 QTAILQ_ENTRY(SnapshotEntry
) next
;
892 typedef struct ImageEntry
{
893 const char *imagename
;
894 QTAILQ_ENTRY(ImageEntry
) next
;
895 QTAILQ_HEAD(, SnapshotEntry
) snapshots
;
898 QTAILQ_HEAD(, ImageEntry
) image_list
=
899 QTAILQ_HEAD_INITIALIZER(image_list
);
901 ImageEntry
*image_entry
, *next_ie
;
902 SnapshotEntry
*snapshot_entry
;
905 GRAPH_RDLOCK_GUARD_MAINLOOP();
907 bs
= bdrv_all_find_vmstate_bs(NULL
, false, NULL
, &err
);
909 error_report_err(err
);
912 aio_context
= bdrv_get_aio_context(bs
);
914 aio_context_acquire(aio_context
);
915 nb_sns
= bdrv_snapshot_list(bs
, &sn_tab
);
916 aio_context_release(aio_context
);
919 monitor_printf(mon
, "bdrv_snapshot_list: error %d\n", nb_sns
);
923 for (bs1
= bdrv_first(&it1
); bs1
; bs1
= bdrv_next(&it1
)) {
927 AioContext
*ctx
= bdrv_get_aio_context(bs1
);
929 aio_context_acquire(ctx
);
930 if (bdrv_can_snapshot(bs1
)) {
932 bs1_nb_sns
= bdrv_snapshot_list(bs1
, &sn
);
933 if (bs1_nb_sns
> 0) {
935 ie
= g_new0(ImageEntry
, 1);
936 ie
->imagename
= bdrv_get_device_name(bs1
);
937 QTAILQ_INIT(&ie
->snapshots
);
938 QTAILQ_INSERT_TAIL(&image_list
, ie
, next
);
939 for (i
= 0; i
< bs1_nb_sns
; i
++) {
940 se
= g_new0(SnapshotEntry
, 1);
942 QTAILQ_INSERT_TAIL(&ie
->snapshots
, se
, next
);
947 aio_context_release(ctx
);
951 monitor_printf(mon
, "There is no snapshot available.\n");
955 global_snapshots
= g_new0(int, nb_sns
);
957 for (i
= 0; i
< nb_sns
; i
++) {
958 SnapshotEntry
*next_sn
;
959 if (bdrv_all_has_snapshot(sn_tab
[i
].name
, false, NULL
, NULL
) == 1) {
960 global_snapshots
[total
] = i
;
962 QTAILQ_FOREACH(image_entry
, &image_list
, next
) {
963 QTAILQ_FOREACH_SAFE(snapshot_entry
, &image_entry
->snapshots
,
965 if (!strcmp(sn_tab
[i
].name
, snapshot_entry
->sn
.name
)) {
966 QTAILQ_REMOVE(&image_entry
->snapshots
, snapshot_entry
,
968 g_free(snapshot_entry
);
974 monitor_printf(mon
, "List of snapshots present on all disks:\n");
977 bdrv_snapshot_dump(NULL
);
978 monitor_printf(mon
, "\n");
979 for (i
= 0; i
< total
; i
++) {
980 sn
= &sn_tab
[global_snapshots
[i
]];
982 * The ID is not guaranteed to be the same on all images, so
985 pstrcpy(sn
->id_str
, sizeof(sn
->id_str
), "--");
986 bdrv_snapshot_dump(sn
);
987 monitor_printf(mon
, "\n");
990 monitor_printf(mon
, "None\n");
993 QTAILQ_FOREACH(image_entry
, &image_list
, next
) {
994 if (QTAILQ_EMPTY(&image_entry
->snapshots
)) {
998 "\nList of partial (non-loadable) snapshots on '%s':\n",
999 image_entry
->imagename
);
1000 bdrv_snapshot_dump(NULL
);
1001 monitor_printf(mon
, "\n");
1002 QTAILQ_FOREACH(snapshot_entry
, &image_entry
->snapshots
, next
) {
1003 bdrv_snapshot_dump(&snapshot_entry
->sn
);
1004 monitor_printf(mon
, "\n");
1008 QTAILQ_FOREACH_SAFE(image_entry
, &image_list
, next
, next_ie
) {
1009 SnapshotEntry
*next_sn
;
1010 QTAILQ_FOREACH_SAFE(snapshot_entry
, &image_entry
->snapshots
, next
,
1012 g_free(snapshot_entry
);
1014 g_free(image_entry
);
1017 g_free(global_snapshots
);
1020 void hmp_change_medium(Monitor
*mon
, const char *device
, const char *target
,
1021 const char *arg
, const char *read_only
, bool force
,
1025 BlockdevChangeReadOnlyMode read_only_mode
= 0;
1029 qapi_enum_parse(&BlockdevChangeReadOnlyMode_lookup
,
1031 BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN
, errp
);
1037 qmp_blockdev_change_medium(device
, NULL
, target
, arg
, true, force
,
1038 !!read_only
, read_only_mode
, errp
);