2 * QMP command handlers specific to the system emulators
4 * Copyright (c) 2003-2008 Fabrice Bellard
6 * This work is licensed under the terms of the GNU GPL, version 2 or
7 * later. See the COPYING file in the top-level directory.
9 * This file incorporates work covered by the following copyright and
12 * Copyright (c) 2003-2008 Fabrice Bellard
14 * Permission is hereby granted, free of charge, to any person obtaining a copy
15 * of this software and associated documentation files (the "Software"), to deal
16 * in the Software without restriction, including without limitation the rights
17 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18 * copies of the Software, and to permit persons to whom the Software is
19 * furnished to do so, subject to the following conditions:
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
33 #include "qemu/osdep.h"
35 #include "qapi/error.h"
36 #include "qapi/qapi-commands-block.h"
37 #include "qapi/qmp/qdict.h"
38 #include "sysemu/block-backend.h"
39 #include "sysemu/blockdev.h"
41 static BlockBackend
*qmp_get_blk(const char *blk_name
, const char *qdev_id
,
46 if (!blk_name
== !qdev_id
) {
47 error_setg(errp
, "Need exactly one of 'device' and 'id'");
52 blk
= blk_by_qdev_id(qdev_id
, errp
);
54 blk
= blk_by_name(blk_name
);
56 error_set(errp
, ERROR_CLASS_DEVICE_NOT_FOUND
,
57 "Device '%s' not found", blk_name
);
65 * Attempt to open the tray of @device.
66 * If @force, ignore its tray lock.
67 * Else, if the tray is locked, don't open it, but ask the guest to open it.
68 * On error, store an error through @errp and return -errno.
69 * If @device does not exist, return -ENODEV.
70 * If it has no removable media, return -ENOTSUP.
71 * If it has no tray, return -ENOSYS.
72 * If the guest was asked to open the tray, return -EINPROGRESS.
75 static int do_open_tray(const char *blk_name
, const char *qdev_id
,
76 bool force
, Error
**errp
)
79 const char *device
= qdev_id
?: blk_name
;
82 blk
= qmp_get_blk(blk_name
, qdev_id
, errp
);
87 if (!blk_dev_has_removable_media(blk
)) {
88 error_setg(errp
, "Device '%s' is not removable", device
);
92 if (!blk_dev_has_tray(blk
)) {
93 error_setg(errp
, "Device '%s' does not have a tray", device
);
97 if (blk_dev_is_tray_open(blk
)) {
101 locked
= blk_dev_is_medium_locked(blk
);
103 blk_dev_eject_request(blk
, force
);
106 if (!locked
|| force
) {
107 blk_dev_change_media_cb(blk
, false, &error_abort
);
110 if (locked
&& !force
) {
111 error_setg(errp
, "Device '%s' is locked and force was not specified, "
112 "wait for tray to open and try again", device
);
119 void qmp_blockdev_open_tray(const char *device
,
121 bool has_force
, bool force
,
124 Error
*local_err
= NULL
;
130 rc
= do_open_tray(device
, id
, force
, &local_err
);
131 if (rc
&& rc
!= -ENOSYS
&& rc
!= -EINPROGRESS
) {
132 error_propagate(errp
, local_err
);
135 error_free(local_err
);
138 void qmp_blockdev_close_tray(const char *device
,
143 Error
*local_err
= NULL
;
145 blk
= qmp_get_blk(device
, id
, errp
);
150 if (!blk_dev_has_removable_media(blk
)) {
151 error_setg(errp
, "Device '%s' is not removable", device
?: id
);
155 if (!blk_dev_has_tray(blk
)) {
156 /* Ignore this command on tray-less devices */
160 if (!blk_dev_is_tray_open(blk
)) {
164 blk_dev_change_media_cb(blk
, true, &local_err
);
166 error_propagate(errp
, local_err
);
171 static void blockdev_remove_medium(const char *device
, const char *id
,
175 BlockDriverState
*bs
;
176 AioContext
*aio_context
;
177 bool has_attached_device
;
179 blk
= qmp_get_blk(device
, id
, errp
);
184 /* For BBs without a device, we can exchange the BDS tree at will */
185 has_attached_device
= blk_get_attached_dev(blk
);
187 if (has_attached_device
&& !blk_dev_has_removable_media(blk
)) {
188 error_setg(errp
, "Device '%s' is not removable", device
?: id
);
192 if (has_attached_device
&& blk_dev_has_tray(blk
) &&
193 !blk_dev_is_tray_open(blk
))
195 error_setg(errp
, "Tray of device '%s' is not open", device
?: id
);
204 aio_context
= bdrv_get_aio_context(bs
);
205 aio_context_acquire(aio_context
);
207 if (bdrv_op_is_blocked(bs
, BLOCK_OP_TYPE_EJECT
, errp
)) {
213 if (!blk_dev_has_tray(blk
)) {
214 /* For tray-less devices, blockdev-open-tray is a no-op (or may not be
215 * called at all); therefore, the medium needs to be ejected here.
216 * Do it after blk_remove_bs() so blk_is_inserted(blk) returns the @load
217 * value passed here (i.e. false). */
218 blk_dev_change_media_cb(blk
, false, &error_abort
);
222 aio_context_release(aio_context
);
225 void qmp_blockdev_remove_medium(const char *id
, Error
**errp
)
227 blockdev_remove_medium(NULL
, id
, errp
);
230 static void qmp_blockdev_insert_anon_medium(BlockBackend
*blk
,
231 BlockDriverState
*bs
, Error
**errp
)
233 Error
*local_err
= NULL
;
237 /* For BBs without a device, we can exchange the BDS tree at will */
238 has_device
= blk_get_attached_dev(blk
);
240 if (has_device
&& !blk_dev_has_removable_media(blk
)) {
241 error_setg(errp
, "Device is not removable");
245 if (has_device
&& blk_dev_has_tray(blk
) && !blk_dev_is_tray_open(blk
)) {
246 error_setg(errp
, "Tray of the device is not open");
251 error_setg(errp
, "There already is a medium in the device");
255 ret
= blk_insert_bs(blk
, bs
, errp
);
260 if (!blk_dev_has_tray(blk
)) {
261 /* For tray-less devices, blockdev-close-tray is a no-op (or may not be
262 * called at all); therefore, the medium needs to be pushed into the
264 * Do it after blk_insert_bs() so blk_is_inserted(blk) returns the @load
265 * value passed here (i.e. true). */
266 blk_dev_change_media_cb(blk
, true, &local_err
);
268 error_propagate(errp
, local_err
);
275 static void blockdev_insert_medium(const char *device
, const char *id
,
276 const char *node_name
, Error
**errp
)
279 BlockDriverState
*bs
;
281 blk
= qmp_get_blk(device
, id
, errp
);
286 bs
= bdrv_find_node(node_name
);
288 error_setg(errp
, "Node '%s' not found", node_name
);
292 if (bdrv_has_blk(bs
)) {
293 error_setg(errp
, "Node '%s' is already in use", node_name
);
297 qmp_blockdev_insert_anon_medium(blk
, bs
, errp
);
300 void qmp_blockdev_insert_medium(const char *id
, const char *node_name
,
303 blockdev_insert_medium(NULL
, id
, node_name
, errp
);
306 void qmp_blockdev_change_medium(const char *device
,
308 const char *filename
,
310 bool has_force
, bool force
,
312 BlockdevChangeReadOnlyMode read_only
,
316 BlockDriverState
*medium_bs
= NULL
;
320 QDict
*options
= NULL
;
323 blk
= qmp_get_blk(device
, id
, errp
);
329 blk_update_root_state(blk
);
332 bdrv_flags
= blk_get_open_flags_from_root_state(blk
);
333 bdrv_flags
&= ~(BDRV_O_TEMPORARY
| BDRV_O_SNAPSHOT
| BDRV_O_NO_BACKING
|
334 BDRV_O_PROTOCOL
| BDRV_O_AUTO_RDONLY
);
336 if (!has_read_only
) {
337 read_only
= BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN
;
341 case BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN
:
344 case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_ONLY
:
345 bdrv_flags
&= ~BDRV_O_RDWR
;
348 case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_WRITE
:
349 bdrv_flags
|= BDRV_O_RDWR
;
356 options
= qdict_new();
357 detect_zeroes
= blk_get_detect_zeroes_from_root_state(blk
);
358 qdict_put_str(options
, "detect-zeroes", detect_zeroes
? "on" : "off");
361 qdict_put_str(options
, "driver", format
);
364 medium_bs
= bdrv_open(filename
, NULL
, options
, bdrv_flags
, errp
);
369 rc
= do_open_tray(device
, id
, force
, &err
);
370 if (rc
&& rc
!= -ENOSYS
) {
371 error_propagate(errp
, err
);
377 blockdev_remove_medium(device
, id
, &err
);
379 error_propagate(errp
, err
);
383 qmp_blockdev_insert_anon_medium(blk
, medium_bs
, &err
);
385 error_propagate(errp
, err
);
389 qmp_blockdev_close_tray(device
, id
, errp
);
392 /* If the medium has been inserted, the device has its own reference, so
393 * ours must be relinquished; and if it has not been inserted successfully,
394 * the reference must be relinquished anyway */
395 bdrv_unref(medium_bs
);
398 void qmp_eject(const char *device
, const char *id
,
399 bool has_force
, bool force
, Error
**errp
)
401 Error
*local_err
= NULL
;
408 rc
= do_open_tray(device
, id
, force
, &local_err
);
409 if (rc
&& rc
!= -ENOSYS
) {
410 error_propagate(errp
, local_err
);
413 error_free(local_err
);
415 blockdev_remove_medium(device
, id
, errp
);
418 /* throttling disk I/O limits */
419 void qmp_block_set_io_throttle(BlockIOThrottle
*arg
, Error
**errp
)
422 BlockDriverState
*bs
;
424 AioContext
*aio_context
;
426 blk
= qmp_get_blk(arg
->device
, arg
->id
, errp
);
431 aio_context
= blk_get_aio_context(blk
);
432 aio_context_acquire(aio_context
);
436 error_setg(errp
, "Device has no medium");
440 throttle_config_init(&cfg
);
441 cfg
.buckets
[THROTTLE_BPS_TOTAL
].avg
= arg
->bps
;
442 cfg
.buckets
[THROTTLE_BPS_READ
].avg
= arg
->bps_rd
;
443 cfg
.buckets
[THROTTLE_BPS_WRITE
].avg
= arg
->bps_wr
;
445 cfg
.buckets
[THROTTLE_OPS_TOTAL
].avg
= arg
->iops
;
446 cfg
.buckets
[THROTTLE_OPS_READ
].avg
= arg
->iops_rd
;
447 cfg
.buckets
[THROTTLE_OPS_WRITE
].avg
= arg
->iops_wr
;
449 if (arg
->has_bps_max
) {
450 cfg
.buckets
[THROTTLE_BPS_TOTAL
].max
= arg
->bps_max
;
452 if (arg
->has_bps_rd_max
) {
453 cfg
.buckets
[THROTTLE_BPS_READ
].max
= arg
->bps_rd_max
;
455 if (arg
->has_bps_wr_max
) {
456 cfg
.buckets
[THROTTLE_BPS_WRITE
].max
= arg
->bps_wr_max
;
458 if (arg
->has_iops_max
) {
459 cfg
.buckets
[THROTTLE_OPS_TOTAL
].max
= arg
->iops_max
;
461 if (arg
->has_iops_rd_max
) {
462 cfg
.buckets
[THROTTLE_OPS_READ
].max
= arg
->iops_rd_max
;
464 if (arg
->has_iops_wr_max
) {
465 cfg
.buckets
[THROTTLE_OPS_WRITE
].max
= arg
->iops_wr_max
;
468 if (arg
->has_bps_max_length
) {
469 cfg
.buckets
[THROTTLE_BPS_TOTAL
].burst_length
= arg
->bps_max_length
;
471 if (arg
->has_bps_rd_max_length
) {
472 cfg
.buckets
[THROTTLE_BPS_READ
].burst_length
= arg
->bps_rd_max_length
;
474 if (arg
->has_bps_wr_max_length
) {
475 cfg
.buckets
[THROTTLE_BPS_WRITE
].burst_length
= arg
->bps_wr_max_length
;
477 if (arg
->has_iops_max_length
) {
478 cfg
.buckets
[THROTTLE_OPS_TOTAL
].burst_length
= arg
->iops_max_length
;
480 if (arg
->has_iops_rd_max_length
) {
481 cfg
.buckets
[THROTTLE_OPS_READ
].burst_length
= arg
->iops_rd_max_length
;
483 if (arg
->has_iops_wr_max_length
) {
484 cfg
.buckets
[THROTTLE_OPS_WRITE
].burst_length
= arg
->iops_wr_max_length
;
487 if (arg
->has_iops_size
) {
488 cfg
.op_size
= arg
->iops_size
;
491 if (!throttle_is_valid(&cfg
, errp
)) {
495 if (throttle_enabled(&cfg
)) {
496 /* Enable I/O limits if they're not enabled yet, otherwise
497 * just update the throttling group. */
498 if (!blk_get_public(blk
)->throttle_group_member
.throttle_state
) {
499 blk_io_limits_enable(blk
, arg
->group
?: arg
->device
?: arg
->id
);
500 } else if (arg
->group
) {
501 blk_io_limits_update_group(blk
, arg
->group
);
503 /* Set the new throttling configuration */
504 blk_set_io_limits(blk
, &cfg
);
505 } else if (blk_get_public(blk
)->throttle_group_member
.throttle_state
) {
506 /* If all throttling settings are set to 0, disable I/O limits */
507 blk_io_limits_disable(blk
);
511 aio_context_release(aio_context
);
514 void qmp_block_latency_histogram_set(
516 bool has_boundaries
, uint64List
*boundaries
,
517 bool has_boundaries_read
, uint64List
*boundaries_read
,
518 bool has_boundaries_write
, uint64List
*boundaries_write
,
519 bool has_boundaries_flush
, uint64List
*boundaries_flush
,
522 BlockBackend
*blk
= qmp_get_blk(NULL
, id
, errp
);
523 BlockAcctStats
*stats
;
530 stats
= blk_get_stats(blk
);
532 if (!has_boundaries
&& !has_boundaries_read
&& !has_boundaries_write
&&
533 !has_boundaries_flush
)
535 block_latency_histograms_clear(stats
);
539 if (has_boundaries
|| has_boundaries_read
) {
540 ret
= block_latency_histogram_set(
541 stats
, BLOCK_ACCT_READ
,
542 has_boundaries_read
? boundaries_read
: boundaries
);
544 error_setg(errp
, "Device '%s' set read boundaries fail", id
);
549 if (has_boundaries
|| has_boundaries_write
) {
550 ret
= block_latency_histogram_set(
551 stats
, BLOCK_ACCT_WRITE
,
552 has_boundaries_write
? boundaries_write
: boundaries
);
554 error_setg(errp
, "Device '%s' set write boundaries fail", id
);
559 if (has_boundaries
|| has_boundaries_flush
) {
560 ret
= block_latency_histogram_set(
561 stats
, BLOCK_ACCT_FLUSH
,
562 has_boundaries_flush
? boundaries_flush
: boundaries
);
564 error_setg(errp
, "Device '%s' set flush boundaries fail", id
);