From f67503e5bd8997ea7ec3f4bfa0af0e06321771a6 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 18 Feb 2014 18:33:05 +0100 Subject: block: Change BDS parameter of bdrv_open() to ** Make bdrv_open() take a pointer to a BDS pointer, similarly to bdrv_file_open(). If a pointer to a NULL pointer is given, bdrv_open() will create a new BDS with an empty name; if the BDS pointer is not NULL, that existing BDS will be reused (in the same way as bdrv_open() already did). Signed-off-by: Max Reitz Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- include/block/block.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/block/block.h b/include/block/block.h index 963a61fa4c..980869dd3f 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -190,7 +190,7 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename, QDict *options, const char *bdref_key, int flags, bool force_raw, bool allow_none, Error **errp); int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp); -int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, +int bdrv_open(BlockDriverState **pbs, const char *filename, QDict *options, int flags, BlockDriver *drv, Error **errp); BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, BlockDriverState *bs, int flags); -- cgit v1.2.3-55-g7522 From ddf5636dc9e4be894f2ab4a5f803d915478b5099 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 18 Feb 2014 18:33:06 +0100 Subject: block: Add reference parameter to bdrv_open() Allow bdrv_open() to handle references to existing block devices just as bdrv_file_open() is already capable of. Signed-off-by: Max Reitz Signed-off-by: Kevin Wolf --- block.c | 44 +++++++++++++++++++++++++++++++++++++------- block/qcow2.c | 4 ++-- block/vmdk.c | 3 ++- block/vvfat.c | 2 +- blockdev.c | 12 ++++++------ hw/block/xen_disk.c | 4 ++-- include/block/block.h | 5 +++-- qemu-img.c | 8 ++++---- qemu-io.c | 4 +++- qemu-nbd.c | 2 +- 10 files changed, 61 insertions(+), 27 deletions(-) (limited to 'include') diff --git a/block.c b/block.c index c39bd3d198..86a32e7192 100644 --- a/block.c +++ b/block.c @@ -1046,7 +1046,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, } if (!drv->bdrv_file_open) { - ret = bdrv_open(&bs, filename, options, flags, drv, &local_err); + ret = bdrv_open(&bs, filename, NULL, options, flags, drv, &local_err); options = NULL; } else { ret = bdrv_open_common(bs, NULL, options, flags, drv, &local_err); @@ -1125,7 +1125,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp) assert(bs->backing_hd == NULL); ret = bdrv_open(&bs->backing_hd, - *backing_filename ? backing_filename : NULL, options, + *backing_filename ? backing_filename : NULL, NULL, options, back_flags, back_drv, &local_err); if (ret < 0) { bs->backing_hd = NULL; @@ -1206,7 +1206,7 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename, goto done; } - ret = bdrv_open(pbs, filename, image_options, flags, NULL, errp); + ret = bdrv_open(pbs, filename, NULL, image_options, flags, NULL, errp); } else { ret = bdrv_file_open(pbs, filename, reference, image_options, flags, errp); @@ -1227,9 +1227,14 @@ done: * * If *pbs is NULL, a new BDS will be created with a pointer to it stored there. * If it is not NULL, the referenced BDS will be reused. + * + * The reference parameter may be used to specify an existing block device which + * should be opened. If specified, neither options nor a filename may be given, + * nor can an existing BDS be reused (that is, *pbs has to be NULL). */ -int bdrv_open(BlockDriverState **pbs, const char *filename, QDict *options, - int flags, BlockDriver *drv, Error **errp) +int bdrv_open(BlockDriverState **pbs, const char *filename, + const char *reference, QDict *options, int flags, + BlockDriver *drv, Error **errp) { int ret; /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */ @@ -1240,6 +1245,31 @@ int bdrv_open(BlockDriverState **pbs, const char *filename, QDict *options, assert(pbs); + if (reference) { + bool options_non_empty = options ? qdict_size(options) : false; + QDECREF(options); + + if (*pbs) { + error_setg(errp, "Cannot reuse an existing BDS when referencing " + "another block device"); + return -EINVAL; + } + + if (filename || options_non_empty) { + error_setg(errp, "Cannot reference an existing block device with " + "additional options or a new filename"); + return -EINVAL; + } + + bs = bdrv_lookup_bs(reference, reference, errp); + if (!bs) { + return -ENODEV; + } + bdrv_ref(bs); + *pbs = bs; + return 0; + } + if (*pbs) { bs = *pbs; } else { @@ -1268,7 +1298,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename, QDict *options, /* Get the required size from the image */ QINCREF(options); bs1 = NULL; - ret = bdrv_open(&bs1, filename, options, BDRV_O_NO_BACKING, + ret = bdrv_open(&bs1, filename, NULL, options, BDRV_O_NO_BACKING, drv, &local_err); if (ret < 0) { goto fail; @@ -5309,7 +5339,7 @@ void bdrv_img_create(const char *filename, const char *fmt, flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING); bs = NULL; - ret = bdrv_open(&bs, backing_file->value.s, NULL, back_flags, + ret = bdrv_open(&bs, backing_file->value.s, NULL, NULL, back_flags, backing_drv, &local_err); if (ret < 0) { error_setg_errno(errp, -ret, "Could not open '%s': %s", diff --git a/block/qcow2.c b/block/qcow2.c index 309ea12b7d..e2aa5c1b3c 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1553,7 +1553,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, */ BlockDriver* drv = bdrv_find_format("qcow2"); assert(drv != NULL); - ret = bdrv_open(&bs, filename, NULL, + ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, drv, &local_err); if (ret < 0) { error_propagate(errp, local_err); @@ -1604,7 +1604,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, bs = NULL; /* Reopen the image without BDRV_O_NO_FLUSH to flush it before returning */ - ret = bdrv_open(&bs, filename, NULL, + ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_BACKING, drv, &local_err); if (local_err) { diff --git a/block/vmdk.c b/block/vmdk.c index 0622db51c4..5df486fa8e 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -1756,7 +1756,8 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, } if (backing_file) { BlockDriverState *bs = NULL; - ret = bdrv_open(&bs, backing_file, NULL, BDRV_O_NO_BACKING, NULL, errp); + ret = bdrv_open(&bs, backing_file, NULL, NULL, BDRV_O_NO_BACKING, NULL, + errp); if (ret != 0) { goto exit; } diff --git a/block/vvfat.c b/block/vvfat.c index 0a9f886a20..4bde3bd220 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -2937,7 +2937,7 @@ static int enable_write_target(BDRVVVFATState *s) } s->qcow = NULL; - ret = bdrv_open(&s->qcow, s->qcow_filename, NULL, + ret = bdrv_open(&s->qcow, s->qcow_filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, bdrv_qcow, &local_err); if (ret < 0) { diff --git a/blockdev.c b/blockdev.c index 056ec4c8c1..357f7607ff 100644 --- a/blockdev.c +++ b/blockdev.c @@ -504,7 +504,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts, bdrv_flags |= ro ? 0 : BDRV_O_RDWR; QINCREF(bs_opts); - ret = bdrv_open(&dinfo->bdrv, file, bs_opts, bdrv_flags, drv, &error); + ret = bdrv_open(&dinfo->bdrv, file, NULL, bs_opts, bdrv_flags, drv, &error); if (ret < 0) { error_setg(errp, "could not open disk image %s: %s", @@ -1333,7 +1333,7 @@ static void external_snapshot_prepare(BlkTransactionState *common, /* TODO Inherit bs->options or only take explicit options with an * extended QMP command? */ assert(state->new_bs == NULL); - ret = bdrv_open(&state->new_bs, new_image_file, options, + ret = bdrv_open(&state->new_bs, new_image_file, NULL, options, flags | BDRV_O_NO_BACKING, drv, &local_err); /* We will manually add the backing_hd field to the bs later */ if (ret != 0) { @@ -1582,7 +1582,7 @@ static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename, Error *local_err = NULL; int ret; - ret = bdrv_open(&bs, filename, NULL, bdrv_flags, drv, &local_err); + ret = bdrv_open(&bs, filename, NULL, NULL, bdrv_flags, drv, &local_err); if (ret < 0) { error_propagate(errp, local_err); return; @@ -2019,7 +2019,7 @@ void qmp_drive_backup(const char *device, const char *target, } target_bs = NULL; - ret = bdrv_open(&target_bs, target, NULL, flags, drv, &local_err); + ret = bdrv_open(&target_bs, target, NULL, NULL, flags, drv, &local_err); if (ret < 0) { error_propagate(errp, local_err); return; @@ -2162,8 +2162,8 @@ void qmp_drive_mirror(const char *device, const char *target, * file. */ target_bs = NULL; - ret = bdrv_open(&target_bs, target, NULL, flags | BDRV_O_NO_BACKING, drv, - &local_err); + ret = bdrv_open(&target_bs, target, NULL, NULL, flags | BDRV_O_NO_BACKING, + drv, &local_err); if (ret < 0) { error_propagate(errp, local_err); return; diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c index 14e6d0b56e..61e6ff3208 100644 --- a/hw/block/xen_disk.c +++ b/hw/block/xen_disk.c @@ -813,8 +813,8 @@ static int blk_connect(struct XenDevice *xendev) Error *local_err = NULL; BlockDriver *drv = bdrv_find_whitelisted_format(blkdev->fileproto, readonly); - if (bdrv_open(&blkdev->bs, - blkdev->filename, NULL, qflags, drv, &local_err) != 0) + if (bdrv_open(&blkdev->bs, blkdev->filename, NULL, NULL, qflags, + drv, &local_err) != 0) { xen_be_printf(&blkdev->xendev, 0, "error: %s\n", error_get_pretty(local_err)); diff --git a/include/block/block.h b/include/block/block.h index 980869dd3f..a421041690 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -190,8 +190,9 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename, QDict *options, const char *bdref_key, int flags, bool force_raw, bool allow_none, Error **errp); int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp); -int bdrv_open(BlockDriverState **pbs, const char *filename, QDict *options, - int flags, BlockDriver *drv, Error **errp); +int bdrv_open(BlockDriverState **pbs, const char *filename, + const char *reference, QDict *options, int flags, + BlockDriver *drv, Error **errp); BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, BlockDriverState *bs, int flags); int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp); diff --git a/qemu-img.c b/qemu-img.c index 59b101347c..79ab3e8cbe 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -289,7 +289,7 @@ static BlockDriverState *bdrv_new_open(const char *filename, drv = NULL; } - ret = bdrv_open(&bs, filename, NULL, flags, drv, &local_err); + ret = bdrv_open(&bs, filename, NULL, NULL, flags, drv, &local_err); if (ret < 0) { error_report("Could not open '%s': %s", filename, error_get_pretty(local_err)); @@ -2312,7 +2312,7 @@ static int img_rebase(int argc, char **argv) bs_old_backing = bdrv_new("old_backing"); bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name)); - ret = bdrv_open(&bs_old_backing, backing_name, NULL, BDRV_O_FLAGS, + ret = bdrv_open(&bs_old_backing, backing_name, NULL, NULL, BDRV_O_FLAGS, old_backing_drv, &local_err); if (ret) { error_report("Could not open old backing file '%s': %s", @@ -2322,8 +2322,8 @@ static int img_rebase(int argc, char **argv) } if (out_baseimg[0]) { bs_new_backing = bdrv_new("new_backing"); - ret = bdrv_open(&bs_new_backing, out_baseimg, NULL, BDRV_O_FLAGS, - new_backing_drv, &local_err); + ret = bdrv_open(&bs_new_backing, out_baseimg, NULL, NULL, + BDRV_O_FLAGS, new_backing_drv, &local_err); if (ret) { error_report("Could not open new backing file '%s': %s", out_baseimg, error_get_pretty(local_err)); diff --git a/qemu-io.c b/qemu-io.c index 8da8f6ec67..61d54c01a0 100644 --- a/qemu-io.c +++ b/qemu-io.c @@ -68,7 +68,9 @@ static int openfile(char *name, int flags, int growable, QDict *opts) } else { qemuio_bs = bdrv_new("hda"); - if (bdrv_open(&qemuio_bs, name, opts, flags, NULL, &local_err) < 0) { + if (bdrv_open(&qemuio_bs, name, NULL, opts, flags, NULL, &local_err) + < 0) + { fprintf(stderr, "%s: can't open device %s: %s\n", progname, name, error_get_pretty(local_err)); error_free(local_err); diff --git a/qemu-nbd.c b/qemu-nbd.c index 0cf123cef2..711162c2ec 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -597,7 +597,7 @@ int main(int argc, char **argv) bs = bdrv_new("hda"); srcpath = argv[optind]; - ret = bdrv_open(&bs, srcpath, NULL, flags, drv, &local_err); + ret = bdrv_open(&bs, srcpath, NULL, NULL, flags, drv, &local_err); if (ret < 0) { errno = -ret; err(EXIT_FAILURE, "Failed to bdrv_open '%s': %s", argv[optind], -- cgit v1.2.3-55-g7522 From 2e40134bfdbb073512f9f264cb96162787ec62b1 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 18 Feb 2014 18:33:07 +0100 Subject: block: Make bdrv_file_open() static Add the bdrv_open() option BDRV_O_PROTOCOL which results in passing the call to bdrv_file_open(). Additionally, make bdrv_file_open() static and therefore bdrv_open() the only way to call it. Consequently, all existing calls to bdrv_file_open() have to be adjusted to use bdrv_open() with the BDRV_O_PROTOCOL flag instead. Signed-off-by: Max Reitz Reviewed-by: Kevin Wolf Reviewed-by: Benoit Canet Signed-off-by: Kevin Wolf --- block.c | 16 +++++++++++----- block/cow.c | 5 +++-- block/qcow.c | 5 +++-- block/qcow2.c | 4 +++- block/qed.c | 8 +++++--- block/sheepdog.c | 7 +++++-- block/vhdx.c | 4 +++- block/vmdk.c | 13 +++++++++---- include/block/block.h | 6 +++--- qemu-io.c | 4 +++- 10 files changed, 48 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/block.c b/block.c index 86a32e7192..8abbbefbd5 100644 --- a/block.c +++ b/block.c @@ -960,9 +960,9 @@ free_and_fail: * after the call (even on failure), so if the caller intends to reuse the * dictionary, it needs to use QINCREF() before calling bdrv_file_open. */ -int bdrv_file_open(BlockDriverState **pbs, const char *filename, - const char *reference, QDict *options, int flags, - Error **errp) +static int bdrv_file_open(BlockDriverState **pbs, const char *filename, + const char *reference, QDict *options, int flags, + Error **errp) { BlockDriverState *bs = NULL; BlockDriver *drv; @@ -1208,8 +1208,8 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename, ret = bdrv_open(pbs, filename, NULL, image_options, flags, NULL, errp); } else { - ret = bdrv_file_open(pbs, filename, reference, image_options, flags, - errp); + ret = bdrv_open(pbs, filename, reference, image_options, + flags | BDRV_O_PROTOCOL, NULL, errp); } done: @@ -1245,6 +1245,12 @@ int bdrv_open(BlockDriverState **pbs, const char *filename, assert(pbs); + if (flags & BDRV_O_PROTOCOL) { + assert(!drv); + return bdrv_file_open(pbs, filename, reference, options, + flags & ~BDRV_O_PROTOCOL, errp); + } + if (reference) { bool options_non_empty = options ? qdict_size(options) : false; QDECREF(options); diff --git a/block/cow.c b/block/cow.c index 7fc0b12163..d0385be1c5 100644 --- a/block/cow.c +++ b/block/cow.c @@ -351,8 +351,9 @@ static int cow_create(const char *filename, QEMUOptionParameter *options, return ret; } - ret = bdrv_file_open(&cow_bs, filename, NULL, NULL, BDRV_O_RDWR, - &local_err); + cow_bs = NULL; + ret = bdrv_open(&cow_bs, filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err); if (ret < 0) { qerror_report_err(local_err); error_free(local_err); diff --git a/block/qcow.c b/block/qcow.c index 948b0c5601..8d00853ab5 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -691,8 +691,9 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options, return ret; } - ret = bdrv_file_open(&qcow_bs, filename, NULL, NULL, BDRV_O_RDWR, - &local_err); + qcow_bs = NULL; + ret = bdrv_open(&qcow_bs, filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err); if (ret < 0) { qerror_report_err(local_err); error_free(local_err); diff --git a/block/qcow2.c b/block/qcow2.c index e2aa5c1b3c..9dfd90896b 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1493,7 +1493,9 @@ static int qcow2_create2(const char *filename, int64_t total_size, return ret; } - ret = bdrv_file_open(&bs, filename, NULL, NULL, BDRV_O_RDWR, &local_err); + bs = NULL; + ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, + NULL, &local_err); if (ret < 0) { error_propagate(errp, local_err); return ret; diff --git a/block/qed.c b/block/qed.c index b9ca7ac0da..9bc181f041 100644 --- a/block/qed.c +++ b/block/qed.c @@ -562,7 +562,7 @@ static int qed_create(const char *filename, uint32_t cluster_size, size_t l1_size = header.cluster_size * header.table_size; Error *local_err = NULL; int ret = 0; - BlockDriverState *bs = NULL; + BlockDriverState *bs; ret = bdrv_create_file(filename, NULL, &local_err); if (ret < 0) { @@ -571,8 +571,10 @@ static int qed_create(const char *filename, uint32_t cluster_size, return ret; } - ret = bdrv_file_open(&bs, filename, NULL, NULL, - BDRV_O_RDWR | BDRV_O_CACHE_WB, &local_err); + bs = NULL; + ret = bdrv_open(&bs, filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL, NULL, + &local_err); if (ret < 0) { qerror_report_err(local_err); error_free(local_err); diff --git a/block/sheepdog.c b/block/sheepdog.c index e6c0376566..f7bd0242e5 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -1534,7 +1534,8 @@ static int sd_prealloc(const char *filename) Error *local_err = NULL; int ret; - ret = bdrv_file_open(&bs, filename, NULL, NULL, BDRV_O_RDWR, &local_err); + ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, + NULL, &local_err); if (ret < 0) { qerror_report_err(local_err); error_free(local_err); @@ -1695,7 +1696,9 @@ static int sd_create(const char *filename, QEMUOptionParameter *options, goto out; } - ret = bdrv_file_open(&bs, backing_file, NULL, NULL, 0, &local_err); + bs = NULL; + ret = bdrv_open(&bs, backing_file, NULL, NULL, BDRV_O_PROTOCOL, NULL, + &local_err); if (ret < 0) { qerror_report_err(local_err); error_free(local_err); diff --git a/block/vhdx.c b/block/vhdx.c index 55689cf641..366ff2e627 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -1797,7 +1797,9 @@ static int vhdx_create(const char *filename, QEMUOptionParameter *options, goto exit; } - ret = bdrv_file_open(&bs, filename, NULL, NULL, BDRV_O_RDWR, &local_err); + bs = NULL; + ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, + NULL, &local_err); if (ret < 0) { error_propagate(errp, local_err); goto exit; diff --git a/block/vmdk.c b/block/vmdk.c index 5df486fa8e..54a1c59427 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -776,8 +776,9 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, path_combine(extent_path, sizeof(extent_path), desc_file_path, fname); - ret = bdrv_file_open(&extent_file, extent_path, NULL, NULL, - bs->open_flags, errp); + extent_file = NULL; + ret = bdrv_open(&extent_file, extent_path, NULL, NULL, + bs->open_flags | BDRV_O_PROTOCOL, NULL, errp); if (ret) { return ret; } @@ -1493,7 +1494,9 @@ static int vmdk_create_extent(const char *filename, int64_t filesize, goto exit; } - ret = bdrv_file_open(&bs, filename, NULL, NULL, BDRV_O_RDWR, &local_err); + assert(bs == NULL); + ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, + NULL, &local_err); if (ret < 0) { error_propagate(errp, local_err); goto exit; @@ -1831,7 +1834,9 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, goto exit; } } - ret = bdrv_file_open(&new_bs, filename, NULL, NULL, BDRV_O_RDWR, &local_err); + assert(new_bs == NULL); + ret = bdrv_open(&new_bs, filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err); if (ret < 0) { error_setg_errno(errp, -ret, "Could not write description"); goto exit; diff --git a/include/block/block.h b/include/block/block.h index a421041690..bf78db5ada 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -102,6 +102,9 @@ typedef enum { #define BDRV_O_CHECK 0x1000 /* open solely for consistency check */ #define BDRV_O_ALLOW_RDWR 0x2000 /* allow reopen to change from r/o to r/w */ #define BDRV_O_UNMAP 0x4000 /* execute guest UNMAP/TRIM operations */ +#define BDRV_O_PROTOCOL 0x8000 /* if no block driver is explicitly given: + select an appropriate protocol driver, + ignoring the format layer */ #define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH) @@ -183,9 +186,6 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old); void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top); int bdrv_parse_cache_flags(const char *mode, int *flags); int bdrv_parse_discard_flags(const char *mode, int *flags); -int bdrv_file_open(BlockDriverState **pbs, const char *filename, - const char *reference, QDict *options, int flags, - Error **errp); int bdrv_open_image(BlockDriverState **pbs, const char *filename, QDict *options, const char *bdref_key, int flags, bool force_raw, bool allow_none, Error **errp); diff --git a/qemu-io.c b/qemu-io.c index 61d54c01a0..71d7806ed9 100644 --- a/qemu-io.c +++ b/qemu-io.c @@ -59,7 +59,9 @@ static int openfile(char *name, int flags, int growable, QDict *opts) } if (growable) { - if (bdrv_file_open(&qemuio_bs, name, NULL, opts, flags, &local_err)) { + if (bdrv_open(&qemuio_bs, name, NULL, opts, flags | BDRV_O_PROTOCOL, + NULL, &local_err)) + { fprintf(stderr, "%s: can't open device %s: %s\n", progname, name, error_get_pretty(local_err)); error_free(local_err); -- cgit v1.2.3-55-g7522 From f7d9fd8c7270de25b1e0d0a462b6958b53aa31b2 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 18 Feb 2014 18:33:12 +0100 Subject: block: Remove bdrv_open_image()'s force_raw option This option is now unnecessary since specifying BDRV_O_PROTOCOL as flag will do exactly the same. Signed-off-by: Max Reitz Reviewed-by: Benoit Canet Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block.c | 27 ++++----------------------- block/blkdebug.c | 2 +- block/blkverify.c | 4 ++-- include/block/block.h | 2 +- 4 files changed, 8 insertions(+), 27 deletions(-) (limited to 'include') diff --git a/block.c b/block.c index 308e7bacb4..2fd5482572 100644 --- a/block.c +++ b/block.c @@ -1109,10 +1109,6 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp) * Opens a disk image whose options are given as BlockdevRef in another block * device's options. * - * If force_raw is true, bdrv_file_open() will be used, thereby preventing any - * image format auto-detection. If it is false and a filename is given, - * bdrv_open() will be used for auto-detection. - * * If allow_none is true, no image will be opened if filename is false and no * BlockdevRef is given. *pbs will remain unchanged and 0 will be returned. * @@ -1127,7 +1123,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp) */ int bdrv_open_image(BlockDriverState **pbs, const char *filename, QDict *options, const char *bdref_key, int flags, - bool force_raw, bool allow_none, Error **errp) + bool allow_none, Error **errp) { QDict *image_options; int ret; @@ -1153,22 +1149,7 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename, goto done; } - if (filename && !force_raw) { - /* If a filename is given and the block driver should be detected - automatically (instead of using none), use bdrv_open() in order to do - that auto-detection. */ - if (reference) { - error_setg(errp, "Cannot reference an existing block device while " - "giving a filename"); - ret = -EINVAL; - goto done; - } - - ret = bdrv_open(pbs, filename, NULL, image_options, flags, NULL, errp); - } else { - ret = bdrv_open(pbs, filename, reference, image_options, - flags | BDRV_O_PROTOCOL, NULL, errp); - } + ret = bdrv_open(pbs, filename, reference, image_options, flags, NULL, errp); done: qdict_del(options, bdref_key); @@ -1330,8 +1311,8 @@ int bdrv_open(BlockDriverState **pbs, const char *filename, assert(file == NULL); ret = bdrv_open_image(&file, filename, options, "file", - bdrv_open_flags(bs, flags | BDRV_O_UNMAP), true, true, - &local_err); + bdrv_open_flags(bs, flags | BDRV_O_UNMAP) | + BDRV_O_PROTOCOL, true, &local_err); if (ret < 0) { goto fail; } diff --git a/block/blkdebug.c b/block/blkdebug.c index 46bd086da9..380c736101 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -412,7 +412,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, /* Open the backing file */ assert(bs->file == NULL); ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-image"), options, "image", - flags, true, false, &local_err); + flags | BDRV_O_PROTOCOL, false, &local_err); if (ret < 0) { error_propagate(errp, local_err); goto out; diff --git a/block/blkverify.c b/block/blkverify.c index 7d8a32ec79..0e28502e8e 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -137,7 +137,7 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags, /* Open the raw file */ assert(bs->file == NULL); ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-raw"), options, - "raw", flags, true, false, &local_err); + "raw", flags | BDRV_O_PROTOCOL, false, &local_err); if (ret < 0) { error_propagate(errp, local_err); goto fail; @@ -146,7 +146,7 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags, /* Open the test file */ assert(s->test_file == NULL); ret = bdrv_open_image(&s->test_file, qemu_opt_get(opts, "x-image"), options, - "test", flags, false, false, &local_err); + "test", flags, false, &local_err); if (ret < 0) { error_propagate(errp, local_err); s->test_file = NULL; diff --git a/include/block/block.h b/include/block/block.h index bf78db5ada..780f48b7b3 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -188,7 +188,7 @@ int bdrv_parse_cache_flags(const char *mode, int *flags); int bdrv_parse_discard_flags(const char *mode, int *flags); int bdrv_open_image(BlockDriverState **pbs, const char *filename, QDict *options, const char *bdref_key, int flags, - bool force_raw, bool allow_none, Error **errp); + bool allow_none, Error **errp); int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp); int bdrv_open(BlockDriverState **pbs, const char *filename, const char *reference, QDict *options, int flags, -- cgit v1.2.3-55-g7522 From 77e8b9ca64e85d3d309f322410964b7852ec091e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 17 Feb 2014 14:43:49 +0100 Subject: nbd: correctly propagate errors Before: $ ./qemu-io-old qemu-io-old> open -r -o file.driver=nbd one of path and host must be specified. qemu-io-old: can't open device (null): Could not open image: Invalid argument $ ./qemu-io-old qemu-io-old> open -r -o file.driver=nbd,file.host=foo,file.path=bar path and host may not be used at the same time. qemu-io-old: can't open device (null): Could not open image: Invalid argument After: $ ./qemu-io qemu-io> open -r -o file.driver=nbd qemu-io: can't open device (null): one of path and host must be specified. $ ./qemu-io qemu-io> open -r -o file.driver=nbd,file.host=foo,file.path=bar qemu-io: can't open device (null): path and host may not be used at the same time. Signed-off-by: Paolo Bonzini Reviewed-by: Fam Zheng Signed-off-by: Kevin Wolf --- block/nbd.c | 34 ++++++++++++++++------------------ include/block/nbd.h | 1 - nbd.c | 12 ------------ tests/qemu-iotests/051.out | 6 ++---- 4 files changed, 18 insertions(+), 35 deletions(-) (limited to 'include') diff --git a/block/nbd.c b/block/nbd.c index a83e8565e5..55124239df 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -188,19 +188,18 @@ out: g_free(file); } -static int nbd_config(BDRVNBDState *s, QDict *options, char **export) +static void nbd_config(BDRVNBDState *s, QDict *options, char **export, + Error **errp) { Error *local_err = NULL; if (qdict_haskey(options, "path") == qdict_haskey(options, "host")) { if (qdict_haskey(options, "path")) { - qerror_report(ERROR_CLASS_GENERIC_ERROR, "path and host may not " - "be used at the same time."); + error_setg(errp, "path and host may not be used at the same time."); } else { - qerror_report(ERROR_CLASS_GENERIC_ERROR, "one of path and host " - "must be specified."); + error_setg(errp, "one of path and host must be specified."); } - return -EINVAL; + return; } s->client.is_unix = qdict_haskey(options, "path"); @@ -209,9 +208,8 @@ static int nbd_config(BDRVNBDState *s, QDict *options, char **export) qemu_opts_absorb_qdict(s->socket_opts, options, &local_err); if (local_err) { - qerror_report_err(local_err); - error_free(local_err); - return -EINVAL; + error_propagate(errp, local_err); + return; } if (!qemu_opt_get(s->socket_opts, "port")) { @@ -222,19 +220,17 @@ static int nbd_config(BDRVNBDState *s, QDict *options, char **export) if (*export) { qdict_del(options, "export"); } - - return 0; } -static int nbd_establish_connection(BlockDriverState *bs) +static int nbd_establish_connection(BlockDriverState *bs, Error **errp) { BDRVNBDState *s = bs->opaque; int sock; if (s->client.is_unix) { - sock = unix_socket_outgoing(qemu_opt_get(s->socket_opts, "path")); + sock = unix_connect_opts(s->socket_opts, errp, NULL, NULL); } else { - sock = tcp_socket_outgoing_opts(s->socket_opts); + sock = inet_connect_opts(s->socket_opts, errp, NULL, NULL); if (sock >= 0) { socket_set_nodelay(sock); } @@ -255,17 +251,19 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags, BDRVNBDState *s = bs->opaque; char *export = NULL; int result, sock; + Error *local_err = NULL; /* Pop the config into our state object. Exit if invalid. */ - result = nbd_config(s, options, &export); - if (result != 0) { - return result; + nbd_config(s, options, &export, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return -EINVAL; } /* establish TCP connection, return error if it fails * TODO: Configurable retry-until-timeout behaviour. */ - sock = nbd_establish_connection(bs); + sock = nbd_establish_connection(bs, errp); if (sock < 0) { return sock; } diff --git a/include/block/nbd.h b/include/block/nbd.h index c90f5e4d9e..e10ab82155 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -64,7 +64,6 @@ enum { ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read); int tcp_socket_incoming(const char *address, uint16_t port); int tcp_socket_incoming_spec(const char *address_and_port); -int tcp_socket_outgoing_opts(QemuOpts *opts); int unix_socket_outgoing(const char *path); int unix_socket_incoming(const char *path); diff --git a/nbd.c b/nbd.c index 030f56b5c7..17ca95bf0d 100644 --- a/nbd.c +++ b/nbd.c @@ -199,18 +199,6 @@ static void combine_addr(char *buf, size_t len, const char* address, } } -int tcp_socket_outgoing_opts(QemuOpts *opts) -{ - Error *local_err = NULL; - int fd = inet_connect_opts(opts, &local_err, NULL, NULL); - if (local_err != NULL) { - qerror_report_err(local_err); - error_free(local_err); - } - - return fd; -} - int tcp_socket_incoming(const char *address, uint16_t port) { char address_and_port[128]; diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index 3e8d9621b7..7de18704f8 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -231,8 +231,7 @@ Testing: -drive driver=file QEMU_PROG: -drive driver=file: could not open disk image ide0-hd0: The 'file' block driver requires a file name Testing: -drive driver=nbd -QEMU_PROG: -drive driver=nbd: one of path and host must be specified. -QEMU_PROG: -drive driver=nbd: could not open disk image ide0-hd0: Could not open image: Invalid argument +QEMU_PROG: -drive driver=nbd: could not open disk image ide0-hd0: one of path and host must be specified. Testing: -drive driver=raw QEMU_PROG: -drive driver=raw: could not open disk image ide0-hd0: Can't use 'raw' as a block driver for the protocol level @@ -241,8 +240,7 @@ Testing: -drive file.driver=file QEMU_PROG: -drive file.driver=file: could not open disk image ide0-hd0: The 'file' block driver requires a file name Testing: -drive file.driver=nbd -QEMU_PROG: -drive file.driver=nbd: one of path and host must be specified. -QEMU_PROG: -drive file.driver=nbd: could not open disk image ide0-hd0: Could not open image: Invalid argument +QEMU_PROG: -drive file.driver=nbd: could not open disk image ide0-hd0: one of path and host must be specified. Testing: -drive file.driver=raw QEMU_PROG: -drive file.driver=raw: could not open disk image ide0-hd0: Can't use 'raw' as a block driver for the protocol level -- cgit v1.2.3-55-g7522 From c06b72781dc6dff3f1e8209b7280ff4650eb6f36 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 17 Feb 2014 14:43:50 +0100 Subject: nbd: inline tcp_socket_incoming_spec into sole caller Signed-off-by: Paolo Bonzini Reviewed-by: Fam Zheng Signed-off-by: Kevin Wolf --- include/block/nbd.h | 1 - nbd.c | 8 ++------ 2 files changed, 2 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/block/nbd.h b/include/block/nbd.h index e10ab82155..1b39c064f5 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -63,7 +63,6 @@ enum { ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read); int tcp_socket_incoming(const char *address, uint16_t port); -int tcp_socket_incoming_spec(const char *address_and_port); int unix_socket_outgoing(const char *path); int unix_socket_incoming(const char *path); diff --git a/nbd.c b/nbd.c index 17ca95bf0d..2fc1f1fbf8 100644 --- a/nbd.c +++ b/nbd.c @@ -202,13 +202,9 @@ static void combine_addr(char *buf, size_t len, const char* address, int tcp_socket_incoming(const char *address, uint16_t port) { char address_and_port[128]; - combine_addr(address_and_port, 128, address, port); - return tcp_socket_incoming_spec(address_and_port); -} - -int tcp_socket_incoming_spec(const char *address_and_port) -{ Error *local_err = NULL; + + combine_addr(address_and_port, 128, address, port); int fd = inet_listen(address_and_port, NULL, 0, SOCK_STREAM, 0, &local_err); if (local_err != NULL) { -- cgit v1.2.3-55-g7522 From 537b41f5013e1951fa15e8f18855b18d76124ce4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 17 Feb 2014 14:43:51 +0100 Subject: nbd: move socket wrappers to qemu-nbd qemu-nbd is one of the few valid users of qerror_report_err. Move the error-reporting socket wrappers there. Signed-off-by: Paolo Bonzini Reviewed-by: Fam Zheng Signed-off-by: Kevin Wolf --- include/block/nbd.h | 4 ---- nbd.c | 50 -------------------------------------------------- qemu-nbd.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 54 deletions(-) (limited to 'include') diff --git a/include/block/nbd.h b/include/block/nbd.h index 1b39c064f5..79502a090b 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -62,10 +62,6 @@ enum { #define NBD_MAX_BUFFER_SIZE (32 * 1024 * 1024) ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read); -int tcp_socket_incoming(const char *address, uint16_t port); -int unix_socket_outgoing(const char *path); -int unix_socket_incoming(const char *path); - int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags, off_t *size, size_t *blocksize); int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize); diff --git a/nbd.c b/nbd.c index 2fc1f1fbf8..e5084b6e7c 100644 --- a/nbd.c +++ b/nbd.c @@ -188,56 +188,6 @@ static ssize_t write_sync(int fd, void *buffer, size_t size) return ret; } -static void combine_addr(char *buf, size_t len, const char* address, - uint16_t port) -{ - /* If the address-part contains a colon, it's an IPv6 IP so needs [] */ - if (strstr(address, ":")) { - snprintf(buf, len, "[%s]:%u", address, port); - } else { - snprintf(buf, len, "%s:%u", address, port); - } -} - -int tcp_socket_incoming(const char *address, uint16_t port) -{ - char address_and_port[128]; - Error *local_err = NULL; - - combine_addr(address_and_port, 128, address, port); - int fd = inet_listen(address_and_port, NULL, 0, SOCK_STREAM, 0, &local_err); - - if (local_err != NULL) { - qerror_report_err(local_err); - error_free(local_err); - } - return fd; -} - -int unix_socket_incoming(const char *path) -{ - Error *local_err = NULL; - int fd = unix_listen(path, NULL, 0, &local_err); - - if (local_err != NULL) { - qerror_report_err(local_err); - error_free(local_err); - } - return fd; -} - -int unix_socket_outgoing(const char *path) -{ - Error *local_err = NULL; - int fd = unix_connect(path, &local_err); - - if (local_err != NULL) { - qerror_report_err(local_err); - error_free(local_err); - } - return fd; -} - /* Basic flow for negotiation Server Client diff --git a/qemu-nbd.c b/qemu-nbd.c index 711162c2ec..c1dfff3b85 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -20,6 +20,8 @@ #include "block/block.h" #include "block/nbd.h" #include "qemu/main-loop.h" +#include "qemu/sockets.h" +#include "qemu/error-report.h" #include "block/snapshot.h" #include @@ -201,6 +203,56 @@ static void termsig_handler(int signum) qemu_notify_event(); } +static void combine_addr(char *buf, size_t len, const char* address, + uint16_t port) +{ + /* If the address-part contains a colon, it's an IPv6 IP so needs [] */ + if (strstr(address, ":")) { + snprintf(buf, len, "[%s]:%u", address, port); + } else { + snprintf(buf, len, "%s:%u", address, port); + } +} + +static int tcp_socket_incoming(const char *address, uint16_t port) +{ + char address_and_port[128]; + Error *local_err = NULL; + + combine_addr(address_and_port, 128, address, port); + int fd = inet_listen(address_and_port, NULL, 0, SOCK_STREAM, 0, &local_err); + + if (local_err != NULL) { + qerror_report_err(local_err); + error_free(local_err); + } + return fd; +} + +static int unix_socket_incoming(const char *path) +{ + Error *local_err = NULL; + int fd = unix_listen(path, NULL, 0, &local_err); + + if (local_err != NULL) { + qerror_report_err(local_err); + error_free(local_err); + } + return fd; +} + +static int unix_socket_outgoing(const char *path) +{ + Error *local_err = NULL; + int fd = unix_connect(path, &local_err); + + if (local_err != NULL) { + qerror_report_err(local_err); + error_free(local_err); + } + return fd; +} + static void *show_parts(void *arg) { char *device = arg; -- cgit v1.2.3-55-g7522 From 7cc07ab8daa01f100f36ab63382d491f2d278c64 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 21 Feb 2014 16:24:03 +0100 Subject: qemu-option: has_help_option() and is_valid_option_list() has_help_option() checks if any help option ('help' or '?') occurs anywhere in an option string, so that things like 'cluster_size=4k,help' are recognised. is_valid_option_list() ensures that the option list doesn't have options with leading commas or trailing unescaped commas. Signed-off-by: Kevin Wolf Reviewed-by: Jeff Cody Reviewed-by: Eric Blake --- include/qemu/option.h | 2 ++ util/qemu-option.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) (limited to 'include') diff --git a/include/qemu/option.h b/include/qemu/option.h index 3ea871a3ba..8c0ac3485e 100644 --- a/include/qemu/option.h +++ b/include/qemu/option.h @@ -79,6 +79,8 @@ void parse_option_size(const char *name, const char *value, void free_option_parameters(QEMUOptionParameter *list); void print_option_parameters(QEMUOptionParameter *list); void print_option_help(QEMUOptionParameter *list); +bool has_help_option(const char *param); +bool is_valid_option_list(const char *param); /* ------------------------------------------------------------------ */ diff --git a/util/qemu-option.c b/util/qemu-option.c index fd76cd2ada..9d898af443 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -450,6 +450,55 @@ fail: return NULL; } +bool has_help_option(const char *param) +{ + size_t buflen = strlen(param) + 1; + char *buf = g_malloc0(buflen); + const char *p = param; + bool result = false; + + while (*p) { + p = get_opt_value(buf, buflen, p); + if (*p) { + p++; + } + + if (is_help_option(buf)) { + result = true; + goto out; + } + } + +out: + free(buf); + return result; +} + +bool is_valid_option_list(const char *param) +{ + size_t buflen = strlen(param) + 1; + char *buf = g_malloc0(buflen); + const char *p = param; + bool result = true; + + while (*p) { + p = get_opt_value(buf, buflen, p); + if (*p && !*++p) { + result = false; + goto out; + } + + if (!*buf || *buf == ',') { + result = false; + goto out; + } + } + +out: + free(buf); + return result; +} + /* * Prints all options of a list that have a value to stdout */ -- cgit v1.2.3-55-g7522 From f70d7f7e4d05b7a7797815afdcb83f4375740838 Mon Sep 17 00:00:00 2001 From: Benoît Canet Date: Fri, 21 Feb 2014 22:21:13 +0100 Subject: blkverify: Extract qemu_iovec_clone() and qemu_iovec_compare() from blkverify. qemu_iovec_compare() will be used to compare IOs vectors in quorum blkverify mode. The patch extracts these functions in order to factorize the code. Signed-off-by: Benoit Canet Reviewed-by: Max Reitz Signed-off-by: Kevin Wolf --- block/blkverify.c | 108 +------------------------------------------------- include/qemu-common.h | 2 + util/iov.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 106 deletions(-) (limited to 'include') diff --git a/block/blkverify.c b/block/blkverify.c index 0e28502e8e..b98b08bedf 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -173,110 +173,6 @@ static int64_t blkverify_getlength(BlockDriverState *bs) return bdrv_getlength(s->test_file); } -/** - * Check that I/O vector contents are identical - * - * @a: I/O vector - * @b: I/O vector - * @ret: Offset to first mismatching byte or -1 if match - */ -static ssize_t blkverify_iovec_compare(QEMUIOVector *a, QEMUIOVector *b) -{ - int i; - ssize_t offset = 0; - - assert(a->niov == b->niov); - for (i = 0; i < a->niov; i++) { - size_t len = 0; - uint8_t *p = (uint8_t *)a->iov[i].iov_base; - uint8_t *q = (uint8_t *)b->iov[i].iov_base; - - assert(a->iov[i].iov_len == b->iov[i].iov_len); - while (len < a->iov[i].iov_len && *p++ == *q++) { - len++; - } - - offset += len; - - if (len != a->iov[i].iov_len) { - return offset; - } - } - return -1; -} - -typedef struct { - int src_index; - struct iovec *src_iov; - void *dest_base; -} IOVectorSortElem; - -static int sortelem_cmp_src_base(const void *a, const void *b) -{ - const IOVectorSortElem *elem_a = a; - const IOVectorSortElem *elem_b = b; - - /* Don't overflow */ - if (elem_a->src_iov->iov_base < elem_b->src_iov->iov_base) { - return -1; - } else if (elem_a->src_iov->iov_base > elem_b->src_iov->iov_base) { - return 1; - } else { - return 0; - } -} - -static int sortelem_cmp_src_index(const void *a, const void *b) -{ - const IOVectorSortElem *elem_a = a; - const IOVectorSortElem *elem_b = b; - - return elem_a->src_index - elem_b->src_index; -} - -/** - * Copy contents of I/O vector - * - * The relative relationships of overlapping iovecs are preserved. This is - * necessary to ensure identical semantics in the cloned I/O vector. - */ -static void blkverify_iovec_clone(QEMUIOVector *dest, const QEMUIOVector *src, - void *buf) -{ - IOVectorSortElem sortelems[src->niov]; - void *last_end; - int i; - - /* Sort by source iovecs by base address */ - for (i = 0; i < src->niov; i++) { - sortelems[i].src_index = i; - sortelems[i].src_iov = &src->iov[i]; - } - qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_base); - - /* Allocate buffer space taking into account overlapping iovecs */ - last_end = NULL; - for (i = 0; i < src->niov; i++) { - struct iovec *cur = sortelems[i].src_iov; - ptrdiff_t rewind = 0; - - /* Detect overlap */ - if (last_end && last_end > cur->iov_base) { - rewind = last_end - cur->iov_base; - } - - sortelems[i].dest_base = buf - rewind; - buf += cur->iov_len - MIN(rewind, cur->iov_len); - last_end = MAX(cur->iov_base + cur->iov_len, last_end); - } - - /* Sort by source iovec index and build destination iovec */ - qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_index); - for (i = 0; i < src->niov; i++) { - qemu_iovec_add(dest, sortelems[i].dest_base, src->iov[i].iov_len); - } -} - static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, @@ -340,7 +236,7 @@ static void blkverify_aio_cb(void *opaque, int ret) static void blkverify_verify_readv(BlkverifyAIOCB *acb) { - ssize_t offset = blkverify_iovec_compare(acb->qiov, &acb->raw_qiov); + ssize_t offset = qemu_iovec_compare(acb->qiov, &acb->raw_qiov); if (offset != -1) { blkverify_err(acb, "contents mismatch in sector %" PRId64, acb->sector_num + (int64_t)(offset / BDRV_SECTOR_SIZE)); @@ -358,7 +254,7 @@ static BlockDriverAIOCB *blkverify_aio_readv(BlockDriverState *bs, acb->verify = blkverify_verify_readv; acb->buf = qemu_blockalign(bs->file, qiov->size); qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov); - blkverify_iovec_clone(&acb->raw_qiov, qiov, acb->buf); + qemu_iovec_clone(&acb->raw_qiov, qiov, acb->buf); bdrv_aio_readv(s->test_file, sector_num, qiov, nb_sectors, blkverify_aio_cb, acb); diff --git a/include/qemu-common.h b/include/qemu-common.h index b0e34b2e15..20ace93098 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -338,6 +338,8 @@ size_t qemu_iovec_from_buf(QEMUIOVector *qiov, size_t offset, const void *buf, size_t bytes); size_t qemu_iovec_memset(QEMUIOVector *qiov, size_t offset, int fillc, size_t bytes); +ssize_t qemu_iovec_compare(QEMUIOVector *a, QEMUIOVector *b); +void qemu_iovec_clone(QEMUIOVector *dest, const QEMUIOVector *src, void *buf); bool buffer_is_zero(const void *buf, size_t len); diff --git a/util/iov.c b/util/iov.c index bb46c04e4d..03934da74d 100644 --- a/util/iov.c +++ b/util/iov.c @@ -378,6 +378,112 @@ size_t qemu_iovec_memset(QEMUIOVector *qiov, size_t offset, return iov_memset(qiov->iov, qiov->niov, offset, fillc, bytes); } +/** + * Check that I/O vector contents are identical + * + * The IO vectors must have the same structure (same length of all parts). + * A typical usage is to compare vectors created with qemu_iovec_clone(). + * + * @a: I/O vector + * @b: I/O vector + * @ret: Offset to first mismatching byte or -1 if match + */ +ssize_t qemu_iovec_compare(QEMUIOVector *a, QEMUIOVector *b) +{ + int i; + ssize_t offset = 0; + + assert(a->niov == b->niov); + for (i = 0; i < a->niov; i++) { + size_t len = 0; + uint8_t *p = (uint8_t *)a->iov[i].iov_base; + uint8_t *q = (uint8_t *)b->iov[i].iov_base; + + assert(a->iov[i].iov_len == b->iov[i].iov_len); + while (len < a->iov[i].iov_len && *p++ == *q++) { + len++; + } + + offset += len; + + if (len != a->iov[i].iov_len) { + return offset; + } + } + return -1; +} + +typedef struct { + int src_index; + struct iovec *src_iov; + void *dest_base; +} IOVectorSortElem; + +static int sortelem_cmp_src_base(const void *a, const void *b) +{ + const IOVectorSortElem *elem_a = a; + const IOVectorSortElem *elem_b = b; + + /* Don't overflow */ + if (elem_a->src_iov->iov_base < elem_b->src_iov->iov_base) { + return -1; + } else if (elem_a->src_iov->iov_base > elem_b->src_iov->iov_base) { + return 1; + } else { + return 0; + } +} + +static int sortelem_cmp_src_index(const void *a, const void *b) +{ + const IOVectorSortElem *elem_a = a; + const IOVectorSortElem *elem_b = b; + + return elem_a->src_index - elem_b->src_index; +} + +/** + * Copy contents of I/O vector + * + * The relative relationships of overlapping iovecs are preserved. This is + * necessary to ensure identical semantics in the cloned I/O vector. + */ +void qemu_iovec_clone(QEMUIOVector *dest, const QEMUIOVector *src, void *buf) +{ + IOVectorSortElem sortelems[src->niov]; + void *last_end; + int i; + + /* Sort by source iovecs by base address */ + for (i = 0; i < src->niov; i++) { + sortelems[i].src_index = i; + sortelems[i].src_iov = &src->iov[i]; + } + qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_base); + + /* Allocate buffer space taking into account overlapping iovecs */ + last_end = NULL; + for (i = 0; i < src->niov; i++) { + struct iovec *cur = sortelems[i].src_iov; + ptrdiff_t rewind = 0; + + /* Detect overlap */ + if (last_end && last_end > cur->iov_base) { + rewind = last_end - cur->iov_base; + } + + sortelems[i].dest_base = buf - rewind; + buf += cur->iov_len - MIN(rewind, cur->iov_len); + last_end = MAX(cur->iov_base + cur->iov_len, last_end); + } + + /* Sort by source iovec index and build destination iovec */ + qsort(sortelems, src->niov, sizeof(sortelems[0]), sortelem_cmp_src_index); + for (i = 0; i < src->niov; i++) { + qemu_iovec_add(dest, sortelems[i].dest_base, src->iov[i].iov_len); + } +} + size_t iov_discard_front(struct iovec **iov, unsigned int *iov_cnt, size_t bytes) { -- cgit v1.2.3-55-g7522 From 95c6bff3561eedaf7c7de287bc4a002720605a8d Mon Sep 17 00:00:00 2001 From: Benoît Canet Date: Fri, 21 Feb 2014 22:21:15 +0100 Subject: quorum: Add quorum mechanism. This patchset enables the core of the quorum mechanism. The num_children reads are compared to get the majority version and if this version exists more than threshold times the guest won't see the error at all. If a block is corrupted or if an error occurs during an IO or if the quorum cannot be established QMP events are used to report to the management. Use gnutls's SHA-256 to compare versions. --enable-quorum must be used to enable the feature. Signed-off-by: Benoit Canet Reviewed-by: Max Reitz Signed-off-by: Kevin Wolf --- block/Makefile.objs | 2 +- block/quorum.c | 391 +++++++++++++++++++++++++++++++++++++++++++++- configure | 36 +++++ docs/qmp/qmp-events.txt | 36 +++++ include/monitor/monitor.h | 2 + monitor.c | 2 + 6 files changed, 467 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/block/Makefile.objs b/block/Makefile.objs index 716556f6ec..425d7fbb59 100644 --- a/block/Makefile.objs +++ b/block/Makefile.objs @@ -3,7 +3,7 @@ block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-c block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o block-obj-y += qed-check.o block-obj-$(CONFIG_VHDX) += vhdx.o vhdx-endian.o vhdx-log.o -block-obj-y += quorum.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-$(CONFIG_WIN32) += raw-win32.o win32-aio.o diff --git a/block/quorum.c b/block/quorum.c index fd19662bcb..4beee96ffa 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -13,7 +13,43 @@ * See the COPYING file in the top-level directory. */ +#include +#include #include "block/block_int.h" +#include "qapi/qmp/qjson.h" + +#define HASH_LENGTH 32 + +/* This union holds a vote hash value */ +typedef union QuorumVoteValue { + char h[HASH_LENGTH]; /* SHA-256 hash */ + int64_t l; /* simpler 64 bits hash */ +} QuorumVoteValue; + +/* A vote item */ +typedef struct QuorumVoteItem { + int index; + QLIST_ENTRY(QuorumVoteItem) next; +} QuorumVoteItem; + +/* this structure is a vote version. A version is the set of votes sharing the + * same vote value. + * The set of votes will be tracked with the items field and its cardinality is + * vote_count. + */ +typedef struct QuorumVoteVersion { + QuorumVoteValue value; + int index; + int vote_count; + QLIST_HEAD(, QuorumVoteItem) items; + QLIST_ENTRY(QuorumVoteVersion) next; +} QuorumVoteVersion; + +/* this structure holds a group of vote versions together */ +typedef struct QuorumVotes { + QLIST_HEAD(, QuorumVoteVersion) vote_list; + bool (*compare)(QuorumVoteValue *a, QuorumVoteValue *b); +} QuorumVotes; /* the following structure holds the state of one quorum instance */ typedef struct BDRVQuorumState { @@ -65,10 +101,14 @@ struct QuorumAIOCB { int count; /* number of completed AIOCB */ int success_count; /* number of successfully completed AIOCB */ + QuorumVotes votes; + bool is_read; int vote_ret; }; +static void quorum_vote(QuorumAIOCB *acb); + static void quorum_aio_cancel(BlockDriverAIOCB *blockacb) { QuorumAIOCB *acb = container_of(blockacb, QuorumAIOCB, common); @@ -94,6 +134,10 @@ static void quorum_aio_finalize(QuorumAIOCB *acb) BDRVQuorumState *s = acb->common.bs->opaque; int i, ret = 0; + if (acb->vote_ret) { + ret = acb->vote_ret; + } + acb->common.cb(acb->common.opaque, ret); if (acb->is_read) { @@ -107,6 +151,16 @@ static void quorum_aio_finalize(QuorumAIOCB *acb) qemu_aio_release(acb); } +static bool quorum_sha256_compare(QuorumVoteValue *a, QuorumVoteValue *b) +{ + return !memcmp(a->h, b->h, HASH_LENGTH); +} + +static bool quorum_64bits_compare(QuorumVoteValue *a, QuorumVoteValue *b) +{ + return a->l == b->l; +} + static QuorumAIOCB *quorum_aio_get(BDRVQuorumState *s, BlockDriverState *bs, QEMUIOVector *qiov, @@ -125,6 +179,8 @@ static QuorumAIOCB *quorum_aio_get(BDRVQuorumState *s, acb->qcrs = g_new0(QuorumChildRequest, s->num_children); acb->count = 0; acb->success_count = 0; + acb->votes.compare = quorum_sha256_compare; + QLIST_INIT(&acb->votes.vote_list); acb->is_read = false; acb->vote_ret = 0; @@ -137,6 +193,48 @@ static QuorumAIOCB *quorum_aio_get(BDRVQuorumState *s, return acb; } +static void quorum_report_bad(QuorumAIOCB *acb, char *node_name, int ret) +{ + QObject *data; + assert(node_name); + data = qobject_from_jsonf("{ 'ret': %d" + ", 'node-name': %s" + ", 'sector-num': %" PRId64 + ", 'sectors-count': %d }", + ret, node_name, acb->sector_num, acb->nb_sectors); + monitor_protocol_event(QEVENT_QUORUM_REPORT_BAD, data); + qobject_decref(data); +} + +static void quorum_report_failure(QuorumAIOCB *acb) +{ + QObject *data; + const char *reference = acb->common.bs->device_name[0] ? + acb->common.bs->device_name : + acb->common.bs->node_name; + data = qobject_from_jsonf("{ 'reference': %s" + ", 'sector-num': %" PRId64 + ", 'sectors-count': %d }", + reference, acb->sector_num, acb->nb_sectors); + monitor_protocol_event(QEVENT_QUORUM_FAILURE, data); + qobject_decref(data); +} + +static int quorum_vote_error(QuorumAIOCB *acb); + +static bool quorum_has_too_much_io_failed(QuorumAIOCB *acb) +{ + BDRVQuorumState *s = acb->common.bs->opaque; + + if (acb->success_count < s->threshold) { + acb->vote_ret = quorum_vote_error(acb); + quorum_report_failure(acb); + return true; + } + + return false; +} + static void quorum_aio_cb(void *opaque, int ret) { QuorumChildRequest *sacb = opaque; @@ -147,6 +245,8 @@ static void quorum_aio_cb(void *opaque, int ret) acb->count++; if (ret == 0) { acb->success_count++; + } else { + quorum_report_bad(acb, sacb->aiocb->bs->node_name, ret); } assert(acb->count <= s->num_children); assert(acb->success_count <= s->num_children); @@ -154,9 +254,298 @@ static void quorum_aio_cb(void *opaque, int ret) return; } + /* Do the vote on read */ + if (acb->is_read) { + quorum_vote(acb); + } else { + quorum_has_too_much_io_failed(acb); + } + quorum_aio_finalize(acb); } +static void quorum_report_bad_versions(BDRVQuorumState *s, + QuorumAIOCB *acb, + QuorumVoteValue *value) +{ + QuorumVoteVersion *version; + QuorumVoteItem *item; + + QLIST_FOREACH(version, &acb->votes.vote_list, next) { + if (acb->votes.compare(&version->value, value)) { + continue; + } + QLIST_FOREACH(item, &version->items, next) { + quorum_report_bad(acb, s->bs[item->index]->node_name, 0); + } + } +} + +static void quorum_copy_qiov(QEMUIOVector *dest, QEMUIOVector *source) +{ + int i; + assert(dest->niov == source->niov); + assert(dest->size == source->size); + for (i = 0; i < source->niov; i++) { + assert(dest->iov[i].iov_len == source->iov[i].iov_len); + memcpy(dest->iov[i].iov_base, + source->iov[i].iov_base, + source->iov[i].iov_len); + } +} + +static void quorum_count_vote(QuorumVotes *votes, + QuorumVoteValue *value, + int index) +{ + QuorumVoteVersion *v = NULL, *version = NULL; + QuorumVoteItem *item; + + /* look if we have something with this hash */ + QLIST_FOREACH(v, &votes->vote_list, next) { + if (votes->compare(&v->value, value)) { + version = v; + break; + } + } + + /* It's a version not yet in the list add it */ + if (!version) { + version = g_new0(QuorumVoteVersion, 1); + QLIST_INIT(&version->items); + memcpy(&version->value, value, sizeof(version->value)); + version->index = index; + version->vote_count = 0; + QLIST_INSERT_HEAD(&votes->vote_list, version, next); + } + + version->vote_count++; + + item = g_new0(QuorumVoteItem, 1); + item->index = index; + QLIST_INSERT_HEAD(&version->items, item, next); +} + +static void quorum_free_vote_list(QuorumVotes *votes) +{ + QuorumVoteVersion *version, *next_version; + QuorumVoteItem *item, *next_item; + + QLIST_FOREACH_SAFE(version, &votes->vote_list, next, next_version) { + QLIST_REMOVE(version, next); + QLIST_FOREACH_SAFE(item, &version->items, next, next_item) { + QLIST_REMOVE(item, next); + g_free(item); + } + g_free(version); + } +} + +static int quorum_compute_hash(QuorumAIOCB *acb, int i, QuorumVoteValue *hash) +{ + int j, ret; + gnutls_hash_hd_t dig; + QEMUIOVector *qiov = &acb->qcrs[i].qiov; + + ret = gnutls_hash_init(&dig, GNUTLS_DIG_SHA256); + + if (ret < 0) { + return ret; + } + + for (j = 0; j < qiov->niov; j++) { + ret = gnutls_hash(dig, qiov->iov[j].iov_base, qiov->iov[j].iov_len); + if (ret < 0) { + break; + } + } + + gnutls_hash_deinit(dig, (void *) hash); + return ret; +} + +static QuorumVoteVersion *quorum_get_vote_winner(QuorumVotes *votes) +{ + int max = 0; + QuorumVoteVersion *candidate, *winner = NULL; + + QLIST_FOREACH(candidate, &votes->vote_list, next) { + if (candidate->vote_count > max) { + max = candidate->vote_count; + winner = candidate; + } + } + + return winner; +} + +/* qemu_iovec_compare is handy for blkverify mode because it returns the first + * differing byte location. Yet it is handcoded to compare vectors one byte + * after another so it does not benefit from the libc SIMD optimizations. + * quorum_iovec_compare is written for speed and should be used in the non + * blkverify mode of quorum. + */ +static bool quorum_iovec_compare(QEMUIOVector *a, QEMUIOVector *b) +{ + int i; + int result; + + assert(a->niov == b->niov); + for (i = 0; i < a->niov; i++) { + assert(a->iov[i].iov_len == b->iov[i].iov_len); + result = memcmp(a->iov[i].iov_base, + b->iov[i].iov_base, + a->iov[i].iov_len); + if (result) { + return false; + } + } + + return true; +} + +static void GCC_FMT_ATTR(2, 3) quorum_err(QuorumAIOCB *acb, + const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "quorum: sector_num=%" PRId64 " nb_sectors=%d ", + acb->sector_num, acb->nb_sectors); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + exit(1); +} + +static bool quorum_compare(QuorumAIOCB *acb, + QEMUIOVector *a, + QEMUIOVector *b) +{ + BDRVQuorumState *s = acb->common.bs->opaque; + ssize_t offset; + + /* This driver will replace blkverify in this particular case */ + if (s->is_blkverify) { + offset = qemu_iovec_compare(a, b); + if (offset != -1) { + quorum_err(acb, "contents mismatch in sector %" PRId64, + acb->sector_num + + (uint64_t)(offset / BDRV_SECTOR_SIZE)); + } + return true; + } + + return quorum_iovec_compare(a, b); +} + +/* Do a vote to get the error code */ +static int quorum_vote_error(QuorumAIOCB *acb) +{ + BDRVQuorumState *s = acb->common.bs->opaque; + QuorumVoteVersion *winner = NULL; + QuorumVotes error_votes; + QuorumVoteValue result_value; + int i, ret = 0; + bool error = false; + + QLIST_INIT(&error_votes.vote_list); + error_votes.compare = quorum_64bits_compare; + + for (i = 0; i < s->num_children; i++) { + ret = acb->qcrs[i].ret; + if (ret) { + error = true; + result_value.l = ret; + quorum_count_vote(&error_votes, &result_value, i); + } + } + + if (error) { + winner = quorum_get_vote_winner(&error_votes); + ret = winner->value.l; + } + + quorum_free_vote_list(&error_votes); + + return ret; +} + +static void quorum_vote(QuorumAIOCB *acb) +{ + bool quorum = true; + int i, j, ret; + QuorumVoteValue hash; + BDRVQuorumState *s = acb->common.bs->opaque; + QuorumVoteVersion *winner; + + if (quorum_has_too_much_io_failed(acb)) { + return; + } + + /* get the index of the first successful read */ + for (i = 0; i < s->num_children; i++) { + if (!acb->qcrs[i].ret) { + break; + } + } + + assert(i < s->num_children); + + /* compare this read with all other successful reads stopping at quorum + * failure + */ + for (j = i + 1; j < s->num_children; j++) { + if (acb->qcrs[j].ret) { + continue; + } + quorum = quorum_compare(acb, &acb->qcrs[i].qiov, &acb->qcrs[j].qiov); + if (!quorum) { + break; + } + } + + /* Every successful read agrees */ + if (quorum) { + quorum_copy_qiov(acb->qiov, &acb->qcrs[i].qiov); + return; + } + + /* compute hashes for each successful read, also store indexes */ + for (i = 0; i < s->num_children; i++) { + if (acb->qcrs[i].ret) { + continue; + } + ret = quorum_compute_hash(acb, i, &hash); + /* if ever the hash computation failed */ + if (ret < 0) { + acb->vote_ret = ret; + goto free_exit; + } + quorum_count_vote(&acb->votes, &hash, i); + } + + /* vote to select the most represented version */ + winner = quorum_get_vote_winner(&acb->votes); + + /* if the winner count is smaller than threshold the read fails */ + if (winner->vote_count < s->threshold) { + quorum_report_failure(acb); + acb->vote_ret = -EIO; + goto free_exit; + } + + /* we have a winner: copy it */ + quorum_copy_qiov(acb->qiov, &acb->qcrs[winner->index].qiov); + + /* some versions are bad print them */ + quorum_report_bad_versions(s, acb, &winner->value); + +free_exit: + /* free lists */ + quorum_free_vote_list(&acb->votes); +} + static BlockDriverAIOCB *quorum_aio_readv(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, @@ -178,7 +567,7 @@ static BlockDriverAIOCB *quorum_aio_readv(BlockDriverState *bs, } for (i = 0; i < s->num_children; i++) { - bdrv_aio_readv(s->bs[i], sector_num, qiov, nb_sectors, + bdrv_aio_readv(s->bs[i], sector_num, &acb->qcrs[i].qiov, nb_sectors, quorum_aio_cb, &acb->qcrs[i]); } diff --git a/configure b/configure index 39f2a1acd2..6143acbcbf 100755 --- a/configure +++ b/configure @@ -264,6 +264,7 @@ gtkabi="2.0" tpm="no" libssh2="" vhdx="" +quorum="no" # parse CC options first for opt do @@ -1005,6 +1006,10 @@ for opt do ;; --disable-vhdx) vhdx="no" ;; + --disable-quorum) quorum="no" + ;; + --enable-quorum) quorum="yes" + ;; *) echo "ERROR: unknown option $opt"; show_help="yes" ;; esac @@ -1261,6 +1266,8 @@ Advanced options (experts only): --enable-libssh2 enable ssh block device support --disable-vhdx disables support for the Microsoft VHDX image format --enable-vhdx enable support for the Microsoft VHDX image format + --disable-quorum disable quorum block filter support + --enable-quorum enable quorum block filter support NOTE: The object files are built at the place where configure is launched EOF @@ -1936,6 +1943,30 @@ EOF fi fi +########################################## +# Quorum probe (check for gnutls) +if test "$quorum" != "no" ; then +cat > $TMPC < +#include +int main(void) {char data[4096], digest[32]; +gnutls_hash_fast(GNUTLS_DIG_SHA256, data, 4096, digest); +return 0; +} +EOF +quorum_tls_cflags=`$pkg_config --cflags gnutls 2> /dev/null` +quorum_tls_libs=`$pkg_config --libs gnutls 2> /dev/null` +if compile_prog "$quorum_tls_cflags" "$quorum_tls_libs" ; then + qcow_tls=yes + libs_softmmu="$quorum_tls_libs $libs_softmmu" + libs_tools="$quorum_tls_libs $libs_softmmu" + QEMU_CFLAGS="$QEMU_CFLAGS $quorum_tls_cflags" +else + echo "gnutls > 2.10.0 required to compile Quorum" + exit 1 +fi +fi + ########################################## # VNC SASL detection if test "$vnc" = "yes" -a "$vnc_sasl" != "no" ; then @@ -3893,6 +3924,7 @@ echo "libssh2 support $libssh2" echo "TPM passthrough $tpm_passthrough" echo "QOM debugging $qom_cast_debug" echo "vhdx $vhdx" +echo "Quorum $quorum" if test "$sdl_too_old" = "yes"; then echo "-> Your SDL version is too old - please upgrade to have SDL support" @@ -4295,6 +4327,10 @@ if test "$libssh2" = "yes" ; then echo "CONFIG_LIBSSH2=y" >> $config_host_mak fi +if test "$quorum" = "yes" ; then + echo "CONFIG_QUORUM=y" >> $config_host_mak +fi + if test "$virtio_blk_data_plane" = "yes" ; then echo 'CONFIG_VIRTIO_BLK_DATA_PLANE=$(CONFIG_VIRTIO)' >> $config_host_mak fi diff --git a/docs/qmp/qmp-events.txt b/docs/qmp/qmp-events.txt index a378c87583..00f95154dd 100644 --- a/docs/qmp/qmp-events.txt +++ b/docs/qmp/qmp-events.txt @@ -500,3 +500,39 @@ Example: Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is followed respectively by the RESET, SHUTDOWN, or STOP events. + +QUORUM_FAILURE +-------------- + +Emitted by the Quorum block driver if it fails to establish a quorum. + +Data: + +- "reference": device name if defined else node name. +- "sector-num": Number of the first sector of the failed read operation. +- "sector-count": Failed read operation sector count. + +Example: + +{ "event": "QUORUM_FAILURE", + "data": { "reference": "usr1", "sector-num": 345435, "sector-count": 5 }, + "timestamp": { "seconds": 1344522075, "microseconds": 745528 } } + +QUORUM_REPORT_BAD +----------------- + +Emitted to report a corruption of a Quorum file. + +Data: + +- "ret": The IO return code. +- "node-name": The graph node name of the block driver state. +- "sector-num": Number of the first sector of the failed read operation. +- "sector-count": Failed read operation sector count. + +Example: + +{ "event": "QUORUM_REPORT_BAD", + "data": { "ret": 0, "node-name": "1.raw", "sector-num": 345435, + "sector-count": 5 }, + "timestamp": { "seconds": 1344522075, "microseconds": 745528 } } diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index 7e5f752b7a..a49ea11eb4 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -49,6 +49,8 @@ typedef enum MonitorEvent { QEVENT_SPICE_MIGRATE_COMPLETED, QEVENT_GUEST_PANICKED, QEVENT_BLOCK_IMAGE_CORRUPTED, + QEVENT_QUORUM_FAILURE, + QEVENT_QUORUM_REPORT_BAD, /* Add to 'monitor_event_names' array in monitor.c when * defining new events here */ diff --git a/monitor.c b/monitor.c index de90fba41e..8ae095f16a 100644 --- a/monitor.c +++ b/monitor.c @@ -508,6 +508,8 @@ static const char *monitor_event_names[] = { [QEVENT_SPICE_MIGRATE_COMPLETED] = "SPICE_MIGRATE_COMPLETED", [QEVENT_GUEST_PANICKED] = "GUEST_PANICKED", [QEVENT_BLOCK_IMAGE_CORRUPTED] = "BLOCK_IMAGE_CORRUPTED", + [QEVENT_QUORUM_FAILURE] = "QUORUM_FAILURE", + [QEVENT_QUORUM_REPORT_BAD] = "QUORUM_REPORT_BAD", }; QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX) -- cgit v1.2.3-55-g7522