master
c 953 lines 29 KB
Raw
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/core/boards.h"
40 #include "system/block-backend.h"
41 #include "system/blockdev.h"
42 #include "qapi/qapi-commands-block.h"
43 #include "qapi/qapi-commands-block-export.h"
44 #include "qobject/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 "system/system.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"
59
60 static void hmp_drive_add_node(MonitorHMP *hmp, const char *optstr)
61 {
62 QemuOpts *opts;
63 QDict *qdict;
64 Error *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_setg(&err, "'node-name' needs to be specified");
76 goto out;
77 }
78
79 BlockDriverState *bs = bds_tree_init(qdict, &err);
80 if (!bs) {
81 goto out;
82 }
83
84 bdrv_set_monitor_owned(bs);
85 out:
86 qemu_opts_del(opts);
87 hmp_handle_error(hmp, err);
88 }
89
90 void hmp_drive_add(MonitorHMP *hmp, 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(hmp, optstr);
101 return;
102 }
103
104 opts = qemu_opts_parse_noisily(qemu_find_opts("drive"), optstr, false);
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 qemu_opts_del(opts);
112 goto err;
113 }
114
115 if (!dinfo) {
116 return;
117 }
118
119 switch (dinfo->type) {
120 case IF_NONE:
121 monitor_hmp_printf(hmp, "OK\n");
122 break;
123 default:
124 error_setg(&err, "Can't hot-add drive to type %d", dinfo->type);
125 goto err;
126 }
127 return;
128
129 err:
130 if (dinfo) {
131 BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
132 monitor_remove_blk(blk);
133 blk_unref(blk);
134 }
135 hmp_handle_error(hmp, err);
136 }
137
138 void hmp_drive_del(MonitorHMP *hmp, const QDict *qdict)
139 {
140 const char *id = qdict_get_str(qdict, "id");
141 BlockBackend *blk;
142 BlockDriverState *bs;
143 Error *err = NULL;
144
145 GLOBAL_STATE_CODE();
146 bdrv_graph_rdlock_main_loop();
147
148 bs = bdrv_find_node(id);
149 if (bs) {
150 qmp_blockdev_del(id, &err);
151 goto unlock;
152 }
153
154 blk = blk_by_name(id);
155 if (!blk) {
156 error_setg(&err, "Device '%s' not found", id);
157 goto unlock;
158 }
159
160 if (!blk_legacy_dinfo(blk)) {
161 error_setg(&err, "Deleting device added with blockdev-add"
162 " is not supported");
163 goto unlock;
164 }
165
166 bs = blk_bs(blk);
167 if (bs) {
168 if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &err)) {
169 goto unlock;
170 }
171
172 bdrv_graph_rdunlock_main_loop();
173 blk_remove_bs(blk);
174 bdrv_graph_rdlock_main_loop();
175 }
176
177 /* Make the BlockBackend and the attached BlockDriverState anonymous */
178 monitor_remove_blk(blk);
179
180 /*
181 * If this BlockBackend has a device attached to it, its refcount will be
182 * decremented when the device is removed; otherwise we have to do so here.
183 */
184 if (blk_get_attached_dev(blk)) {
185 /* Further I/O must not pause the guest */
186 blk_set_on_error(blk, BLOCKDEV_ON_ERROR_REPORT,
187 BLOCKDEV_ON_ERROR_REPORT);
188 } else {
189 blk_unref(blk);
190 }
191
192 unlock:
193 bdrv_graph_rdunlock_main_loop();
194 hmp_handle_error(hmp, err);
195 }
196
197 void hmp_commit(MonitorHMP *hmp, const QDict *qdict)
198 {
199 const char *device = qdict_get_str(qdict, "device");
200 BlockBackend *blk;
201 int ret;
202 Error *err = NULL;
203
204 GLOBAL_STATE_CODE();
205 GRAPH_RDLOCK_GUARD_MAINLOOP();
206
207 if (!strcmp(device, "all")) {
208 ret = blk_commit_all();
209 } else {
210 BlockDriverState *bs;
211
212 blk = blk_by_name(device);
213 if (!blk) {
214 error_setg(&err, "Device '%s' not found", device);
215 goto end;
216 }
217
218 bs = bdrv_skip_implicit_filters(blk_bs(blk));
219
220 if (!blk_is_available(blk)) {
221 error_setg(&err, "Device '%s' has no medium", device);
222 goto end;
223 }
224
225 ret = bdrv_commit(bs);
226 }
227 if (ret < 0) {
228 error_setg(&err, "'commit' error for '%s': %s", device, strerror(-ret));
229 }
230
231 end:
232 hmp_handle_error(hmp, err);
233 }
234
235 void hmp_drive_mirror(MonitorHMP *hmp, const QDict *qdict)
236 {
237 const char *filename = qdict_get_str(qdict, "target");
238 const char *format = qdict_get_try_str(qdict, "format");
239 bool reuse = qdict_get_try_bool(qdict, "reuse", false);
240 bool full = qdict_get_try_bool(qdict, "full", false);
241 Error *err = NULL;
242 DriveMirror mirror = {
243 .device = (char *)qdict_get_str(qdict, "device"),
244 .target = (char *)filename,
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);
257 end:
258 hmp_handle_error(hmp, err);
259 }
260
261 void hmp_drive_backup(MonitorHMP *hmp, 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 .format = (char *)format,
274 .sync = full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
275 .has_mode = true,
276 .mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS,
277 .has_compress = !!compress,
278 .compress = compress,
279 };
280
281 if (!filename) {
282 error_setg(&err, QERR_MISSING_PARAMETER, "target");
283 goto end;
284 }
285
286 qmp_drive_backup(&backup, &err);
287 end:
288 hmp_handle_error(hmp, err);
289 }
290
291 void hmp_block_job_set_speed(MonitorHMP *hmp, const QDict *qdict)
292 {
293 Error *error = NULL;
294 const char *device = qdict_get_str(qdict, "device");
295 int64_t value = qdict_get_int(qdict, "speed");
296
297 qmp_block_job_set_speed(device, value, &error);
298
299 hmp_handle_error(hmp, error);
300 }
301
302 void hmp_block_job_cancel(MonitorHMP *hmp, const QDict *qdict)
303 {
304 Error *error = NULL;
305 const char *device = qdict_get_str(qdict, "device");
306 bool force = qdict_get_try_bool(qdict, "force", false);
307
308 qmp_block_job_cancel(device, true, force, &error);
309
310 hmp_handle_error(hmp, error);
311 }
312
313 void hmp_block_job_pause(MonitorHMP *hmp, const QDict *qdict)
314 {
315 Error *error = NULL;
316 const char *device = qdict_get_str(qdict, "device");
317
318 qmp_block_job_pause(device, &error);
319
320 hmp_handle_error(hmp, error);
321 }
322
323 void hmp_block_job_resume(MonitorHMP *hmp, const QDict *qdict)
324 {
325 Error *error = NULL;
326 const char *device = qdict_get_str(qdict, "device");
327
328 qmp_block_job_resume(device, &error);
329
330 hmp_handle_error(hmp, error);
331 }
332
333 void hmp_block_job_complete(MonitorHMP *hmp, const QDict *qdict)
334 {
335 Error *error = NULL;
336 const char *device = qdict_get_str(qdict, "device");
337
338 qmp_block_job_complete(device, &error);
339
340 hmp_handle_error(hmp, error);
341 }
342
343 void hmp_snapshot_blkdev(MonitorHMP *hmp, const QDict *qdict)
344 {
345 const char *device = qdict_get_str(qdict, "device");
346 const char *filename = qdict_get_str(qdict, "snapshot-file");
347 const char *format = qdict_get_try_str(qdict, "format");
348 bool reuse = qdict_get_try_bool(qdict, "reuse", false);
349 enum NewImageMode mode;
350 Error *err = NULL;
351
352 mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS;
353 qmp_blockdev_snapshot_sync(device, NULL, filename, NULL, format,
354 true, mode, &err);
355 hmp_handle_error(hmp, err);
356 }
357
358 void hmp_snapshot_blkdev_internal(MonitorHMP *hmp, const QDict *qdict)
359 {
360 const char *device = qdict_get_str(qdict, "device");
361 const char *name = qdict_get_str(qdict, "name");
362 Error *err = NULL;
363
364 qmp_blockdev_snapshot_internal_sync(device, name, &err);
365 hmp_handle_error(hmp, err);
366 }
367
368 void hmp_snapshot_delete_blkdev_internal(MonitorHMP *hmp, const QDict *qdict)
369 {
370 const char *device = qdict_get_str(qdict, "device");
371 const char *name = qdict_get_str(qdict, "name");
372 const char *id = qdict_get_try_str(qdict, "id");
373 Error *err = NULL;
374
375 qmp_blockdev_snapshot_delete_internal_sync(device, id, name, &err);
376 hmp_handle_error(hmp, err);
377 }
378
379 void hmp_nbd_server_start(MonitorHMP *hmp, const QDict *qdict)
380 {
381 const char *uri = qdict_get_str(qdict, "uri");
382 bool writable = qdict_get_try_bool(qdict, "writable", false);
383 bool all = qdict_get_try_bool(qdict, "all", false);
384 Error *local_err = NULL;
385 BlockInfoList *block_list, *info;
386 SocketAddress *addr;
387 NbdServerAddOptions export;
388
389 if (writable && !all) {
390 error_setg(&local_err, "-w only valid together with -a");
391 goto exit;
392 }
393
394 /* First check if the address is valid and start the server. */
395 addr = socket_parse(uri, &local_err);
396 if (local_err != NULL) {
397 goto exit;
398 }
399
400 nbd_server_start(addr, NBD_DEFAULT_HANDSHAKE_MAX_SECS, NULL, NULL,
401 NBD_DEFAULT_MAX_CONNECTIONS, &local_err);
402 qapi_free_SocketAddress(addr);
403 if (local_err != NULL) {
404 goto exit;
405 }
406
407 if (!all) {
408 return;
409 }
410
411 /* Then try adding all block devices. If one fails, close all and
412 * exit.
413 */
414 block_list = qmp_query_block(true, true, NULL);
415
416 for (info = block_list; info; info = info->next) {
417 if (!info->value->inserted) {
418 continue;
419 }
420
421 export = (NbdServerAddOptions) {
422 .device = info->value->device,
423 .has_writable = true,
424 .writable = writable,
425 };
426
427 qmp_nbd_server_add(&export, &local_err);
428
429 if (local_err != NULL) {
430 qmp_nbd_server_stop(NULL);
431 break;
432 }
433 }
434
435 qapi_free_BlockInfoList(block_list);
436
437 exit:
438 hmp_handle_error(hmp, local_err);
439 }
440
441 void hmp_nbd_server_add(MonitorHMP *hmp, const QDict *qdict)
442 {
443 const char *device = qdict_get_str(qdict, "device");
444 const char *name = qdict_get_try_str(qdict, "name");
445 bool writable = qdict_get_try_bool(qdict, "writable", false);
446 Error *local_err = NULL;
447
448 NbdServerAddOptions export = {
449 .device = (char *) device,
450 .name = (char *) name,
451 .has_writable = true,
452 .writable = writable,
453 };
454
455 qmp_nbd_server_add(&export, &local_err);
456 hmp_handle_error(hmp, local_err);
457 }
458
459 void hmp_nbd_server_remove(MonitorHMP *hmp, const QDict *qdict)
460 {
461 const char *name = qdict_get_str(qdict, "name");
462 bool force = qdict_get_try_bool(qdict, "force", false);
463 Error *err = NULL;
464
465 /* Rely on BLOCK_EXPORT_REMOVE_MODE_SAFE being the default */
466 qmp_nbd_server_remove(name, force, BLOCK_EXPORT_REMOVE_MODE_HARD, &err);
467 hmp_handle_error(hmp, err);
468 }
469
470 void hmp_nbd_server_stop(MonitorHMP *hmp, const QDict *qdict)
471 {
472 Error *err = NULL;
473
474 qmp_nbd_server_stop(&err);
475 hmp_handle_error(hmp, err);
476 }
477
478 void coroutine_fn hmp_block_resize(MonitorHMP *hmp, const QDict *qdict)
479 {
480 const char *device = qdict_get_str(qdict, "device");
481 int64_t size = qdict_get_int(qdict, "size");
482 Error *err = NULL;
483
484 qmp_block_resize(device, NULL, size, &err);
485 hmp_handle_error(hmp, err);
486 }
487
488 void hmp_block_stream(MonitorHMP *hmp, const QDict *qdict)
489 {
490 Error *error = NULL;
491 const char *device = qdict_get_str(qdict, "device");
492 const char *base = qdict_get_try_str(qdict, "base");
493 int64_t speed = qdict_get_try_int(qdict, "speed", 0);
494
495 qmp_block_stream(device, device, base, NULL, NULL, false, false, NULL,
496 qdict_haskey(qdict, "speed"), speed,
497 true, BLOCKDEV_ON_ERROR_REPORT, NULL,
498 false, false, false, false, &error);
499
500 hmp_handle_error(hmp, error);
501 }
502
503 void hmp_block_set_io_throttle(MonitorHMP *hmp, const QDict *qdict)
504 {
505 Error *err = NULL;
506 char *device = (char *) qdict_get_str(qdict, "device");
507 BlockIOThrottle throttle = {
508 .bps = qdict_get_int(qdict, "bps"),
509 .bps_rd = qdict_get_int(qdict, "bps_rd"),
510 .bps_wr = qdict_get_int(qdict, "bps_wr"),
511 .iops = qdict_get_int(qdict, "iops"),
512 .iops_rd = qdict_get_int(qdict, "iops_rd"),
513 .iops_wr = qdict_get_int(qdict, "iops_wr"),
514 };
515
516 /*
517 * qmp_block_set_io_throttle has separate parameters for the
518 * (deprecated) block device name and the qdev ID but the HMP
519 * version has only one, so we must decide which one to pass.
520 */
521 if (blk_by_name(device)) {
522 throttle.device = device;
523 } else {
524 throttle.id = device;
525 }
526
527 qmp_block_set_io_throttle(&throttle, &err);
528 hmp_handle_error(hmp, err);
529 }
530
531 void hmp_eject(MonitorHMP *hmp, const QDict *qdict)
532 {
533 bool force = qdict_get_try_bool(qdict, "force", false);
534 const char *device = qdict_get_str(qdict, "device");
535 Error *err = NULL;
536
537 qmp_eject(device, NULL, true, force, &err);
538 hmp_handle_error(hmp, err);
539 }
540
541 void hmp_qemu_io(MonitorHMP *hmp, const QDict *qdict)
542 {
543 bool qdev = qdict_get_try_bool(qdict, "qdev", false);
544 const char *device = qdict_get_str(qdict, "device");
545 const char *command = qdict_get_str(qdict, "command");
546 Error *err = NULL;
547
548 qmp_x_qemu_io(qdev ? NULL : device,
549 qdev ? device : NULL,
550 command, &err);
551 hmp_handle_error(hmp, err);
552 }
553
554 static void print_block_info(MonitorHMP *hmp, BlockInfo *info,
555 BlockDeviceInfo *inserted, bool verbose)
556 {
557 Monitor *mon = MONITOR(hmp);
558 ImageInfo *image_info;
559
560 assert(!info || !info->inserted || info->inserted == inserted);
561
562 if (info && *info->device) {
563 monitor_puts(mon, info->device);
564 if (inserted && inserted->node_name) {
565 monitor_hmp_printf(hmp, " (%s)", inserted->node_name);
566 }
567 } else {
568 assert(info || inserted);
569 monitor_puts(mon,
570 inserted && inserted->node_name ? inserted->node_name
571 : info && info->qdev ? info->qdev
572 : "<anonymous>");
573 }
574
575 if (inserted) {
576 monitor_hmp_printf(hmp, ": %s (%s%s%s%s)\n",
577 inserted->file,
578 inserted->drv,
579 inserted->ro ? ", read-only" : "",
580 inserted->encrypted ? ", encrypted" : "",
581 inserted->active ? "" : ", inactive");
582 } else {
583 monitor_hmp_printf(hmp, ": [not inserted]\n");
584 }
585
586 if (info) {
587 if (info->qdev) {
588 monitor_hmp_printf(hmp, " Attached to: %s\n", info->qdev);
589 }
590 if (info->has_io_status && info->io_status != BLOCK_DEVICE_IO_STATUS_OK) {
591 monitor_hmp_printf(hmp, " I/O status: %s\n",
592 BlockDeviceIoStatus_str(info->io_status));
593 }
594
595 if (info->removable) {
596 monitor_hmp_printf(hmp, " Removable device: %slocked, tray %s\n",
597 info->locked ? "" : "not ",
598 info->tray_open ? "open" : "closed");
599 }
600 }
601
602
603 if (!inserted) {
604 return;
605 }
606
607 monitor_hmp_printf(hmp, " Cache mode: %s%s%s\n",
608 inserted->cache->writeback ? "writeback" : "writethrough",
609 inserted->cache->direct ? ", direct" : "",
610 inserted->cache->no_flush ? ", ignore flushes" : "");
611
612 if (inserted->backing_file) {
613 monitor_hmp_printf(hmp,
614 " Backing file: %s "
615 "(chain depth: %" PRId64 ")\n",
616 inserted->backing_file,
617 inserted->backing_file_depth);
618 }
619
620 if (inserted->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF) {
621 monitor_hmp_printf(hmp, " Detect zeroes: %s\n",
622 BlockdevDetectZeroesOptions_str(inserted->detect_zeroes));
623 }
624
625 if (inserted->bps || inserted->bps_rd || inserted->bps_wr ||
626 inserted->iops || inserted->iops_rd || inserted->iops_wr)
627 {
628 monitor_hmp_printf(hmp, " I/O throttling: bps=%" PRId64
629 " bps_rd=%" PRId64 " bps_wr=%" PRId64
630 " bps_max=%" PRId64
631 " bps_rd_max=%" PRId64
632 " bps_wr_max=%" PRId64
633 " iops=%" PRId64 " iops_rd=%" PRId64
634 " iops_wr=%" PRId64
635 " iops_max=%" PRId64
636 " iops_rd_max=%" PRId64
637 " iops_wr_max=%" PRId64
638 " iops_size=%" PRId64
639 " group=%s\n",
640 inserted->bps,
641 inserted->bps_rd,
642 inserted->bps_wr,
643 inserted->bps_max,
644 inserted->bps_rd_max,
645 inserted->bps_wr_max,
646 inserted->iops,
647 inserted->iops_rd,
648 inserted->iops_wr,
649 inserted->iops_max,
650 inserted->iops_rd_max,
651 inserted->iops_wr_max,
652 inserted->iops_size,
653 inserted->group);
654 }
655
656 if (verbose) {
657 monitor_hmp_printf(hmp, "\nImages:\n");
658 image_info = inserted->image;
659 while (1) {
660 bdrv_node_info_dump(qapi_ImageInfo_base(image_info), 0, false);
661 if (image_info->backing_image) {
662 image_info = image_info->backing_image;
663 } else {
664 break;
665 }
666 }
667 }
668 }
669
670 void hmp_info_block(MonitorHMP *hmp, const QDict *qdict)
671 {
672 BlockInfoList *block_list, *info;
673 BlockDeviceInfoList *blockdev_list, *blockdev;
674 const char *device = qdict_get_try_str(qdict, "device");
675 bool verbose = qdict_get_try_bool(qdict, "verbose", false);
676 bool nodes = qdict_get_try_bool(qdict, "nodes", false);
677 bool printed = false;
678
679 /* Print BlockBackend information */
680 if (!nodes) {
681 block_list = qmp_query_block(false, false, NULL);
682 } else {
683 block_list = NULL;
684 }
685
686 for (info = block_list; info; info = info->next) {
687 if (device && strcmp(device, info->value->device)) {
688 continue;
689 }
690
691 if (info != block_list) {
692 monitor_hmp_printf(hmp, "\n");
693 }
694
695 print_block_info(hmp, info->value, info->value->inserted,
696 verbose);
697 printed = true;
698 }
699
700 qapi_free_BlockInfoList(block_list);
701
702 if ((!device && !nodes) || printed) {
703 return;
704 }
705
706 /* Print node information */
707 blockdev_list = qmp_query_named_block_nodes(false, false, NULL);
708 for (blockdev = blockdev_list; blockdev; blockdev = blockdev->next) {
709 assert(blockdev->value->node_name);
710 if (device && strcmp(device, blockdev->value->node_name)) {
711 continue;
712 }
713
714 if (blockdev != blockdev_list) {
715 monitor_hmp_printf(hmp, "\n");
716 }
717
718 print_block_info(hmp, NULL, blockdev->value, verbose);
719 }
720 qapi_free_BlockDeviceInfoList(blockdev_list);
721 }
722
723 void hmp_info_blockstats(MonitorHMP *hmp, const QDict *qdict)
724 {
725 BlockStatsList *stats_list, *stats;
726
727 stats_list = qmp_query_blockstats(false, false, NULL);
728
729 for (stats = stats_list; stats; stats = stats->next) {
730 if (!stats->value->device) {
731 continue;
732 }
733
734 monitor_hmp_printf(hmp, "%s%s: idle_time_ns=%" PRId64 "\n",
735 stats != stats_list ? "\n" : "",
736 stats->value->device,
737 stats->value->stats->idle_time_ns);
738 monitor_hmp_printf(hmp, " %24s %16s %24s %10s\n", "bytes",
739 "operations", "total_time_ns", "merged");
740 monitor_hmp_printf(hmp, "Read: %24" PRId64 " %16" PRId64 " %24" PRId64
741 " %10" PRId64 "\n",
742 stats->value->stats->rd_bytes,
743 stats->value->stats->rd_operations,
744 stats->value->stats->rd_total_time_ns,
745 stats->value->stats->rd_merged);
746 monitor_hmp_printf(hmp, "Write: %24" PRId64 " %16" PRId64 " %24" PRId64
747 " %10" PRId64 "\n",
748 stats->value->stats->wr_bytes,
749 stats->value->stats->wr_operations,
750 stats->value->stats->wr_total_time_ns,
751 stats->value->stats->wr_merged);
752 monitor_hmp_printf(hmp, "Flush: %24s %16" PRId64 " %24" PRId64 "\n",
753 "",
754 stats->value->stats->flush_operations,
755 stats->value->stats->flush_total_time_ns);
756 }
757
758 qapi_free_BlockStatsList(stats_list);
759 }
760
761 void hmp_info_block_jobs(MonitorHMP *hmp, const QDict *qdict)
762 {
763 BlockJobInfoList *list;
764
765 list = qmp_query_block_jobs(&error_abort);
766
767 if (!list) {
768 monitor_hmp_printf(hmp, "No active jobs\n");
769 return;
770 }
771
772 while (list) {
773 if (list->value->type == JOB_TYPE_STREAM) {
774 monitor_hmp_printf(hmp, "Streaming device %s: Completed %" PRId64
775 " of %" PRId64 " bytes, speed limit %" PRId64
776 " bytes/s\n",
777 list->value->device,
778 list->value->offset,
779 list->value->len,
780 list->value->speed);
781 } else {
782 monitor_hmp_printf(hmp, "Type %s, device %s: Completed %" PRId64
783 " of %" PRId64 " bytes, speed limit %" PRId64
784 " bytes/s\n",
785 JobType_str(list->value->type),
786 list->value->device,
787 list->value->offset,
788 list->value->len,
789 list->value->speed);
790 }
791 list = list->next;
792 }
793
794 qapi_free_BlockJobInfoList(list);
795 }
796
797 void hmp_info_snapshots(MonitorHMP *hmp, const QDict *qdict)
798 {
799 BlockDriverState *bs, *bs1;
800 BdrvNextIterator it1;
801 QEMUSnapshotInfo *sn_tab, *sn;
802 bool no_snapshot = true;
803 int nb_sns, i;
804 int total;
805 int *global_snapshots;
806
807 typedef struct SnapshotEntry {
808 QEMUSnapshotInfo sn;
809 QTAILQ_ENTRY(SnapshotEntry) next;
810 } SnapshotEntry;
811
812 typedef struct ImageEntry {
813 const char *imagename;
814 QTAILQ_ENTRY(ImageEntry) next;
815 QTAILQ_HEAD(, SnapshotEntry) snapshots;
816 } ImageEntry;
817
818 QTAILQ_HEAD(, ImageEntry) image_list =
819 QTAILQ_HEAD_INITIALIZER(image_list);
820
821 ImageEntry *image_entry, *next_ie;
822 SnapshotEntry *snapshot_entry;
823 Error *err = NULL;
824
825 GRAPH_RDLOCK_GUARD_MAINLOOP();
826
827 bs = bdrv_all_find_vmstate_bs(NULL, false, NULL, &err);
828 if (!bs) {
829 hmp_handle_error(hmp, err);
830 return;
831 }
832
833 nb_sns = bdrv_snapshot_list(bs, &sn_tab);
834
835 if (nb_sns < 0) {
836 monitor_hmp_printf(hmp, "bdrv_snapshot_list: error %d\n", nb_sns);
837 return;
838 }
839
840 for (bs1 = bdrv_first(&it1); bs1; bs1 = bdrv_next(&it1)) {
841 int bs1_nb_sns = 0;
842 ImageEntry *ie;
843 SnapshotEntry *se;
844
845 if (bdrv_can_snapshot(bs1)) {
846 sn = NULL;
847 bs1_nb_sns = bdrv_snapshot_list(bs1, &sn);
848 if (bs1_nb_sns > 0) {
849 no_snapshot = false;
850 ie = g_new0(ImageEntry, 1);
851 ie->imagename = bdrv_get_device_name(bs1);
852 QTAILQ_INIT(&ie->snapshots);
853 QTAILQ_INSERT_TAIL(&image_list, ie, next);
854 for (i = 0; i < bs1_nb_sns; i++) {
855 se = g_new0(SnapshotEntry, 1);
856 se->sn = sn[i];
857 QTAILQ_INSERT_TAIL(&ie->snapshots, se, next);
858 }
859 }
860 g_free(sn);
861 }
862 }
863
864 if (no_snapshot) {
865 monitor_hmp_printf(hmp, "There is no snapshot available.\n");
866 return;
867 }
868
869 global_snapshots = g_new0(int, nb_sns);
870 total = 0;
871 for (i = 0; i < nb_sns; i++) {
872 SnapshotEntry *next_sn;
873 if (bdrv_all_has_snapshot(sn_tab[i].name, false, NULL, NULL) == 1) {
874 global_snapshots[total] = i;
875 total++;
876 QTAILQ_FOREACH(image_entry, &image_list, next) {
877 QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots,
878 next, next_sn) {
879 if (!strcmp(sn_tab[i].name, snapshot_entry->sn.name)) {
880 QTAILQ_REMOVE(&image_entry->snapshots, snapshot_entry,
881 next);
882 g_free(snapshot_entry);
883 }
884 }
885 }
886 }
887 }
888 monitor_hmp_printf(hmp, "List of snapshots present on all disks:\n");
889
890 if (total > 0) {
891 bdrv_snapshot_dump(NULL);
892 monitor_hmp_printf(hmp, "\n");
893 for (i = 0; i < total; i++) {
894 sn = &sn_tab[global_snapshots[i]];
895 /*
896 * The ID is not guaranteed to be the same on all images, so
897 * overwrite it.
898 */
899 pstrcpy(sn->id_str, sizeof(sn->id_str), "--");
900 bdrv_snapshot_dump(sn);
901 monitor_hmp_printf(hmp, "\n");
902 }
903 } else {
904 monitor_hmp_printf(hmp, "None\n");
905 }
906
907 QTAILQ_FOREACH(image_entry, &image_list, next) {
908 if (QTAILQ_EMPTY(&image_entry->snapshots)) {
909 continue;
910 }
911 monitor_hmp_printf(hmp,
912 "\nList of partial (non-loadable) snapshots on '%s':\n",
913 image_entry->imagename);
914 bdrv_snapshot_dump(NULL);
915 monitor_hmp_printf(hmp, "\n");
916 QTAILQ_FOREACH(snapshot_entry, &image_entry->snapshots, next) {
917 bdrv_snapshot_dump(&snapshot_entry->sn);
918 monitor_hmp_printf(hmp, "\n");
919 }
920 }
921
922 QTAILQ_FOREACH_SAFE(image_entry, &image_list, next, next_ie) {
923 SnapshotEntry *next_sn;
924 QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots, next,
925 next_sn) {
926 g_free(snapshot_entry);
927 }
928 g_free(image_entry);
929 }
930 g_free(sn_tab);
931 g_free(global_snapshots);
932 }
933
934 void hmp_change_medium(MonitorHMP *hmp, const char *device, const char *target,
935 const char *arg, const char *read_only, bool force,
936 Error **errp)
937 {
938 ERRP_GUARD();
939 BlockdevChangeReadOnlyMode read_only_mode = 0;
940
941 if (read_only) {
942 read_only_mode =
943 qapi_enum_parse(&BlockdevChangeReadOnlyMode_lookup,
944 read_only,
945 BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN, errp);
946 if (*errp) {
947 return;
948 }
949 }
950
951 qmp_blockdev_change_medium(device, NULL, target, arg, true, force,
952 !!read_only, read_only_mode, errp);
953 }