]> git.proxmox.com Git - mirror_qemu.git/blob - block/qapi-sysemu.c
qapi block: Elide redundant has_FOO in generated C
[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 "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"
40
41 static BlockBackend *qmp_get_blk(const char *blk_name, const char *qdev_id,
42 Error **errp)
43 {
44 BlockBackend *blk;
45
46 if (!blk_name == !qdev_id) {
47 error_setg(errp, "Need exactly one of 'device' and 'id'");
48 return NULL;
49 }
50
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);
58 }
59 }
60
61 return blk;
62 }
63
64 /*
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.
74 */
75 static int do_open_tray(const char *blk_name, const char *qdev_id,
76 bool force, Error **errp)
77 {
78 BlockBackend *blk;
79 const char *device = qdev_id ?: blk_name;
80 bool locked;
81
82 blk = qmp_get_blk(blk_name, qdev_id, errp);
83 if (!blk) {
84 return -ENODEV;
85 }
86
87 if (!blk_dev_has_removable_media(blk)) {
88 error_setg(errp, "Device '%s' is not removable", device);
89 return -ENOTSUP;
90 }
91
92 if (!blk_dev_has_tray(blk)) {
93 error_setg(errp, "Device '%s' does not have a tray", device);
94 return -ENOSYS;
95 }
96
97 if (blk_dev_is_tray_open(blk)) {
98 return 0;
99 }
100
101 locked = blk_dev_is_medium_locked(blk);
102 if (locked) {
103 blk_dev_eject_request(blk, force);
104 }
105
106 if (!locked || force) {
107 blk_dev_change_media_cb(blk, false, &error_abort);
108 }
109
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;
114 }
115
116 return 0;
117 }
118
119 void qmp_blockdev_open_tray(const char *device,
120 const char *id,
121 bool has_force, bool force,
122 Error **errp)
123 {
124 Error *local_err = NULL;
125 int rc;
126
127 if (!has_force) {
128 force = false;
129 }
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;
134 }
135 error_free(local_err);
136 }
137
138 void qmp_blockdev_close_tray(const char *device,
139 const char *id,
140 Error **errp)
141 {
142 BlockBackend *blk;
143 Error *local_err = NULL;
144
145 blk = qmp_get_blk(device, id, errp);
146 if (!blk) {
147 return;
148 }
149
150 if (!blk_dev_has_removable_media(blk)) {
151 error_setg(errp, "Device '%s' is not removable", device ?: id);
152 return;
153 }
154
155 if (!blk_dev_has_tray(blk)) {
156 /* Ignore this command on tray-less devices */
157 return;
158 }
159
160 if (!blk_dev_is_tray_open(blk)) {
161 return;
162 }
163
164 blk_dev_change_media_cb(blk, true, &local_err);
165 if (local_err) {
166 error_propagate(errp, local_err);
167 return;
168 }
169 }
170
171 static void blockdev_remove_medium(const char *device, const char *id,
172 Error **errp)
173 {
174 BlockBackend *blk;
175 BlockDriverState *bs;
176 AioContext *aio_context;
177 bool has_attached_device;
178
179 blk = qmp_get_blk(device, id, errp);
180 if (!blk) {
181 return;
182 }
183
184 /* For BBs without a device, we can exchange the BDS tree at will */
185 has_attached_device = blk_get_attached_dev(blk);
186
187 if (has_attached_device && !blk_dev_has_removable_media(blk)) {
188 error_setg(errp, "Device '%s' is not removable", device ?: id);
189 return;
190 }
191
192 if (has_attached_device && blk_dev_has_tray(blk) &&
193 !blk_dev_is_tray_open(blk))
194 {
195 error_setg(errp, "Tray of device '%s' is not open", device ?: id);
196 return;
197 }
198
199 bs = blk_bs(blk);
200 if (!bs) {
201 return;
202 }
203
204 aio_context = bdrv_get_aio_context(bs);
205 aio_context_acquire(aio_context);
206
207 if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
208 goto out;
209 }
210
211 blk_remove_bs(blk);
212
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);
219 }
220
221 out:
222 aio_context_release(aio_context);
223 }
224
225 void qmp_blockdev_remove_medium(const char *id, Error **errp)
226 {
227 blockdev_remove_medium(NULL, id, errp);
228 }
229
230 static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
231 BlockDriverState *bs, Error **errp)
232 {
233 Error *local_err = NULL;
234 bool has_device;
235 int ret;
236
237 /* For BBs without a device, we can exchange the BDS tree at will */
238 has_device = blk_get_attached_dev(blk);
239
240 if (has_device && !blk_dev_has_removable_media(blk)) {
241 error_setg(errp, "Device is not removable");
242 return;
243 }
244
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;
248 }
249
250 if (blk_bs(blk)) {
251 error_setg(errp, "There already is a medium in the device");
252 return;
253 }
254
255 ret = blk_insert_bs(blk, bs, errp);
256 if (ret < 0) {
257 return;
258 }
259
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;
271 }
272 }
273 }
274
275 static void blockdev_insert_medium(const char *device, const char *id,
276 const char *node_name, Error **errp)
277 {
278 BlockBackend *blk;
279 BlockDriverState *bs;
280
281 blk = qmp_get_blk(device, id, errp);
282 if (!blk) {
283 return;
284 }
285
286 bs = bdrv_find_node(node_name);
287 if (!bs) {
288 error_setg(errp, "Node '%s' not found", node_name);
289 return;
290 }
291
292 if (bdrv_has_blk(bs)) {
293 error_setg(errp, "Node '%s' is already in use", node_name);
294 return;
295 }
296
297 qmp_blockdev_insert_anon_medium(blk, bs, errp);
298 }
299
300 void qmp_blockdev_insert_medium(const char *id, const char *node_name,
301 Error **errp)
302 {
303 blockdev_insert_medium(NULL, id, node_name, errp);
304 }
305
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)
314 {
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;
322
323 blk = qmp_get_blk(device, id, errp);
324 if (!blk) {
325 goto fail;
326 }
327
328 if (blk_bs(blk)) {
329 blk_update_root_state(blk);
330 }
331
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);
335
336 if (!has_read_only) {
337 read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN;
338 }
339
340 switch (read_only) {
341 case BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN:
342 break;
343
344 case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_ONLY:
345 bdrv_flags &= ~BDRV_O_RDWR;
346 break;
347
348 case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_WRITE:
349 bdrv_flags |= BDRV_O_RDWR;
350 break;
351
352 default:
353 abort();
354 }
355
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");
359
360 if (format) {
361 qdict_put_str(options, "driver", format);
362 }
363
364 medium_bs = bdrv_open(filename, NULL, options, bdrv_flags, errp);
365 if (!medium_bs) {
366 goto fail;
367 }
368
369 rc = do_open_tray(device, id, force, &err);
370 if (rc && rc != -ENOSYS) {
371 error_propagate(errp, err);
372 goto fail;
373 }
374 error_free(err);
375 err = NULL;
376
377 blockdev_remove_medium(device, id, &err);
378 if (err) {
379 error_propagate(errp, err);
380 goto fail;
381 }
382
383 qmp_blockdev_insert_anon_medium(blk, medium_bs, &err);
384 if (err) {
385 error_propagate(errp, err);
386 goto fail;
387 }
388
389 qmp_blockdev_close_tray(device, id, errp);
390
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);
396 }
397
398 void qmp_eject(const char *device, const char *id,
399 bool has_force, bool force, Error **errp)
400 {
401 Error *local_err = NULL;
402 int rc;
403
404 if (!has_force) {
405 force = false;
406 }
407
408 rc = do_open_tray(device, id, force, &local_err);
409 if (rc && rc != -ENOSYS) {
410 error_propagate(errp, local_err);
411 return;
412 }
413 error_free(local_err);
414
415 blockdev_remove_medium(device, id, errp);
416 }
417
418 /* throttling disk I/O limits */
419 void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp)
420 {
421 ThrottleConfig cfg;
422 BlockDriverState *bs;
423 BlockBackend *blk;
424 AioContext *aio_context;
425
426 blk = qmp_get_blk(arg->device, arg->id, errp);
427 if (!blk) {
428 return;
429 }
430
431 aio_context = blk_get_aio_context(blk);
432 aio_context_acquire(aio_context);
433
434 bs = blk_bs(blk);
435 if (!bs) {
436 error_setg(errp, "Device has no medium");
437 goto out;
438 }
439
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;
444
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;
448
449 if (arg->has_bps_max) {
450 cfg.buckets[THROTTLE_BPS_TOTAL].max = arg->bps_max;
451 }
452 if (arg->has_bps_rd_max) {
453 cfg.buckets[THROTTLE_BPS_READ].max = arg->bps_rd_max;
454 }
455 if (arg->has_bps_wr_max) {
456 cfg.buckets[THROTTLE_BPS_WRITE].max = arg->bps_wr_max;
457 }
458 if (arg->has_iops_max) {
459 cfg.buckets[THROTTLE_OPS_TOTAL].max = arg->iops_max;
460 }
461 if (arg->has_iops_rd_max) {
462 cfg.buckets[THROTTLE_OPS_READ].max = arg->iops_rd_max;
463 }
464 if (arg->has_iops_wr_max) {
465 cfg.buckets[THROTTLE_OPS_WRITE].max = arg->iops_wr_max;
466 }
467
468 if (arg->has_bps_max_length) {
469 cfg.buckets[THROTTLE_BPS_TOTAL].burst_length = arg->bps_max_length;
470 }
471 if (arg->has_bps_rd_max_length) {
472 cfg.buckets[THROTTLE_BPS_READ].burst_length = arg->bps_rd_max_length;
473 }
474 if (arg->has_bps_wr_max_length) {
475 cfg.buckets[THROTTLE_BPS_WRITE].burst_length = arg->bps_wr_max_length;
476 }
477 if (arg->has_iops_max_length) {
478 cfg.buckets[THROTTLE_OPS_TOTAL].burst_length = arg->iops_max_length;
479 }
480 if (arg->has_iops_rd_max_length) {
481 cfg.buckets[THROTTLE_OPS_READ].burst_length = arg->iops_rd_max_length;
482 }
483 if (arg->has_iops_wr_max_length) {
484 cfg.buckets[THROTTLE_OPS_WRITE].burst_length = arg->iops_wr_max_length;
485 }
486
487 if (arg->has_iops_size) {
488 cfg.op_size = arg->iops_size;
489 }
490
491 if (!throttle_is_valid(&cfg, errp)) {
492 goto out;
493 }
494
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);
502 }
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);
508 }
509
510 out:
511 aio_context_release(aio_context);
512 }
513
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)
521 {
522 BlockBackend *blk = qmp_get_blk(NULL, id, errp);
523 BlockAcctStats *stats;
524 int ret;
525
526 if (!blk) {
527 return;
528 }
529
530 stats = blk_get_stats(blk);
531
532 if (!has_boundaries && !has_boundaries_read && !has_boundaries_write &&
533 !has_boundaries_flush)
534 {
535 block_latency_histograms_clear(stats);
536 return;
537 }
538
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;
546 }
547 }
548
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;
556 }
557 }
558
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;
566 }
567 }
568 }