iotests: fix copy-before-write for macOS and FreeBSD
[qemu/rayw.git] / block / qapi-sysemu.c
blob680c7ee342c9ce34d72e1fe2bf580ee9d039269d
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(bool has_device, const char *device,
120 bool has_id, 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(has_device ? device : NULL,
131 has_id ? id : NULL,
132 force, &local_err);
133 if (rc && rc != -ENOSYS && rc != -EINPROGRESS) {
134 error_propagate(errp, local_err);
135 return;
137 error_free(local_err);
140 void qmp_blockdev_close_tray(bool has_device, const char *device,
141 bool has_id, const char *id,
142 Error **errp)
144 BlockBackend *blk;
145 Error *local_err = NULL;
147 device = has_device ? device : NULL;
148 id = has_id ? id : NULL;
150 blk = qmp_get_blk(device, id, errp);
151 if (!blk) {
152 return;
155 if (!blk_dev_has_removable_media(blk)) {
156 error_setg(errp, "Device '%s' is not removable", device ?: id);
157 return;
160 if (!blk_dev_has_tray(blk)) {
161 /* Ignore this command on tray-less devices */
162 return;
165 if (!blk_dev_is_tray_open(blk)) {
166 return;
169 blk_dev_change_media_cb(blk, true, &local_err);
170 if (local_err) {
171 error_propagate(errp, local_err);
172 return;
176 static void blockdev_remove_medium(bool has_device, const char *device,
177 bool has_id, const char *id, Error **errp)
179 BlockBackend *blk;
180 BlockDriverState *bs;
181 AioContext *aio_context;
182 bool has_attached_device;
184 device = has_device ? device : NULL;
185 id = has_id ? id : NULL;
187 blk = qmp_get_blk(device, id, errp);
188 if (!blk) {
189 return;
192 /* For BBs without a device, we can exchange the BDS tree at will */
193 has_attached_device = blk_get_attached_dev(blk);
195 if (has_attached_device && !blk_dev_has_removable_media(blk)) {
196 error_setg(errp, "Device '%s' is not removable", device ?: id);
197 return;
200 if (has_attached_device && blk_dev_has_tray(blk) &&
201 !blk_dev_is_tray_open(blk))
203 error_setg(errp, "Tray of device '%s' is not open", device ?: id);
204 return;
207 bs = blk_bs(blk);
208 if (!bs) {
209 return;
212 aio_context = bdrv_get_aio_context(bs);
213 aio_context_acquire(aio_context);
215 if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
216 goto out;
219 blk_remove_bs(blk);
221 if (!blk_dev_has_tray(blk)) {
222 /* For tray-less devices, blockdev-open-tray is a no-op (or may not be
223 * called at all); therefore, the medium needs to be ejected here.
224 * Do it after blk_remove_bs() so blk_is_inserted(blk) returns the @load
225 * value passed here (i.e. false). */
226 blk_dev_change_media_cb(blk, false, &error_abort);
229 out:
230 aio_context_release(aio_context);
233 void qmp_blockdev_remove_medium(const char *id, Error **errp)
235 blockdev_remove_medium(false, NULL, true, id, errp);
238 static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
239 BlockDriverState *bs, Error **errp)
241 Error *local_err = NULL;
242 bool has_device;
243 int ret;
245 /* For BBs without a device, we can exchange the BDS tree at will */
246 has_device = blk_get_attached_dev(blk);
248 if (has_device && !blk_dev_has_removable_media(blk)) {
249 error_setg(errp, "Device is not removable");
250 return;
253 if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) {
254 error_setg(errp, "Tray of the device is not open");
255 return;
258 if (blk_bs(blk)) {
259 error_setg(errp, "There already is a medium in the device");
260 return;
263 ret = blk_insert_bs(blk, bs, errp);
264 if (ret < 0) {
265 return;
268 if (!blk_dev_has_tray(blk)) {
269 /* For tray-less devices, blockdev-close-tray is a no-op (or may not be
270 * called at all); therefore, the medium needs to be pushed into the
271 * slot here.
272 * Do it after blk_insert_bs() so blk_is_inserted(blk) returns the @load
273 * value passed here (i.e. true). */
274 blk_dev_change_media_cb(blk, true, &local_err);
275 if (local_err) {
276 error_propagate(errp, local_err);
277 blk_remove_bs(blk);
278 return;
283 static void blockdev_insert_medium(bool has_device, const char *device,
284 bool has_id, const char *id,
285 const char *node_name, Error **errp)
287 BlockBackend *blk;
288 BlockDriverState *bs;
290 blk = qmp_get_blk(has_device ? device : NULL,
291 has_id ? id : NULL,
292 errp);
293 if (!blk) {
294 return;
297 bs = bdrv_find_node(node_name);
298 if (!bs) {
299 error_setg(errp, "Node '%s' not found", node_name);
300 return;
303 if (bdrv_has_blk(bs)) {
304 error_setg(errp, "Node '%s' is already in use", node_name);
305 return;
308 qmp_blockdev_insert_anon_medium(blk, bs, errp);
311 void qmp_blockdev_insert_medium(const char *id, const char *node_name,
312 Error **errp)
314 blockdev_insert_medium(false, NULL, true, id, node_name, errp);
317 void qmp_blockdev_change_medium(bool has_device, const char *device,
318 bool has_id, const char *id,
319 const char *filename,
320 bool has_format, const char *format,
321 bool has_force, bool force,
322 bool has_read_only,
323 BlockdevChangeReadOnlyMode read_only,
324 Error **errp)
326 BlockBackend *blk;
327 BlockDriverState *medium_bs = NULL;
328 int bdrv_flags;
329 bool detect_zeroes;
330 int rc;
331 QDict *options = NULL;
332 Error *err = NULL;
334 blk = qmp_get_blk(has_device ? device : NULL,
335 has_id ? id : NULL,
336 errp);
337 if (!blk) {
338 goto fail;
341 if (blk_bs(blk)) {
342 blk_update_root_state(blk);
345 bdrv_flags = blk_get_open_flags_from_root_state(blk);
346 bdrv_flags &= ~(BDRV_O_TEMPORARY | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING |
347 BDRV_O_PROTOCOL | BDRV_O_AUTO_RDONLY);
349 if (!has_read_only) {
350 read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN;
353 switch (read_only) {
354 case BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN:
355 break;
357 case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_ONLY:
358 bdrv_flags &= ~BDRV_O_RDWR;
359 break;
361 case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_WRITE:
362 bdrv_flags |= BDRV_O_RDWR;
363 break;
365 default:
366 abort();
369 options = qdict_new();
370 detect_zeroes = blk_get_detect_zeroes_from_root_state(blk);
371 qdict_put_str(options, "detect-zeroes", detect_zeroes ? "on" : "off");
373 if (has_format) {
374 qdict_put_str(options, "driver", format);
377 medium_bs = bdrv_open(filename, NULL, options, bdrv_flags, errp);
378 if (!medium_bs) {
379 goto fail;
382 rc = do_open_tray(has_device ? device : NULL,
383 has_id ? id : NULL,
384 force, &err);
385 if (rc && rc != -ENOSYS) {
386 error_propagate(errp, err);
387 goto fail;
389 error_free(err);
390 err = NULL;
392 blockdev_remove_medium(has_device, device, has_id, id, &err);
393 if (err) {
394 error_propagate(errp, err);
395 goto fail;
398 qmp_blockdev_insert_anon_medium(blk, medium_bs, &err);
399 if (err) {
400 error_propagate(errp, err);
401 goto fail;
404 qmp_blockdev_close_tray(has_device, device, has_id, id, errp);
406 fail:
407 /* If the medium has been inserted, the device has its own reference, so
408 * ours must be relinquished; and if it has not been inserted successfully,
409 * the reference must be relinquished anyway */
410 bdrv_unref(medium_bs);
413 void qmp_eject(bool has_device, const char *device,
414 bool has_id, const char *id,
415 bool has_force, bool force, Error **errp)
417 Error *local_err = NULL;
418 int rc;
420 if (!has_force) {
421 force = false;
424 rc = do_open_tray(has_device ? device : NULL,
425 has_id ? id : NULL,
426 force, &local_err);
427 if (rc && rc != -ENOSYS) {
428 error_propagate(errp, local_err);
429 return;
431 error_free(local_err);
433 blockdev_remove_medium(has_device, device, has_id, id, errp);
436 /* throttling disk I/O limits */
437 void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp)
439 ThrottleConfig cfg;
440 BlockDriverState *bs;
441 BlockBackend *blk;
442 AioContext *aio_context;
444 blk = qmp_get_blk(arg->has_device ? arg->device : NULL,
445 arg->has_id ? arg->id : NULL,
446 errp);
447 if (!blk) {
448 return;
451 aio_context = blk_get_aio_context(blk);
452 aio_context_acquire(aio_context);
454 bs = blk_bs(blk);
455 if (!bs) {
456 error_setg(errp, "Device has no medium");
457 goto out;
460 throttle_config_init(&cfg);
461 cfg.buckets[THROTTLE_BPS_TOTAL].avg = arg->bps;
462 cfg.buckets[THROTTLE_BPS_READ].avg = arg->bps_rd;
463 cfg.buckets[THROTTLE_BPS_WRITE].avg = arg->bps_wr;
465 cfg.buckets[THROTTLE_OPS_TOTAL].avg = arg->iops;
466 cfg.buckets[THROTTLE_OPS_READ].avg = arg->iops_rd;
467 cfg.buckets[THROTTLE_OPS_WRITE].avg = arg->iops_wr;
469 if (arg->has_bps_max) {
470 cfg.buckets[THROTTLE_BPS_TOTAL].max = arg->bps_max;
472 if (arg->has_bps_rd_max) {
473 cfg.buckets[THROTTLE_BPS_READ].max = arg->bps_rd_max;
475 if (arg->has_bps_wr_max) {
476 cfg.buckets[THROTTLE_BPS_WRITE].max = arg->bps_wr_max;
478 if (arg->has_iops_max) {
479 cfg.buckets[THROTTLE_OPS_TOTAL].max = arg->iops_max;
481 if (arg->has_iops_rd_max) {
482 cfg.buckets[THROTTLE_OPS_READ].max = arg->iops_rd_max;
484 if (arg->has_iops_wr_max) {
485 cfg.buckets[THROTTLE_OPS_WRITE].max = arg->iops_wr_max;
488 if (arg->has_bps_max_length) {
489 cfg.buckets[THROTTLE_BPS_TOTAL].burst_length = arg->bps_max_length;
491 if (arg->has_bps_rd_max_length) {
492 cfg.buckets[THROTTLE_BPS_READ].burst_length = arg->bps_rd_max_length;
494 if (arg->has_bps_wr_max_length) {
495 cfg.buckets[THROTTLE_BPS_WRITE].burst_length = arg->bps_wr_max_length;
497 if (arg->has_iops_max_length) {
498 cfg.buckets[THROTTLE_OPS_TOTAL].burst_length = arg->iops_max_length;
500 if (arg->has_iops_rd_max_length) {
501 cfg.buckets[THROTTLE_OPS_READ].burst_length = arg->iops_rd_max_length;
503 if (arg->has_iops_wr_max_length) {
504 cfg.buckets[THROTTLE_OPS_WRITE].burst_length = arg->iops_wr_max_length;
507 if (arg->has_iops_size) {
508 cfg.op_size = arg->iops_size;
511 if (!throttle_is_valid(&cfg, errp)) {
512 goto out;
515 if (throttle_enabled(&cfg)) {
516 /* Enable I/O limits if they're not enabled yet, otherwise
517 * just update the throttling group. */
518 if (!blk_get_public(blk)->throttle_group_member.throttle_state) {
519 blk_io_limits_enable(blk,
520 arg->has_group ? arg->group :
521 arg->has_device ? arg->device :
522 arg->id);
523 } else if (arg->has_group) {
524 blk_io_limits_update_group(blk, arg->group);
526 /* Set the new throttling configuration */
527 blk_set_io_limits(blk, &cfg);
528 } else if (blk_get_public(blk)->throttle_group_member.throttle_state) {
529 /* If all throttling settings are set to 0, disable I/O limits */
530 blk_io_limits_disable(blk);
533 out:
534 aio_context_release(aio_context);
537 void qmp_block_latency_histogram_set(
538 const char *id,
539 bool has_boundaries, uint64List *boundaries,
540 bool has_boundaries_read, uint64List *boundaries_read,
541 bool has_boundaries_write, uint64List *boundaries_write,
542 bool has_boundaries_flush, uint64List *boundaries_flush,
543 Error **errp)
545 BlockBackend *blk = qmp_get_blk(NULL, id, errp);
546 BlockAcctStats *stats;
547 int ret;
549 if (!blk) {
550 return;
553 stats = blk_get_stats(blk);
555 if (!has_boundaries && !has_boundaries_read && !has_boundaries_write &&
556 !has_boundaries_flush)
558 block_latency_histograms_clear(stats);
559 return;
562 if (has_boundaries || has_boundaries_read) {
563 ret = block_latency_histogram_set(
564 stats, BLOCK_ACCT_READ,
565 has_boundaries_read ? boundaries_read : boundaries);
566 if (ret) {
567 error_setg(errp, "Device '%s' set read boundaries fail", id);
568 return;
572 if (has_boundaries || has_boundaries_write) {
573 ret = block_latency_histogram_set(
574 stats, BLOCK_ACCT_WRITE,
575 has_boundaries_write ? boundaries_write : boundaries);
576 if (ret) {
577 error_setg(errp, "Device '%s' set write boundaries fail", id);
578 return;
582 if (has_boundaries || has_boundaries_flush) {
583 ret = block_latency_histogram_set(
584 stats, BLOCK_ACCT_FLUSH,
585 has_boundaries_flush ? boundaries_flush : boundaries);
586 if (ret) {
587 error_setg(errp, "Device '%s' set flush boundaries fail", id);
588 return;