@@ -173,3 +173,12 @@
'nbd': 'BlockExportOptionsNbd'
} }
+##
+# @block-export-add:
+#
+# Creates a new block export.
+#
+# Since: 5.2
+##
+{ 'command': 'block-export-add',
+ 'data': 'BlockExportOptions', 'boxed': true }
new file mode 100644
@@ -0,0 +1,33 @@
+/*
+ * Declarations for block exports
+ *
+ * Copyright (c) 2012, 2020 Red Hat, Inc.
+ *
+ * Authors:
+ * Paolo Bonzini <pbonzini@redhat.com>
+ * Kevin Wolf <kwolf@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+
+#ifndef BLOCK_EXPORT_H
+#define BLOCK_EXPORT_H
+
+#include "qapi/qapi-types-block-export.h"
+
+typedef struct BlockExport BlockExport;
+
+typedef struct BlockExportDriver {
+ /* The export type that this driver services */
+ BlockExportType type;
+
+ /* Creates and starts a new block export */
+ BlockExport *(*create)(BlockExportOptions *, Error **);
+} BlockExportDriver;
+
+struct BlockExport {
+ const BlockExportDriver *drv;
+};
+
+#endif
@@ -20,11 +20,13 @@
#ifndef NBD_H
#define NBD_H
-#include "qapi/qapi-types-block-export.h"
+#include "block/export.h"
#include "io/channel-socket.h"
#include "crypto/tlscreds.h"
#include "qapi/error.h"
+extern const BlockExportDriver blk_exp_nbd;
+
/* Handshake phase structs - this struct is passed on the wire */
struct NBDOption {
@@ -328,6 +330,7 @@ int nbd_errno_to_system_errno(int err);
typedef struct NBDExport NBDExport;
typedef struct NBDClient NBDClient;
+BlockExport *nbd_export_create(BlockExportOptions *exp_args, Error **errp);
NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
uint64_t size, const char *name, const char *desc,
const char *bitmap, bool readonly, bool shared,
new file mode 100644
@@ -0,0 +1,48 @@
+/*
+ * Common block export infrastructure
+ *
+ * Copyright (c) 2012, 2020 Red Hat, Inc.
+ *
+ * Authors:
+ * Paolo Bonzini <pbonzini@redhat.com>
+ * Kevin Wolf <kwolf@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "block/export.h"
+#include "block/nbd.h"
+#include "qapi/error.h"
+#include "qapi/qapi-commands-block-export.h"
+
+static const BlockExportDriver *blk_exp_drivers[] = {
+ &blk_exp_nbd,
+};
+
+static const BlockExportDriver *blk_exp_find_driver(BlockExportType type)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(blk_exp_drivers); i++) {
+ if (blk_exp_drivers[i]->type == type) {
+ return blk_exp_drivers[i];
+ }
+ }
+ return NULL;
+}
+
+void qmp_block_export_add(BlockExportOptions *export, Error **errp)
+{
+ const BlockExportDriver *drv;
+
+ drv = blk_exp_find_driver(export->type);
+ if (!drv) {
+ error_setg(errp, "No driver found for the requested export type");
+ return;
+ }
+
+ drv->create(export, errp);
+}
@@ -148,17 +148,20 @@ void qmp_nbd_server_start(SocketAddressLegacy *addr,
qapi_free_SocketAddress(addr_flat);
}
-void qmp_nbd_server_add(BlockExportOptionsNbd *arg, Error **errp)
+BlockExport *nbd_export_create(BlockExportOptions *exp_args, Error **errp)
{
+ BlockExportOptionsNbd *arg = &exp_args->u.nbd;
BlockDriverState *bs = NULL;
BlockBackend *on_eject_blk;
- NBDExport *exp;
+ NBDExport *exp = NULL;
int64_t len;
AioContext *aio_context;
+ assert(exp_args->type == BLOCK_EXPORT_TYPE_NBD);
+
if (!nbd_server) {
error_setg(errp, "NBD server not running");
- return;
+ return NULL;
}
if (!arg->has_name) {
@@ -167,24 +170,24 @@ void qmp_nbd_server_add(BlockExportOptionsNbd *arg, Error **errp)
if (strlen(arg->name) > NBD_MAX_STRING_SIZE) {
error_setg(errp, "export name '%s' too long", arg->name);
- return;
+ return NULL;
}
if (arg->description && strlen(arg->description) > NBD_MAX_STRING_SIZE) {
error_setg(errp, "description '%s' too long", arg->description);
- return;
+ return NULL;
}
if (nbd_export_find(arg->name)) {
error_setg(errp, "NBD server already has export named '%s'", arg->name);
- return;
+ return NULL;
}
on_eject_blk = blk_by_name(arg->device);
bs = bdrv_lookup_bs(arg->device, arg->device, errp);
if (!bs) {
- return;
+ return NULL;
}
aio_context = bdrv_get_aio_context(bs);
@@ -217,6 +220,17 @@ void qmp_nbd_server_add(BlockExportOptionsNbd *arg, Error **errp)
out:
aio_context_release(aio_context);
+ /* TODO Remove the cast: nbd_export_new() will return a BlockExport. */
+ return (BlockExport*) exp;
+}
+
+void qmp_nbd_server_add(BlockExportOptionsNbd *arg, Error **errp)
+{
+ BlockExportOptions export = {
+ .type = BLOCK_EXPORT_TYPE_NBD,
+ .u.nbd = *arg,
+ };
+ qmp_block_export_add(&export, errp);
}
void qmp_nbd_server_remove(const char *name,
@@ -18,6 +18,8 @@
*/
#include "qemu/osdep.h"
+
+#include "block/export.h"
#include "qapi/error.h"
#include "qemu/queue.h"
#include "trace.h"
@@ -80,6 +82,7 @@ struct NBDRequestData {
};
struct NBDExport {
+ BlockExport common;
int refcount;
void (*close)(NBDExport *exp);
@@ -1512,10 +1515,15 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
{
AioContext *ctx;
BlockBackend *blk;
- NBDExport *exp = g_new0(NBDExport, 1);
+ NBDExport *exp;
uint64_t perm;
int ret;
+ exp = g_new0(NBDExport, 1);
+ exp->common = (BlockExport) {
+ .drv = &blk_exp_nbd,
+ };
+
/*
* NBD exports are used for non-shared storage migration. Make sure
* that BDRV_O_INACTIVE is cleared and the image is ready for write
@@ -1731,6 +1739,11 @@ void nbd_export_put(NBDExport *exp)
}
}
+const BlockExportDriver blk_exp_nbd = {
+ .type = BLOCK_EXPORT_TYPE_NBD,
+ .create = nbd_export_create,
+};
+
void nbd_export_close_all(void)
{
NBDExport *exp, *next;
new file mode 100644
@@ -0,0 +1 @@
+block_ss.add(files('export.c'))
@@ -110,6 +110,8 @@ block_ss.add(module_block_h)
block_ss.add(files('stream.c'))
softmmu_ss.add(files('qapi-sysemu.c'))
+
+subdir('export')
subdir('monitor')
modules += {'block': block_modules}
@@ -830,6 +830,7 @@ subdir('dump')
block_ss.add(files(
'block.c',
+ 'blockdev-nbd.c',
'blockjob.c',
'job.c',
'qemu-io-cmds.c',
@@ -842,7 +843,6 @@ subdir('block')
blockdev_ss.add(files(
'blockdev.c',
- 'blockdev-nbd.c',
'iothread.c',
'job-qmp.c',
))