blob: e4282631d23deb3f7f780746ac2c42f52cbeed31 [file] [log] [blame]
Kevin Wolf12c929b2020-02-24 15:29:51 +01001/*
2 * QMP command handlers specific to the system emulators
3 *
4 * Copyright (c) 2003-2008 Fabrice Bellard
5 *
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.
8 *
9 * This file incorporates work covered by the following copyright and
10 * permission notice:
11 *
12 * Copyright (c) 2003-2008 Fabrice Bellard
13 *
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:
20 *
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
23 *
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
30 * THE SOFTWARE.
31 */
32
33#include "qemu/osdep.h"
34
Markus Armbrustere2c1c342022-12-21 14:35:49 +010035#include "block/block_int.h"
Kevin Wolf12c929b2020-02-24 15:29:51 +010036#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"
41
42static BlockBackend *qmp_get_blk(const char *blk_name, const char *qdev_id,
43 Error **errp)
44{
45 BlockBackend *blk;
46
47 if (!blk_name == !qdev_id) {
48 error_setg(errp, "Need exactly one of 'device' and 'id'");
49 return NULL;
50 }
51
52 if (qdev_id) {
53 blk = blk_by_qdev_id(qdev_id, errp);
54 } else {
55 blk = blk_by_name(blk_name);
56 if (blk == NULL) {
57 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
58 "Device '%s' not found", blk_name);
59 }
60 }
61
62 return blk;
63}
64
65/*
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.
74 * Else, return 0.
75 */
76static int do_open_tray(const char *blk_name, const char *qdev_id,
77 bool force, Error **errp)
78{
79 BlockBackend *blk;
80 const char *device = qdev_id ?: blk_name;
81 bool locked;
82
83 blk = qmp_get_blk(blk_name, qdev_id, errp);
84 if (!blk) {
85 return -ENODEV;
86 }
87
88 if (!blk_dev_has_removable_media(blk)) {
89 error_setg(errp, "Device '%s' is not removable", device);
90 return -ENOTSUP;
91 }
92
93 if (!blk_dev_has_tray(blk)) {
94 error_setg(errp, "Device '%s' does not have a tray", device);
95 return -ENOSYS;
96 }
97
98 if (blk_dev_is_tray_open(blk)) {
99 return 0;
100 }
101
102 locked = blk_dev_is_medium_locked(blk);
103 if (locked) {
104 blk_dev_eject_request(blk, force);
105 }
106
107 if (!locked || force) {
108 blk_dev_change_media_cb(blk, false, &error_abort);
109 }
110
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);
114 return -EINPROGRESS;
115 }
116
117 return 0;
118}
119
Markus Armbruster54fde4f2022-11-04 17:06:52 +0100120void qmp_blockdev_open_tray(const char *device,
121 const char *id,
Kevin Wolf12c929b2020-02-24 15:29:51 +0100122 bool has_force, bool force,
123 Error **errp)
124{
125 Error *local_err = NULL;
126 int rc;
127
128 if (!has_force) {
129 force = false;
130 }
Markus Armbruster54fde4f2022-11-04 17:06:52 +0100131 rc = do_open_tray(device, id, force, &local_err);
Kevin Wolf12c929b2020-02-24 15:29:51 +0100132 if (rc && rc != -ENOSYS && rc != -EINPROGRESS) {
133 error_propagate(errp, local_err);
134 return;
135 }
136 error_free(local_err);
137}
138
Markus Armbruster54fde4f2022-11-04 17:06:52 +0100139void qmp_blockdev_close_tray(const char *device,
140 const char *id,
Kevin Wolf12c929b2020-02-24 15:29:51 +0100141 Error **errp)
142{
143 BlockBackend *blk;
144 Error *local_err = NULL;
145
Kevin Wolf12c929b2020-02-24 15:29:51 +0100146 blk = qmp_get_blk(device, id, errp);
147 if (!blk) {
148 return;
149 }
150
151 if (!blk_dev_has_removable_media(blk)) {
152 error_setg(errp, "Device '%s' is not removable", device ?: id);
153 return;
154 }
155
156 if (!blk_dev_has_tray(blk)) {
157 /* Ignore this command on tray-less devices */
158 return;
159 }
160
161 if (!blk_dev_is_tray_open(blk)) {
162 return;
163 }
164
165 blk_dev_change_media_cb(blk, true, &local_err);
166 if (local_err) {
167 error_propagate(errp, local_err);
168 return;
169 }
170}
171
Kevin Wolf277f2002023-09-29 16:51:52 +0200172static void GRAPH_UNLOCKED
173blockdev_remove_medium(const char *device, const char *id, Error **errp)
Kevin Wolf12c929b2020-02-24 15:29:51 +0100174{
175 BlockBackend *blk;
176 BlockDriverState *bs;
Kevin Wolf12c929b2020-02-24 15:29:51 +0100177 bool has_attached_device;
178
Kevin Wolf277f2002023-09-29 16:51:52 +0200179 GLOBAL_STATE_CODE();
180
Kevin Wolf12c929b2020-02-24 15:29:51 +0100181 blk = qmp_get_blk(device, id, errp);
182 if (!blk) {
183 return;
184 }
185
186 /* For BBs without a device, we can exchange the BDS tree at will */
187 has_attached_device = blk_get_attached_dev(blk);
188
189 if (has_attached_device && !blk_dev_has_removable_media(blk)) {
190 error_setg(errp, "Device '%s' is not removable", device ?: id);
191 return;
192 }
193
194 if (has_attached_device && blk_dev_has_tray(blk) &&
195 !blk_dev_is_tray_open(blk))
196 {
197 error_setg(errp, "Tray of device '%s' is not open", device ?: id);
198 return;
199 }
200
201 bs = blk_bs(blk);
202 if (!bs) {
203 return;
204 }
205
Kevin Wolf277f2002023-09-29 16:51:52 +0200206 bdrv_graph_rdlock_main_loop();
Kevin Wolf12c929b2020-02-24 15:29:51 +0100207 if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
Kevin Wolf277f2002023-09-29 16:51:52 +0200208 bdrv_graph_rdunlock_main_loop();
Stefan Hajnoczib49f4752023-12-05 13:20:03 -0500209 return;
Kevin Wolf12c929b2020-02-24 15:29:51 +0100210 }
Kevin Wolf277f2002023-09-29 16:51:52 +0200211 bdrv_graph_rdunlock_main_loop();
Kevin Wolf12c929b2020-02-24 15:29:51 +0100212
213 blk_remove_bs(blk);
214
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);
221 }
Kevin Wolf12c929b2020-02-24 15:29:51 +0100222}
223
224void qmp_blockdev_remove_medium(const char *id, Error **errp)
225{
Markus Armbruster54fde4f2022-11-04 17:06:52 +0100226 blockdev_remove_medium(NULL, id, errp);
Kevin Wolf12c929b2020-02-24 15:29:51 +0100227}
228
229static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
230 BlockDriverState *bs, Error **errp)
231{
232 Error *local_err = NULL;
233 bool has_device;
234 int ret;
235
236 /* For BBs without a device, we can exchange the BDS tree at will */
237 has_device = blk_get_attached_dev(blk);
238
239 if (has_device && !blk_dev_has_removable_media(blk)) {
240 error_setg(errp, "Device is not removable");
241 return;
242 }
243
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");
246 return;
247 }
248
249 if (blk_bs(blk)) {
250 error_setg(errp, "There already is a medium in the device");
251 return;
252 }
253
254 ret = blk_insert_bs(blk, bs, errp);
255 if (ret < 0) {
256 return;
257 }
258
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
262 * slot here.
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);
266 if (local_err) {
267 error_propagate(errp, local_err);
268 blk_remove_bs(blk);
269 return;
270 }
271 }
272}
273
Markus Armbruster54fde4f2022-11-04 17:06:52 +0100274static void blockdev_insert_medium(const char *device, const char *id,
Kevin Wolf12c929b2020-02-24 15:29:51 +0100275 const char *node_name, Error **errp)
276{
277 BlockBackend *blk;
278 BlockDriverState *bs;
279
Kevin Wolf2b3912f2023-09-29 16:51:39 +0200280 GRAPH_RDLOCK_GUARD_MAINLOOP();
281
Markus Armbruster54fde4f2022-11-04 17:06:52 +0100282 blk = qmp_get_blk(device, id, errp);
Kevin Wolf12c929b2020-02-24 15:29:51 +0100283 if (!blk) {
284 return;
285 }
286
287 bs = bdrv_find_node(node_name);
288 if (!bs) {
289 error_setg(errp, "Node '%s' not found", node_name);
290 return;
291 }
292
293 if (bdrv_has_blk(bs)) {
294 error_setg(errp, "Node '%s' is already in use", node_name);
295 return;
296 }
297
298 qmp_blockdev_insert_anon_medium(blk, bs, errp);
299}
300
301void qmp_blockdev_insert_medium(const char *id, const char *node_name,
302 Error **errp)
303{
Markus Armbruster54fde4f2022-11-04 17:06:52 +0100304 blockdev_insert_medium(NULL, id, node_name, errp);
Kevin Wolf12c929b2020-02-24 15:29:51 +0100305}
306
Markus Armbruster54fde4f2022-11-04 17:06:52 +0100307void qmp_blockdev_change_medium(const char *device,
308 const char *id,
Kevin Wolf12c929b2020-02-24 15:29:51 +0100309 const char *filename,
Markus Armbruster54fde4f2022-11-04 17:06:52 +0100310 const char *format,
Denis V. Lunev80dd5af2022-04-13 01:18:46 +0300311 bool has_force, bool force,
Kevin Wolf12c929b2020-02-24 15:29:51 +0100312 bool has_read_only,
313 BlockdevChangeReadOnlyMode read_only,
314 Error **errp)
315{
316 BlockBackend *blk;
317 BlockDriverState *medium_bs = NULL;
318 int bdrv_flags;
319 bool detect_zeroes;
320 int rc;
321 QDict *options = NULL;
322 Error *err = NULL;
323
Markus Armbruster54fde4f2022-11-04 17:06:52 +0100324 blk = qmp_get_blk(device, id, errp);
Kevin Wolf12c929b2020-02-24 15:29:51 +0100325 if (!blk) {
326 goto fail;
327 }
328
329 if (blk_bs(blk)) {
330 blk_update_root_state(blk);
331 }
332
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);
336
337 if (!has_read_only) {
338 read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN;
339 }
340
341 switch (read_only) {
342 case BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN:
343 break;
344
345 case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_ONLY:
346 bdrv_flags &= ~BDRV_O_RDWR;
347 break;
348
349 case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_WRITE:
350 bdrv_flags |= BDRV_O_RDWR;
351 break;
352
353 default:
354 abort();
355 }
356
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");
360
Markus Armbruster54fde4f2022-11-04 17:06:52 +0100361 if (format) {
Kevin Wolf12c929b2020-02-24 15:29:51 +0100362 qdict_put_str(options, "driver", format);
363 }
364
365 medium_bs = bdrv_open(filename, NULL, options, bdrv_flags, errp);
Kevin Wolfc6e0a6d2023-05-25 14:47:04 +0200366
Kevin Wolf12c929b2020-02-24 15:29:51 +0100367 if (!medium_bs) {
368 goto fail;
369 }
370
Markus Armbruster54fde4f2022-11-04 17:06:52 +0100371 rc = do_open_tray(device, id, force, &err);
Kevin Wolf12c929b2020-02-24 15:29:51 +0100372 if (rc && rc != -ENOSYS) {
373 error_propagate(errp, err);
374 goto fail;
375 }
376 error_free(err);
377 err = NULL;
378
Markus Armbruster54fde4f2022-11-04 17:06:52 +0100379 blockdev_remove_medium(device, id, &err);
Kevin Wolf12c929b2020-02-24 15:29:51 +0100380 if (err) {
381 error_propagate(errp, err);
382 goto fail;
383 }
384
385 qmp_blockdev_insert_anon_medium(blk, medium_bs, &err);
386 if (err) {
387 error_propagate(errp, err);
388 goto fail;
389 }
390
Markus Armbruster54fde4f2022-11-04 17:06:52 +0100391 qmp_blockdev_close_tray(device, id, errp);
Kevin Wolf12c929b2020-02-24 15:29:51 +0100392
393fail:
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);
398}
399
Markus Armbruster54fde4f2022-11-04 17:06:52 +0100400void qmp_eject(const char *device, const char *id,
Kevin Wolf12c929b2020-02-24 15:29:51 +0100401 bool has_force, bool force, Error **errp)
402{
403 Error *local_err = NULL;
404 int rc;
405
406 if (!has_force) {
407 force = false;
408 }
409
Markus Armbruster54fde4f2022-11-04 17:06:52 +0100410 rc = do_open_tray(device, id, force, &local_err);
Kevin Wolf12c929b2020-02-24 15:29:51 +0100411 if (rc && rc != -ENOSYS) {
412 error_propagate(errp, local_err);
413 return;
414 }
415 error_free(local_err);
416
Markus Armbruster54fde4f2022-11-04 17:06:52 +0100417 blockdev_remove_medium(device, id, errp);
Kevin Wolf12c929b2020-02-24 15:29:51 +0100418}
419
420/* throttling disk I/O limits */
421void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp)
422{
423 ThrottleConfig cfg;
424 BlockDriverState *bs;
425 BlockBackend *blk;
Kevin Wolf12c929b2020-02-24 15:29:51 +0100426
Markus Armbruster54fde4f2022-11-04 17:06:52 +0100427 blk = qmp_get_blk(arg->device, arg->id, errp);
Kevin Wolf12c929b2020-02-24 15:29:51 +0100428 if (!blk) {
429 return;
430 }
431
Kevin Wolf12c929b2020-02-24 15:29:51 +0100432 bs = blk_bs(blk);
433 if (!bs) {
434 error_setg(errp, "Device has no medium");
Stefan Hajnoczib49f4752023-12-05 13:20:03 -0500435 return;
Kevin Wolf12c929b2020-02-24 15:29:51 +0100436 }
437
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;
442
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;
446
447 if (arg->has_bps_max) {
448 cfg.buckets[THROTTLE_BPS_TOTAL].max = arg->bps_max;
449 }
450 if (arg->has_bps_rd_max) {
451 cfg.buckets[THROTTLE_BPS_READ].max = arg->bps_rd_max;
452 }
453 if (arg->has_bps_wr_max) {
454 cfg.buckets[THROTTLE_BPS_WRITE].max = arg->bps_wr_max;
455 }
456 if (arg->has_iops_max) {
457 cfg.buckets[THROTTLE_OPS_TOTAL].max = arg->iops_max;
458 }
459 if (arg->has_iops_rd_max) {
460 cfg.buckets[THROTTLE_OPS_READ].max = arg->iops_rd_max;
461 }
462 if (arg->has_iops_wr_max) {
463 cfg.buckets[THROTTLE_OPS_WRITE].max = arg->iops_wr_max;
464 }
465
466 if (arg->has_bps_max_length) {
467 cfg.buckets[THROTTLE_BPS_TOTAL].burst_length = arg->bps_max_length;
468 }
469 if (arg->has_bps_rd_max_length) {
470 cfg.buckets[THROTTLE_BPS_READ].burst_length = arg->bps_rd_max_length;
471 }
472 if (arg->has_bps_wr_max_length) {
473 cfg.buckets[THROTTLE_BPS_WRITE].burst_length = arg->bps_wr_max_length;
474 }
475 if (arg->has_iops_max_length) {
476 cfg.buckets[THROTTLE_OPS_TOTAL].burst_length = arg->iops_max_length;
477 }
478 if (arg->has_iops_rd_max_length) {
479 cfg.buckets[THROTTLE_OPS_READ].burst_length = arg->iops_rd_max_length;
480 }
481 if (arg->has_iops_wr_max_length) {
482 cfg.buckets[THROTTLE_OPS_WRITE].burst_length = arg->iops_wr_max_length;
483 }
484
485 if (arg->has_iops_size) {
486 cfg.op_size = arg->iops_size;
487 }
488
489 if (!throttle_is_valid(&cfg, errp)) {
Stefan Hajnoczib49f4752023-12-05 13:20:03 -0500490 return;
Kevin Wolf12c929b2020-02-24 15:29:51 +0100491 }
492
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) {
Markus Armbruster54fde4f2022-11-04 17:06:52 +0100497 blk_io_limits_enable(blk, arg->group ?: arg->device ?: arg->id);
498 } else if (arg->group) {
Kevin Wolf12c929b2020-02-24 15:29:51 +0100499 blk_io_limits_update_group(blk, arg->group);
500 }
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);
506 }
Kevin Wolf12c929b2020-02-24 15:29:51 +0100507}
508
509void qmp_block_latency_histogram_set(
510 const char *id,
511 bool has_boundaries, uint64List *boundaries,
512 bool has_boundaries_read, uint64List *boundaries_read,
513 bool has_boundaries_write, uint64List *boundaries_write,
Sam Li52eb76f2023-05-08 13:19:14 +0800514 bool has_boundaries_append, uint64List *boundaries_append,
Kevin Wolf12c929b2020-02-24 15:29:51 +0100515 bool has_boundaries_flush, uint64List *boundaries_flush,
516 Error **errp)
517{
518 BlockBackend *blk = qmp_get_blk(NULL, id, errp);
519 BlockAcctStats *stats;
520 int ret;
521
522 if (!blk) {
523 return;
524 }
525
526 stats = blk_get_stats(blk);
527
528 if (!has_boundaries && !has_boundaries_read && !has_boundaries_write &&
529 !has_boundaries_flush)
530 {
531 block_latency_histograms_clear(stats);
532 return;
533 }
534
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);
539 if (ret) {
540 error_setg(errp, "Device '%s' set read boundaries fail", id);
541 return;
542 }
543 }
544
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);
549 if (ret) {
550 error_setg(errp, "Device '%s' set write boundaries fail", id);
551 return;
552 }
553 }
554
Sam Li52eb76f2023-05-08 13:19:14 +0800555 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);
559 if (ret) {
560 error_setg(errp, "Device '%s' set append write boundaries fail", id);
561 return;
562 }
563 }
564
Kevin Wolf12c929b2020-02-24 15:29:51 +0100565 if (has_boundaries || has_boundaries_flush) {
566 ret = block_latency_histogram_set(
567 stats, BLOCK_ACCT_FLUSH,
568 has_boundaries_flush ? boundaries_flush : boundaries);
569 if (ret) {
570 error_setg(errp, "Device '%s' set flush boundaries fail", id);
571 return;
572 }
573 }
574}