diff options
-rw-r--r-- | block/Makefile.objs | 2 | ||||
-rw-r--r-- | block/block-backend.c | 120 | ||||
-rw-r--r-- | blockdev.c | 13 | ||||
-rw-r--r-- | hw/block/xen_disk.c | 11 | ||||
-rw-r--r-- | include/qemu/typedefs.h | 1 | ||||
-rw-r--r-- | include/sysemu/block-backend.h | 26 | ||||
-rw-r--r-- | qemu-img.c | 70 | ||||
-rw-r--r-- | qemu-io.c | 8 | ||||
-rw-r--r-- | qemu-nbd.c | 5 |
9 files changed, 245 insertions, 11 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; +} diff --git a/blockdev.c b/blockdev.c index 7608f469ef..508188ea9f 100644 --- a/blockdev.c +++ b/blockdev.c @@ -30,6 +30,7 @@ * THE SOFTWARE. */ +#include "sysemu/block-backend.h" #include "sysemu/blockdev.h" #include "hw/block/block.h" #include "block/blockjob.h" @@ -278,7 +279,10 @@ static void bdrv_format_print(void *opaque, const char *name) void drive_del(DriveInfo *dinfo) { + BlockBackend *blk = blk_by_name(dinfo->id); + bdrv_unref(dinfo->bdrv); + blk_unref(blk); } void drive_info_del(DriveInfo *dinfo) @@ -367,6 +371,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts, int ro = 0; int bdrv_flags = 0; int on_read_error, on_write_error; + BlockBackend *blk; BlockDriverState *bs; DriveInfo *dinfo; ThrottleConfig cfg; @@ -523,9 +528,13 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts, } /* init */ + blk = blk_new(qemu_opts_id(opts), errp); + if (!blk) { + goto early_err; + } bs = bdrv_new_root(qemu_opts_id(opts), errp); if (!bs) { - goto early_err; + goto bdrv_new_err; } bs->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0; bs->read_only = ro; @@ -591,6 +600,8 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts, err: bdrv_unref(bs); +bdrv_new_err: + blk_unref(blk); early_err: qemu_opts_del(opts); err_no_opts: diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c index 7f0f66bc46..265cf13aa9 100644 --- a/hw/block/xen_disk.c +++ b/hw/block/xen_disk.c @@ -39,6 +39,7 @@ #include "hw/xen/xen_backend.h" #include "xen_blkif.h" #include "sysemu/blockdev.h" +#include "sysemu/block-backend.h" /* ------------------------------------------------------------- */ @@ -854,12 +855,18 @@ static int blk_connect(struct XenDevice *xendev) blkdev->dinfo = drive_get(IF_XEN, 0, index); if (!blkdev->dinfo) { Error *local_err = NULL; + BlockBackend *blk; BlockDriver *drv; /* setup via xenbus -> create new block driver instance */ xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n"); + blk = blk_new(blkdev->dev, NULL); + if (!blk) { + return -1; + } blkdev->bs = bdrv_new_root(blkdev->dev, NULL); if (!blkdev->bs) { + blk_unref(blk); return -1; } @@ -870,6 +877,7 @@ static int blk_connect(struct XenDevice *xendev) error_get_pretty(local_err)); error_free(local_err); bdrv_unref(blkdev->bs); + blk_unref(blk); blkdev->bs = NULL; return -1; } @@ -985,6 +993,9 @@ static void blk_disconnect(struct XenDevice *xendev) if (blkdev->bs) { bdrv_detach_dev(blkdev->bs, blkdev); bdrv_unref(blkdev->bs); + if (!blkdev->dinfo) { + blk_unref(blk_by_name(blkdev->dev)); + } blkdev->bs = NULL; } xen_be_unbind_evtchn(&blkdev->xendev); diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 168a4086d8..34751778a3 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -36,6 +36,7 @@ typedef struct MachineState MachineState; typedef struct NICInfo NICInfo; typedef struct HCIInfo HCIInfo; typedef struct AudioState AudioState; +typedef struct BlockBackend BlockBackend; typedef struct BlockDriverState BlockDriverState; typedef struct DriveInfo DriveInfo; typedef struct DisplayState DisplayState; diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h new file mode 100644 index 0000000000..198062a00e --- /dev/null +++ b/include/sysemu/block-backend.h @@ -0,0 +1,26 @@ +/* + * 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. + */ + +#ifndef BLOCK_BACKEND_H +#define BLOCK_BACKEND_H + +#include "qemu/typedefs.h" +#include "qapi/error.h" + +BlockBackend *blk_new(const char *name, Error **errp); +void blk_ref(BlockBackend *blk); +void blk_unref(BlockBackend *blk); +const char *blk_name(BlockBackend *blk); +BlockBackend *blk_by_name(const char *name); +BlockBackend *blk_next(BlockBackend *blk); + +#endif diff --git a/qemu-img.c b/qemu-img.c index 9c77dcc927..bdb95a4a3f 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -29,6 +29,7 @@ #include "qemu/error-report.h" #include "qemu/osdep.h" #include "sysemu/sysemu.h" +#include "sysemu/block-backend.h" #include "block/block_int.h" #include "block/qapi.h" #include <getopt.h> @@ -575,10 +576,11 @@ static int img_check(int argc, char **argv) int c, ret; OutputFormat output_format = OFORMAT_HUMAN; const char *filename, *fmt, *output, *cache; + BlockBackend *blk; BlockDriverState *bs; int fix = 0; int flags = BDRV_O_FLAGS | BDRV_O_CHECK; - ImageCheck *check; + ImageCheck *check = NULL; bool quiet = false; fmt = NULL; @@ -649,9 +651,11 @@ static int img_check(int argc, char **argv) return 1; } + blk = blk_new("image", &error_abort); bs = bdrv_new_open("image", filename, fmt, flags, true, quiet); if (!bs) { - return 1; + ret = 1; + goto fail; } check = g_new0(ImageCheck, 1); @@ -710,6 +714,7 @@ static int img_check(int argc, char **argv) fail: qapi_free_ImageCheck(check); bdrv_unref(bs); + blk_unref(blk); return ret; } @@ -718,6 +723,7 @@ static int img_commit(int argc, char **argv) { int c, ret, flags; const char *filename, *fmt, *cache; + BlockBackend *blk; BlockDriverState *bs; bool quiet = false; @@ -756,9 +762,11 @@ static int img_commit(int argc, char **argv) return 1; } + blk = blk_new("image", &error_abort); bs = bdrv_new_open("image", filename, fmt, flags, true, quiet); if (!bs) { - return 1; + ret = -1; + goto out; } ret = bdrv_commit(bs); switch(ret) { @@ -779,7 +787,9 @@ static int img_commit(int argc, char **argv) break; } +out: bdrv_unref(bs); + blk_unref(blk); if (ret) { return 1; } @@ -942,6 +952,7 @@ static int check_empty_sectors(BlockDriverState *bs, int64_t sect_num, static int img_compare(int argc, char **argv) { const char *fmt1 = NULL, *fmt2 = NULL, *cache, *filename1, *filename2; + BlockBackend *blk1, *blk2; BlockDriverState *bs1, *bs2; int64_t total_sectors1, total_sectors2; uint8_t *buf1 = NULL, *buf2 = NULL; @@ -1011,18 +1022,20 @@ static int img_compare(int argc, char **argv) goto out3; } + blk1 = blk_new("image_1", &error_abort); bs1 = bdrv_new_open("image_1", filename1, fmt1, flags, true, quiet); if (!bs1) { error_report("Can't open file %s", filename1); ret = 2; - goto out3; + goto out2; } + blk2 = blk_new("image_2", &error_abort); bs2 = bdrv_new_open("image_2", filename2, fmt2, flags, true, quiet); if (!bs2) { error_report("Can't open file %s", filename2); ret = 2; - goto out2; + goto out1; } buf1 = qemu_blockalign(bs1, IO_BUF_SIZE); @@ -1183,11 +1196,14 @@ static int img_compare(int argc, char **argv) ret = 0; out: - bdrv_unref(bs2); qemu_vfree(buf1); qemu_vfree(buf2); +out1: + bdrv_unref(bs2); + blk_unref(blk2); out2: bdrv_unref(bs1); + blk_unref(blk1); out3: qemu_progress_end(); return ret; @@ -1200,6 +1216,7 @@ static int img_convert(int argc, char **argv) int progress = 0, flags, src_flags; const char *fmt, *out_fmt, *cache, *src_cache, *out_baseimg, *out_filename; BlockDriver *drv, *proto_drv; + BlockBackend **blk = NULL, *out_blk = NULL; BlockDriverState **bs = NULL, *out_bs = NULL; int64_t total_sectors, nb_sectors, sector_num, bs_offset; int64_t *bs_sectors = NULL; @@ -1354,6 +1371,7 @@ static int img_convert(int argc, char **argv) qemu_progress_print(0, 100); + blk = g_new0(BlockBackend *, bs_n); bs = g_new0(BlockDriverState *, bs_n); bs_sectors = g_new(int64_t, bs_n); @@ -1361,6 +1379,7 @@ static int img_convert(int argc, char **argv) for (bs_i = 0; bs_i < bs_n; bs_i++) { char *id = bs_n > 1 ? g_strdup_printf("source_%d", bs_i) : g_strdup("source"); + blk[bs_i] = blk_new(id, &error_abort); bs[bs_i] = bdrv_new_open(id, argv[optind + bs_i], fmt, src_flags, true, quiet); g_free(id); @@ -1486,6 +1505,7 @@ static int img_convert(int argc, char **argv) goto out; } + out_blk = blk_new("target", &error_abort); out_bs = bdrv_new_open("target", out_filename, out_fmt, flags, true, quiet); if (!out_bs) { ret = -1; @@ -1740,6 +1760,7 @@ out: if (out_bs) { bdrv_unref(out_bs); } + blk_unref(out_blk); if (bs) { for (bs_i = 0; bs_i < bs_n; bs_i++) { if (bs[bs_i]) { @@ -1748,6 +1769,12 @@ out: } g_free(bs); } + if (blk) { + for (bs_i = 0; bs_i < bs_n; bs_i++) { + blk_unref(blk[bs_i]); + } + g_free(blk); + } g_free(bs_sectors); fail_getopt: g_free(options); @@ -1856,6 +1883,7 @@ static ImageInfoList *collect_image_info_list(const char *filename, filenames = g_hash_table_new_full(g_str_hash, str_equal_func, NULL, NULL); while (filename) { + BlockBackend *blk; BlockDriverState *bs; ImageInfo *info; ImageInfoList *elem; @@ -1867,9 +1895,11 @@ static ImageInfoList *collect_image_info_list(const char *filename, } g_hash_table_insert(filenames, (gpointer)filename, NULL); + blk = blk_new("image", &error_abort); bs = bdrv_new_open("image", filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING, false, false); if (!bs) { + blk_unref(blk); goto err; } @@ -1878,6 +1908,7 @@ static ImageInfoList *collect_image_info_list(const char *filename, error_report("%s", error_get_pretty(err)); error_free(err); bdrv_unref(bs); + blk_unref(blk); goto err; } @@ -1887,6 +1918,7 @@ static ImageInfoList *collect_image_info_list(const char *filename, last = &elem->next; bdrv_unref(bs); + blk_unref(blk); filename = fmt = NULL; if (chain) { @@ -2080,6 +2112,7 @@ static int img_map(int argc, char **argv) { int c; OutputFormat output_format = OFORMAT_HUMAN; + BlockBackend *blk; BlockDriverState *bs; const char *filename, *fmt, *output; int64_t length; @@ -2128,9 +2161,11 @@ static int img_map(int argc, char **argv) return 1; } + blk = blk_new("image", &error_abort); bs = bdrv_new_open("image", filename, fmt, BDRV_O_FLAGS, true, false); if (!bs) { - return 1; + ret = -1; + goto out; } if (output_format == OFORMAT_HUMAN) { @@ -2173,6 +2208,7 @@ static int img_map(int argc, char **argv) out: bdrv_unref(bs); + blk_unref(blk); return ret < 0; } @@ -2183,6 +2219,7 @@ out: static int img_snapshot(int argc, char **argv) { + BlockBackend *blk; BlockDriverState *bs; QEMUSnapshotInfo sn; char *filename, *snapshot_name = NULL; @@ -2248,9 +2285,11 @@ static int img_snapshot(int argc, char **argv) filename = argv[optind++]; /* Open the image */ + blk = blk_new("image", &error_abort); bs = bdrv_new_open("image", filename, NULL, bdrv_oflags, true, quiet); if (!bs) { - return 1; + ret = -1; + goto out; } /* Perform the requested action */ @@ -2294,7 +2333,9 @@ static int img_snapshot(int argc, char **argv) } /* Cleanup */ +out: bdrv_unref(bs); + blk_unref(blk); if (ret) { return 1; } @@ -2303,6 +2344,7 @@ static int img_snapshot(int argc, char **argv) static int img_rebase(int argc, char **argv) { + BlockBackend *blk = NULL, *blk_old_backing = NULL, *blk_new_backing = NULL; BlockDriverState *bs = NULL, *bs_old_backing = NULL, *bs_new_backing = NULL; BlockDriver *old_backing_drv, *new_backing_drv; char *filename; @@ -2391,6 +2433,7 @@ static int img_rebase(int argc, char **argv) * Ignore the old backing file for unsafe rebase in case we want to correct * the reference to a renamed or moved backing file. */ + blk = blk_new("image", &error_abort); bs = bdrv_new_open("image", filename, fmt, flags, true, quiet); if (!bs) { ret = -1; @@ -2423,6 +2466,7 @@ static int img_rebase(int argc, char **argv) if (!unsafe) { char backing_name[1024]; + blk_old_backing = blk_new("old_backing", &error_abort); bs_old_backing = bdrv_new_root("old_backing", &error_abort); bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name)); ret = bdrv_open(&bs_old_backing, backing_name, NULL, NULL, src_flags, @@ -2434,6 +2478,7 @@ static int img_rebase(int argc, char **argv) goto out; } if (out_baseimg[0]) { + blk_new_backing = blk_new("new_backing", &error_abort); bs_new_backing = bdrv_new_root("new_backing", &error_abort); ret = bdrv_open(&bs_new_backing, out_baseimg, NULL, NULL, src_flags, new_backing_drv, &local_err); @@ -2612,12 +2657,15 @@ out: if (bs_old_backing != NULL) { bdrv_unref(bs_old_backing); } + blk_unref(blk_old_backing); if (bs_new_backing != NULL) { bdrv_unref(bs_new_backing); } + blk_unref(blk_new_backing); } bdrv_unref(bs); + blk_unref(blk); if (ret) { return 1; } @@ -2630,6 +2678,7 @@ static int img_resize(int argc, char **argv) const char *filename, *fmt, *size; int64_t n, total_size; bool quiet = false; + BlockBackend *blk = NULL; BlockDriverState *bs = NULL; QemuOpts *param; static QemuOptsList resize_options = { @@ -2706,6 +2755,7 @@ static int img_resize(int argc, char **argv) n = qemu_opt_get_size(param, BLOCK_OPT_SIZE, 0); qemu_opts_del(param); + blk = blk_new("image", &error_abort); bs = bdrv_new_open("image", filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR, true, quiet); if (!bs) { @@ -2743,6 +2793,7 @@ out: if (bs) { bdrv_unref(bs); } + blk_unref(blk); if (ret) { return 1; } @@ -2758,6 +2809,7 @@ static int img_amend(int argc, char **argv) const char *fmt = NULL, *filename, *cache; int flags; bool quiet = false; + BlockBackend *blk = NULL; BlockDriverState *bs = NULL; cache = BDRV_DEFAULT_CACHE; @@ -2821,6 +2873,7 @@ static int img_amend(int argc, char **argv) goto out; } + blk = blk_new("image", &error_abort); bs = bdrv_new_open("image", filename, fmt, flags, true, quiet); if (!bs) { error_report("Could not open image '%s'", filename); @@ -2854,6 +2907,7 @@ out: if (bs) { bdrv_unref(bs); } + blk_unref(blk); qemu_opts_del(opts); qemu_opts_free(create_opts); g_free(options); @@ -19,6 +19,7 @@ #include "qemu/option.h" #include "qemu/config-file.h" #include "qemu/readline.h" +#include "sysemu/block-backend.h" #include "block/block_int.h" #include "trace/control.h" @@ -26,6 +27,7 @@ static char *progname; +static BlockBackend *qemuio_blk; static BlockDriverState *qemuio_bs; /* qemu-io commands passed using -c */ @@ -37,7 +39,9 @@ static ReadLineState *readline_state; static int close_f(BlockDriverState *bs, int argc, char **argv) { bdrv_unref(bs); + blk_unref(qemuio_blk); qemuio_bs = NULL; + qemuio_blk = NULL; return 0; } @@ -58,6 +62,7 @@ static int openfile(char *name, int flags, int growable, QDict *opts) return 1; } + qemuio_blk = blk_new("hda", &error_abort); qemuio_bs = bdrv_new_root("hda", &error_abort); if (growable) { @@ -70,7 +75,9 @@ static int openfile(char *name, int flags, int growable, QDict *opts) error_get_pretty(local_err)); error_free(local_err); bdrv_unref(qemuio_bs); + blk_unref(qemuio_blk); qemuio_bs = NULL; + qemuio_blk = NULL; return 1; } @@ -484,6 +491,7 @@ int main(int argc, char **argv) if (qemuio_bs) { bdrv_unref(qemuio_bs); } + blk_unref(qemuio_blk); g_free(readline_state); return 0; } diff --git a/qemu-nbd.c b/qemu-nbd.c index d9f1749def..634ba11260 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -17,7 +17,7 @@ */ #include "qemu-common.h" -#include "block/block.h" +#include "sysemu/block-backend.h" #include "block/block_int.h" #include "block/nbd.h" #include "qemu/main-loop.h" @@ -384,6 +384,7 @@ static void nbd_accept(void *opaque) int main(int argc, char **argv) { + BlockBackend *blk; BlockDriverState *bs; BlockDriver *drv; off_t dev_offset = 0; @@ -691,6 +692,7 @@ int main(int argc, char **argv) drv = NULL; } + blk = blk_new("hda", &error_abort); bs = bdrv_new_root("hda", &error_abort); srcpath = argv[optind]; @@ -774,6 +776,7 @@ int main(int argc, char **argv) } while (state != TERMINATED); bdrv_unref(bs); + blk_unref(blk); if (sockpath) { unlink(sockpath); } |