block: Mark bdrv_first_blk() and bdrv_is_root_node() GRAPH_RDLOCK
[qemu/kevin.git] / block / qapi-sysemu.c
blobe885a64c32f069c1d38450dd5751c584ded6dd71
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 "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,
43 Error **errp)
45 BlockBackend *blk;
47 if (!blk_name == !qdev_id) {
48 error_setg(errp, "Need exactly one of 'device' and 'id'");
49 return NULL;
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);
62 return blk;
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.
76 static int do_open_tray(const char *blk_name, const char *qdev_id,
77 bool force, Error **errp)
79 BlockBackend *blk;
80 const char *device = qdev_id ?: blk_name;
81 bool locked;
83 blk = qmp_get_blk(blk_name, qdev_id, errp);
84 if (!blk) {
85 return -ENODEV;
88 if (!blk_dev_has_removable_media(blk)) {
89 error_setg(errp, "Device '%s' is not removable", device);
90 return -ENOTSUP;
93 if (!blk_dev_has_tray(blk)) {
94 error_setg(errp, "Device '%s' does not have a tray", device);
95 return -ENOSYS;
98 if (blk_dev_is_tray_open(blk)) {
99 return 0;
102 locked = blk_dev_is_medium_locked(blk);
103 if (locked) {
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);
114 return -EINPROGRESS;
117 return 0;
120 void qmp_blockdev_open_tray(const char *device,
121 const char *id,
122 bool has_force, bool force,
123 Error **errp)
125 Error *local_err = NULL;
126 int rc;
128 if (!has_force) {
129 force = false;
131 rc = do_open_tray(device, id, force, &local_err);
132 if (rc && rc != -ENOSYS && rc != -EINPROGRESS) {
133 error_propagate(errp, local_err);
134 return;
136 error_free(local_err);
139 void qmp_blockdev_close_tray(const char *device,
140 const char *id,
141 Error **errp)
143 BlockBackend *blk;
144 Error *local_err = NULL;
146 blk = qmp_get_blk(device, id, errp);
147 if (!blk) {
148 return;
151 if (!blk_dev_has_removable_media(blk)) {
152 error_setg(errp, "Device '%s' is not removable", device ?: id);
153 return;
156 if (!blk_dev_has_tray(blk)) {
157 /* Ignore this command on tray-less devices */
158 return;
161 if (!blk_dev_is_tray_open(blk)) {
162 return;
165 blk_dev_change_media_cb(blk, true, &local_err);
166 if (local_err) {
167 error_propagate(errp, local_err);
168 return;
172 static void blockdev_remove_medium(const char *device, const char *id,
173 Error **errp)
175 BlockBackend *blk;
176 BlockDriverState *bs;
177 AioContext *aio_context;
178 bool has_attached_device;
180 blk = qmp_get_blk(device, id, errp);
181 if (!blk) {
182 return;
185 /* For BBs without a device, we can exchange the BDS tree at will */
186 has_attached_device = blk_get_attached_dev(blk);
188 if (has_attached_device && !blk_dev_has_removable_media(blk)) {
189 error_setg(errp, "Device '%s' is not removable", device ?: id);
190 return;
193 if (has_attached_device && blk_dev_has_tray(blk) &&
194 !blk_dev_is_tray_open(blk))
196 error_setg(errp, "Tray of device '%s' is not open", device ?: id);
197 return;
200 bs = blk_bs(blk);
201 if (!bs) {
202 return;
205 aio_context = bdrv_get_aio_context(bs);
206 aio_context_acquire(aio_context);
208 if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
209 goto out;
212 blk_remove_bs(blk);
214 if (!blk_dev_has_tray(blk)) {
215 /* For tray-less devices, blockdev-open-tray is a no-op (or may not be
216 * called at all); therefore, the medium needs to be ejected here.
217 * Do it after blk_remove_bs() so blk_is_inserted(blk) returns the @load
218 * value passed here (i.e. false). */
219 blk_dev_change_media_cb(blk, false, &error_abort);
222 out:
223 aio_context_release(aio_context);
226 void qmp_blockdev_remove_medium(const char *id, Error **errp)
228 blockdev_remove_medium(NULL, id, errp);
231 static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
232 BlockDriverState *bs, Error **errp)
234 Error *local_err = NULL;
235 bool has_device;
236 int ret;
238 /* For BBs without a device, we can exchange the BDS tree at will */
239 has_device = blk_get_attached_dev(blk);
241 if (has_device && !blk_dev_has_removable_media(blk)) {
242 error_setg(errp, "Device is not removable");
243 return;
246 if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) {
247 error_setg(errp, "Tray of the device is not open");
248 return;
251 if (blk_bs(blk)) {
252 error_setg(errp, "There already is a medium in the device");
253 return;
256 ret = blk_insert_bs(blk, bs, errp);
257 if (ret < 0) {
258 return;
261 if (!blk_dev_has_tray(blk)) {
262 /* For tray-less devices, blockdev-close-tray is a no-op (or may not be
263 * called at all); therefore, the medium needs to be pushed into the
264 * slot here.
265 * Do it after blk_insert_bs() so blk_is_inserted(blk) returns the @load
266 * value passed here (i.e. true). */
267 blk_dev_change_media_cb(blk, true, &local_err);
268 if (local_err) {
269 error_propagate(errp, local_err);
270 blk_remove_bs(blk);
271 return;
276 static void blockdev_insert_medium(const char *device, const char *id,
277 const char *node_name, Error **errp)
279 BlockBackend *blk;
280 BlockDriverState *bs;
282 GRAPH_RDLOCK_GUARD_MAINLOOP();
284 blk = qmp_get_blk(device, id, errp);
285 if (!blk) {
286 return;
289 bs = bdrv_find_node(node_name);
290 if (!bs) {
291 error_setg(errp, "Node '%s' not found", node_name);
292 return;
295 if (bdrv_has_blk(bs)) {
296 error_setg(errp, "Node '%s' is already in use", node_name);
297 return;
300 qmp_blockdev_insert_anon_medium(blk, bs, errp);
303 void qmp_blockdev_insert_medium(const char *id, const char *node_name,
304 Error **errp)
306 blockdev_insert_medium(NULL, id, node_name, errp);
309 void qmp_blockdev_change_medium(const char *device,
310 const char *id,
311 const char *filename,
312 const char *format,
313 bool has_force, bool force,
314 bool has_read_only,
315 BlockdevChangeReadOnlyMode read_only,
316 Error **errp)
318 BlockBackend *blk;
319 BlockDriverState *medium_bs = NULL;
320 int bdrv_flags;
321 bool detect_zeroes;
322 int rc;
323 QDict *options = NULL;
324 Error *err = NULL;
326 blk = qmp_get_blk(device, id, errp);
327 if (!blk) {
328 goto fail;
331 if (blk_bs(blk)) {
332 blk_update_root_state(blk);
335 bdrv_flags = blk_get_open_flags_from_root_state(blk);
336 bdrv_flags &= ~(BDRV_O_TEMPORARY | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING |
337 BDRV_O_PROTOCOL | BDRV_O_AUTO_RDONLY);
339 if (!has_read_only) {
340 read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN;
343 switch (read_only) {
344 case BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN:
345 break;
347 case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_ONLY:
348 bdrv_flags &= ~BDRV_O_RDWR;
349 break;
351 case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_WRITE:
352 bdrv_flags |= BDRV_O_RDWR;
353 break;
355 default:
356 abort();
359 options = qdict_new();
360 detect_zeroes = blk_get_detect_zeroes_from_root_state(blk);
361 qdict_put_str(options, "detect-zeroes", detect_zeroes ? "on" : "off");
363 if (format) {
364 qdict_put_str(options, "driver", format);
367 aio_context_acquire(qemu_get_aio_context());
368 medium_bs = bdrv_open(filename, NULL, options, bdrv_flags, errp);
369 aio_context_release(qemu_get_aio_context());
371 if (!medium_bs) {
372 goto fail;
375 rc = do_open_tray(device, id, force, &err);
376 if (rc && rc != -ENOSYS) {
377 error_propagate(errp, err);
378 goto fail;
380 error_free(err);
381 err = NULL;
383 blockdev_remove_medium(device, id, &err);
384 if (err) {
385 error_propagate(errp, err);
386 goto fail;
389 qmp_blockdev_insert_anon_medium(blk, medium_bs, &err);
390 if (err) {
391 error_propagate(errp, err);
392 goto fail;
395 qmp_blockdev_close_tray(device, id, errp);
397 fail:
398 /* If the medium has been inserted, the device has its own reference, so
399 * ours must be relinquished; and if it has not been inserted successfully,
400 * the reference must be relinquished anyway */
401 bdrv_unref(medium_bs);
404 void qmp_eject(const char *device, const char *id,
405 bool has_force, bool force, Error **errp)
407 Error *local_err = NULL;
408 int rc;
410 if (!has_force) {
411 force = false;
414 rc = do_open_tray(device, id, force, &local_err);
415 if (rc && rc != -ENOSYS) {
416 error_propagate(errp, local_err);
417 return;
419 error_free(local_err);
421 blockdev_remove_medium(device, id, errp);
424 /* throttling disk I/O limits */
425 void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp)
427 ThrottleConfig cfg;
428 BlockDriverState *bs;
429 BlockBackend *blk;
430 AioContext *aio_context;
432 blk = qmp_get_blk(arg->device, arg->id, errp);
433 if (!blk) {
434 return;
437 aio_context = blk_get_aio_context(blk);
438 aio_context_acquire(aio_context);
440 bs = blk_bs(blk);
441 if (!bs) {
442 error_setg(errp, "Device has no medium");
443 goto out;
446 throttle_config_init(&cfg);
447 cfg.buckets[THROTTLE_BPS_TOTAL].avg = arg->bps;
448 cfg.buckets[THROTTLE_BPS_READ].avg = arg->bps_rd;
449 cfg.buckets[THROTTLE_BPS_WRITE].avg = arg->bps_wr;
451 cfg.buckets[THROTTLE_OPS_TOTAL].avg = arg->iops;
452 cfg.buckets[THROTTLE_OPS_READ].avg = arg->iops_rd;
453 cfg.buckets[THROTTLE_OPS_WRITE].avg = arg->iops_wr;
455 if (arg->has_bps_max) {
456 cfg.buckets[THROTTLE_BPS_TOTAL].max = arg->bps_max;
458 if (arg->has_bps_rd_max) {
459 cfg.buckets[THROTTLE_BPS_READ].max = arg->bps_rd_max;
461 if (arg->has_bps_wr_max) {
462 cfg.buckets[THROTTLE_BPS_WRITE].max = arg->bps_wr_max;
464 if (arg->has_iops_max) {
465 cfg.buckets[THROTTLE_OPS_TOTAL].max = arg->iops_max;
467 if (arg->has_iops_rd_max) {
468 cfg.buckets[THROTTLE_OPS_READ].max = arg->iops_rd_max;
470 if (arg->has_iops_wr_max) {
471 cfg.buckets[THROTTLE_OPS_WRITE].max = arg->iops_wr_max;
474 if (arg->has_bps_max_length) {
475 cfg.buckets[THROTTLE_BPS_TOTAL].burst_length = arg->bps_max_length;
477 if (arg->has_bps_rd_max_length) {
478 cfg.buckets[THROTTLE_BPS_READ].burst_length = arg->bps_rd_max_length;
480 if (arg->has_bps_wr_max_length) {
481 cfg.buckets[THROTTLE_BPS_WRITE].burst_length = arg->bps_wr_max_length;
483 if (arg->has_iops_max_length) {
484 cfg.buckets[THROTTLE_OPS_TOTAL].burst_length = arg->iops_max_length;
486 if (arg->has_iops_rd_max_length) {
487 cfg.buckets[THROTTLE_OPS_READ].burst_length = arg->iops_rd_max_length;
489 if (arg->has_iops_wr_max_length) {
490 cfg.buckets[THROTTLE_OPS_WRITE].burst_length = arg->iops_wr_max_length;
493 if (arg->has_iops_size) {
494 cfg.op_size = arg->iops_size;
497 if (!throttle_is_valid(&cfg, errp)) {
498 goto out;
501 if (throttle_enabled(&cfg)) {
502 /* Enable I/O limits if they're not enabled yet, otherwise
503 * just update the throttling group. */
504 if (!blk_get_public(blk)->throttle_group_member.throttle_state) {
505 blk_io_limits_enable(blk, arg->group ?: arg->device ?: arg->id);
506 } else if (arg->group) {
507 blk_io_limits_update_group(blk, arg->group);
509 /* Set the new throttling configuration */
510 blk_set_io_limits(blk, &cfg);
511 } else if (blk_get_public(blk)->throttle_group_member.throttle_state) {
512 /* If all throttling settings are set to 0, disable I/O limits */
513 blk_io_limits_disable(blk);
516 out:
517 aio_context_release(aio_context);
520 void qmp_block_latency_histogram_set(
521 const char *id,
522 bool has_boundaries, uint64List *boundaries,
523 bool has_boundaries_read, uint64List *boundaries_read,
524 bool has_boundaries_write, uint64List *boundaries_write,
525 bool has_boundaries_append, uint64List *boundaries_append,
526 bool has_boundaries_flush, uint64List *boundaries_flush,
527 Error **errp)
529 BlockBackend *blk = qmp_get_blk(NULL, id, errp);
530 BlockAcctStats *stats;
531 int ret;
533 if (!blk) {
534 return;
537 stats = blk_get_stats(blk);
539 if (!has_boundaries && !has_boundaries_read && !has_boundaries_write &&
540 !has_boundaries_flush)
542 block_latency_histograms_clear(stats);
543 return;
546 if (has_boundaries || has_boundaries_read) {
547 ret = block_latency_histogram_set(
548 stats, BLOCK_ACCT_READ,
549 has_boundaries_read ? boundaries_read : boundaries);
550 if (ret) {
551 error_setg(errp, "Device '%s' set read boundaries fail", id);
552 return;
556 if (has_boundaries || has_boundaries_write) {
557 ret = block_latency_histogram_set(
558 stats, BLOCK_ACCT_WRITE,
559 has_boundaries_write ? boundaries_write : boundaries);
560 if (ret) {
561 error_setg(errp, "Device '%s' set write boundaries fail", id);
562 return;
566 if (has_boundaries || has_boundaries_append) {
567 ret = block_latency_histogram_set(
568 stats, BLOCK_ACCT_ZONE_APPEND,
569 has_boundaries_append ? boundaries_append : boundaries);
570 if (ret) {
571 error_setg(errp, "Device '%s' set append write boundaries fail", id);
572 return;
576 if (has_boundaries || has_boundaries_flush) {
577 ret = block_latency_histogram_set(
578 stats, BLOCK_ACCT_FLUSH,
579 has_boundaries_flush ? boundaries_flush : boundaries);
580 if (ret) {
581 error_setg(errp, "Device '%s' set flush boundaries fail", id);
582 return;