xref: /openbmc/qemu/block/export/export.c (revision 1a9f7a804f52caee6bc6769a8bb0a018e6c8ec81)
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*1a9f7a80SKevin Wolf #include "qapi/qapi-events-block-export.h"
23d53be9ceSKevin Wolf #include "qemu/id.h"
2456ee8626SKevin Wolf 
2556ee8626SKevin Wolf static const BlockExportDriver *blk_exp_drivers[] = {
2656ee8626SKevin Wolf     &blk_exp_nbd,
2756ee8626SKevin Wolf };
2856ee8626SKevin Wolf 
29bc4ee65bSKevin Wolf /* Only accessed from the main thread */
30bc4ee65bSKevin Wolf static QLIST_HEAD(, BlockExport) block_exports =
31bc4ee65bSKevin Wolf     QLIST_HEAD_INITIALIZER(block_exports);
32bc4ee65bSKevin Wolf 
333c3bc462SKevin Wolf BlockExport *blk_exp_find(const char *id)
34d53be9ceSKevin Wolf {
35d53be9ceSKevin Wolf     BlockExport *exp;
36d53be9ceSKevin Wolf 
37d53be9ceSKevin Wolf     QLIST_FOREACH(exp, &block_exports, next) {
38d53be9ceSKevin Wolf         if (strcmp(id, exp->id) == 0) {
39d53be9ceSKevin Wolf             return exp;
40d53be9ceSKevin Wolf         }
41d53be9ceSKevin Wolf     }
42d53be9ceSKevin Wolf 
43d53be9ceSKevin Wolf     return NULL;
44d53be9ceSKevin Wolf }
45d53be9ceSKevin Wolf 
4656ee8626SKevin Wolf static const BlockExportDriver *blk_exp_find_driver(BlockExportType type)
4756ee8626SKevin Wolf {
4856ee8626SKevin Wolf     int i;
4956ee8626SKevin Wolf 
5056ee8626SKevin Wolf     for (i = 0; i < ARRAY_SIZE(blk_exp_drivers); i++) {
5156ee8626SKevin Wolf         if (blk_exp_drivers[i]->type == type) {
5256ee8626SKevin Wolf             return blk_exp_drivers[i];
5356ee8626SKevin Wolf         }
5456ee8626SKevin Wolf     }
5556ee8626SKevin Wolf     return NULL;
5656ee8626SKevin Wolf }
5756ee8626SKevin Wolf 
589b562c64SKevin Wolf BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
5956ee8626SKevin Wolf {
6056ee8626SKevin Wolf     const BlockExportDriver *drv;
61a6ff7989SKevin Wolf     BlockExport *exp;
62a6ff7989SKevin Wolf     int ret;
6356ee8626SKevin Wolf 
64d53be9ceSKevin Wolf     if (!id_wellformed(export->id)) {
65d53be9ceSKevin Wolf         error_setg(errp, "Invalid block export id");
66d53be9ceSKevin Wolf         return NULL;
67d53be9ceSKevin Wolf     }
68d53be9ceSKevin Wolf     if (blk_exp_find(export->id)) {
69d53be9ceSKevin Wolf         error_setg(errp, "Block export id '%s' is already in use", export->id);
70d53be9ceSKevin Wolf         return NULL;
71d53be9ceSKevin Wolf     }
72d53be9ceSKevin Wolf 
7356ee8626SKevin Wolf     drv = blk_exp_find_driver(export->type);
7456ee8626SKevin Wolf     if (!drv) {
7556ee8626SKevin Wolf         error_setg(errp, "No driver found for the requested export type");
769b562c64SKevin Wolf         return NULL;
7756ee8626SKevin Wolf     }
7856ee8626SKevin Wolf 
79a6ff7989SKevin Wolf     assert(drv->instance_size >= sizeof(BlockExport));
80a6ff7989SKevin Wolf     exp = g_malloc0(drv->instance_size);
81a6ff7989SKevin Wolf     *exp = (BlockExport) {
82a6ff7989SKevin Wolf         .drv        = drv,
83a6ff7989SKevin Wolf         .refcount   = 1,
843859ad36SKevin Wolf         .user_owned = true,
85d53be9ceSKevin Wolf         .id         = g_strdup(export->id),
86a6ff7989SKevin Wolf     };
87a6ff7989SKevin Wolf 
88a6ff7989SKevin Wolf     ret = drv->create(exp, export, errp);
89a6ff7989SKevin Wolf     if (ret < 0) {
90d53be9ceSKevin Wolf         g_free(exp->id);
91a6ff7989SKevin Wolf         g_free(exp);
92a6ff7989SKevin Wolf         return NULL;
93a6ff7989SKevin Wolf     }
94a6ff7989SKevin Wolf 
95bc4ee65bSKevin Wolf     QLIST_INSERT_HEAD(&block_exports, exp, next);
96a6ff7989SKevin Wolf     return exp;
979b562c64SKevin Wolf }
989b562c64SKevin Wolf 
998612c686SKevin Wolf /* Callers must hold exp->ctx lock */
100c69de1beSKevin Wolf void blk_exp_ref(BlockExport *exp)
101c69de1beSKevin Wolf {
102c69de1beSKevin Wolf     assert(exp->refcount > 0);
103c69de1beSKevin Wolf     exp->refcount++;
104c69de1beSKevin Wolf }
105c69de1beSKevin Wolf 
106bc4ee65bSKevin Wolf /* Runs in the main thread */
107bc4ee65bSKevin Wolf static void blk_exp_delete_bh(void *opaque)
108bc4ee65bSKevin Wolf {
109bc4ee65bSKevin Wolf     BlockExport *exp = opaque;
110bc4ee65bSKevin Wolf     AioContext *aio_context = exp->ctx;
111bc4ee65bSKevin Wolf 
112bc4ee65bSKevin Wolf     aio_context_acquire(aio_context);
113bc4ee65bSKevin Wolf 
114bc4ee65bSKevin Wolf     assert(exp->refcount == 0);
115bc4ee65bSKevin Wolf     QLIST_REMOVE(exp, next);
116bc4ee65bSKevin Wolf     exp->drv->delete(exp);
117*1a9f7a80SKevin Wolf     qapi_event_send_block_export_deleted(exp->id);
118d53be9ceSKevin Wolf     g_free(exp->id);
119bc4ee65bSKevin Wolf     g_free(exp);
120bc4ee65bSKevin Wolf 
121bc4ee65bSKevin Wolf     aio_context_release(aio_context);
122bc4ee65bSKevin Wolf }
123bc4ee65bSKevin Wolf 
1248612c686SKevin Wolf /* Callers must hold exp->ctx lock */
125c69de1beSKevin Wolf void blk_exp_unref(BlockExport *exp)
126c69de1beSKevin Wolf {
127c69de1beSKevin Wolf     assert(exp->refcount > 0);
128c69de1beSKevin Wolf     if (--exp->refcount == 0) {
129bc4ee65bSKevin Wolf         /* Touch the block_exports list only in the main thread */
130bc4ee65bSKevin Wolf         aio_bh_schedule_oneshot(qemu_get_aio_context(), blk_exp_delete_bh,
131bc4ee65bSKevin Wolf                                 exp);
132c69de1beSKevin Wolf     }
133c69de1beSKevin Wolf }
134c69de1beSKevin Wolf 
135bc4ee65bSKevin Wolf /*
136bc4ee65bSKevin Wolf  * Drops the user reference to the export and requests that all client
137bc4ee65bSKevin Wolf  * connections and other internally held references start to shut down. When
138bc4ee65bSKevin Wolf  * the function returns, there may still be active references while the export
139bc4ee65bSKevin Wolf  * is in the process of shutting down.
140bc4ee65bSKevin Wolf  *
141bc4ee65bSKevin Wolf  * Acquires exp->ctx internally. Callers must *not* hold the lock.
142bc4ee65bSKevin Wolf  */
143bc4ee65bSKevin Wolf void blk_exp_request_shutdown(BlockExport *exp)
144bc4ee65bSKevin Wolf {
145bc4ee65bSKevin Wolf     AioContext *aio_context = exp->ctx;
146bc4ee65bSKevin Wolf 
147bc4ee65bSKevin Wolf     aio_context_acquire(aio_context);
1483c3bc462SKevin Wolf 
1493c3bc462SKevin Wolf     /*
1503c3bc462SKevin Wolf      * If the user doesn't own the export any more, it is already shutting
1513c3bc462SKevin Wolf      * down. We must not call .request_shutdown and decrease the refcount a
1523c3bc462SKevin Wolf      * second time.
1533c3bc462SKevin Wolf      */
1543c3bc462SKevin Wolf     if (!exp->user_owned) {
1553c3bc462SKevin Wolf         goto out;
1563c3bc462SKevin Wolf     }
1573c3bc462SKevin Wolf 
158bc4ee65bSKevin Wolf     exp->drv->request_shutdown(exp);
1593859ad36SKevin Wolf 
1603859ad36SKevin Wolf     assert(exp->user_owned);
1613859ad36SKevin Wolf     exp->user_owned = false;
1623859ad36SKevin Wolf     blk_exp_unref(exp);
1633859ad36SKevin Wolf 
1643c3bc462SKevin Wolf out:
165bc4ee65bSKevin Wolf     aio_context_release(aio_context);
166bc4ee65bSKevin Wolf }
167bc4ee65bSKevin Wolf 
168bc4ee65bSKevin Wolf /*
169bc4ee65bSKevin Wolf  * Returns whether a block export of the given type exists.
170bc4ee65bSKevin Wolf  * type == BLOCK_EXPORT_TYPE__MAX checks for an export of any type.
171bc4ee65bSKevin Wolf  */
172bc4ee65bSKevin Wolf static bool blk_exp_has_type(BlockExportType type)
173bc4ee65bSKevin Wolf {
174bc4ee65bSKevin Wolf     BlockExport *exp;
175bc4ee65bSKevin Wolf 
176bc4ee65bSKevin Wolf     if (type == BLOCK_EXPORT_TYPE__MAX) {
177bc4ee65bSKevin Wolf         return !QLIST_EMPTY(&block_exports);
178bc4ee65bSKevin Wolf     }
179bc4ee65bSKevin Wolf 
180bc4ee65bSKevin Wolf     QLIST_FOREACH(exp, &block_exports, next) {
181bc4ee65bSKevin Wolf         if (exp->drv->type == type) {
182bc4ee65bSKevin Wolf             return true;
183bc4ee65bSKevin Wolf         }
184bc4ee65bSKevin Wolf     }
185bc4ee65bSKevin Wolf 
186bc4ee65bSKevin Wolf     return false;
187bc4ee65bSKevin Wolf }
188bc4ee65bSKevin Wolf 
189bc4ee65bSKevin Wolf /* type == BLOCK_EXPORT_TYPE__MAX for all types */
190bc4ee65bSKevin Wolf void blk_exp_close_all_type(BlockExportType type)
191bc4ee65bSKevin Wolf {
192bc4ee65bSKevin Wolf     BlockExport *exp, *next;
193bc4ee65bSKevin Wolf 
194bc4ee65bSKevin Wolf     assert(in_aio_context_home_thread(qemu_get_aio_context()));
195bc4ee65bSKevin Wolf 
196bc4ee65bSKevin Wolf     QLIST_FOREACH_SAFE(exp, &block_exports, next, next) {
197bc4ee65bSKevin Wolf         if (type != BLOCK_EXPORT_TYPE__MAX && exp->drv->type != type) {
198bc4ee65bSKevin Wolf             continue;
199bc4ee65bSKevin Wolf         }
200bc4ee65bSKevin Wolf         blk_exp_request_shutdown(exp);
201bc4ee65bSKevin Wolf     }
202bc4ee65bSKevin Wolf 
203bc4ee65bSKevin Wolf     AIO_WAIT_WHILE(NULL, blk_exp_has_type(type));
204bc4ee65bSKevin Wolf }
205bc4ee65bSKevin Wolf 
206bc4ee65bSKevin Wolf void blk_exp_close_all(void)
207bc4ee65bSKevin Wolf {
208bc4ee65bSKevin Wolf     blk_exp_close_all_type(BLOCK_EXPORT_TYPE__MAX);
209bc4ee65bSKevin Wolf }
210bc4ee65bSKevin Wolf 
2119b562c64SKevin Wolf void qmp_block_export_add(BlockExportOptions *export, Error **errp)
2129b562c64SKevin Wolf {
2139b562c64SKevin Wolf     blk_exp_add(export, errp);
21456ee8626SKevin Wolf }
2153c3bc462SKevin Wolf 
2163c3bc462SKevin Wolf void qmp_block_export_del(const char *id,
2173c3bc462SKevin Wolf                           bool has_mode, BlockExportRemoveMode mode,
2183c3bc462SKevin Wolf                           Error **errp)
2193c3bc462SKevin Wolf {
2203c3bc462SKevin Wolf     ERRP_GUARD();
2213c3bc462SKevin Wolf     BlockExport *exp;
2223c3bc462SKevin Wolf 
2233c3bc462SKevin Wolf     exp = blk_exp_find(id);
2243c3bc462SKevin Wolf     if (exp == NULL) {
2253c3bc462SKevin Wolf         error_setg(errp, "Export '%s' is not found", id);
2263c3bc462SKevin Wolf         return;
2273c3bc462SKevin Wolf     }
2283c3bc462SKevin Wolf     if (!exp->user_owned) {
2293c3bc462SKevin Wolf         error_setg(errp, "Export '%s' is already shutting down", id);
2303c3bc462SKevin Wolf         return;
2313c3bc462SKevin Wolf     }
2323c3bc462SKevin Wolf 
2333c3bc462SKevin Wolf     if (!has_mode) {
2343c3bc462SKevin Wolf         mode = BLOCK_EXPORT_REMOVE_MODE_SAFE;
2353c3bc462SKevin Wolf     }
2363c3bc462SKevin Wolf     if (mode == BLOCK_EXPORT_REMOVE_MODE_SAFE && exp->refcount > 1) {
2373c3bc462SKevin Wolf         error_setg(errp, "export '%s' still in use", exp->id);
2383c3bc462SKevin Wolf         error_append_hint(errp, "Use mode='hard' to force client "
2393c3bc462SKevin Wolf                           "disconnect\n");
2403c3bc462SKevin Wolf         return;
2413c3bc462SKevin Wolf     }
2423c3bc462SKevin Wolf 
2433c3bc462SKevin Wolf     blk_exp_request_shutdown(exp);
2443c3bc462SKevin Wolf }
245