diff options
Diffstat (limited to 'block')
-rw-r--r-- | block/Makefile.objs | 2 | ||||
-rw-r--r-- | block/block-backend.c | 120 |
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; +} |