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 "block/block_int.h"
36
#include "qapi/error.h"
37
#include "qapi/qapi-commands-block.h"
38
#include "qapi/qmp/qdict.h"
39
#include "sysemu/block-backend.h"
40
#include "sysemu/blockdev.h"
42
static BlockBackend *qmp_get_blk(const char *blk_name, const char *qdev_id,
47
if (!blk_name == !qdev_id) {
48
error_setg(errp, "Need exactly one of 'device' and 'id'");
53
blk = blk_by_qdev_id(qdev_id, errp);
55
blk = blk_by_name(blk_name);
57
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
58
"Device '%s' not found", blk_name);
66
* Attempt to open the tray of @device.
67
* If @force, ignore its tray lock.
68
* Else, if the tray is locked, don't open it, but ask the guest to open it.
69
* On error, store an error through @errp and return -errno.
70
* If @device does not exist, return -ENODEV.
71
* If it has no removable media, return -ENOTSUP.
72
* If it has no tray, return -ENOSYS.
73
* If the guest was asked to open the tray, return -EINPROGRESS.
76
static int do_open_tray(const char *blk_name, const char *qdev_id,
77
bool force, Error **errp)
80
const char *device = qdev_id ?: blk_name;
83
blk = qmp_get_blk(blk_name, qdev_id, errp);
88
if (!blk_dev_has_removable_media(blk)) {
89
error_setg(errp, "Device '%s' is not removable", device);
93
if (!blk_dev_has_tray(blk)) {
94
error_setg(errp, "Device '%s' does not have a tray", device);
98
if (blk_dev_is_tray_open(blk)) {
102
locked = blk_dev_is_medium_locked(blk);
104
blk_dev_eject_request(blk, force);
107
if (!locked || force) {
108
blk_dev_change_media_cb(blk, false, &error_abort);
111
if (locked && !force) {
112
error_setg(errp, "Device '%s' is locked and force was not specified, "
113
"wait for tray to open and try again", device);
120
void qmp_blockdev_open_tray(const char *device,
122
bool has_force, bool force,
125
Error *local_err = NULL;
131
rc = do_open_tray(device, id, force, &local_err);
132
if (rc && rc != -ENOSYS && rc != -EINPROGRESS) {
133
error_propagate(errp, local_err);
136
error_free(local_err);
139
void qmp_blockdev_close_tray(const char *device,
144
Error *local_err = NULL;
146
blk = qmp_get_blk(device, id, errp);
151
if (!blk_dev_has_removable_media(blk)) {
152
error_setg(errp, "Device '%s' is not removable", device ?: id);
156
if (!blk_dev_has_tray(blk)) {
157
/* Ignore this command on tray-less devices */
161
if (!blk_dev_is_tray_open(blk)) {
165
blk_dev_change_media_cb(blk, true, &local_err);
167
error_propagate(errp, local_err);
172
static void GRAPH_UNLOCKED
173
blockdev_remove_medium(const char *device, const char *id, Error **errp)
176
BlockDriverState *bs;
177
bool has_attached_device;
181
blk = qmp_get_blk(device, id, errp);
186
/* For BBs without a device, we can exchange the BDS tree at will */
187
has_attached_device = blk_get_attached_dev(blk);
189
if (has_attached_device && !blk_dev_has_removable_media(blk)) {
190
error_setg(errp, "Device '%s' is not removable", device ?: id);
194
if (has_attached_device && blk_dev_has_tray(blk) &&
195
!blk_dev_is_tray_open(blk))
197
error_setg(errp, "Tray of device '%s' is not open", device ?: id);
206
bdrv_graph_rdlock_main_loop();
207
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
208
bdrv_graph_rdunlock_main_loop();
211
bdrv_graph_rdunlock_main_loop();
215
if (!blk_dev_has_tray(blk)) {
216
/* For tray-less devices, blockdev-open-tray is a no-op (or may not be
217
* called at all); therefore, the medium needs to be ejected here.
218
* Do it after blk_remove_bs() so blk_is_inserted(blk) returns the @load
219
* value passed here (i.e. false). */
220
blk_dev_change_media_cb(blk, false, &error_abort);
224
void qmp_blockdev_remove_medium(const char *id, Error **errp)
226
blockdev_remove_medium(NULL, id, errp);
229
static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
230
BlockDriverState *bs, Error **errp)
232
Error *local_err = NULL;
236
/* For BBs without a device, we can exchange the BDS tree at will */
237
has_device = blk_get_attached_dev(blk);
239
if (has_device && !blk_dev_has_removable_media(blk)) {
240
error_setg(errp, "Device is not removable");
244
if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) {
245
error_setg(errp, "Tray of the device is not open");
250
error_setg(errp, "There already is a medium in the device");
254
ret = blk_insert_bs(blk, bs, errp);
259
if (!blk_dev_has_tray(blk)) {
260
/* For tray-less devices, blockdev-close-tray is a no-op (or may not be
261
* called at all); therefore, the medium needs to be pushed into the
263
* Do it after blk_insert_bs() so blk_is_inserted(blk) returns the @load
264
* value passed here (i.e. true). */
265
blk_dev_change_media_cb(blk, true, &local_err);
267
error_propagate(errp, local_err);
274
static void blockdev_insert_medium(const char *device, const char *id,
275
const char *node_name, Error **errp)
278
BlockDriverState *bs;
280
GRAPH_RDLOCK_GUARD_MAINLOOP();
282
blk = qmp_get_blk(device, id, errp);
287
bs = bdrv_find_node(node_name);
289
error_setg(errp, "Node '%s' not found", node_name);
293
if (bdrv_has_blk(bs)) {
294
error_setg(errp, "Node '%s' is already in use", node_name);
298
qmp_blockdev_insert_anon_medium(blk, bs, errp);
301
void qmp_blockdev_insert_medium(const char *id, const char *node_name,
304
blockdev_insert_medium(NULL, id, node_name, errp);
307
void qmp_blockdev_change_medium(const char *device,
309
const char *filename,
311
bool has_force, bool force,
313
BlockdevChangeReadOnlyMode read_only,
317
BlockDriverState *medium_bs = NULL;
321
QDict *options = NULL;
324
blk = qmp_get_blk(device, id, errp);
330
blk_update_root_state(blk);
333
bdrv_flags = blk_get_open_flags_from_root_state(blk);
334
bdrv_flags &= ~(BDRV_O_TEMPORARY | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING |
335
BDRV_O_PROTOCOL | BDRV_O_AUTO_RDONLY);
337
if (!has_read_only) {
338
read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN;
342
case BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN:
345
case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_ONLY:
346
bdrv_flags &= ~BDRV_O_RDWR;
349
case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_WRITE:
350
bdrv_flags |= BDRV_O_RDWR;
357
options = qdict_new();
358
detect_zeroes = blk_get_detect_zeroes_from_root_state(blk);
359
qdict_put_str(options, "detect-zeroes", detect_zeroes ? "on" : "off");
362
qdict_put_str(options, "driver", format);
365
medium_bs = bdrv_open(filename, NULL, options, bdrv_flags, errp);
371
rc = do_open_tray(device, id, force, &err);
372
if (rc && rc != -ENOSYS) {
373
error_propagate(errp, err);
379
blockdev_remove_medium(device, id, &err);
381
error_propagate(errp, err);
385
qmp_blockdev_insert_anon_medium(blk, medium_bs, &err);
387
error_propagate(errp, err);
391
qmp_blockdev_close_tray(device, id, errp);
394
/* If the medium has been inserted, the device has its own reference, so
395
* ours must be relinquished; and if it has not been inserted successfully,
396
* the reference must be relinquished anyway */
397
bdrv_unref(medium_bs);
400
void qmp_eject(const char *device, const char *id,
401
bool has_force, bool force, Error **errp)
403
Error *local_err = NULL;
410
rc = do_open_tray(device, id, force, &local_err);
411
if (rc && rc != -ENOSYS) {
412
error_propagate(errp, local_err);
415
error_free(local_err);
417
blockdev_remove_medium(device, id, errp);
420
/* throttling disk I/O limits */
421
void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp)
424
BlockDriverState *bs;
427
blk = qmp_get_blk(arg->device, arg->id, errp);
434
error_setg(errp, "Device has no medium");
438
throttle_config_init(&cfg);
439
cfg.buckets[THROTTLE_BPS_TOTAL].avg = arg->bps;
440
cfg.buckets[THROTTLE_BPS_READ].avg = arg->bps_rd;
441
cfg.buckets[THROTTLE_BPS_WRITE].avg = arg->bps_wr;
443
cfg.buckets[THROTTLE_OPS_TOTAL].avg = arg->iops;
444
cfg.buckets[THROTTLE_OPS_READ].avg = arg->iops_rd;
445
cfg.buckets[THROTTLE_OPS_WRITE].avg = arg->iops_wr;
447
if (arg->has_bps_max) {
448
cfg.buckets[THROTTLE_BPS_TOTAL].max = arg->bps_max;
450
if (arg->has_bps_rd_max) {
451
cfg.buckets[THROTTLE_BPS_READ].max = arg->bps_rd_max;
453
if (arg->has_bps_wr_max) {
454
cfg.buckets[THROTTLE_BPS_WRITE].max = arg->bps_wr_max;
456
if (arg->has_iops_max) {
457
cfg.buckets[THROTTLE_OPS_TOTAL].max = arg->iops_max;
459
if (arg->has_iops_rd_max) {
460
cfg.buckets[THROTTLE_OPS_READ].max = arg->iops_rd_max;
462
if (arg->has_iops_wr_max) {
463
cfg.buckets[THROTTLE_OPS_WRITE].max = arg->iops_wr_max;
466
if (arg->has_bps_max_length) {
467
cfg.buckets[THROTTLE_BPS_TOTAL].burst_length = arg->bps_max_length;
469
if (arg->has_bps_rd_max_length) {
470
cfg.buckets[THROTTLE_BPS_READ].burst_length = arg->bps_rd_max_length;
472
if (arg->has_bps_wr_max_length) {
473
cfg.buckets[THROTTLE_BPS_WRITE].burst_length = arg->bps_wr_max_length;
475
if (arg->has_iops_max_length) {
476
cfg.buckets[THROTTLE_OPS_TOTAL].burst_length = arg->iops_max_length;
478
if (arg->has_iops_rd_max_length) {
479
cfg.buckets[THROTTLE_OPS_READ].burst_length = arg->iops_rd_max_length;
481
if (arg->has_iops_wr_max_length) {
482
cfg.buckets[THROTTLE_OPS_WRITE].burst_length = arg->iops_wr_max_length;
485
if (arg->has_iops_size) {
486
cfg.op_size = arg->iops_size;
489
if (!throttle_is_valid(&cfg, errp)) {
493
if (throttle_enabled(&cfg)) {
494
/* Enable I/O limits if they're not enabled yet, otherwise
495
* just update the throttling group. */
496
if (!blk_get_public(blk)->throttle_group_member.throttle_state) {
497
blk_io_limits_enable(blk, arg->group ?: arg->device ?: arg->id);
498
} else if (arg->group) {
499
blk_io_limits_update_group(blk, arg->group);
501
/* Set the new throttling configuration */
502
blk_set_io_limits(blk, &cfg);
503
} else if (blk_get_public(blk)->throttle_group_member.throttle_state) {
504
/* If all throttling settings are set to 0, disable I/O limits */
505
blk_io_limits_disable(blk);
509
void qmp_block_latency_histogram_set(
511
bool has_boundaries, uint64List *boundaries,
512
bool has_boundaries_read, uint64List *boundaries_read,
513
bool has_boundaries_write, uint64List *boundaries_write,
514
bool has_boundaries_append, uint64List *boundaries_append,
515
bool has_boundaries_flush, uint64List *boundaries_flush,
518
BlockBackend *blk = qmp_get_blk(NULL, id, errp);
519
BlockAcctStats *stats;
526
stats = blk_get_stats(blk);
528
if (!has_boundaries && !has_boundaries_read && !has_boundaries_write &&
529
!has_boundaries_flush)
531
block_latency_histograms_clear(stats);
535
if (has_boundaries || has_boundaries_read) {
536
ret = block_latency_histogram_set(
537
stats, BLOCK_ACCT_READ,
538
has_boundaries_read ? boundaries_read : boundaries);
540
error_setg(errp, "Device '%s' set read boundaries fail", id);
545
if (has_boundaries || has_boundaries_write) {
546
ret = block_latency_histogram_set(
547
stats, BLOCK_ACCT_WRITE,
548
has_boundaries_write ? boundaries_write : boundaries);
550
error_setg(errp, "Device '%s' set write boundaries fail", id);
555
if (has_boundaries || has_boundaries_append) {
556
ret = block_latency_histogram_set(
557
stats, BLOCK_ACCT_ZONE_APPEND,
558
has_boundaries_append ? boundaries_append : boundaries);
560
error_setg(errp, "Device '%s' set append write boundaries fail", id);
565
if (has_boundaries || has_boundaries_flush) {
566
ret = block_latency_histogram_set(
567
stats, BLOCK_ACCT_FLUSH,
568
has_boundaries_flush ? boundaries_flush : boundaries);
570
error_setg(errp, "Device '%s' set flush boundaries fail", id);