xref: /openbmc/qemu/block/export/export.c (revision d53be9ce55a38e430b88985f637f696bf99cbf0b)
156ee8626SKevin Wolf /*
256ee8626SKevin Wolf  * Common block export infrastructure
356ee8626SKevin Wolf  *
456ee8626SKevin Wolf  * Copyright (c) 2012, 2020 Red Hat, Inc.
556ee8626SKevin Wolf  *
656ee8626SKevin Wolf  * Authors:
756ee8626SKevin Wolf  * Paolo Bonzini <pbonzini@redhat.com>
856ee8626SKevin Wolf  * Kevin Wolf <kwolf@redhat.com>
956ee8626SKevin Wolf  *
1056ee8626SKevin Wolf  * This work is licensed under the terms of the GNU GPL, version 2 or
1156ee8626SKevin Wolf  * later.  See the COPYING file in the top-level directory.
1256ee8626SKevin Wolf  */
1356ee8626SKevin Wolf 
1456ee8626SKevin Wolf #include "qemu/osdep.h"
1556ee8626SKevin Wolf 
169b562c64SKevin Wolf #include "block/block.h"
179b562c64SKevin Wolf #include "sysemu/block-backend.h"
1856ee8626SKevin Wolf #include "block/export.h"
1956ee8626SKevin Wolf #include "block/nbd.h"
2056ee8626SKevin Wolf #include "qapi/error.h"
2156ee8626SKevin Wolf #include "qapi/qapi-commands-block-export.h"
22*d53be9ceSKevin Wolf #include "qemu/id.h"
2356ee8626SKevin Wolf 
2456ee8626SKevin Wolf static const BlockExportDriver *blk_exp_drivers[] = {
2556ee8626SKevin Wolf     &blk_exp_nbd,
2656ee8626SKevin Wolf };
2756ee8626SKevin Wolf 
28bc4ee65bSKevin Wolf /* Only accessed from the main thread */
29bc4ee65bSKevin Wolf static QLIST_HEAD(, BlockExport) block_exports =
30bc4ee65bSKevin Wolf     QLIST_HEAD_INITIALIZER(block_exports);
31bc4ee65bSKevin Wolf 
32*d53be9ceSKevin Wolf static BlockExport *blk_exp_find(const char *id)
33*d53be9ceSKevin Wolf {
34*d53be9ceSKevin Wolf     BlockExport *exp;
35*d53be9ceSKevin Wolf 
36*d53be9ceSKevin Wolf     QLIST_FOREACH(exp, &block_exports, next) {
37*d53be9ceSKevin Wolf         if (strcmp(id, exp->id) == 0) {
38*d53be9ceSKevin Wolf             return exp;
39*d53be9ceSKevin Wolf         }
40*d53be9ceSKevin Wolf     }
41*d53be9ceSKevin Wolf 
42*d53be9ceSKevin Wolf     return NULL;
43*d53be9ceSKevin Wolf }
44*d53be9ceSKevin Wolf 
4556ee8626SKevin Wolf static const BlockExportDriver *blk_exp_find_driver(BlockExportType type)
4656ee8626SKevin Wolf {
4756ee8626SKevin Wolf     int i;
4856ee8626SKevin Wolf 
4956ee8626SKevin Wolf     for (i = 0; i < ARRAY_SIZE(blk_exp_drivers); i++) {
5056ee8626SKevin Wolf         if (blk_exp_drivers[i]->type == type) {
5156ee8626SKevin Wolf             return blk_exp_drivers[i];
5256ee8626SKevin Wolf         }
5356ee8626SKevin Wolf     }
5456ee8626SKevin Wolf     return NULL;
5556ee8626SKevin Wolf }
5656ee8626SKevin Wolf 
579b562c64SKevin Wolf BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
5856ee8626SKevin Wolf {
5956ee8626SKevin Wolf     const BlockExportDriver *drv;
60a6ff7989SKevin Wolf     BlockExport *exp;
61a6ff7989SKevin Wolf     int ret;
6256ee8626SKevin Wolf 
63*d53be9ceSKevin Wolf     if (!id_wellformed(export->id)) {
64*d53be9ceSKevin Wolf         error_setg(errp, "Invalid block export id");
65*d53be9ceSKevin Wolf         return NULL;
66*d53be9ceSKevin Wolf     }
67*d53be9ceSKevin Wolf     if (blk_exp_find(export->id)) {
68*d53be9ceSKevin Wolf         error_setg(errp, "Block export id '%s' is already in use", export->id);
69*d53be9ceSKevin Wolf         return NULL;
70*d53be9ceSKevin Wolf     }
71*d53be9ceSKevin Wolf 
7256ee8626SKevin Wolf     drv = blk_exp_find_driver(export->type);
7356ee8626SKevin Wolf     if (!drv) {
7456ee8626SKevin Wolf         error_setg(errp, "No driver found for the requested export type");
759b562c64SKevin Wolf         return NULL;
7656ee8626SKevin Wolf     }
7756ee8626SKevin Wolf 
78a6ff7989SKevin Wolf     assert(drv->instance_size >= sizeof(BlockExport));
79a6ff7989SKevin Wolf     exp = g_malloc0(drv->instance_size);
80a6ff7989SKevin Wolf     *exp = (BlockExport) {
81a6ff7989SKevin Wolf         .drv        = drv,
82a6ff7989SKevin Wolf         .refcount   = 1,
83*d53be9ceSKevin Wolf         .id         = g_strdup(export->id),
84a6ff7989SKevin Wolf     };
85a6ff7989SKevin Wolf 
86a6ff7989SKevin Wolf     ret = drv->create(exp, export, errp);
87a6ff7989SKevin Wolf     if (ret < 0) {
88*d53be9ceSKevin Wolf         g_free(exp->id);
89a6ff7989SKevin Wolf         g_free(exp);
90a6ff7989SKevin Wolf         return NULL;
91a6ff7989SKevin Wolf     }
92a6ff7989SKevin Wolf 
93bc4ee65bSKevin Wolf     QLIST_INSERT_HEAD(&block_exports, exp, next);
94a6ff7989SKevin Wolf     return exp;
959b562c64SKevin Wolf }
969b562c64SKevin Wolf 
978612c686SKevin Wolf /* Callers must hold exp->ctx lock */
98c69de1beSKevin Wolf void blk_exp_ref(BlockExport *exp)
99c69de1beSKevin Wolf {
100c69de1beSKevin Wolf     assert(exp->refcount > 0);
101c69de1beSKevin Wolf     exp->refcount++;
102c69de1beSKevin Wolf }
103c69de1beSKevin Wolf 
104bc4ee65bSKevin Wolf /* Runs in the main thread */
105bc4ee65bSKevin Wolf static void blk_exp_delete_bh(void *opaque)
106bc4ee65bSKevin Wolf {
107bc4ee65bSKevin Wolf     BlockExport *exp = opaque;
108bc4ee65bSKevin Wolf     AioContext *aio_context = exp->ctx;
109bc4ee65bSKevin Wolf 
110bc4ee65bSKevin Wolf     aio_context_acquire(aio_context);
111bc4ee65bSKevin Wolf 
112bc4ee65bSKevin Wolf     assert(exp->refcount == 0);
113bc4ee65bSKevin Wolf     QLIST_REMOVE(exp, next);
114bc4ee65bSKevin Wolf     exp->drv->delete(exp);
115*d53be9ceSKevin Wolf     g_free(exp->id);
116bc4ee65bSKevin Wolf     g_free(exp);
117bc4ee65bSKevin Wolf 
118bc4ee65bSKevin Wolf     aio_context_release(aio_context);
119bc4ee65bSKevin Wolf }
120bc4ee65bSKevin Wolf 
1218612c686SKevin Wolf /* Callers must hold exp->ctx lock */
122c69de1beSKevin Wolf void blk_exp_unref(BlockExport *exp)
123c69de1beSKevin Wolf {
124c69de1beSKevin Wolf     assert(exp->refcount > 0);
125c69de1beSKevin Wolf     if (--exp->refcount == 0) {
126bc4ee65bSKevin Wolf         /* Touch the block_exports list only in the main thread */
127bc4ee65bSKevin Wolf         aio_bh_schedule_oneshot(qemu_get_aio_context(), blk_exp_delete_bh,
128bc4ee65bSKevin Wolf                                 exp);
129c69de1beSKevin Wolf     }
130c69de1beSKevin Wolf }
131c69de1beSKevin Wolf 
132bc4ee65bSKevin Wolf /*
133bc4ee65bSKevin Wolf  * Drops the user reference to the export and requests that all client
134bc4ee65bSKevin Wolf  * connections and other internally held references start to shut down. When
135bc4ee65bSKevin Wolf  * the function returns, there may still be active references while the export
136bc4ee65bSKevin Wolf  * is in the process of shutting down.
137bc4ee65bSKevin Wolf  *
138bc4ee65bSKevin Wolf  * Acquires exp->ctx internally. Callers must *not* hold the lock.
139bc4ee65bSKevin Wolf  */
140bc4ee65bSKevin Wolf void blk_exp_request_shutdown(BlockExport *exp)
141bc4ee65bSKevin Wolf {
142bc4ee65bSKevin Wolf     AioContext *aio_context = exp->ctx;
143bc4ee65bSKevin Wolf 
144bc4ee65bSKevin Wolf     aio_context_acquire(aio_context);
145bc4ee65bSKevin Wolf     exp->drv->request_shutdown(exp);
146bc4ee65bSKevin Wolf     aio_context_release(aio_context);
147bc4ee65bSKevin Wolf }
148bc4ee65bSKevin Wolf 
149bc4ee65bSKevin Wolf /*
150bc4ee65bSKevin Wolf  * Returns whether a block export of the given type exists.
151bc4ee65bSKevin Wolf  * type == BLOCK_EXPORT_TYPE__MAX checks for an export of any type.
152bc4ee65bSKevin Wolf  */
153bc4ee65bSKevin Wolf static bool blk_exp_has_type(BlockExportType type)
154bc4ee65bSKevin Wolf {
155bc4ee65bSKevin Wolf     BlockExport *exp;
156bc4ee65bSKevin Wolf 
157bc4ee65bSKevin Wolf     if (type == BLOCK_EXPORT_TYPE__MAX) {
158bc4ee65bSKevin Wolf         return !QLIST_EMPTY(&block_exports);
159bc4ee65bSKevin Wolf     }
160bc4ee65bSKevin Wolf 
161bc4ee65bSKevin Wolf     QLIST_FOREACH(exp, &block_exports, next) {
162bc4ee65bSKevin Wolf         if (exp->drv->type == type) {
163bc4ee65bSKevin Wolf             return true;
164bc4ee65bSKevin Wolf         }
165bc4ee65bSKevin Wolf     }
166bc4ee65bSKevin Wolf 
167bc4ee65bSKevin Wolf     return false;
168bc4ee65bSKevin Wolf }
169bc4ee65bSKevin Wolf 
170bc4ee65bSKevin Wolf /* type == BLOCK_EXPORT_TYPE__MAX for all types */
171bc4ee65bSKevin Wolf void blk_exp_close_all_type(BlockExportType type)
172bc4ee65bSKevin Wolf {
173bc4ee65bSKevin Wolf     BlockExport *exp, *next;
174bc4ee65bSKevin Wolf 
175bc4ee65bSKevin Wolf     assert(in_aio_context_home_thread(qemu_get_aio_context()));
176bc4ee65bSKevin Wolf 
177bc4ee65bSKevin Wolf     QLIST_FOREACH_SAFE(exp, &block_exports, next, next) {
178bc4ee65bSKevin Wolf         if (type != BLOCK_EXPORT_TYPE__MAX && exp->drv->type != type) {
179bc4ee65bSKevin Wolf             continue;
180bc4ee65bSKevin Wolf         }
181bc4ee65bSKevin Wolf         blk_exp_request_shutdown(exp);
182bc4ee65bSKevin Wolf     }
183bc4ee65bSKevin Wolf 
184bc4ee65bSKevin Wolf     AIO_WAIT_WHILE(NULL, blk_exp_has_type(type));
185bc4ee65bSKevin Wolf }
186bc4ee65bSKevin Wolf 
187bc4ee65bSKevin Wolf void blk_exp_close_all(void)
188bc4ee65bSKevin Wolf {
189bc4ee65bSKevin Wolf     blk_exp_close_all_type(BLOCK_EXPORT_TYPE__MAX);
190bc4ee65bSKevin Wolf }
191bc4ee65bSKevin Wolf 
1929b562c64SKevin Wolf void qmp_block_export_add(BlockExportOptions *export, Error **errp)
1939b562c64SKevin Wolf {
1949b562c64SKevin Wolf     blk_exp_add(export, errp);
19556ee8626SKevin Wolf }
196