xref: /openbmc/qemu/block/export/export.c (revision 3859ad36f0bdf45a6610d93296b52c9604b6d6f7)
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"
22d53be9ceSKevin 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 
32d53be9ceSKevin Wolf static BlockExport *blk_exp_find(const char *id)
33d53be9ceSKevin Wolf {
34d53be9ceSKevin Wolf     BlockExport *exp;
35d53be9ceSKevin Wolf 
36d53be9ceSKevin Wolf     QLIST_FOREACH(exp, &block_exports, next) {
37d53be9ceSKevin Wolf         if (strcmp(id, exp->id) == 0) {
38d53be9ceSKevin Wolf             return exp;
39d53be9ceSKevin Wolf         }
40d53be9ceSKevin Wolf     }
41d53be9ceSKevin Wolf 
42d53be9ceSKevin Wolf     return NULL;
43d53be9ceSKevin Wolf }
44d53be9ceSKevin 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 
63d53be9ceSKevin Wolf     if (!id_wellformed(export->id)) {
64d53be9ceSKevin Wolf         error_setg(errp, "Invalid block export id");
65d53be9ceSKevin Wolf         return NULL;
66d53be9ceSKevin Wolf     }
67d53be9ceSKevin Wolf     if (blk_exp_find(export->id)) {
68d53be9ceSKevin Wolf         error_setg(errp, "Block export id '%s' is already in use", export->id);
69d53be9ceSKevin Wolf         return NULL;
70d53be9ceSKevin Wolf     }
71d53be9ceSKevin 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*3859ad36SKevin Wolf         .user_owned = true,
84d53be9ceSKevin Wolf         .id         = g_strdup(export->id),
85a6ff7989SKevin Wolf     };
86a6ff7989SKevin Wolf 
87a6ff7989SKevin Wolf     ret = drv->create(exp, export, errp);
88a6ff7989SKevin Wolf     if (ret < 0) {
89d53be9ceSKevin Wolf         g_free(exp->id);
90a6ff7989SKevin Wolf         g_free(exp);
91a6ff7989SKevin Wolf         return NULL;
92a6ff7989SKevin Wolf     }
93a6ff7989SKevin Wolf 
94bc4ee65bSKevin Wolf     QLIST_INSERT_HEAD(&block_exports, exp, next);
95a6ff7989SKevin Wolf     return exp;
969b562c64SKevin Wolf }
979b562c64SKevin Wolf 
988612c686SKevin Wolf /* Callers must hold exp->ctx lock */
99c69de1beSKevin Wolf void blk_exp_ref(BlockExport *exp)
100c69de1beSKevin Wolf {
101c69de1beSKevin Wolf     assert(exp->refcount > 0);
102c69de1beSKevin Wolf     exp->refcount++;
103c69de1beSKevin Wolf }
104c69de1beSKevin Wolf 
105bc4ee65bSKevin Wolf /* Runs in the main thread */
106bc4ee65bSKevin Wolf static void blk_exp_delete_bh(void *opaque)
107bc4ee65bSKevin Wolf {
108bc4ee65bSKevin Wolf     BlockExport *exp = opaque;
109bc4ee65bSKevin Wolf     AioContext *aio_context = exp->ctx;
110bc4ee65bSKevin Wolf 
111bc4ee65bSKevin Wolf     aio_context_acquire(aio_context);
112bc4ee65bSKevin Wolf 
113bc4ee65bSKevin Wolf     assert(exp->refcount == 0);
114bc4ee65bSKevin Wolf     QLIST_REMOVE(exp, next);
115bc4ee65bSKevin Wolf     exp->drv->delete(exp);
116d53be9ceSKevin Wolf     g_free(exp->id);
117bc4ee65bSKevin Wolf     g_free(exp);
118bc4ee65bSKevin Wolf 
119bc4ee65bSKevin Wolf     aio_context_release(aio_context);
120bc4ee65bSKevin Wolf }
121bc4ee65bSKevin Wolf 
1228612c686SKevin Wolf /* Callers must hold exp->ctx lock */
123c69de1beSKevin Wolf void blk_exp_unref(BlockExport *exp)
124c69de1beSKevin Wolf {
125c69de1beSKevin Wolf     assert(exp->refcount > 0);
126c69de1beSKevin Wolf     if (--exp->refcount == 0) {
127bc4ee65bSKevin Wolf         /* Touch the block_exports list only in the main thread */
128bc4ee65bSKevin Wolf         aio_bh_schedule_oneshot(qemu_get_aio_context(), blk_exp_delete_bh,
129bc4ee65bSKevin Wolf                                 exp);
130c69de1beSKevin Wolf     }
131c69de1beSKevin Wolf }
132c69de1beSKevin Wolf 
133bc4ee65bSKevin Wolf /*
134bc4ee65bSKevin Wolf  * Drops the user reference to the export and requests that all client
135bc4ee65bSKevin Wolf  * connections and other internally held references start to shut down. When
136bc4ee65bSKevin Wolf  * the function returns, there may still be active references while the export
137bc4ee65bSKevin Wolf  * is in the process of shutting down.
138bc4ee65bSKevin Wolf  *
139bc4ee65bSKevin Wolf  * Acquires exp->ctx internally. Callers must *not* hold the lock.
140bc4ee65bSKevin Wolf  */
141bc4ee65bSKevin Wolf void blk_exp_request_shutdown(BlockExport *exp)
142bc4ee65bSKevin Wolf {
143bc4ee65bSKevin Wolf     AioContext *aio_context = exp->ctx;
144bc4ee65bSKevin Wolf 
145bc4ee65bSKevin Wolf     aio_context_acquire(aio_context);
146bc4ee65bSKevin Wolf     exp->drv->request_shutdown(exp);
147*3859ad36SKevin Wolf 
148*3859ad36SKevin Wolf     assert(exp->user_owned);
149*3859ad36SKevin Wolf     exp->user_owned = false;
150*3859ad36SKevin Wolf     blk_exp_unref(exp);
151*3859ad36SKevin Wolf 
152bc4ee65bSKevin Wolf     aio_context_release(aio_context);
153bc4ee65bSKevin Wolf }
154bc4ee65bSKevin Wolf 
155bc4ee65bSKevin Wolf /*
156bc4ee65bSKevin Wolf  * Returns whether a block export of the given type exists.
157bc4ee65bSKevin Wolf  * type == BLOCK_EXPORT_TYPE__MAX checks for an export of any type.
158bc4ee65bSKevin Wolf  */
159bc4ee65bSKevin Wolf static bool blk_exp_has_type(BlockExportType type)
160bc4ee65bSKevin Wolf {
161bc4ee65bSKevin Wolf     BlockExport *exp;
162bc4ee65bSKevin Wolf 
163bc4ee65bSKevin Wolf     if (type == BLOCK_EXPORT_TYPE__MAX) {
164bc4ee65bSKevin Wolf         return !QLIST_EMPTY(&block_exports);
165bc4ee65bSKevin Wolf     }
166bc4ee65bSKevin Wolf 
167bc4ee65bSKevin Wolf     QLIST_FOREACH(exp, &block_exports, next) {
168bc4ee65bSKevin Wolf         if (exp->drv->type == type) {
169bc4ee65bSKevin Wolf             return true;
170bc4ee65bSKevin Wolf         }
171bc4ee65bSKevin Wolf     }
172bc4ee65bSKevin Wolf 
173bc4ee65bSKevin Wolf     return false;
174bc4ee65bSKevin Wolf }
175bc4ee65bSKevin Wolf 
176bc4ee65bSKevin Wolf /* type == BLOCK_EXPORT_TYPE__MAX for all types */
177bc4ee65bSKevin Wolf void blk_exp_close_all_type(BlockExportType type)
178bc4ee65bSKevin Wolf {
179bc4ee65bSKevin Wolf     BlockExport *exp, *next;
180bc4ee65bSKevin Wolf 
181bc4ee65bSKevin Wolf     assert(in_aio_context_home_thread(qemu_get_aio_context()));
182bc4ee65bSKevin Wolf 
183bc4ee65bSKevin Wolf     QLIST_FOREACH_SAFE(exp, &block_exports, next, next) {
184bc4ee65bSKevin Wolf         if (type != BLOCK_EXPORT_TYPE__MAX && exp->drv->type != type) {
185bc4ee65bSKevin Wolf             continue;
186bc4ee65bSKevin Wolf         }
187bc4ee65bSKevin Wolf         blk_exp_request_shutdown(exp);
188bc4ee65bSKevin Wolf     }
189bc4ee65bSKevin Wolf 
190bc4ee65bSKevin Wolf     AIO_WAIT_WHILE(NULL, blk_exp_has_type(type));
191bc4ee65bSKevin Wolf }
192bc4ee65bSKevin Wolf 
193bc4ee65bSKevin Wolf void blk_exp_close_all(void)
194bc4ee65bSKevin Wolf {
195bc4ee65bSKevin Wolf     blk_exp_close_all_type(BLOCK_EXPORT_TYPE__MAX);
196bc4ee65bSKevin Wolf }
197bc4ee65bSKevin Wolf 
1989b562c64SKevin Wolf void qmp_block_export_add(BlockExportOptions *export, Error **errp)
1999b562c64SKevin Wolf {
2009b562c64SKevin Wolf     blk_exp_add(export, errp);
20156ee8626SKevin Wolf }
202