aboutsummaryrefslogtreecommitdiff
path: root/block
diff options
context:
space:
mode:
Diffstat (limited to 'block')
-rw-r--r--block/Makefile.objs2
-rw-r--r--block/block-backend.c120
2 files changed, 121 insertions, 1 deletions
diff --git a/block/Makefile.objs b/block/Makefile.objs
index a833ed5745..27911b6b88 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -5,7 +5,7 @@ block-obj-y += qed-check.o
block-obj-$(CONFIG_VHDX) += vhdx.o vhdx-endian.o vhdx-log.o
block-obj-$(CONFIG_QUORUM) += quorum.o
block-obj-y += parallels.o blkdebug.o blkverify.o
-block-obj-y += snapshot.o qapi.o
+block-obj-y += block-backend.o snapshot.o qapi.o
block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
block-obj-$(CONFIG_POSIX) += raw-posix.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
diff --git a/block/block-backend.c b/block/block-backend.c
new file mode 100644
index 0000000000..e89caa9611
--- /dev/null
+++ b/block/block-backend.c
@@ -0,0 +1,120 @@
+/*
+ * QEMU Block backends
+ *
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * Authors:
+ * Markus Armbruster <armbru@redhat.com>,
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1
+ * or later. See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "sysemu/block-backend.h"
+#include "block/block_int.h"
+
+struct BlockBackend {
+ char *name;
+ int refcnt;
+ QTAILQ_ENTRY(BlockBackend) link; /* for blk_backends */
+};
+
+/* All the BlockBackends */
+static QTAILQ_HEAD(, BlockBackend) blk_backends =
+ QTAILQ_HEAD_INITIALIZER(blk_backends);
+
+/*
+ * Create a new BlockBackend with @name, with a reference count of one.
+ * @name must not be null or empty.
+ * Fail if a BlockBackend with this name already exists.
+ * Store an error through @errp on failure, unless it's null.
+ * Return the new BlockBackend on success, null on failure.
+ */
+BlockBackend *blk_new(const char *name, Error **errp)
+{
+ BlockBackend *blk;
+
+ assert(name && name[0]);
+ if (blk_by_name(name)) {
+ error_setg(errp, "Device with id '%s' already exists", name);
+ return NULL;
+ }
+
+ blk = g_new0(BlockBackend, 1);
+ blk->name = g_strdup(name);
+ blk->refcnt = 1;
+ QTAILQ_INSERT_TAIL(&blk_backends, blk, link);
+ return blk;
+}
+
+static void blk_delete(BlockBackend *blk)
+{
+ assert(!blk->refcnt);
+ QTAILQ_REMOVE(&blk_backends, blk, link);
+ g_free(blk->name);
+ g_free(blk);
+}
+
+/*
+ * Increment @blk's reference count.
+ * @blk must not be null.
+ */
+void blk_ref(BlockBackend *blk)
+{
+ blk->refcnt++;
+}
+
+/*
+ * Decrement @blk's reference count.
+ * If this drops it to zero, destroy @blk.
+ * For convenience, do nothing if @blk is null.
+ */
+void blk_unref(BlockBackend *blk)
+{
+ if (blk) {
+ assert(blk->refcnt > 0);
+ if (!--blk->refcnt) {
+ blk_delete(blk);
+ }
+ }
+}
+
+/*
+ * Return the BlockBackend after @blk.
+ * If @blk is null, return the first one.
+ * Else, return @blk's next sibling, which may be null.
+ *
+ * To iterate over all BlockBackends, do
+ * for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
+ * ...
+ * }
+ */
+BlockBackend *blk_next(BlockBackend *blk)
+{
+ return blk ? QTAILQ_NEXT(blk, link) : QTAILQ_FIRST(&blk_backends);
+}
+
+/*
+ * Return @blk's name, a non-null, non-empty string.
+ */
+const char *blk_name(BlockBackend *blk)
+{
+ return blk->name;
+}
+
+/*
+ * Return the BlockBackend with name @name if it exists, else null.
+ * @name must not be null.
+ */
+BlockBackend *blk_by_name(const char *name)
+{
+ BlockBackend *blk;
+
+ assert(name);
+ QTAILQ_FOREACH(blk, &blk_backends, link) {
+ if (!strcmp(name, blk->name)) {
+ return blk;
+ }
+ }
+ return NULL;
+}