monitor/hmp: move hmp_info_block* to block-hmp-cmds.c
[qemu/ar7.git] / block / monitor / block-hmp-cmds.c
blobaebf1dce0d9cdaad25b34dd710ed091279c594a0
1 /*
2 * Blockdev HMP commands
4 * Authors:
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
15 * permission notice:
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
35 * THE SOFTWARE.
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/qmp/qdict.h"
44 #include "qapi/error.h"
45 #include "qapi/qmp/qerror.h"
46 #include "qemu/config-file.h"
47 #include "qemu/option.h"
48 #include "qemu/sockets.h"
49 #include "qemu/cutils.h"
50 #include "sysemu/sysemu.h"
51 #include "monitor/monitor.h"
52 #include "monitor/hmp.h"
53 #include "block/nbd.h"
54 #include "block/qapi.h"
55 #include "block/block_int.h"
56 #include "block/block-hmp-cmds.h"
57 #include "qemu-io.h"
59 void hmp_drive_add(Monitor *mon, const QDict *qdict)
61 Error *err = NULL;
62 DriveInfo *dinfo;
63 QemuOpts *opts;
64 MachineClass *mc;
65 const char *optstr = qdict_get_str(qdict, "opts");
66 bool node = qdict_get_try_bool(qdict, "node", false);
68 if (node) {
69 hmp_drive_add_node(mon, optstr);
70 return;
73 opts = drive_def(optstr);
74 if (!opts)
75 return;
77 mc = MACHINE_GET_CLASS(current_machine);
78 dinfo = drive_new(opts, mc->block_default_type, &err);
79 if (err) {
80 error_report_err(err);
81 qemu_opts_del(opts);
82 goto err;
85 if (!dinfo) {
86 return;
89 switch (dinfo->type) {
90 case IF_NONE:
91 monitor_printf(mon, "OK\n");
92 break;
93 default:
94 monitor_printf(mon, "Can't hot-add drive to type %d\n", dinfo->type);
95 goto err;
97 return;
99 err:
100 if (dinfo) {
101 BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
102 monitor_remove_blk(blk);
103 blk_unref(blk);
107 void hmp_drive_del(Monitor *mon, const QDict *qdict)
109 const char *id = qdict_get_str(qdict, "id");
110 BlockBackend *blk;
111 BlockDriverState *bs;
112 AioContext *aio_context;
113 Error *local_err = NULL;
115 bs = bdrv_find_node(id);
116 if (bs) {
117 qmp_blockdev_del(id, &local_err);
118 if (local_err) {
119 error_report_err(local_err);
121 return;
124 blk = blk_by_name(id);
125 if (!blk) {
126 error_report("Device '%s' not found", id);
127 return;
130 if (!blk_legacy_dinfo(blk)) {
131 error_report("Deleting device added with blockdev-add"
132 " is not supported");
133 return;
136 aio_context = blk_get_aio_context(blk);
137 aio_context_acquire(aio_context);
139 bs = blk_bs(blk);
140 if (bs) {
141 if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &local_err)) {
142 error_report_err(local_err);
143 aio_context_release(aio_context);
144 return;
147 blk_remove_bs(blk);
150 /* Make the BlockBackend and the attached BlockDriverState anonymous */
151 monitor_remove_blk(blk);
154 * If this BlockBackend has a device attached to it, its refcount will be
155 * decremented when the device is removed; otherwise we have to do so here.
157 if (blk_get_attached_dev(blk)) {
158 /* Further I/O must not pause the guest */
159 blk_set_on_error(blk, BLOCKDEV_ON_ERROR_REPORT,
160 BLOCKDEV_ON_ERROR_REPORT);
161 } else {
162 blk_unref(blk);
165 aio_context_release(aio_context);
168 void hmp_commit(Monitor *mon, const QDict *qdict)
170 const char *device = qdict_get_str(qdict, "device");
171 BlockBackend *blk;
172 int ret;
174 if (!strcmp(device, "all")) {
175 ret = blk_commit_all();
176 } else {
177 BlockDriverState *bs;
178 AioContext *aio_context;
180 blk = blk_by_name(device);
181 if (!blk) {
182 error_report("Device '%s' not found", device);
183 return;
185 if (!blk_is_available(blk)) {
186 error_report("Device '%s' has no medium", device);
187 return;
190 bs = blk_bs(blk);
191 aio_context = bdrv_get_aio_context(bs);
192 aio_context_acquire(aio_context);
194 ret = bdrv_commit(bs);
196 aio_context_release(aio_context);
198 if (ret < 0) {
199 error_report("'commit' error for '%s': %s", device, strerror(-ret));
203 void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
205 const char *filename = qdict_get_str(qdict, "target");
206 const char *format = qdict_get_try_str(qdict, "format");
207 bool reuse = qdict_get_try_bool(qdict, "reuse", false);
208 bool full = qdict_get_try_bool(qdict, "full", false);
209 Error *err = NULL;
210 DriveMirror mirror = {
211 .device = (char *)qdict_get_str(qdict, "device"),
212 .target = (char *)filename,
213 .has_format = !!format,
214 .format = (char *)format,
215 .sync = full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
216 .has_mode = true,
217 .mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS,
218 .unmap = true,
221 if (!filename) {
222 error_setg(&err, QERR_MISSING_PARAMETER, "target");
223 hmp_handle_error(mon, err);
224 return;
226 qmp_drive_mirror(&mirror, &err);
227 hmp_handle_error(mon, err);
230 void hmp_drive_backup(Monitor *mon, const QDict *qdict)
232 const char *device = qdict_get_str(qdict, "device");
233 const char *filename = qdict_get_str(qdict, "target");
234 const char *format = qdict_get_try_str(qdict, "format");
235 bool reuse = qdict_get_try_bool(qdict, "reuse", false);
236 bool full = qdict_get_try_bool(qdict, "full", false);
237 bool compress = qdict_get_try_bool(qdict, "compress", false);
238 Error *err = NULL;
239 DriveBackup backup = {
240 .device = (char *)device,
241 .target = (char *)filename,
242 .has_format = !!format,
243 .format = (char *)format,
244 .sync = full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
245 .has_mode = true,
246 .mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS,
247 .has_compress = !!compress,
248 .compress = compress,
251 if (!filename) {
252 error_setg(&err, QERR_MISSING_PARAMETER, "target");
253 hmp_handle_error(mon, err);
254 return;
257 qmp_drive_backup(&backup, &err);
258 hmp_handle_error(mon, err);
261 void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict)
263 Error *error = NULL;
264 const char *device = qdict_get_str(qdict, "device");
265 int64_t value = qdict_get_int(qdict, "speed");
267 qmp_block_job_set_speed(device, value, &error);
269 hmp_handle_error(mon, error);
272 void hmp_block_job_cancel(Monitor *mon, const QDict *qdict)
274 Error *error = NULL;
275 const char *device = qdict_get_str(qdict, "device");
276 bool force = qdict_get_try_bool(qdict, "force", false);
278 qmp_block_job_cancel(device, true, force, &error);
280 hmp_handle_error(mon, error);
283 void hmp_block_job_pause(Monitor *mon, const QDict *qdict)
285 Error *error = NULL;
286 const char *device = qdict_get_str(qdict, "device");
288 qmp_block_job_pause(device, &error);
290 hmp_handle_error(mon, error);
293 void hmp_block_job_resume(Monitor *mon, const QDict *qdict)
295 Error *error = NULL;
296 const char *device = qdict_get_str(qdict, "device");
298 qmp_block_job_resume(device, &error);
300 hmp_handle_error(mon, error);
303 void hmp_block_job_complete(Monitor *mon, const QDict *qdict)
305 Error *error = NULL;
306 const char *device = qdict_get_str(qdict, "device");
308 qmp_block_job_complete(device, &error);
310 hmp_handle_error(mon, error);
313 void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
315 const char *device = qdict_get_str(qdict, "device");
316 const char *filename = qdict_get_try_str(qdict, "snapshot-file");
317 const char *format = qdict_get_try_str(qdict, "format");
318 bool reuse = qdict_get_try_bool(qdict, "reuse", false);
319 enum NewImageMode mode;
320 Error *err = NULL;
322 if (!filename) {
324 * In the future, if 'snapshot-file' is not specified, the snapshot
325 * will be taken internally. Today it's actually required.
327 error_setg(&err, QERR_MISSING_PARAMETER, "snapshot-file");
328 hmp_handle_error(mon, err);
329 return;
332 mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS;
333 qmp_blockdev_snapshot_sync(true, device, false, NULL,
334 filename, false, NULL,
335 !!format, format,
336 true, mode, &err);
337 hmp_handle_error(mon, err);
340 void hmp_snapshot_blkdev_internal(Monitor *mon, const QDict *qdict)
342 const char *device = qdict_get_str(qdict, "device");
343 const char *name = qdict_get_str(qdict, "name");
344 Error *err = NULL;
346 qmp_blockdev_snapshot_internal_sync(device, name, &err);
347 hmp_handle_error(mon, err);
350 void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict)
352 const char *device = qdict_get_str(qdict, "device");
353 const char *name = qdict_get_str(qdict, "name");
354 const char *id = qdict_get_try_str(qdict, "id");
355 Error *err = NULL;
357 qmp_blockdev_snapshot_delete_internal_sync(device, !!id, id,
358 true, name, &err);
359 hmp_handle_error(mon, err);
362 void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
364 const char *uri = qdict_get_str(qdict, "uri");
365 bool writable = qdict_get_try_bool(qdict, "writable", false);
366 bool all = qdict_get_try_bool(qdict, "all", false);
367 Error *local_err = NULL;
368 BlockInfoList *block_list, *info;
369 SocketAddress *addr;
370 BlockExportNbd export;
372 if (writable && !all) {
373 error_setg(&local_err, "-w only valid together with -a");
374 goto exit;
377 /* First check if the address is valid and start the server. */
378 addr = socket_parse(uri, &local_err);
379 if (local_err != NULL) {
380 goto exit;
383 nbd_server_start(addr, NULL, NULL, &local_err);
384 qapi_free_SocketAddress(addr);
385 if (local_err != NULL) {
386 goto exit;
389 if (!all) {
390 return;
393 /* Then try adding all block devices. If one fails, close all and
394 * exit.
396 block_list = qmp_query_block(NULL);
398 for (info = block_list; info; info = info->next) {
399 if (!info->value->has_inserted) {
400 continue;
403 export = (BlockExportNbd) {
404 .device = info->value->device,
405 .has_writable = true,
406 .writable = writable,
409 qmp_nbd_server_add(&export, &local_err);
411 if (local_err != NULL) {
412 qmp_nbd_server_stop(NULL);
413 break;
417 qapi_free_BlockInfoList(block_list);
419 exit:
420 hmp_handle_error(mon, local_err);
423 void hmp_nbd_server_add(Monitor *mon, const QDict *qdict)
425 const char *device = qdict_get_str(qdict, "device");
426 const char *name = qdict_get_try_str(qdict, "name");
427 bool writable = qdict_get_try_bool(qdict, "writable", false);
428 Error *local_err = NULL;
430 BlockExportNbd export = {
431 .device = (char *) device,
432 .has_name = !!name,
433 .name = (char *) name,
434 .has_writable = true,
435 .writable = writable,
438 qmp_nbd_server_add(&export, &local_err);
439 hmp_handle_error(mon, local_err);
442 void hmp_nbd_server_remove(Monitor *mon, const QDict *qdict)
444 const char *name = qdict_get_str(qdict, "name");
445 bool force = qdict_get_try_bool(qdict, "force", false);
446 Error *err = NULL;
448 /* Rely on NBD_SERVER_REMOVE_MODE_SAFE being the default */
449 qmp_nbd_server_remove(name, force, NBD_SERVER_REMOVE_MODE_HARD, &err);
450 hmp_handle_error(mon, err);
453 void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict)
455 Error *err = NULL;
457 qmp_nbd_server_stop(&err);
458 hmp_handle_error(mon, err);
461 void hmp_block_resize(Monitor *mon, const QDict *qdict)
463 const char *device = qdict_get_str(qdict, "device");
464 int64_t size = qdict_get_int(qdict, "size");
465 Error *err = NULL;
467 qmp_block_resize(true, device, false, NULL, size, &err);
468 hmp_handle_error(mon, err);
471 void hmp_block_stream(Monitor *mon, const QDict *qdict)
473 Error *error = NULL;
474 const char *device = qdict_get_str(qdict, "device");
475 const char *base = qdict_get_try_str(qdict, "base");
476 int64_t speed = qdict_get_try_int(qdict, "speed", 0);
478 qmp_block_stream(true, device, device, base != NULL, base, false, NULL,
479 false, NULL, qdict_haskey(qdict, "speed"), speed, true,
480 BLOCKDEV_ON_ERROR_REPORT, false, false, false, false,
481 &error);
483 hmp_handle_error(mon, error);
486 void hmp_block_passwd(Monitor *mon, const QDict *qdict)
488 const char *device = qdict_get_str(qdict, "device");
489 const char *password = qdict_get_str(qdict, "password");
490 Error *err = NULL;
492 qmp_block_passwd(true, device, false, NULL, password, &err);
493 hmp_handle_error(mon, err);
496 void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
498 Error *err = NULL;
499 char *device = (char *) qdict_get_str(qdict, "device");
500 BlockIOThrottle throttle = {
501 .bps = qdict_get_int(qdict, "bps"),
502 .bps_rd = qdict_get_int(qdict, "bps_rd"),
503 .bps_wr = qdict_get_int(qdict, "bps_wr"),
504 .iops = qdict_get_int(qdict, "iops"),
505 .iops_rd = qdict_get_int(qdict, "iops_rd"),
506 .iops_wr = qdict_get_int(qdict, "iops_wr"),
510 * qmp_block_set_io_throttle has separate parameters for the
511 * (deprecated) block device name and the qdev ID but the HMP
512 * version has only one, so we must decide which one to pass.
514 if (blk_by_name(device)) {
515 throttle.has_device = true;
516 throttle.device = device;
517 } else {
518 throttle.has_id = true;
519 throttle.id = device;
522 qmp_block_set_io_throttle(&throttle, &err);
523 hmp_handle_error(mon, err);
526 void hmp_eject(Monitor *mon, const QDict *qdict)
528 bool force = qdict_get_try_bool(qdict, "force", false);
529 const char *device = qdict_get_str(qdict, "device");
530 Error *err = NULL;
532 qmp_eject(true, device, false, NULL, true, force, &err);
533 hmp_handle_error(mon, err);
536 void hmp_qemu_io(Monitor *mon, const QDict *qdict)
538 BlockBackend *blk;
539 BlockBackend *local_blk = NULL;
540 bool qdev = qdict_get_try_bool(qdict, "qdev", false);
541 const char *device = qdict_get_str(qdict, "device");
542 const char *command = qdict_get_str(qdict, "command");
543 Error *err = NULL;
544 int ret;
546 if (qdev) {
547 blk = blk_by_qdev_id(device, &err);
548 if (!blk) {
549 goto fail;
551 } else {
552 blk = blk_by_name(device);
553 if (!blk) {
554 BlockDriverState *bs = bdrv_lookup_bs(NULL, device, &err);
555 if (bs) {
556 blk = local_blk = blk_new(bdrv_get_aio_context(bs),
557 0, BLK_PERM_ALL);
558 ret = blk_insert_bs(blk, bs, &err);
559 if (ret < 0) {
560 goto fail;
562 } else {
563 goto fail;
569 * Notably absent: Proper permission management. This is sad, but it seems
570 * almost impossible to achieve without changing the semantics and thereby
571 * limiting the use cases of the qemu-io HMP command.
573 * In an ideal world we would unconditionally create a new BlockBackend for
574 * qemuio_command(), but we have commands like 'reopen' and want them to
575 * take effect on the exact BlockBackend whose name the user passed instead
576 * of just on a temporary copy of it.
578 * Another problem is that deleting the temporary BlockBackend involves
579 * draining all requests on it first, but some qemu-iotests cases want to
580 * issue multiple aio_read/write requests and expect them to complete in
581 * the background while the monitor has already returned.
583 * This is also what prevents us from saving the original permissions and
584 * restoring them later: We can't revoke permissions until all requests
585 * have completed, and we don't know when that is nor can we really let
586 * anything else run before we have revoken them to avoid race conditions.
588 * What happens now is that command() in qemu-io-cmds.c can extend the
589 * permissions if necessary for the qemu-io command. And they simply stay
590 * extended, possibly resulting in a read-only guest device keeping write
591 * permissions. Ugly, but it appears to be the lesser evil.
593 qemuio_command(blk, command);
595 fail:
596 blk_unref(local_blk);
597 hmp_handle_error(mon, err);
600 static void print_block_info(Monitor *mon, BlockInfo *info,
601 BlockDeviceInfo *inserted, bool verbose)
603 ImageInfo *image_info;
605 assert(!info || !info->has_inserted || info->inserted == inserted);
607 if (info && *info->device) {
608 monitor_printf(mon, "%s", info->device);
609 if (inserted && inserted->has_node_name) {
610 monitor_printf(mon, " (%s)", inserted->node_name);
612 } else {
613 assert(info || inserted);
614 monitor_printf(mon, "%s",
615 inserted && inserted->has_node_name ? inserted->node_name
616 : info && info->has_qdev ? info->qdev
617 : "<anonymous>");
620 if (inserted) {
621 monitor_printf(mon, ": %s (%s%s%s)\n",
622 inserted->file,
623 inserted->drv,
624 inserted->ro ? ", read-only" : "",
625 inserted->encrypted ? ", encrypted" : "");
626 } else {
627 monitor_printf(mon, ": [not inserted]\n");
630 if (info) {
631 if (info->has_qdev) {
632 monitor_printf(mon, " Attached to: %s\n", info->qdev);
634 if (info->has_io_status && info->io_status != BLOCK_DEVICE_IO_STATUS_OK) {
635 monitor_printf(mon, " I/O status: %s\n",
636 BlockDeviceIoStatus_str(info->io_status));
639 if (info->removable) {
640 monitor_printf(mon, " Removable device: %slocked, tray %s\n",
641 info->locked ? "" : "not ",
642 info->tray_open ? "open" : "closed");
647 if (!inserted) {
648 return;
651 monitor_printf(mon, " Cache mode: %s%s%s\n",
652 inserted->cache->writeback ? "writeback" : "writethrough",
653 inserted->cache->direct ? ", direct" : "",
654 inserted->cache->no_flush ? ", ignore flushes" : "");
656 if (inserted->has_backing_file) {
657 monitor_printf(mon,
658 " Backing file: %s "
659 "(chain depth: %" PRId64 ")\n",
660 inserted->backing_file,
661 inserted->backing_file_depth);
664 if (inserted->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF) {
665 monitor_printf(mon, " Detect zeroes: %s\n",
666 BlockdevDetectZeroesOptions_str(inserted->detect_zeroes));
669 if (inserted->bps || inserted->bps_rd || inserted->bps_wr ||
670 inserted->iops || inserted->iops_rd || inserted->iops_wr)
672 monitor_printf(mon, " I/O throttling: bps=%" PRId64
673 " bps_rd=%" PRId64 " bps_wr=%" PRId64
674 " bps_max=%" PRId64
675 " bps_rd_max=%" PRId64
676 " bps_wr_max=%" PRId64
677 " iops=%" PRId64 " iops_rd=%" PRId64
678 " iops_wr=%" PRId64
679 " iops_max=%" PRId64
680 " iops_rd_max=%" PRId64
681 " iops_wr_max=%" PRId64
682 " iops_size=%" PRId64
683 " group=%s\n",
684 inserted->bps,
685 inserted->bps_rd,
686 inserted->bps_wr,
687 inserted->bps_max,
688 inserted->bps_rd_max,
689 inserted->bps_wr_max,
690 inserted->iops,
691 inserted->iops_rd,
692 inserted->iops_wr,
693 inserted->iops_max,
694 inserted->iops_rd_max,
695 inserted->iops_wr_max,
696 inserted->iops_size,
697 inserted->group);
700 if (verbose) {
701 monitor_printf(mon, "\nImages:\n");
702 image_info = inserted->image;
703 while (1) {
704 bdrv_image_info_dump(image_info);
705 if (image_info->has_backing_image) {
706 image_info = image_info->backing_image;
707 } else {
708 break;
714 void hmp_info_block(Monitor *mon, const QDict *qdict)
716 BlockInfoList *block_list, *info;
717 BlockDeviceInfoList *blockdev_list, *blockdev;
718 const char *device = qdict_get_try_str(qdict, "device");
719 bool verbose = qdict_get_try_bool(qdict, "verbose", false);
720 bool nodes = qdict_get_try_bool(qdict, "nodes", false);
721 bool printed = false;
723 /* Print BlockBackend information */
724 if (!nodes) {
725 block_list = qmp_query_block(NULL);
726 } else {
727 block_list = NULL;
730 for (info = block_list; info; info = info->next) {
731 if (device && strcmp(device, info->value->device)) {
732 continue;
735 if (info != block_list) {
736 monitor_printf(mon, "\n");
739 print_block_info(mon, info->value, info->value->has_inserted
740 ? info->value->inserted : NULL,
741 verbose);
742 printed = true;
745 qapi_free_BlockInfoList(block_list);
747 if ((!device && !nodes) || printed) {
748 return;
751 /* Print node information */
752 blockdev_list = qmp_query_named_block_nodes(false, false, NULL);
753 for (blockdev = blockdev_list; blockdev; blockdev = blockdev->next) {
754 assert(blockdev->value->has_node_name);
755 if (device && strcmp(device, blockdev->value->node_name)) {
756 continue;
759 if (blockdev != blockdev_list) {
760 monitor_printf(mon, "\n");
763 print_block_info(mon, NULL, blockdev->value, verbose);
765 qapi_free_BlockDeviceInfoList(blockdev_list);
768 void hmp_info_blockstats(Monitor *mon, const QDict *qdict)
770 BlockStatsList *stats_list, *stats;
772 stats_list = qmp_query_blockstats(false, false, NULL);
774 for (stats = stats_list; stats; stats = stats->next) {
775 if (!stats->value->has_device) {
776 continue;
779 monitor_printf(mon, "%s:", stats->value->device);
780 monitor_printf(mon, " rd_bytes=%" PRId64
781 " wr_bytes=%" PRId64
782 " rd_operations=%" PRId64
783 " wr_operations=%" PRId64
784 " flush_operations=%" PRId64
785 " wr_total_time_ns=%" PRId64
786 " rd_total_time_ns=%" PRId64
787 " flush_total_time_ns=%" PRId64
788 " rd_merged=%" PRId64
789 " wr_merged=%" PRId64
790 " idle_time_ns=%" PRId64
791 "\n",
792 stats->value->stats->rd_bytes,
793 stats->value->stats->wr_bytes,
794 stats->value->stats->rd_operations,
795 stats->value->stats->wr_operations,
796 stats->value->stats->flush_operations,
797 stats->value->stats->wr_total_time_ns,
798 stats->value->stats->rd_total_time_ns,
799 stats->value->stats->flush_total_time_ns,
800 stats->value->stats->rd_merged,
801 stats->value->stats->wr_merged,
802 stats->value->stats->idle_time_ns);
805 qapi_free_BlockStatsList(stats_list);
808 void hmp_info_block_jobs(Monitor *mon, const QDict *qdict)
810 BlockJobInfoList *list;
811 Error *err = NULL;
813 list = qmp_query_block_jobs(&err);
814 assert(!err);
816 if (!list) {
817 monitor_printf(mon, "No active jobs\n");
818 return;
821 while (list) {
822 if (strcmp(list->value->type, "stream") == 0) {
823 monitor_printf(mon, "Streaming device %s: Completed %" PRId64
824 " of %" PRId64 " bytes, speed limit %" PRId64
825 " bytes/s\n",
826 list->value->device,
827 list->value->offset,
828 list->value->len,
829 list->value->speed);
830 } else {
831 monitor_printf(mon, "Type %s, device %s: Completed %" PRId64
832 " of %" PRId64 " bytes, speed limit %" PRId64
833 " bytes/s\n",
834 list->value->type,
835 list->value->device,
836 list->value->offset,
837 list->value->len,
838 list->value->speed);
840 list = list->next;
843 qapi_free_BlockJobInfoList(list);
846 void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
848 BlockDriverState *bs, *bs1;
849 BdrvNextIterator it1;
850 QEMUSnapshotInfo *sn_tab, *sn;
851 bool no_snapshot = true;
852 int nb_sns, i;
853 int total;
854 int *global_snapshots;
855 AioContext *aio_context;
857 typedef struct SnapshotEntry {
858 QEMUSnapshotInfo sn;
859 QTAILQ_ENTRY(SnapshotEntry) next;
860 } SnapshotEntry;
862 typedef struct ImageEntry {
863 const char *imagename;
864 QTAILQ_ENTRY(ImageEntry) next;
865 QTAILQ_HEAD(, SnapshotEntry) snapshots;
866 } ImageEntry;
868 QTAILQ_HEAD(, ImageEntry) image_list =
869 QTAILQ_HEAD_INITIALIZER(image_list);
871 ImageEntry *image_entry, *next_ie;
872 SnapshotEntry *snapshot_entry;
874 bs = bdrv_all_find_vmstate_bs();
875 if (!bs) {
876 monitor_printf(mon, "No available block device supports snapshots\n");
877 return;
879 aio_context = bdrv_get_aio_context(bs);
881 aio_context_acquire(aio_context);
882 nb_sns = bdrv_snapshot_list(bs, &sn_tab);
883 aio_context_release(aio_context);
885 if (nb_sns < 0) {
886 monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);
887 return;
890 for (bs1 = bdrv_first(&it1); bs1; bs1 = bdrv_next(&it1)) {
891 int bs1_nb_sns = 0;
892 ImageEntry *ie;
893 SnapshotEntry *se;
894 AioContext *ctx = bdrv_get_aio_context(bs1);
896 aio_context_acquire(ctx);
897 if (bdrv_can_snapshot(bs1)) {
898 sn = NULL;
899 bs1_nb_sns = bdrv_snapshot_list(bs1, &sn);
900 if (bs1_nb_sns > 0) {
901 no_snapshot = false;
902 ie = g_new0(ImageEntry, 1);
903 ie->imagename = bdrv_get_device_name(bs1);
904 QTAILQ_INIT(&ie->snapshots);
905 QTAILQ_INSERT_TAIL(&image_list, ie, next);
906 for (i = 0; i < bs1_nb_sns; i++) {
907 se = g_new0(SnapshotEntry, 1);
908 se->sn = sn[i];
909 QTAILQ_INSERT_TAIL(&ie->snapshots, se, next);
912 g_free(sn);
914 aio_context_release(ctx);
917 if (no_snapshot) {
918 monitor_printf(mon, "There is no snapshot available.\n");
919 return;
922 global_snapshots = g_new0(int, nb_sns);
923 total = 0;
924 for (i = 0; i < nb_sns; i++) {
925 SnapshotEntry *next_sn;
926 if (bdrv_all_find_snapshot(sn_tab[i].name, &bs1) == 0) {
927 global_snapshots[total] = i;
928 total++;
929 QTAILQ_FOREACH(image_entry, &image_list, next) {
930 QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots,
931 next, next_sn) {
932 if (!strcmp(sn_tab[i].name, snapshot_entry->sn.name)) {
933 QTAILQ_REMOVE(&image_entry->snapshots, snapshot_entry,
934 next);
935 g_free(snapshot_entry);
941 monitor_printf(mon, "List of snapshots present on all disks:\n");
943 if (total > 0) {
944 bdrv_snapshot_dump(NULL);
945 monitor_printf(mon, "\n");
946 for (i = 0; i < total; i++) {
947 sn = &sn_tab[global_snapshots[i]];
949 * The ID is not guaranteed to be the same on all images, so
950 * overwrite it.
952 pstrcpy(sn->id_str, sizeof(sn->id_str), "--");
953 bdrv_snapshot_dump(sn);
954 monitor_printf(mon, "\n");
956 } else {
957 monitor_printf(mon, "None\n");
960 QTAILQ_FOREACH(image_entry, &image_list, next) {
961 if (QTAILQ_EMPTY(&image_entry->snapshots)) {
962 continue;
964 monitor_printf(mon,
965 "\nList of partial (non-loadable) snapshots on '%s':\n",
966 image_entry->imagename);
967 bdrv_snapshot_dump(NULL);
968 monitor_printf(mon, "\n");
969 QTAILQ_FOREACH(snapshot_entry, &image_entry->snapshots, next) {
970 bdrv_snapshot_dump(&snapshot_entry->sn);
971 monitor_printf(mon, "\n");
975 QTAILQ_FOREACH_SAFE(image_entry, &image_list, next, next_ie) {
976 SnapshotEntry *next_sn;
977 QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots, next,
978 next_sn) {
979 g_free(snapshot_entry);
981 g_free(image_entry);
983 g_free(sn_tab);
984 g_free(global_snapshots);