]> git.proxmox.com Git - mirror_qemu.git/blob - block/qapi-sysemu.c
Merge tag 'python-pull-request' of https://gitlab.com/jsnow/qemu into staging
[mirror_qemu.git] / block / qapi-sysemu.c
1 /*
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
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"
41
42 static 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 */
76 static 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
120 void qmp_blockdev_open_tray(const char *device,
121 const char *id,
122 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 }
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;
135 }
136 error_free(local_err);
137 }
138
139 void qmp_blockdev_close_tray(const char *device,
140 const char *id,
141 Error **errp)
142 {
143 BlockBackend *blk;
144 Error *local_err = NULL;
145
146 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
172 static void GRAPH_UNLOCKED
173 blockdev_remove_medium(const char *device, const char *id, Error **errp)
174 {
175 BlockBackend *blk;
176 BlockDriverState *bs;
177 AioContext *aio_context;
178 bool has_attached_device;
179
180 GLOBAL_STATE_CODE();
181
182 blk = qmp_get_blk(device, id, errp);
183 if (!blk) {
184 return;
185 }
186
187 /* For BBs without a device, we can exchange the BDS tree at will */
188 has_attached_device = blk_get_attached_dev(blk);
189
190 if (has_attached_device && !blk_dev_has_removable_media(blk)) {
191 error_setg(errp, "Device '%s' is not removable", device ?: id);
192 return;
193 }
194
195 if (has_attached_device && blk_dev_has_tray(blk) &&
196 !blk_dev_is_tray_open(blk))
197 {
198 error_setg(errp, "Tray of device '%s' is not open", device ?: id);
199 return;
200 }
201
202 bs = blk_bs(blk);
203 if (!bs) {
204 return;
205 }
206
207 aio_context = bdrv_get_aio_context(bs);
208 aio_context_acquire(aio_context);
209
210 bdrv_graph_rdlock_main_loop();
211 if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
212 bdrv_graph_rdunlock_main_loop();
213 goto out;
214 }
215 bdrv_graph_rdunlock_main_loop();
216
217 blk_remove_bs(blk);
218
219 if (!blk_dev_has_tray(blk)) {
220 /* For tray-less devices, blockdev-open-tray is a no-op (or may not be
221 * called at all); therefore, the medium needs to be ejected here.
222 * Do it after blk_remove_bs() so blk_is_inserted(blk) returns the @load
223 * value passed here (i.e. false). */
224 blk_dev_change_media_cb(blk, false, &error_abort);
225 }
226
227 out:
228 aio_context_release(aio_context);
229 }
230
231 void qmp_blockdev_remove_medium(const char *id, Error **errp)
232 {
233 blockdev_remove_medium(NULL, id, errp);
234 }
235
236 static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
237 BlockDriverState *bs, Error **errp)
238 {
239 Error *local_err = NULL;
240 bool has_device;
241 int ret;
242
243 /* For BBs without a device, we can exchange the BDS tree at will */
244 has_device = blk_get_attached_dev(blk);
245
246 if (has_device && !blk_dev_has_removable_media(blk)) {
247 error_setg(errp, "Device is not removable");
248 return;
249 }
250
251 if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) {
252 error_setg(errp, "Tray of the device is not open");
253 return;
254 }
255
256 if (blk_bs(blk)) {
257 error_setg(errp, "There already is a medium in the device");
258 return;
259 }
260
261 ret = blk_insert_bs(blk, bs, errp);
262 if (ret < 0) {
263 return;
264 }
265
266 if (!blk_dev_has_tray(blk)) {
267 /* For tray-less devices, blockdev-close-tray is a no-op (or may not be
268 * called at all); therefore, the medium needs to be pushed into the
269 * slot here.
270 * Do it after blk_insert_bs() so blk_is_inserted(blk) returns the @load
271 * value passed here (i.e. true). */
272 blk_dev_change_media_cb(blk, true, &local_err);
273 if (local_err) {
274 error_propagate(errp, local_err);
275 blk_remove_bs(blk);
276 return;
277 }
278 }
279 }
280
281 static void blockdev_insert_medium(const char *device, const char *id,
282 const char *node_name, Error **errp)
283 {
284 BlockBackend *blk;
285 BlockDriverState *bs;
286
287 GRAPH_RDLOCK_GUARD_MAINLOOP();
288
289 blk = qmp_get_blk(device, id, errp);
290 if (!blk) {
291 return;
292 }
293
294 bs = bdrv_find_node(node_name);
295 if (!bs) {
296 error_setg(errp, "Node '%s' not found", node_name);
297 return;
298 }
299
300 if (bdrv_has_blk(bs)) {
301 error_setg(errp, "Node '%s' is already in use", node_name);
302 return;
303 }
304
305 qmp_blockdev_insert_anon_medium(blk, bs, errp);
306 }
307
308 void qmp_blockdev_insert_medium(const char *id, const char *node_name,
309 Error **errp)
310 {
311 blockdev_insert_medium(NULL, id, node_name, errp);
312 }
313
314 void qmp_blockdev_change_medium(const char *device,
315 const char *id,
316 const char *filename,
317 const char *format,
318 bool has_force, bool force,
319 bool has_read_only,
320 BlockdevChangeReadOnlyMode read_only,
321 Error **errp)
322 {
323 BlockBackend *blk;
324 BlockDriverState *medium_bs = NULL;
325 int bdrv_flags;
326 bool detect_zeroes;
327 int rc;
328 QDict *options = NULL;
329 Error *err = NULL;
330
331 blk = qmp_get_blk(device, id, errp);
332 if (!blk) {
333 goto fail;
334 }
335
336 if (blk_bs(blk)) {
337 blk_update_root_state(blk);
338 }
339
340 bdrv_flags = blk_get_open_flags_from_root_state(blk);
341 bdrv_flags &= ~(BDRV_O_TEMPORARY | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING |
342 BDRV_O_PROTOCOL | BDRV_O_AUTO_RDONLY);
343
344 if (!has_read_only) {
345 read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN;
346 }
347
348 switch (read_only) {
349 case BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN:
350 break;
351
352 case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_ONLY:
353 bdrv_flags &= ~BDRV_O_RDWR;
354 break;
355
356 case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_WRITE:
357 bdrv_flags |= BDRV_O_RDWR;
358 break;
359
360 default:
361 abort();
362 }
363
364 options = qdict_new();
365 detect_zeroes = blk_get_detect_zeroes_from_root_state(blk);
366 qdict_put_str(options, "detect-zeroes", detect_zeroes ? "on" : "off");
367
368 if (format) {
369 qdict_put_str(options, "driver", format);
370 }
371
372 aio_context_acquire(qemu_get_aio_context());
373 medium_bs = bdrv_open(filename, NULL, options, bdrv_flags, errp);
374 aio_context_release(qemu_get_aio_context());
375
376 if (!medium_bs) {
377 goto fail;
378 }
379
380 rc = do_open_tray(device, id, force, &err);
381 if (rc && rc != -ENOSYS) {
382 error_propagate(errp, err);
383 goto fail;
384 }
385 error_free(err);
386 err = NULL;
387
388 blockdev_remove_medium(device, id, &err);
389 if (err) {
390 error_propagate(errp, err);
391 goto fail;
392 }
393
394 qmp_blockdev_insert_anon_medium(blk, medium_bs, &err);
395 if (err) {
396 error_propagate(errp, err);
397 goto fail;
398 }
399
400 qmp_blockdev_close_tray(device, id, errp);
401
402 fail:
403 /* If the medium has been inserted, the device has its own reference, so
404 * ours must be relinquished; and if it has not been inserted successfully,
405 * the reference must be relinquished anyway */
406 bdrv_unref(medium_bs);
407 }
408
409 void qmp_eject(const char *device, const char *id,
410 bool has_force, bool force, Error **errp)
411 {
412 Error *local_err = NULL;
413 int rc;
414
415 if (!has_force) {
416 force = false;
417 }
418
419 rc = do_open_tray(device, id, force, &local_err);
420 if (rc && rc != -ENOSYS) {
421 error_propagate(errp, local_err);
422 return;
423 }
424 error_free(local_err);
425
426 blockdev_remove_medium(device, id, errp);
427 }
428
429 /* throttling disk I/O limits */
430 void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp)
431 {
432 ThrottleConfig cfg;
433 BlockDriverState *bs;
434 BlockBackend *blk;
435 AioContext *aio_context;
436
437 blk = qmp_get_blk(arg->device, arg->id, errp);
438 if (!blk) {
439 return;
440 }
441
442 aio_context = blk_get_aio_context(blk);
443 aio_context_acquire(aio_context);
444
445 bs = blk_bs(blk);
446 if (!bs) {
447 error_setg(errp, "Device has no medium");
448 goto out;
449 }
450
451 throttle_config_init(&cfg);
452 cfg.buckets[THROTTLE_BPS_TOTAL].avg = arg->bps;
453 cfg.buckets[THROTTLE_BPS_READ].avg = arg->bps_rd;
454 cfg.buckets[THROTTLE_BPS_WRITE].avg = arg->bps_wr;
455
456 cfg.buckets[THROTTLE_OPS_TOTAL].avg = arg->iops;
457 cfg.buckets[THROTTLE_OPS_READ].avg = arg->iops_rd;
458 cfg.buckets[THROTTLE_OPS_WRITE].avg = arg->iops_wr;
459
460 if (arg->has_bps_max) {
461 cfg.buckets[THROTTLE_BPS_TOTAL].max = arg->bps_max;
462 }
463 if (arg->has_bps_rd_max) {
464 cfg.buckets[THROTTLE_BPS_READ].max = arg->bps_rd_max;
465 }
466 if (arg->has_bps_wr_max) {
467 cfg.buckets[THROTTLE_BPS_WRITE].max = arg->bps_wr_max;
468 }
469 if (arg->has_iops_max) {
470 cfg.buckets[THROTTLE_OPS_TOTAL].max = arg->iops_max;
471 }
472 if (arg->has_iops_rd_max) {
473 cfg.buckets[THROTTLE_OPS_READ].max = arg->iops_rd_max;
474 }
475 if (arg->has_iops_wr_max) {
476 cfg.buckets[THROTTLE_OPS_WRITE].max = arg->iops_wr_max;
477 }
478
479 if (arg->has_bps_max_length) {
480 cfg.buckets[THROTTLE_BPS_TOTAL].burst_length = arg->bps_max_length;
481 }
482 if (arg->has_bps_rd_max_length) {
483 cfg.buckets[THROTTLE_BPS_READ].burst_length = arg->bps_rd_max_length;
484 }
485 if (arg->has_bps_wr_max_length) {
486 cfg.buckets[THROTTLE_BPS_WRITE].burst_length = arg->bps_wr_max_length;
487 }
488 if (arg->has_iops_max_length) {
489 cfg.buckets[THROTTLE_OPS_TOTAL].burst_length = arg->iops_max_length;
490 }
491 if (arg->has_iops_rd_max_length) {
492 cfg.buckets[THROTTLE_OPS_READ].burst_length = arg->iops_rd_max_length;
493 }
494 if (arg->has_iops_wr_max_length) {
495 cfg.buckets[THROTTLE_OPS_WRITE].burst_length = arg->iops_wr_max_length;
496 }
497
498 if (arg->has_iops_size) {
499 cfg.op_size = arg->iops_size;
500 }
501
502 if (!throttle_is_valid(&cfg, errp)) {
503 goto out;
504 }
505
506 if (throttle_enabled(&cfg)) {
507 /* Enable I/O limits if they're not enabled yet, otherwise
508 * just update the throttling group. */
509 if (!blk_get_public(blk)->throttle_group_member.throttle_state) {
510 blk_io_limits_enable(blk, arg->group ?: arg->device ?: arg->id);
511 } else if (arg->group) {
512 blk_io_limits_update_group(blk, arg->group);
513 }
514 /* Set the new throttling configuration */
515 blk_set_io_limits(blk, &cfg);
516 } else if (blk_get_public(blk)->throttle_group_member.throttle_state) {
517 /* If all throttling settings are set to 0, disable I/O limits */
518 blk_io_limits_disable(blk);
519 }
520
521 out:
522 aio_context_release(aio_context);
523 }
524
525 void qmp_block_latency_histogram_set(
526 const char *id,
527 bool has_boundaries, uint64List *boundaries,
528 bool has_boundaries_read, uint64List *boundaries_read,
529 bool has_boundaries_write, uint64List *boundaries_write,
530 bool has_boundaries_append, uint64List *boundaries_append,
531 bool has_boundaries_flush, uint64List *boundaries_flush,
532 Error **errp)
533 {
534 BlockBackend *blk = qmp_get_blk(NULL, id, errp);
535 BlockAcctStats *stats;
536 int ret;
537
538 if (!blk) {
539 return;
540 }
541
542 stats = blk_get_stats(blk);
543
544 if (!has_boundaries && !has_boundaries_read && !has_boundaries_write &&
545 !has_boundaries_flush)
546 {
547 block_latency_histograms_clear(stats);
548 return;
549 }
550
551 if (has_boundaries || has_boundaries_read) {
552 ret = block_latency_histogram_set(
553 stats, BLOCK_ACCT_READ,
554 has_boundaries_read ? boundaries_read : boundaries);
555 if (ret) {
556 error_setg(errp, "Device '%s' set read boundaries fail", id);
557 return;
558 }
559 }
560
561 if (has_boundaries || has_boundaries_write) {
562 ret = block_latency_histogram_set(
563 stats, BLOCK_ACCT_WRITE,
564 has_boundaries_write ? boundaries_write : boundaries);
565 if (ret) {
566 error_setg(errp, "Device '%s' set write boundaries fail", id);
567 return;
568 }
569 }
570
571 if (has_boundaries || has_boundaries_append) {
572 ret = block_latency_histogram_set(
573 stats, BLOCK_ACCT_ZONE_APPEND,
574 has_boundaries_append ? boundaries_append : boundaries);
575 if (ret) {
576 error_setg(errp, "Device '%s' set append write boundaries fail", id);
577 return;
578 }
579 }
580
581 if (has_boundaries || has_boundaries_flush) {
582 ret = block_latency_histogram_set(
583 stats, BLOCK_ACCT_FLUSH,
584 has_boundaries_flush ? boundaries_flush : boundaries);
585 if (ret) {
586 error_setg(errp, "Device '%s' set flush boundaries fail", id);
587 return;
588 }
589 }
590 }