xref: /qemu/block/qapi-sysemu.c (revision b49f4755)
112c929bcSKevin Wolf /*
212c929bcSKevin Wolf  * QMP command handlers specific to the system emulators
312c929bcSKevin Wolf  *
412c929bcSKevin Wolf  * Copyright (c) 2003-2008 Fabrice Bellard
512c929bcSKevin Wolf  *
612c929bcSKevin Wolf  * This work is licensed under the terms of the GNU GPL, version 2 or
712c929bcSKevin Wolf  * later.  See the COPYING file in the top-level directory.
812c929bcSKevin Wolf  *
912c929bcSKevin Wolf  * This file incorporates work covered by the following copyright and
1012c929bcSKevin Wolf  * permission notice:
1112c929bcSKevin Wolf  *
1212c929bcSKevin Wolf  * Copyright (c) 2003-2008 Fabrice Bellard
1312c929bcSKevin Wolf  *
1412c929bcSKevin Wolf  * Permission is hereby granted, free of charge, to any person obtaining a copy
1512c929bcSKevin Wolf  * of this software and associated documentation files (the "Software"), to deal
1612c929bcSKevin Wolf  * in the Software without restriction, including without limitation the rights
1712c929bcSKevin Wolf  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1812c929bcSKevin Wolf  * copies of the Software, and to permit persons to whom the Software is
1912c929bcSKevin Wolf  * furnished to do so, subject to the following conditions:
2012c929bcSKevin Wolf  *
2112c929bcSKevin Wolf  * The above copyright notice and this permission notice shall be included in
2212c929bcSKevin Wolf  * all copies or substantial portions of the Software.
2312c929bcSKevin Wolf  *
2412c929bcSKevin Wolf  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2512c929bcSKevin Wolf  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2612c929bcSKevin Wolf  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2712c929bcSKevin Wolf  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2812c929bcSKevin Wolf  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2912c929bcSKevin Wolf  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
3012c929bcSKevin Wolf  * THE SOFTWARE.
3112c929bcSKevin Wolf  */
3212c929bcSKevin Wolf 
3312c929bcSKevin Wolf #include "qemu/osdep.h"
3412c929bcSKevin Wolf 
35e2c1c34fSMarkus Armbruster #include "block/block_int.h"
3612c929bcSKevin Wolf #include "qapi/error.h"
3712c929bcSKevin Wolf #include "qapi/qapi-commands-block.h"
3812c929bcSKevin Wolf #include "qapi/qmp/qdict.h"
3912c929bcSKevin Wolf #include "sysemu/block-backend.h"
4012c929bcSKevin Wolf #include "sysemu/blockdev.h"
4112c929bcSKevin Wolf 
qmp_get_blk(const char * blk_name,const char * qdev_id,Error ** errp)4212c929bcSKevin Wolf static BlockBackend *qmp_get_blk(const char *blk_name, const char *qdev_id,
4312c929bcSKevin Wolf                                  Error **errp)
4412c929bcSKevin Wolf {
4512c929bcSKevin Wolf     BlockBackend *blk;
4612c929bcSKevin Wolf 
4712c929bcSKevin Wolf     if (!blk_name == !qdev_id) {
4812c929bcSKevin Wolf         error_setg(errp, "Need exactly one of 'device' and 'id'");
4912c929bcSKevin Wolf         return NULL;
5012c929bcSKevin Wolf     }
5112c929bcSKevin Wolf 
5212c929bcSKevin Wolf     if (qdev_id) {
5312c929bcSKevin Wolf         blk = blk_by_qdev_id(qdev_id, errp);
5412c929bcSKevin Wolf     } else {
5512c929bcSKevin Wolf         blk = blk_by_name(blk_name);
5612c929bcSKevin Wolf         if (blk == NULL) {
5712c929bcSKevin Wolf             error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
5812c929bcSKevin Wolf                       "Device '%s' not found", blk_name);
5912c929bcSKevin Wolf         }
6012c929bcSKevin Wolf     }
6112c929bcSKevin Wolf 
6212c929bcSKevin Wolf     return blk;
6312c929bcSKevin Wolf }
6412c929bcSKevin Wolf 
6512c929bcSKevin Wolf /*
6612c929bcSKevin Wolf  * Attempt to open the tray of @device.
6712c929bcSKevin Wolf  * If @force, ignore its tray lock.
6812c929bcSKevin Wolf  * Else, if the tray is locked, don't open it, but ask the guest to open it.
6912c929bcSKevin Wolf  * On error, store an error through @errp and return -errno.
7012c929bcSKevin Wolf  * If @device does not exist, return -ENODEV.
7112c929bcSKevin Wolf  * If it has no removable media, return -ENOTSUP.
7212c929bcSKevin Wolf  * If it has no tray, return -ENOSYS.
7312c929bcSKevin Wolf  * If the guest was asked to open the tray, return -EINPROGRESS.
7412c929bcSKevin Wolf  * Else, return 0.
7512c929bcSKevin Wolf  */
do_open_tray(const char * blk_name,const char * qdev_id,bool force,Error ** errp)7612c929bcSKevin Wolf static int do_open_tray(const char *blk_name, const char *qdev_id,
7712c929bcSKevin Wolf                         bool force, Error **errp)
7812c929bcSKevin Wolf {
7912c929bcSKevin Wolf     BlockBackend *blk;
8012c929bcSKevin Wolf     const char *device = qdev_id ?: blk_name;
8112c929bcSKevin Wolf     bool locked;
8212c929bcSKevin Wolf 
8312c929bcSKevin Wolf     blk = qmp_get_blk(blk_name, qdev_id, errp);
8412c929bcSKevin Wolf     if (!blk) {
8512c929bcSKevin Wolf         return -ENODEV;
8612c929bcSKevin Wolf     }
8712c929bcSKevin Wolf 
8812c929bcSKevin Wolf     if (!blk_dev_has_removable_media(blk)) {
8912c929bcSKevin Wolf         error_setg(errp, "Device '%s' is not removable", device);
9012c929bcSKevin Wolf         return -ENOTSUP;
9112c929bcSKevin Wolf     }
9212c929bcSKevin Wolf 
9312c929bcSKevin Wolf     if (!blk_dev_has_tray(blk)) {
9412c929bcSKevin Wolf         error_setg(errp, "Device '%s' does not have a tray", device);
9512c929bcSKevin Wolf         return -ENOSYS;
9612c929bcSKevin Wolf     }
9712c929bcSKevin Wolf 
9812c929bcSKevin Wolf     if (blk_dev_is_tray_open(blk)) {
9912c929bcSKevin Wolf         return 0;
10012c929bcSKevin Wolf     }
10112c929bcSKevin Wolf 
10212c929bcSKevin Wolf     locked = blk_dev_is_medium_locked(blk);
10312c929bcSKevin Wolf     if (locked) {
10412c929bcSKevin Wolf         blk_dev_eject_request(blk, force);
10512c929bcSKevin Wolf     }
10612c929bcSKevin Wolf 
10712c929bcSKevin Wolf     if (!locked || force) {
10812c929bcSKevin Wolf         blk_dev_change_media_cb(blk, false, &error_abort);
10912c929bcSKevin Wolf     }
11012c929bcSKevin Wolf 
11112c929bcSKevin Wolf     if (locked && !force) {
11212c929bcSKevin Wolf         error_setg(errp, "Device '%s' is locked and force was not specified, "
11312c929bcSKevin Wolf                    "wait for tray to open and try again", device);
11412c929bcSKevin Wolf         return -EINPROGRESS;
11512c929bcSKevin Wolf     }
11612c929bcSKevin Wolf 
11712c929bcSKevin Wolf     return 0;
11812c929bcSKevin Wolf }
11912c929bcSKevin Wolf 
qmp_blockdev_open_tray(const char * device,const char * id,bool has_force,bool force,Error ** errp)12054fde4ffSMarkus Armbruster void qmp_blockdev_open_tray(const char *device,
12154fde4ffSMarkus Armbruster                             const char *id,
12212c929bcSKevin Wolf                             bool has_force, bool force,
12312c929bcSKevin Wolf                             Error **errp)
12412c929bcSKevin Wolf {
12512c929bcSKevin Wolf     Error *local_err = NULL;
12612c929bcSKevin Wolf     int rc;
12712c929bcSKevin Wolf 
12812c929bcSKevin Wolf     if (!has_force) {
12912c929bcSKevin Wolf         force = false;
13012c929bcSKevin Wolf     }
13154fde4ffSMarkus Armbruster     rc = do_open_tray(device, id, force, &local_err);
13212c929bcSKevin Wolf     if (rc && rc != -ENOSYS && rc != -EINPROGRESS) {
13312c929bcSKevin Wolf         error_propagate(errp, local_err);
13412c929bcSKevin Wolf         return;
13512c929bcSKevin Wolf     }
13612c929bcSKevin Wolf     error_free(local_err);
13712c929bcSKevin Wolf }
13812c929bcSKevin Wolf 
qmp_blockdev_close_tray(const char * device,const char * id,Error ** errp)13954fde4ffSMarkus Armbruster void qmp_blockdev_close_tray(const char *device,
14054fde4ffSMarkus Armbruster                              const char *id,
14112c929bcSKevin Wolf                              Error **errp)
14212c929bcSKevin Wolf {
14312c929bcSKevin Wolf     BlockBackend *blk;
14412c929bcSKevin Wolf     Error *local_err = NULL;
14512c929bcSKevin Wolf 
14612c929bcSKevin Wolf     blk = qmp_get_blk(device, id, errp);
14712c929bcSKevin Wolf     if (!blk) {
14812c929bcSKevin Wolf         return;
14912c929bcSKevin Wolf     }
15012c929bcSKevin Wolf 
15112c929bcSKevin Wolf     if (!blk_dev_has_removable_media(blk)) {
15212c929bcSKevin Wolf         error_setg(errp, "Device '%s' is not removable", device ?: id);
15312c929bcSKevin Wolf         return;
15412c929bcSKevin Wolf     }
15512c929bcSKevin Wolf 
15612c929bcSKevin Wolf     if (!blk_dev_has_tray(blk)) {
15712c929bcSKevin Wolf         /* Ignore this command on tray-less devices */
15812c929bcSKevin Wolf         return;
15912c929bcSKevin Wolf     }
16012c929bcSKevin Wolf 
16112c929bcSKevin Wolf     if (!blk_dev_is_tray_open(blk)) {
16212c929bcSKevin Wolf         return;
16312c929bcSKevin Wolf     }
16412c929bcSKevin Wolf 
16512c929bcSKevin Wolf     blk_dev_change_media_cb(blk, true, &local_err);
16612c929bcSKevin Wolf     if (local_err) {
16712c929bcSKevin Wolf         error_propagate(errp, local_err);
16812c929bcSKevin Wolf         return;
16912c929bcSKevin Wolf     }
17012c929bcSKevin Wolf }
17112c929bcSKevin Wolf 
172277f2007SKevin Wolf static void GRAPH_UNLOCKED
blockdev_remove_medium(const char * device,const char * id,Error ** errp)173277f2007SKevin Wolf blockdev_remove_medium(const char *device, const char *id, Error **errp)
17412c929bcSKevin Wolf {
17512c929bcSKevin Wolf     BlockBackend *blk;
17612c929bcSKevin Wolf     BlockDriverState *bs;
17712c929bcSKevin Wolf     bool has_attached_device;
17812c929bcSKevin Wolf 
179277f2007SKevin Wolf     GLOBAL_STATE_CODE();
180277f2007SKevin Wolf 
18112c929bcSKevin Wolf     blk = qmp_get_blk(device, id, errp);
18212c929bcSKevin Wolf     if (!blk) {
18312c929bcSKevin Wolf         return;
18412c929bcSKevin Wolf     }
18512c929bcSKevin Wolf 
18612c929bcSKevin Wolf     /* For BBs without a device, we can exchange the BDS tree at will */
18712c929bcSKevin Wolf     has_attached_device = blk_get_attached_dev(blk);
18812c929bcSKevin Wolf 
18912c929bcSKevin Wolf     if (has_attached_device && !blk_dev_has_removable_media(blk)) {
19012c929bcSKevin Wolf         error_setg(errp, "Device '%s' is not removable", device ?: id);
19112c929bcSKevin Wolf         return;
19212c929bcSKevin Wolf     }
19312c929bcSKevin Wolf 
19412c929bcSKevin Wolf     if (has_attached_device && blk_dev_has_tray(blk) &&
19512c929bcSKevin Wolf         !blk_dev_is_tray_open(blk))
19612c929bcSKevin Wolf     {
19712c929bcSKevin Wolf         error_setg(errp, "Tray of device '%s' is not open", device ?: id);
19812c929bcSKevin Wolf         return;
19912c929bcSKevin Wolf     }
20012c929bcSKevin Wolf 
20112c929bcSKevin Wolf     bs = blk_bs(blk);
20212c929bcSKevin Wolf     if (!bs) {
20312c929bcSKevin Wolf         return;
20412c929bcSKevin Wolf     }
20512c929bcSKevin Wolf 
206277f2007SKevin Wolf     bdrv_graph_rdlock_main_loop();
20712c929bcSKevin Wolf     if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
208277f2007SKevin Wolf         bdrv_graph_rdunlock_main_loop();
209*b49f4755SStefan Hajnoczi         return;
21012c929bcSKevin Wolf     }
211277f2007SKevin Wolf     bdrv_graph_rdunlock_main_loop();
21212c929bcSKevin Wolf 
21312c929bcSKevin Wolf     blk_remove_bs(blk);
21412c929bcSKevin Wolf 
21512c929bcSKevin Wolf     if (!blk_dev_has_tray(blk)) {
21612c929bcSKevin Wolf         /* For tray-less devices, blockdev-open-tray is a no-op (or may not be
21712c929bcSKevin Wolf          * called at all); therefore, the medium needs to be ejected here.
21812c929bcSKevin Wolf          * Do it after blk_remove_bs() so blk_is_inserted(blk) returns the @load
21912c929bcSKevin Wolf          * value passed here (i.e. false). */
22012c929bcSKevin Wolf         blk_dev_change_media_cb(blk, false, &error_abort);
22112c929bcSKevin Wolf     }
22212c929bcSKevin Wolf }
22312c929bcSKevin Wolf 
qmp_blockdev_remove_medium(const char * id,Error ** errp)22412c929bcSKevin Wolf void qmp_blockdev_remove_medium(const char *id, Error **errp)
22512c929bcSKevin Wolf {
22654fde4ffSMarkus Armbruster     blockdev_remove_medium(NULL, id, errp);
22712c929bcSKevin Wolf }
22812c929bcSKevin Wolf 
qmp_blockdev_insert_anon_medium(BlockBackend * blk,BlockDriverState * bs,Error ** errp)22912c929bcSKevin Wolf static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
23012c929bcSKevin Wolf                                             BlockDriverState *bs, Error **errp)
23112c929bcSKevin Wolf {
23212c929bcSKevin Wolf     Error *local_err = NULL;
23312c929bcSKevin Wolf     bool has_device;
23412c929bcSKevin Wolf     int ret;
23512c929bcSKevin Wolf 
23612c929bcSKevin Wolf     /* For BBs without a device, we can exchange the BDS tree at will */
23712c929bcSKevin Wolf     has_device = blk_get_attached_dev(blk);
23812c929bcSKevin Wolf 
23912c929bcSKevin Wolf     if (has_device && !blk_dev_has_removable_media(blk)) {
24012c929bcSKevin Wolf         error_setg(errp, "Device is not removable");
24112c929bcSKevin Wolf         return;
24212c929bcSKevin Wolf     }
24312c929bcSKevin Wolf 
24412c929bcSKevin Wolf     if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) {
24512c929bcSKevin Wolf         error_setg(errp, "Tray of the device is not open");
24612c929bcSKevin Wolf         return;
24712c929bcSKevin Wolf     }
24812c929bcSKevin Wolf 
24912c929bcSKevin Wolf     if (blk_bs(blk)) {
25012c929bcSKevin Wolf         error_setg(errp, "There already is a medium in the device");
25112c929bcSKevin Wolf         return;
25212c929bcSKevin Wolf     }
25312c929bcSKevin Wolf 
25412c929bcSKevin Wolf     ret = blk_insert_bs(blk, bs, errp);
25512c929bcSKevin Wolf     if (ret < 0) {
25612c929bcSKevin Wolf         return;
25712c929bcSKevin Wolf     }
25812c929bcSKevin Wolf 
25912c929bcSKevin Wolf     if (!blk_dev_has_tray(blk)) {
26012c929bcSKevin Wolf         /* For tray-less devices, blockdev-close-tray is a no-op (or may not be
26112c929bcSKevin Wolf          * called at all); therefore, the medium needs to be pushed into the
26212c929bcSKevin Wolf          * slot here.
26312c929bcSKevin Wolf          * Do it after blk_insert_bs() so blk_is_inserted(blk) returns the @load
26412c929bcSKevin Wolf          * value passed here (i.e. true). */
26512c929bcSKevin Wolf         blk_dev_change_media_cb(blk, true, &local_err);
26612c929bcSKevin Wolf         if (local_err) {
26712c929bcSKevin Wolf             error_propagate(errp, local_err);
26812c929bcSKevin Wolf             blk_remove_bs(blk);
26912c929bcSKevin Wolf             return;
27012c929bcSKevin Wolf         }
27112c929bcSKevin Wolf     }
27212c929bcSKevin Wolf }
27312c929bcSKevin Wolf 
blockdev_insert_medium(const char * device,const char * id,const char * node_name,Error ** errp)27454fde4ffSMarkus Armbruster static void blockdev_insert_medium(const char *device, const char *id,
27512c929bcSKevin Wolf                                    const char *node_name, Error **errp)
27612c929bcSKevin Wolf {
27712c929bcSKevin Wolf     BlockBackend *blk;
27812c929bcSKevin Wolf     BlockDriverState *bs;
27912c929bcSKevin Wolf 
2802b3912f1SKevin Wolf     GRAPH_RDLOCK_GUARD_MAINLOOP();
2812b3912f1SKevin Wolf 
28254fde4ffSMarkus Armbruster     blk = qmp_get_blk(device, id, errp);
28312c929bcSKevin Wolf     if (!blk) {
28412c929bcSKevin Wolf         return;
28512c929bcSKevin Wolf     }
28612c929bcSKevin Wolf 
28712c929bcSKevin Wolf     bs = bdrv_find_node(node_name);
28812c929bcSKevin Wolf     if (!bs) {
28912c929bcSKevin Wolf         error_setg(errp, "Node '%s' not found", node_name);
29012c929bcSKevin Wolf         return;
29112c929bcSKevin Wolf     }
29212c929bcSKevin Wolf 
29312c929bcSKevin Wolf     if (bdrv_has_blk(bs)) {
29412c929bcSKevin Wolf         error_setg(errp, "Node '%s' is already in use", node_name);
29512c929bcSKevin Wolf         return;
29612c929bcSKevin Wolf     }
29712c929bcSKevin Wolf 
29812c929bcSKevin Wolf     qmp_blockdev_insert_anon_medium(blk, bs, errp);
29912c929bcSKevin Wolf }
30012c929bcSKevin Wolf 
qmp_blockdev_insert_medium(const char * id,const char * node_name,Error ** errp)30112c929bcSKevin Wolf void qmp_blockdev_insert_medium(const char *id, const char *node_name,
30212c929bcSKevin Wolf                                 Error **errp)
30312c929bcSKevin Wolf {
30454fde4ffSMarkus Armbruster     blockdev_insert_medium(NULL, id, node_name, errp);
30512c929bcSKevin Wolf }
30612c929bcSKevin Wolf 
qmp_blockdev_change_medium(const char * device,const char * id,const char * filename,const char * format,bool has_force,bool force,bool has_read_only,BlockdevChangeReadOnlyMode read_only,Error ** errp)30754fde4ffSMarkus Armbruster void qmp_blockdev_change_medium(const char *device,
30854fde4ffSMarkus Armbruster                                 const char *id,
30912c929bcSKevin Wolf                                 const char *filename,
31054fde4ffSMarkus Armbruster                                 const char *format,
31180dd5affSDenis V. Lunev                                 bool has_force, bool force,
31212c929bcSKevin Wolf                                 bool has_read_only,
31312c929bcSKevin Wolf                                 BlockdevChangeReadOnlyMode read_only,
31412c929bcSKevin Wolf                                 Error **errp)
31512c929bcSKevin Wolf {
31612c929bcSKevin Wolf     BlockBackend *blk;
31712c929bcSKevin Wolf     BlockDriverState *medium_bs = NULL;
31812c929bcSKevin Wolf     int bdrv_flags;
31912c929bcSKevin Wolf     bool detect_zeroes;
32012c929bcSKevin Wolf     int rc;
32112c929bcSKevin Wolf     QDict *options = NULL;
32212c929bcSKevin Wolf     Error *err = NULL;
32312c929bcSKevin Wolf 
32454fde4ffSMarkus Armbruster     blk = qmp_get_blk(device, id, errp);
32512c929bcSKevin Wolf     if (!blk) {
32612c929bcSKevin Wolf         goto fail;
32712c929bcSKevin Wolf     }
32812c929bcSKevin Wolf 
32912c929bcSKevin Wolf     if (blk_bs(blk)) {
33012c929bcSKevin Wolf         blk_update_root_state(blk);
33112c929bcSKevin Wolf     }
33212c929bcSKevin Wolf 
33312c929bcSKevin Wolf     bdrv_flags = blk_get_open_flags_from_root_state(blk);
33412c929bcSKevin Wolf     bdrv_flags &= ~(BDRV_O_TEMPORARY | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING |
33512c929bcSKevin Wolf         BDRV_O_PROTOCOL | BDRV_O_AUTO_RDONLY);
33612c929bcSKevin Wolf 
33712c929bcSKevin Wolf     if (!has_read_only) {
33812c929bcSKevin Wolf         read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN;
33912c929bcSKevin Wolf     }
34012c929bcSKevin Wolf 
34112c929bcSKevin Wolf     switch (read_only) {
34212c929bcSKevin Wolf     case BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN:
34312c929bcSKevin Wolf         break;
34412c929bcSKevin Wolf 
34512c929bcSKevin Wolf     case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_ONLY:
34612c929bcSKevin Wolf         bdrv_flags &= ~BDRV_O_RDWR;
34712c929bcSKevin Wolf         break;
34812c929bcSKevin Wolf 
34912c929bcSKevin Wolf     case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_WRITE:
35012c929bcSKevin Wolf         bdrv_flags |= BDRV_O_RDWR;
35112c929bcSKevin Wolf         break;
35212c929bcSKevin Wolf 
35312c929bcSKevin Wolf     default:
35412c929bcSKevin Wolf         abort();
35512c929bcSKevin Wolf     }
35612c929bcSKevin Wolf 
35712c929bcSKevin Wolf     options = qdict_new();
35812c929bcSKevin Wolf     detect_zeroes = blk_get_detect_zeroes_from_root_state(blk);
35912c929bcSKevin Wolf     qdict_put_str(options, "detect-zeroes", detect_zeroes ? "on" : "off");
36012c929bcSKevin Wolf 
36154fde4ffSMarkus Armbruster     if (format) {
36212c929bcSKevin Wolf         qdict_put_str(options, "driver", format);
36312c929bcSKevin Wolf     }
36412c929bcSKevin Wolf 
36512c929bcSKevin Wolf     medium_bs = bdrv_open(filename, NULL, options, bdrv_flags, errp);
366c6e0a6deSKevin Wolf 
36712c929bcSKevin Wolf     if (!medium_bs) {
36812c929bcSKevin Wolf         goto fail;
36912c929bcSKevin Wolf     }
37012c929bcSKevin Wolf 
37154fde4ffSMarkus Armbruster     rc = do_open_tray(device, id, force, &err);
37212c929bcSKevin Wolf     if (rc && rc != -ENOSYS) {
37312c929bcSKevin Wolf         error_propagate(errp, err);
37412c929bcSKevin Wolf         goto fail;
37512c929bcSKevin Wolf     }
37612c929bcSKevin Wolf     error_free(err);
37712c929bcSKevin Wolf     err = NULL;
37812c929bcSKevin Wolf 
37954fde4ffSMarkus Armbruster     blockdev_remove_medium(device, id, &err);
38012c929bcSKevin Wolf     if (err) {
38112c929bcSKevin Wolf         error_propagate(errp, err);
38212c929bcSKevin Wolf         goto fail;
38312c929bcSKevin Wolf     }
38412c929bcSKevin Wolf 
38512c929bcSKevin Wolf     qmp_blockdev_insert_anon_medium(blk, medium_bs, &err);
38612c929bcSKevin Wolf     if (err) {
38712c929bcSKevin Wolf         error_propagate(errp, err);
38812c929bcSKevin Wolf         goto fail;
38912c929bcSKevin Wolf     }
39012c929bcSKevin Wolf 
39154fde4ffSMarkus Armbruster     qmp_blockdev_close_tray(device, id, errp);
39212c929bcSKevin Wolf 
39312c929bcSKevin Wolf fail:
39412c929bcSKevin Wolf     /* If the medium has been inserted, the device has its own reference, so
39512c929bcSKevin Wolf      * ours must be relinquished; and if it has not been inserted successfully,
39612c929bcSKevin Wolf      * the reference must be relinquished anyway */
39712c929bcSKevin Wolf     bdrv_unref(medium_bs);
39812c929bcSKevin Wolf }
39912c929bcSKevin Wolf 
qmp_eject(const char * device,const char * id,bool has_force,bool force,Error ** errp)40054fde4ffSMarkus Armbruster void qmp_eject(const char *device, const char *id,
40112c929bcSKevin Wolf                bool has_force, bool force, Error **errp)
40212c929bcSKevin Wolf {
40312c929bcSKevin Wolf     Error *local_err = NULL;
40412c929bcSKevin Wolf     int rc;
40512c929bcSKevin Wolf 
40612c929bcSKevin Wolf     if (!has_force) {
40712c929bcSKevin Wolf         force = false;
40812c929bcSKevin Wolf     }
40912c929bcSKevin Wolf 
41054fde4ffSMarkus Armbruster     rc = do_open_tray(device, id, force, &local_err);
41112c929bcSKevin Wolf     if (rc && rc != -ENOSYS) {
41212c929bcSKevin Wolf         error_propagate(errp, local_err);
41312c929bcSKevin Wolf         return;
41412c929bcSKevin Wolf     }
41512c929bcSKevin Wolf     error_free(local_err);
41612c929bcSKevin Wolf 
41754fde4ffSMarkus Armbruster     blockdev_remove_medium(device, id, errp);
41812c929bcSKevin Wolf }
41912c929bcSKevin Wolf 
42012c929bcSKevin Wolf /* throttling disk I/O limits */
qmp_block_set_io_throttle(BlockIOThrottle * arg,Error ** errp)42112c929bcSKevin Wolf void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp)
42212c929bcSKevin Wolf {
42312c929bcSKevin Wolf     ThrottleConfig cfg;
42412c929bcSKevin Wolf     BlockDriverState *bs;
42512c929bcSKevin Wolf     BlockBackend *blk;
42612c929bcSKevin Wolf 
42754fde4ffSMarkus Armbruster     blk = qmp_get_blk(arg->device, arg->id, errp);
42812c929bcSKevin Wolf     if (!blk) {
42912c929bcSKevin Wolf         return;
43012c929bcSKevin Wolf     }
43112c929bcSKevin Wolf 
43212c929bcSKevin Wolf     bs = blk_bs(blk);
43312c929bcSKevin Wolf     if (!bs) {
43412c929bcSKevin Wolf         error_setg(errp, "Device has no medium");
435*b49f4755SStefan Hajnoczi         return;
43612c929bcSKevin Wolf     }
43712c929bcSKevin Wolf 
43812c929bcSKevin Wolf     throttle_config_init(&cfg);
43912c929bcSKevin Wolf     cfg.buckets[THROTTLE_BPS_TOTAL].avg = arg->bps;
44012c929bcSKevin Wolf     cfg.buckets[THROTTLE_BPS_READ].avg  = arg->bps_rd;
44112c929bcSKevin Wolf     cfg.buckets[THROTTLE_BPS_WRITE].avg = arg->bps_wr;
44212c929bcSKevin Wolf 
44312c929bcSKevin Wolf     cfg.buckets[THROTTLE_OPS_TOTAL].avg = arg->iops;
44412c929bcSKevin Wolf     cfg.buckets[THROTTLE_OPS_READ].avg  = arg->iops_rd;
44512c929bcSKevin Wolf     cfg.buckets[THROTTLE_OPS_WRITE].avg = arg->iops_wr;
44612c929bcSKevin Wolf 
44712c929bcSKevin Wolf     if (arg->has_bps_max) {
44812c929bcSKevin Wolf         cfg.buckets[THROTTLE_BPS_TOTAL].max = arg->bps_max;
44912c929bcSKevin Wolf     }
45012c929bcSKevin Wolf     if (arg->has_bps_rd_max) {
45112c929bcSKevin Wolf         cfg.buckets[THROTTLE_BPS_READ].max = arg->bps_rd_max;
45212c929bcSKevin Wolf     }
45312c929bcSKevin Wolf     if (arg->has_bps_wr_max) {
45412c929bcSKevin Wolf         cfg.buckets[THROTTLE_BPS_WRITE].max = arg->bps_wr_max;
45512c929bcSKevin Wolf     }
45612c929bcSKevin Wolf     if (arg->has_iops_max) {
45712c929bcSKevin Wolf         cfg.buckets[THROTTLE_OPS_TOTAL].max = arg->iops_max;
45812c929bcSKevin Wolf     }
45912c929bcSKevin Wolf     if (arg->has_iops_rd_max) {
46012c929bcSKevin Wolf         cfg.buckets[THROTTLE_OPS_READ].max = arg->iops_rd_max;
46112c929bcSKevin Wolf     }
46212c929bcSKevin Wolf     if (arg->has_iops_wr_max) {
46312c929bcSKevin Wolf         cfg.buckets[THROTTLE_OPS_WRITE].max = arg->iops_wr_max;
46412c929bcSKevin Wolf     }
46512c929bcSKevin Wolf 
46612c929bcSKevin Wolf     if (arg->has_bps_max_length) {
46712c929bcSKevin Wolf         cfg.buckets[THROTTLE_BPS_TOTAL].burst_length = arg->bps_max_length;
46812c929bcSKevin Wolf     }
46912c929bcSKevin Wolf     if (arg->has_bps_rd_max_length) {
47012c929bcSKevin Wolf         cfg.buckets[THROTTLE_BPS_READ].burst_length = arg->bps_rd_max_length;
47112c929bcSKevin Wolf     }
47212c929bcSKevin Wolf     if (arg->has_bps_wr_max_length) {
47312c929bcSKevin Wolf         cfg.buckets[THROTTLE_BPS_WRITE].burst_length = arg->bps_wr_max_length;
47412c929bcSKevin Wolf     }
47512c929bcSKevin Wolf     if (arg->has_iops_max_length) {
47612c929bcSKevin Wolf         cfg.buckets[THROTTLE_OPS_TOTAL].burst_length = arg->iops_max_length;
47712c929bcSKevin Wolf     }
47812c929bcSKevin Wolf     if (arg->has_iops_rd_max_length) {
47912c929bcSKevin Wolf         cfg.buckets[THROTTLE_OPS_READ].burst_length = arg->iops_rd_max_length;
48012c929bcSKevin Wolf     }
48112c929bcSKevin Wolf     if (arg->has_iops_wr_max_length) {
48212c929bcSKevin Wolf         cfg.buckets[THROTTLE_OPS_WRITE].burst_length = arg->iops_wr_max_length;
48312c929bcSKevin Wolf     }
48412c929bcSKevin Wolf 
48512c929bcSKevin Wolf     if (arg->has_iops_size) {
48612c929bcSKevin Wolf         cfg.op_size = arg->iops_size;
48712c929bcSKevin Wolf     }
48812c929bcSKevin Wolf 
48912c929bcSKevin Wolf     if (!throttle_is_valid(&cfg, errp)) {
490*b49f4755SStefan Hajnoczi         return;
49112c929bcSKevin Wolf     }
49212c929bcSKevin Wolf 
49312c929bcSKevin Wolf     if (throttle_enabled(&cfg)) {
49412c929bcSKevin Wolf         /* Enable I/O limits if they're not enabled yet, otherwise
49512c929bcSKevin Wolf          * just update the throttling group. */
49612c929bcSKevin Wolf         if (!blk_get_public(blk)->throttle_group_member.throttle_state) {
49754fde4ffSMarkus Armbruster             blk_io_limits_enable(blk, arg->group ?: arg->device ?: arg->id);
49854fde4ffSMarkus Armbruster         } else if (arg->group) {
49912c929bcSKevin Wolf             blk_io_limits_update_group(blk, arg->group);
50012c929bcSKevin Wolf         }
50112c929bcSKevin Wolf         /* Set the new throttling configuration */
50212c929bcSKevin Wolf         blk_set_io_limits(blk, &cfg);
50312c929bcSKevin Wolf     } else if (blk_get_public(blk)->throttle_group_member.throttle_state) {
50412c929bcSKevin Wolf         /* If all throttling settings are set to 0, disable I/O limits */
50512c929bcSKevin Wolf         blk_io_limits_disable(blk);
50612c929bcSKevin Wolf     }
50712c929bcSKevin Wolf }
50812c929bcSKevin Wolf 
qmp_block_latency_histogram_set(const char * id,bool has_boundaries,uint64List * boundaries,bool has_boundaries_read,uint64List * boundaries_read,bool has_boundaries_write,uint64List * boundaries_write,bool has_boundaries_append,uint64List * boundaries_append,bool has_boundaries_flush,uint64List * boundaries_flush,Error ** errp)50912c929bcSKevin Wolf void qmp_block_latency_histogram_set(
51012c929bcSKevin Wolf     const char *id,
51112c929bcSKevin Wolf     bool has_boundaries, uint64List *boundaries,
51212c929bcSKevin Wolf     bool has_boundaries_read, uint64List *boundaries_read,
51312c929bcSKevin Wolf     bool has_boundaries_write, uint64List *boundaries_write,
51452eb76f4SSam Li     bool has_boundaries_append, uint64List *boundaries_append,
51512c929bcSKevin Wolf     bool has_boundaries_flush, uint64List *boundaries_flush,
51612c929bcSKevin Wolf     Error **errp)
51712c929bcSKevin Wolf {
51812c929bcSKevin Wolf     BlockBackend *blk = qmp_get_blk(NULL, id, errp);
51912c929bcSKevin Wolf     BlockAcctStats *stats;
52012c929bcSKevin Wolf     int ret;
52112c929bcSKevin Wolf 
52212c929bcSKevin Wolf     if (!blk) {
52312c929bcSKevin Wolf         return;
52412c929bcSKevin Wolf     }
52512c929bcSKevin Wolf 
52612c929bcSKevin Wolf     stats = blk_get_stats(blk);
52712c929bcSKevin Wolf 
52812c929bcSKevin Wolf     if (!has_boundaries && !has_boundaries_read && !has_boundaries_write &&
52912c929bcSKevin Wolf         !has_boundaries_flush)
53012c929bcSKevin Wolf     {
53112c929bcSKevin Wolf         block_latency_histograms_clear(stats);
53212c929bcSKevin Wolf         return;
53312c929bcSKevin Wolf     }
53412c929bcSKevin Wolf 
53512c929bcSKevin Wolf     if (has_boundaries || has_boundaries_read) {
53612c929bcSKevin Wolf         ret = block_latency_histogram_set(
53712c929bcSKevin Wolf             stats, BLOCK_ACCT_READ,
53812c929bcSKevin Wolf             has_boundaries_read ? boundaries_read : boundaries);
53912c929bcSKevin Wolf         if (ret) {
54012c929bcSKevin Wolf             error_setg(errp, "Device '%s' set read boundaries fail", id);
54112c929bcSKevin Wolf             return;
54212c929bcSKevin Wolf         }
54312c929bcSKevin Wolf     }
54412c929bcSKevin Wolf 
54512c929bcSKevin Wolf     if (has_boundaries || has_boundaries_write) {
54612c929bcSKevin Wolf         ret = block_latency_histogram_set(
54712c929bcSKevin Wolf             stats, BLOCK_ACCT_WRITE,
54812c929bcSKevin Wolf             has_boundaries_write ? boundaries_write : boundaries);
54912c929bcSKevin Wolf         if (ret) {
55012c929bcSKevin Wolf             error_setg(errp, "Device '%s' set write boundaries fail", id);
55112c929bcSKevin Wolf             return;
55212c929bcSKevin Wolf         }
55312c929bcSKevin Wolf     }
55412c929bcSKevin Wolf 
55552eb76f4SSam Li     if (has_boundaries || has_boundaries_append) {
55652eb76f4SSam Li         ret = block_latency_histogram_set(
55752eb76f4SSam Li                 stats, BLOCK_ACCT_ZONE_APPEND,
55852eb76f4SSam Li                 has_boundaries_append ? boundaries_append : boundaries);
55952eb76f4SSam Li         if (ret) {
56052eb76f4SSam Li             error_setg(errp, "Device '%s' set append write boundaries fail", id);
56152eb76f4SSam Li             return;
56252eb76f4SSam Li         }
56352eb76f4SSam Li     }
56452eb76f4SSam Li 
56512c929bcSKevin Wolf     if (has_boundaries || has_boundaries_flush) {
56612c929bcSKevin Wolf         ret = block_latency_histogram_set(
56712c929bcSKevin Wolf             stats, BLOCK_ACCT_FLUSH,
56812c929bcSKevin Wolf             has_boundaries_flush ? boundaries_flush : boundaries);
56912c929bcSKevin Wolf         if (ret) {
57012c929bcSKevin Wolf             error_setg(errp, "Device '%s' set flush boundaries fail", id);
57112c929bcSKevin Wolf             return;
57212c929bcSKevin Wolf         }
57312c929bcSKevin Wolf     }
57412c929bcSKevin Wolf }
575