xref: /openbmc/qemu/block/export/export.c (revision bc4ee65b8c309ed6a726e3ea1b73f7fa31b4bb95)
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"
2256ee8626SKevin Wolf 
2356ee8626SKevin Wolf static const BlockExportDriver *blk_exp_drivers[] = {
2456ee8626SKevin Wolf     &blk_exp_nbd,
2556ee8626SKevin Wolf };
2656ee8626SKevin Wolf 
27*bc4ee65bSKevin Wolf /* Only accessed from the main thread */
28*bc4ee65bSKevin Wolf static QLIST_HEAD(, BlockExport) block_exports =
29*bc4ee65bSKevin Wolf     QLIST_HEAD_INITIALIZER(block_exports);
30*bc4ee65bSKevin Wolf 
3156ee8626SKevin Wolf static const BlockExportDriver *blk_exp_find_driver(BlockExportType type)
3256ee8626SKevin Wolf {
3356ee8626SKevin Wolf     int i;
3456ee8626SKevin Wolf 
3556ee8626SKevin Wolf     for (i = 0; i < ARRAY_SIZE(blk_exp_drivers); i++) {
3656ee8626SKevin Wolf         if (blk_exp_drivers[i]->type == type) {
3756ee8626SKevin Wolf             return blk_exp_drivers[i];
3856ee8626SKevin Wolf         }
3956ee8626SKevin Wolf     }
4056ee8626SKevin Wolf     return NULL;
4156ee8626SKevin Wolf }
4256ee8626SKevin Wolf 
439b562c64SKevin Wolf BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
4456ee8626SKevin Wolf {
4556ee8626SKevin Wolf     const BlockExportDriver *drv;
46a6ff7989SKevin Wolf     BlockExport *exp;
47a6ff7989SKevin Wolf     int ret;
4856ee8626SKevin Wolf 
4956ee8626SKevin Wolf     drv = blk_exp_find_driver(export->type);
5056ee8626SKevin Wolf     if (!drv) {
5156ee8626SKevin Wolf         error_setg(errp, "No driver found for the requested export type");
529b562c64SKevin Wolf         return NULL;
5356ee8626SKevin Wolf     }
5456ee8626SKevin Wolf 
55a6ff7989SKevin Wolf     assert(drv->instance_size >= sizeof(BlockExport));
56a6ff7989SKevin Wolf     exp = g_malloc0(drv->instance_size);
57a6ff7989SKevin Wolf     *exp = (BlockExport) {
58a6ff7989SKevin Wolf         .drv        = drv,
59a6ff7989SKevin Wolf         .refcount   = 1,
60a6ff7989SKevin Wolf     };
61a6ff7989SKevin Wolf 
62a6ff7989SKevin Wolf     ret = drv->create(exp, export, errp);
63a6ff7989SKevin Wolf     if (ret < 0) {
64a6ff7989SKevin Wolf         g_free(exp);
65a6ff7989SKevin Wolf         return NULL;
66a6ff7989SKevin Wolf     }
67a6ff7989SKevin Wolf 
68*bc4ee65bSKevin Wolf     QLIST_INSERT_HEAD(&block_exports, exp, next);
69a6ff7989SKevin Wolf     return exp;
709b562c64SKevin Wolf }
719b562c64SKevin Wolf 
728612c686SKevin Wolf /* Callers must hold exp->ctx lock */
73c69de1beSKevin Wolf void blk_exp_ref(BlockExport *exp)
74c69de1beSKevin Wolf {
75c69de1beSKevin Wolf     assert(exp->refcount > 0);
76c69de1beSKevin Wolf     exp->refcount++;
77c69de1beSKevin Wolf }
78c69de1beSKevin Wolf 
79*bc4ee65bSKevin Wolf /* Runs in the main thread */
80*bc4ee65bSKevin Wolf static void blk_exp_delete_bh(void *opaque)
81*bc4ee65bSKevin Wolf {
82*bc4ee65bSKevin Wolf     BlockExport *exp = opaque;
83*bc4ee65bSKevin Wolf     AioContext *aio_context = exp->ctx;
84*bc4ee65bSKevin Wolf 
85*bc4ee65bSKevin Wolf     aio_context_acquire(aio_context);
86*bc4ee65bSKevin Wolf 
87*bc4ee65bSKevin Wolf     assert(exp->refcount == 0);
88*bc4ee65bSKevin Wolf     QLIST_REMOVE(exp, next);
89*bc4ee65bSKevin Wolf     exp->drv->delete(exp);
90*bc4ee65bSKevin Wolf     g_free(exp);
91*bc4ee65bSKevin Wolf 
92*bc4ee65bSKevin Wolf     aio_context_release(aio_context);
93*bc4ee65bSKevin Wolf }
94*bc4ee65bSKevin Wolf 
958612c686SKevin Wolf /* Callers must hold exp->ctx lock */
96c69de1beSKevin Wolf void blk_exp_unref(BlockExport *exp)
97c69de1beSKevin Wolf {
98c69de1beSKevin Wolf     assert(exp->refcount > 0);
99c69de1beSKevin Wolf     if (--exp->refcount == 0) {
100*bc4ee65bSKevin Wolf         /* Touch the block_exports list only in the main thread */
101*bc4ee65bSKevin Wolf         aio_bh_schedule_oneshot(qemu_get_aio_context(), blk_exp_delete_bh,
102*bc4ee65bSKevin Wolf                                 exp);
103c69de1beSKevin Wolf     }
104c69de1beSKevin Wolf }
105c69de1beSKevin Wolf 
106*bc4ee65bSKevin Wolf /*
107*bc4ee65bSKevin Wolf  * Drops the user reference to the export and requests that all client
108*bc4ee65bSKevin Wolf  * connections and other internally held references start to shut down. When
109*bc4ee65bSKevin Wolf  * the function returns, there may still be active references while the export
110*bc4ee65bSKevin Wolf  * is in the process of shutting down.
111*bc4ee65bSKevin Wolf  *
112*bc4ee65bSKevin Wolf  * Acquires exp->ctx internally. Callers must *not* hold the lock.
113*bc4ee65bSKevin Wolf  */
114*bc4ee65bSKevin Wolf void blk_exp_request_shutdown(BlockExport *exp)
115*bc4ee65bSKevin Wolf {
116*bc4ee65bSKevin Wolf     AioContext *aio_context = exp->ctx;
117*bc4ee65bSKevin Wolf 
118*bc4ee65bSKevin Wolf     aio_context_acquire(aio_context);
119*bc4ee65bSKevin Wolf     exp->drv->request_shutdown(exp);
120*bc4ee65bSKevin Wolf     aio_context_release(aio_context);
121*bc4ee65bSKevin Wolf }
122*bc4ee65bSKevin Wolf 
123*bc4ee65bSKevin Wolf /*
124*bc4ee65bSKevin Wolf  * Returns whether a block export of the given type exists.
125*bc4ee65bSKevin Wolf  * type == BLOCK_EXPORT_TYPE__MAX checks for an export of any type.
126*bc4ee65bSKevin Wolf  */
127*bc4ee65bSKevin Wolf static bool blk_exp_has_type(BlockExportType type)
128*bc4ee65bSKevin Wolf {
129*bc4ee65bSKevin Wolf     BlockExport *exp;
130*bc4ee65bSKevin Wolf 
131*bc4ee65bSKevin Wolf     if (type == BLOCK_EXPORT_TYPE__MAX) {
132*bc4ee65bSKevin Wolf         return !QLIST_EMPTY(&block_exports);
133*bc4ee65bSKevin Wolf     }
134*bc4ee65bSKevin Wolf 
135*bc4ee65bSKevin Wolf     QLIST_FOREACH(exp, &block_exports, next) {
136*bc4ee65bSKevin Wolf         if (exp->drv->type == type) {
137*bc4ee65bSKevin Wolf             return true;
138*bc4ee65bSKevin Wolf         }
139*bc4ee65bSKevin Wolf     }
140*bc4ee65bSKevin Wolf 
141*bc4ee65bSKevin Wolf     return false;
142*bc4ee65bSKevin Wolf }
143*bc4ee65bSKevin Wolf 
144*bc4ee65bSKevin Wolf /* type == BLOCK_EXPORT_TYPE__MAX for all types */
145*bc4ee65bSKevin Wolf void blk_exp_close_all_type(BlockExportType type)
146*bc4ee65bSKevin Wolf {
147*bc4ee65bSKevin Wolf     BlockExport *exp, *next;
148*bc4ee65bSKevin Wolf 
149*bc4ee65bSKevin Wolf     assert(in_aio_context_home_thread(qemu_get_aio_context()));
150*bc4ee65bSKevin Wolf 
151*bc4ee65bSKevin Wolf     QLIST_FOREACH_SAFE(exp, &block_exports, next, next) {
152*bc4ee65bSKevin Wolf         if (type != BLOCK_EXPORT_TYPE__MAX && exp->drv->type != type) {
153*bc4ee65bSKevin Wolf             continue;
154*bc4ee65bSKevin Wolf         }
155*bc4ee65bSKevin Wolf         blk_exp_request_shutdown(exp);
156*bc4ee65bSKevin Wolf     }
157*bc4ee65bSKevin Wolf 
158*bc4ee65bSKevin Wolf     AIO_WAIT_WHILE(NULL, blk_exp_has_type(type));
159*bc4ee65bSKevin Wolf }
160*bc4ee65bSKevin Wolf 
161*bc4ee65bSKevin Wolf void blk_exp_close_all(void)
162*bc4ee65bSKevin Wolf {
163*bc4ee65bSKevin Wolf     blk_exp_close_all_type(BLOCK_EXPORT_TYPE__MAX);
164*bc4ee65bSKevin Wolf }
165*bc4ee65bSKevin Wolf 
1669b562c64SKevin Wolf void qmp_block_export_add(BlockExportOptions *export, Error **errp)
1679b562c64SKevin Wolf {
1689b562c64SKevin Wolf     blk_exp_add(export, errp);
16956ee8626SKevin Wolf }
170