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