xref: /openbmc/qemu/block/export/export.c (revision 3c3bc462adeb561f5dfdcbb84ae691c95ccef916)
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 
32*3c3bc462SKevin Wolf 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,
833859ad36SKevin 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);
146*3c3bc462SKevin Wolf 
147*3c3bc462SKevin Wolf     /*
148*3c3bc462SKevin Wolf      * If the user doesn't own the export any more, it is already shutting
149*3c3bc462SKevin Wolf      * down. We must not call .request_shutdown and decrease the refcount a
150*3c3bc462SKevin Wolf      * second time.
151*3c3bc462SKevin Wolf      */
152*3c3bc462SKevin Wolf     if (!exp->user_owned) {
153*3c3bc462SKevin Wolf         goto out;
154*3c3bc462SKevin Wolf     }
155*3c3bc462SKevin Wolf 
156bc4ee65bSKevin Wolf     exp->drv->request_shutdown(exp);
1573859ad36SKevin Wolf 
1583859ad36SKevin Wolf     assert(exp->user_owned);
1593859ad36SKevin Wolf     exp->user_owned = false;
1603859ad36SKevin Wolf     blk_exp_unref(exp);
1613859ad36SKevin Wolf 
162*3c3bc462SKevin Wolf out:
163bc4ee65bSKevin Wolf     aio_context_release(aio_context);
164bc4ee65bSKevin Wolf }
165bc4ee65bSKevin Wolf 
166bc4ee65bSKevin Wolf /*
167bc4ee65bSKevin Wolf  * Returns whether a block export of the given type exists.
168bc4ee65bSKevin Wolf  * type == BLOCK_EXPORT_TYPE__MAX checks for an export of any type.
169bc4ee65bSKevin Wolf  */
170bc4ee65bSKevin Wolf static bool blk_exp_has_type(BlockExportType type)
171bc4ee65bSKevin Wolf {
172bc4ee65bSKevin Wolf     BlockExport *exp;
173bc4ee65bSKevin Wolf 
174bc4ee65bSKevin Wolf     if (type == BLOCK_EXPORT_TYPE__MAX) {
175bc4ee65bSKevin Wolf         return !QLIST_EMPTY(&block_exports);
176bc4ee65bSKevin Wolf     }
177bc4ee65bSKevin Wolf 
178bc4ee65bSKevin Wolf     QLIST_FOREACH(exp, &block_exports, next) {
179bc4ee65bSKevin Wolf         if (exp->drv->type == type) {
180bc4ee65bSKevin Wolf             return true;
181bc4ee65bSKevin Wolf         }
182bc4ee65bSKevin Wolf     }
183bc4ee65bSKevin Wolf 
184bc4ee65bSKevin Wolf     return false;
185bc4ee65bSKevin Wolf }
186bc4ee65bSKevin Wolf 
187bc4ee65bSKevin Wolf /* type == BLOCK_EXPORT_TYPE__MAX for all types */
188bc4ee65bSKevin Wolf void blk_exp_close_all_type(BlockExportType type)
189bc4ee65bSKevin Wolf {
190bc4ee65bSKevin Wolf     BlockExport *exp, *next;
191bc4ee65bSKevin Wolf 
192bc4ee65bSKevin Wolf     assert(in_aio_context_home_thread(qemu_get_aio_context()));
193bc4ee65bSKevin Wolf 
194bc4ee65bSKevin Wolf     QLIST_FOREACH_SAFE(exp, &block_exports, next, next) {
195bc4ee65bSKevin Wolf         if (type != BLOCK_EXPORT_TYPE__MAX && exp->drv->type != type) {
196bc4ee65bSKevin Wolf             continue;
197bc4ee65bSKevin Wolf         }
198bc4ee65bSKevin Wolf         blk_exp_request_shutdown(exp);
199bc4ee65bSKevin Wolf     }
200bc4ee65bSKevin Wolf 
201bc4ee65bSKevin Wolf     AIO_WAIT_WHILE(NULL, blk_exp_has_type(type));
202bc4ee65bSKevin Wolf }
203bc4ee65bSKevin Wolf 
204bc4ee65bSKevin Wolf void blk_exp_close_all(void)
205bc4ee65bSKevin Wolf {
206bc4ee65bSKevin Wolf     blk_exp_close_all_type(BLOCK_EXPORT_TYPE__MAX);
207bc4ee65bSKevin Wolf }
208bc4ee65bSKevin Wolf 
2099b562c64SKevin Wolf void qmp_block_export_add(BlockExportOptions *export, Error **errp)
2109b562c64SKevin Wolf {
2119b562c64SKevin Wolf     blk_exp_add(export, errp);
21256ee8626SKevin Wolf }
213*3c3bc462SKevin Wolf 
214*3c3bc462SKevin Wolf void qmp_block_export_del(const char *id,
215*3c3bc462SKevin Wolf                           bool has_mode, BlockExportRemoveMode mode,
216*3c3bc462SKevin Wolf                           Error **errp)
217*3c3bc462SKevin Wolf {
218*3c3bc462SKevin Wolf     ERRP_GUARD();
219*3c3bc462SKevin Wolf     BlockExport *exp;
220*3c3bc462SKevin Wolf 
221*3c3bc462SKevin Wolf     exp = blk_exp_find(id);
222*3c3bc462SKevin Wolf     if (exp == NULL) {
223*3c3bc462SKevin Wolf         error_setg(errp, "Export '%s' is not found", id);
224*3c3bc462SKevin Wolf         return;
225*3c3bc462SKevin Wolf     }
226*3c3bc462SKevin Wolf     if (!exp->user_owned) {
227*3c3bc462SKevin Wolf         error_setg(errp, "Export '%s' is already shutting down", id);
228*3c3bc462SKevin Wolf         return;
229*3c3bc462SKevin Wolf     }
230*3c3bc462SKevin Wolf 
231*3c3bc462SKevin Wolf     if (!has_mode) {
232*3c3bc462SKevin Wolf         mode = BLOCK_EXPORT_REMOVE_MODE_SAFE;
233*3c3bc462SKevin Wolf     }
234*3c3bc462SKevin Wolf     if (mode == BLOCK_EXPORT_REMOVE_MODE_SAFE && exp->refcount > 1) {
235*3c3bc462SKevin Wolf         error_setg(errp, "export '%s' still in use", exp->id);
236*3c3bc462SKevin Wolf         error_append_hint(errp, "Use mode='hard' to force client "
237*3c3bc462SKevin Wolf                           "disconnect\n");
238*3c3bc462SKevin Wolf         return;
239*3c3bc462SKevin Wolf     }
240*3c3bc462SKevin Wolf 
241*3c3bc462SKevin Wolf     blk_exp_request_shutdown(exp);
242*3c3bc462SKevin Wolf }
243