xref: /openbmc/qemu/block/export/export.c (revision e6b5a071)
1 /*
2  * Common block export infrastructure
3  *
4  * Copyright (c) 2012, 2020 Red Hat, Inc.
5  *
6  * Authors:
7  * Paolo Bonzini <pbonzini@redhat.com>
8  * Kevin Wolf <kwolf@redhat.com>
9  *
10  * This work is licensed under the terms of the GNU GPL, version 2 or
11  * later.  See the COPYING file in the top-level directory.
12  */
13 
14 #include "qemu/osdep.h"
15 
16 #include "block/block.h"
17 #include "sysemu/block-backend.h"
18 #include "block/export.h"
19 #include "block/nbd.h"
20 #include "qapi/error.h"
21 #include "qapi/qapi-commands-block-export.h"
22 #include "qapi/qapi-events-block-export.h"
23 #include "qemu/id.h"
24 
25 static const BlockExportDriver *blk_exp_drivers[] = {
26     &blk_exp_nbd,
27 };
28 
29 /* Only accessed from the main thread */
30 static QLIST_HEAD(, BlockExport) block_exports =
31     QLIST_HEAD_INITIALIZER(block_exports);
32 
33 BlockExport *blk_exp_find(const char *id)
34 {
35     BlockExport *exp;
36 
37     QLIST_FOREACH(exp, &block_exports, next) {
38         if (strcmp(id, exp->id) == 0) {
39             return exp;
40         }
41     }
42 
43     return NULL;
44 }
45 
46 static const BlockExportDriver *blk_exp_find_driver(BlockExportType type)
47 {
48     int i;
49 
50     for (i = 0; i < ARRAY_SIZE(blk_exp_drivers); i++) {
51         if (blk_exp_drivers[i]->type == type) {
52             return blk_exp_drivers[i];
53         }
54     }
55     return NULL;
56 }
57 
58 BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
59 {
60     const BlockExportDriver *drv;
61     BlockExport *exp = NULL;
62     BlockDriverState *bs;
63     BlockBackend *blk;
64     AioContext *ctx;
65     uint64_t perm;
66     int ret;
67 
68     if (!id_wellformed(export->id)) {
69         error_setg(errp, "Invalid block export id");
70         return NULL;
71     }
72     if (blk_exp_find(export->id)) {
73         error_setg(errp, "Block export id '%s' is already in use", export->id);
74         return NULL;
75     }
76 
77     drv = blk_exp_find_driver(export->type);
78     if (!drv) {
79         error_setg(errp, "No driver found for the requested export type");
80         return NULL;
81     }
82 
83     bs = bdrv_lookup_bs(NULL, export->node_name, errp);
84     if (!bs) {
85         return NULL;
86     }
87 
88     if (!export->has_writable) {
89         export->writable = false;
90     }
91     if (bdrv_is_read_only(bs) && export->writable) {
92         error_setg(errp, "Cannot export read-only node as writable");
93         return NULL;
94     }
95 
96     ctx = bdrv_get_aio_context(bs);
97     aio_context_acquire(ctx);
98 
99     /*
100      * Block exports are used for non-shared storage migration. Make sure
101      * that BDRV_O_INACTIVE is cleared and the image is ready for write
102      * access since the export could be available before migration handover.
103      * ctx was acquired in the caller.
104      */
105     bdrv_invalidate_cache(bs, NULL);
106 
107     perm = BLK_PERM_CONSISTENT_READ;
108     if (export->writable) {
109         perm |= BLK_PERM_WRITE;
110     }
111 
112     blk = blk_new(ctx, perm, BLK_PERM_ALL);
113     ret = blk_insert_bs(blk, bs, errp);
114     if (ret < 0) {
115         goto fail;
116     }
117 
118     if (!export->has_writethrough) {
119         export->writethrough = false;
120     }
121     blk_set_enable_write_cache(blk, !export->writethrough);
122 
123     assert(drv->instance_size >= sizeof(BlockExport));
124     exp = g_malloc0(drv->instance_size);
125     *exp = (BlockExport) {
126         .drv        = drv,
127         .refcount   = 1,
128         .user_owned = true,
129         .id         = g_strdup(export->id),
130         .ctx        = ctx,
131         .blk        = blk,
132     };
133 
134     ret = drv->create(exp, export, errp);
135     if (ret < 0) {
136         goto fail;
137     }
138 
139     assert(exp->blk != NULL);
140 
141     QLIST_INSERT_HEAD(&block_exports, exp, next);
142 
143     aio_context_release(ctx);
144     return exp;
145 
146 fail:
147     blk_unref(blk);
148     aio_context_release(ctx);
149     if (exp) {
150         g_free(exp->id);
151         g_free(exp);
152     }
153     return NULL;
154 }
155 
156 /* Callers must hold exp->ctx lock */
157 void blk_exp_ref(BlockExport *exp)
158 {
159     assert(exp->refcount > 0);
160     exp->refcount++;
161 }
162 
163 /* Runs in the main thread */
164 static void blk_exp_delete_bh(void *opaque)
165 {
166     BlockExport *exp = opaque;
167     AioContext *aio_context = exp->ctx;
168 
169     aio_context_acquire(aio_context);
170 
171     assert(exp->refcount == 0);
172     QLIST_REMOVE(exp, next);
173     exp->drv->delete(exp);
174     blk_unref(exp->blk);
175     qapi_event_send_block_export_deleted(exp->id);
176     g_free(exp->id);
177     g_free(exp);
178 
179     aio_context_release(aio_context);
180 }
181 
182 /* Callers must hold exp->ctx lock */
183 void blk_exp_unref(BlockExport *exp)
184 {
185     assert(exp->refcount > 0);
186     if (--exp->refcount == 0) {
187         /* Touch the block_exports list only in the main thread */
188         aio_bh_schedule_oneshot(qemu_get_aio_context(), blk_exp_delete_bh,
189                                 exp);
190     }
191 }
192 
193 /*
194  * Drops the user reference to the export and requests that all client
195  * connections and other internally held references start to shut down. When
196  * the function returns, there may still be active references while the export
197  * is in the process of shutting down.
198  *
199  * Acquires exp->ctx internally. Callers must *not* hold the lock.
200  */
201 void blk_exp_request_shutdown(BlockExport *exp)
202 {
203     AioContext *aio_context = exp->ctx;
204 
205     aio_context_acquire(aio_context);
206 
207     /*
208      * If the user doesn't own the export any more, it is already shutting
209      * down. We must not call .request_shutdown and decrease the refcount a
210      * second time.
211      */
212     if (!exp->user_owned) {
213         goto out;
214     }
215 
216     exp->drv->request_shutdown(exp);
217 
218     assert(exp->user_owned);
219     exp->user_owned = false;
220     blk_exp_unref(exp);
221 
222 out:
223     aio_context_release(aio_context);
224 }
225 
226 /*
227  * Returns whether a block export of the given type exists.
228  * type == BLOCK_EXPORT_TYPE__MAX checks for an export of any type.
229  */
230 static bool blk_exp_has_type(BlockExportType type)
231 {
232     BlockExport *exp;
233 
234     if (type == BLOCK_EXPORT_TYPE__MAX) {
235         return !QLIST_EMPTY(&block_exports);
236     }
237 
238     QLIST_FOREACH(exp, &block_exports, next) {
239         if (exp->drv->type == type) {
240             return true;
241         }
242     }
243 
244     return false;
245 }
246 
247 /* type == BLOCK_EXPORT_TYPE__MAX for all types */
248 void blk_exp_close_all_type(BlockExportType type)
249 {
250     BlockExport *exp, *next;
251 
252     assert(in_aio_context_home_thread(qemu_get_aio_context()));
253 
254     QLIST_FOREACH_SAFE(exp, &block_exports, next, next) {
255         if (type != BLOCK_EXPORT_TYPE__MAX && exp->drv->type != type) {
256             continue;
257         }
258         blk_exp_request_shutdown(exp);
259     }
260 
261     AIO_WAIT_WHILE(NULL, blk_exp_has_type(type));
262 }
263 
264 void blk_exp_close_all(void)
265 {
266     blk_exp_close_all_type(BLOCK_EXPORT_TYPE__MAX);
267 }
268 
269 void qmp_block_export_add(BlockExportOptions *export, Error **errp)
270 {
271     blk_exp_add(export, errp);
272 }
273 
274 void qmp_block_export_del(const char *id,
275                           bool has_mode, BlockExportRemoveMode mode,
276                           Error **errp)
277 {
278     ERRP_GUARD();
279     BlockExport *exp;
280 
281     exp = blk_exp_find(id);
282     if (exp == NULL) {
283         error_setg(errp, "Export '%s' is not found", id);
284         return;
285     }
286     if (!exp->user_owned) {
287         error_setg(errp, "Export '%s' is already shutting down", id);
288         return;
289     }
290 
291     if (!has_mode) {
292         mode = BLOCK_EXPORT_REMOVE_MODE_SAFE;
293     }
294     if (mode == BLOCK_EXPORT_REMOVE_MODE_SAFE && exp->refcount > 1) {
295         error_setg(errp, "export '%s' still in use", exp->id);
296         error_append_hint(errp, "Use mode='hard' to force client "
297                           "disconnect\n");
298         return;
299     }
300 
301     blk_exp_request_shutdown(exp);
302 }
303 
304 BlockExportInfoList *qmp_query_block_exports(Error **errp)
305 {
306     BlockExportInfoList *head = NULL, **p_next = &head;
307     BlockExport *exp;
308 
309     QLIST_FOREACH(exp, &block_exports, next) {
310         BlockExportInfoList *entry = g_new0(BlockExportInfoList, 1);
311         BlockExportInfo *info = g_new(BlockExportInfo, 1);
312         *info = (BlockExportInfo) {
313             .id             = g_strdup(exp->id),
314             .type           = exp->drv->type,
315             .node_name      = g_strdup(bdrv_get_node_name(blk_bs(exp->blk))),
316             .shutting_down  = !exp->user_owned,
317         };
318 
319         entry->value = info;
320         *p_next = entry;
321         p_next = &entry->next;
322     }
323 
324     return head;
325 }
326