tcg: Reorg function calls
[qemu/armbru.git] / block / qapi-sysemu.c
blob0c7a1423debd88c0a3eb42c274e896602c0cc189
1 /*
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
10 * permission notice:
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
30 * THE SOFTWARE.
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,
42 Error **errp)
44 BlockBackend *blk;
46 if (!blk_name == !qdev_id) {
47 error_setg(errp, "Need exactly one of 'device' and 'id'");
48 return NULL;
51 if (qdev_id) {
52 blk = blk_by_qdev_id(qdev_id, errp);
53 } else {
54 blk = blk_by_name(blk_name);
55 if (blk == NULL) {
56 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
57 "Device '%s' not found", blk_name);
61 return blk;
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.
73 * Else, return 0.
75 static int do_open_tray(const char *blk_name, const char *qdev_id,
76 bool force, Error **errp)
78 BlockBackend *blk;
79 const char *device = qdev_id ?: blk_name;
80 bool locked;
82 blk = qmp_get_blk(blk_name, qdev_id, errp);
83 if (!blk) {
84 return -ENODEV;
87 if (!blk_dev_has_removable_media(blk)) {
88 error_setg(errp, "Device '%s' is not removable", device);
89 return -ENOTSUP;
92 if (!blk_dev_has_tray(blk)) {
93 error_setg(errp, "Device '%s' does not have a tray", device);
94 return -ENOSYS;
97 if (blk_dev_is_tray_open(blk)) {
98 return 0;
101 locked = blk_dev_is_medium_locked(blk);
102 if (locked) {
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);
113 return -EINPROGRESS;
116 return 0;
119 void qmp_blockdev_open_tray(const char *device,
120 const char *id,
121 bool has_force, bool force,
122 Error **errp)
124 Error *local_err = NULL;
125 int rc;
127 if (!has_force) {
128 force = false;
130 rc = do_open_tray(device, id, force, &local_err);
131 if (rc && rc != -ENOSYS && rc != -EINPROGRESS) {
132 error_propagate(errp, local_err);
133 return;
135 error_free(local_err);
138 void qmp_blockdev_close_tray(const char *device,
139 const char *id,
140 Error **errp)
142 BlockBackend *blk;
143 Error *local_err = NULL;
145 blk = qmp_get_blk(device, id, errp);
146 if (!blk) {
147 return;
150 if (!blk_dev_has_removable_media(blk)) {
151 error_setg(errp, "Device '%s' is not removable", device ?: id);
152 return;
155 if (!blk_dev_has_tray(blk)) {
156 /* Ignore this command on tray-less devices */
157 return;
160 if (!blk_dev_is_tray_open(blk)) {
161 return;
164 blk_dev_change_media_cb(blk, true, &local_err);
165 if (local_err) {
166 error_propagate(errp, local_err);
167 return;
171 static void blockdev_remove_medium(const char *device, const char *id,
172 Error **errp)
174 BlockBackend *blk;
175 BlockDriverState *bs;
176 AioContext *aio_context;
177 bool has_attached_device;
179 blk = qmp_get_blk(device, id, errp);
180 if (!blk) {
181 return;
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);
189 return;
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);
196 return;
199 bs = blk_bs(blk);
200 if (!bs) {
201 return;
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)) {
208 goto out;
211 blk_remove_bs(blk);
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);
221 out:
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;
234 bool has_device;
235 int ret;
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");
242 return;
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");
247 return;
250 if (blk_bs(blk)) {
251 error_setg(errp, "There already is a medium in the device");
252 return;
255 ret = blk_insert_bs(blk, bs, errp);
256 if (ret < 0) {
257 return;
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
263 * slot here.
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);
267 if (local_err) {
268 error_propagate(errp, local_err);
269 blk_remove_bs(blk);
270 return;
275 static void blockdev_insert_medium(const char *device, const char *id,
276 const char *node_name, Error **errp)
278 BlockBackend *blk;
279 BlockDriverState *bs;
281 blk = qmp_get_blk(device, id, errp);
282 if (!blk) {
283 return;
286 bs = bdrv_find_node(node_name);
287 if (!bs) {
288 error_setg(errp, "Node '%s' not found", node_name);
289 return;
292 if (bdrv_has_blk(bs)) {
293 error_setg(errp, "Node '%s' is already in use", node_name);
294 return;
297 qmp_blockdev_insert_anon_medium(blk, bs, errp);
300 void qmp_blockdev_insert_medium(const char *id, const char *node_name,
301 Error **errp)
303 blockdev_insert_medium(NULL, id, node_name, errp);
306 void qmp_blockdev_change_medium(const char *device,
307 const char *id,
308 const char *filename,
309 const char *format,
310 bool has_force, bool force,
311 bool has_read_only,
312 BlockdevChangeReadOnlyMode read_only,
313 Error **errp)
315 BlockBackend *blk;
316 BlockDriverState *medium_bs = NULL;
317 int bdrv_flags;
318 bool detect_zeroes;
319 int rc;
320 QDict *options = NULL;
321 Error *err = NULL;
323 blk = qmp_get_blk(device, id, errp);
324 if (!blk) {
325 goto fail;
328 if (blk_bs(blk)) {
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;
340 switch (read_only) {
341 case BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN:
342 break;
344 case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_ONLY:
345 bdrv_flags &= ~BDRV_O_RDWR;
346 break;
348 case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_WRITE:
349 bdrv_flags |= BDRV_O_RDWR;
350 break;
352 default:
353 abort();
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");
360 if (format) {
361 qdict_put_str(options, "driver", format);
364 medium_bs = bdrv_open(filename, NULL, options, bdrv_flags, errp);
365 if (!medium_bs) {
366 goto fail;
369 rc = do_open_tray(device, id, force, &err);
370 if (rc && rc != -ENOSYS) {
371 error_propagate(errp, err);
372 goto fail;
374 error_free(err);
375 err = NULL;
377 blockdev_remove_medium(device, id, &err);
378 if (err) {
379 error_propagate(errp, err);
380 goto fail;
383 qmp_blockdev_insert_anon_medium(blk, medium_bs, &err);
384 if (err) {
385 error_propagate(errp, err);
386 goto fail;
389 qmp_blockdev_close_tray(device, id, errp);
391 fail:
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;
402 int rc;
404 if (!has_force) {
405 force = false;
408 rc = do_open_tray(device, id, force, &local_err);
409 if (rc && rc != -ENOSYS) {
410 error_propagate(errp, local_err);
411 return;
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)
421 ThrottleConfig cfg;
422 BlockDriverState *bs;
423 BlockBackend *blk;
424 AioContext *aio_context;
426 blk = qmp_get_blk(arg->device, arg->id, errp);
427 if (!blk) {
428 return;
431 aio_context = blk_get_aio_context(blk);
432 aio_context_acquire(aio_context);
434 bs = blk_bs(blk);
435 if (!bs) {
436 error_setg(errp, "Device has no medium");
437 goto out;
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)) {
492 goto out;
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);
510 out:
511 aio_context_release(aio_context);
514 void qmp_block_latency_histogram_set(
515 const char *id,
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,
520 Error **errp)
522 BlockBackend *blk = qmp_get_blk(NULL, id, errp);
523 BlockAcctStats *stats;
524 int ret;
526 if (!blk) {
527 return;
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);
536 return;
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);
543 if (ret) {
544 error_setg(errp, "Device '%s' set read boundaries fail", id);
545 return;
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);
553 if (ret) {
554 error_setg(errp, "Device '%s' set write boundaries fail", id);
555 return;
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);
563 if (ret) {
564 error_setg(errp, "Device '%s' set flush boundaries fail", id);
565 return;