OSDN Git Service

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