qemu
1/*
2* Block layer code related to image options amend
3*
4* Copyright (c) 2018 Kevin Wolf <kwolf@redhat.com>
5* Copyright (c) 2020 Red Hat. Inc
6*
7* Heavily based on create.c
8*
9* Permission is hereby granted, free of charge, to any person obtaining a copy
10* of this software and associated documentation files (the "Software"), to deal
11* in the Software without restriction, including without limitation the rights
12* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13* copies of the Software, and to permit persons to whom the Software is
14* furnished to do so, subject to the following conditions:
15*
16* The above copyright notice and this permission notice shall be included in
17* all copies or substantial portions of the Software.
18*
19* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25* THE SOFTWARE.
26*/
27
28#include "qemu/osdep.h"29#include "block/block-io.h"30#include "block/block_int.h"31#include "qemu/job.h"32#include "qemu/main-loop.h"33#include "qapi/qapi-commands-block-core.h"34#include "qapi/qapi-visit-block-core.h"35#include "qapi/clone-visitor.h"36#include "qapi/error.h"37
38typedef struct BlockdevAmendJob {39Job common;40BlockdevAmendOptions *opts;41BlockDriverState *bs;42bool force;43} BlockdevAmendJob;44
45static int coroutine_fn blockdev_amend_run(Job *job, Error **errp)46{
47BlockdevAmendJob *s = container_of(job, BlockdevAmendJob, common);48int ret;49GRAPH_RDLOCK_GUARD();50
51job_progress_set_remaining(&s->common, 1);52ret = s->bs->drv->bdrv_co_amend(s->bs, s->opts, s->force, errp);53job_progress_update(&s->common, 1);54qapi_free_BlockdevAmendOptions(s->opts);55return ret;56}
57
58static int GRAPH_RDLOCK59blockdev_amend_pre_run(BlockdevAmendJob *s, Error **errp)60{
61if (s->bs->drv->bdrv_amend_pre_run) {62return s->bs->drv->bdrv_amend_pre_run(s->bs, errp);63}64
65return 0;66}
67
68static void blockdev_amend_free(Job *job)69{
70BlockdevAmendJob *s = container_of(job, BlockdevAmendJob, common);71
72bdrv_graph_rdlock_main_loop();73if (s->bs->drv->bdrv_amend_clean) {74s->bs->drv->bdrv_amend_clean(s->bs);75}76bdrv_graph_rdunlock_main_loop();77
78bdrv_unref(s->bs);79}
80
81static const JobDriver blockdev_amend_job_driver = {82.instance_size = sizeof(BlockdevAmendJob),83.job_type = JOB_TYPE_AMEND,84.run = blockdev_amend_run,85.free = blockdev_amend_free,86};87
88void qmp_x_blockdev_amend(const char *job_id,89const char *node_name,90BlockdevAmendOptions *options,91bool has_force,92bool force,93Error **errp)94{
95BlockdevAmendJob *s;96const char *fmt = BlockdevDriver_str(options->driver);97BlockDriver *drv = bdrv_find_format(fmt);98BlockDriverState *bs;99
100GRAPH_RDLOCK_GUARD_MAINLOOP();101
102bs = bdrv_lookup_bs(NULL, node_name, errp);103if (!bs) {104return;105}106
107if (!drv) {108error_setg(errp, "Block driver '%s' not found or not supported", fmt);109return;110}111
112/*113* If the driver is in the schema, we know that it exists. But it may not
114* be whitelisted.
115*/
116if (bdrv_uses_whitelist() && !bdrv_is_whitelisted(drv, false)) {117error_setg(errp, "Driver is not whitelisted");118return;119}120
121if (bs->drv != drv) {122error_setg(errp,123"x-blockdev-amend doesn't support changing the block driver");124return;125}126
127/* Error out if the driver doesn't support .bdrv_co_amend */128if (!drv->bdrv_co_amend) {129error_setg(errp, "Driver does not support x-blockdev-amend");130return;131}132
133/* Create the block job */134s = job_create(job_id, &blockdev_amend_job_driver, NULL,135bdrv_get_aio_context(bs), JOB_DEFAULT | JOB_MANUAL_DISMISS,136NULL, NULL, errp);137if (!s) {138return;139}140
141bdrv_ref(bs);142s->bs = bs,143s->opts = QAPI_CLONE(BlockdevAmendOptions, options),144s->force = has_force ? force : false;145
146if (blockdev_amend_pre_run(s, errp)) {147job_early_fail(&s->common);148return;149}150
151job_start(&s->common);152}
153