diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-04-25 12:22:37 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-04-25 12:22:37 +0100 |
commit | 7931b05987564b07ada5a4467d8e78a786a3e7d4 (patch) | |
tree | c3cb42df6e17e3985c055637700dea279c5b7656 | |
parent | 0e96643c98eb22a5f2e11ac500852133032d38e4 (diff) | |
parent | 370e681629da587af7592a7b83ebc7ec4955461e (diff) | |
download | qemu-7931b05987564b07ada5a4467d8e78a786a3e7d4.zip qemu-7931b05987564b07ada5a4467d8e78a786a3e7d4.tar.gz qemu-7931b05987564b07ada5a4467d8e78a786a3e7d4.tar.bz2 |
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block patches
# gpg: Signature made Wed 23 Apr 2014 11:02:29 BST using RSA key ID C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>"
* remotes/kevin/tags/for-upstream:
block/cloop: use PRIu32 format specifier for uint32_t
vmdk: Fix "%x" to PRIx32 in format strings for cid
qemu-img: Improve error messages
qemu-iotests: Check common namespace for id and node-name
block: Catch duplicate IDs in bdrv_new()
qemu-img: Avoid duplicate block device IDs
block: Add errp to bdrv_new()
convert fprintf() calls to error_setg() in block/qed.c:bdrv_qed_create()
block: Remove -errno return value from bdrv_assign_node_name
curl: Replaced old error handling with error reporting API.
block: Handle error of bdrv_getlength in bdrv_create_dirty_bitmap
vmdk: Fix %d and %lld to PRI* in format strings
block: Check bdrv_getlength() return value in bdrv_make_zero()
block: Catch integer overflow in bdrv_rw_co()
block: Limit size to INT_MAX in bdrv_check_byte_request()
block: Fix nb_sectors check in bdrv_check_byte_request()
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | block-migration.c | 30 | ||||
-rw-r--r-- | block.c | 69 | ||||
-rw-r--r-- | block/cloop.c | 12 | ||||
-rw-r--r-- | block/curl.c | 2 | ||||
-rw-r--r-- | block/iscsi.c | 2 | ||||
-rw-r--r-- | block/mirror.c | 5 | ||||
-rw-r--r-- | block/qed.c | 16 | ||||
-rw-r--r-- | block/vmdk.c | 23 | ||||
-rw-r--r-- | block/vvfat.c | 2 | ||||
-rw-r--r-- | blockdev.c | 15 | ||||
-rw-r--r-- | hw/block/xen_disk.c | 7 | ||||
-rw-r--r-- | include/block/block.h | 5 | ||||
-rw-r--r-- | qemu-img.c | 116 | ||||
-rw-r--r-- | qemu-io.c | 2 | ||||
-rw-r--r-- | qemu-nbd.c | 3 | ||||
-rw-r--r-- | tests/qemu-iotests/084.out | 5 | ||||
-rwxr-xr-x | tests/qemu-iotests/087 | 85 | ||||
-rw-r--r-- | tests/qemu-iotests/087.out | 18 |
18 files changed, 302 insertions, 115 deletions
diff --git a/block-migration.c b/block-migration.c index 897fdba..56951e0 100644 --- a/block-migration.c +++ b/block-migration.c @@ -310,13 +310,28 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) /* Called with iothread lock taken. */ -static void set_dirty_tracking(void) +static int set_dirty_tracking(void) { BlkMigDevState *bmds; + int ret; QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { - bmds->dirty_bitmap = bdrv_create_dirty_bitmap(bmds->bs, BLOCK_SIZE); + bmds->dirty_bitmap = bdrv_create_dirty_bitmap(bmds->bs, BLOCK_SIZE, + NULL); + if (!bmds->dirty_bitmap) { + ret = -errno; + goto fail; + } } + return 0; + +fail: + QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { + if (bmds->dirty_bitmap) { + bdrv_release_dirty_bitmap(bmds->bs, bmds->dirty_bitmap); + } + } + return ret; } static void unset_dirty_tracking(void) @@ -611,10 +626,17 @@ static int block_save_setup(QEMUFile *f, void *opaque) block_mig_state.submitted, block_mig_state.transferred); qemu_mutex_lock_iothread(); - init_blk_migration(f); /* start track dirty blocks */ - set_dirty_tracking(); + ret = set_dirty_tracking(); + + if (ret) { + qemu_mutex_unlock_iothread(); + return ret; + } + + init_blk_migration(f); + qemu_mutex_unlock_iothread(); ret = flush_blks(f); @@ -332,10 +332,21 @@ void bdrv_register(BlockDriver *bdrv) } /* create a new block device (by default it is empty) */ -BlockDriverState *bdrv_new(const char *device_name) +BlockDriverState *bdrv_new(const char *device_name, Error **errp) { BlockDriverState *bs; + if (bdrv_find(device_name)) { + error_setg(errp, "Device with id '%s' already exists", + device_name); + return NULL; + } + if (bdrv_find_node(device_name)) { + error_setg(errp, "Device with node-name '%s' already exists", + device_name); + return NULL; + } + bs = g_malloc0(sizeof(BlockDriverState)); QLIST_INIT(&bs->dirty_bitmaps); pstrcpy(bs->device_name, sizeof(bs->device_name), device_name); @@ -788,38 +799,36 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags) return open_flags; } -static int bdrv_assign_node_name(BlockDriverState *bs, - const char *node_name, - Error **errp) +static void bdrv_assign_node_name(BlockDriverState *bs, + const char *node_name, + Error **errp) { if (!node_name) { - return 0; + return; } /* empty string node name is invalid */ if (node_name[0] == '\0') { error_setg(errp, "Empty node name"); - return -EINVAL; + return; } /* takes care of avoiding namespaces collisions */ if (bdrv_find(node_name)) { error_setg(errp, "node-name=%s is conflicting with a device id", node_name); - return -EINVAL; + return; } /* takes care of avoiding duplicates node names */ if (bdrv_find_node(node_name)) { error_setg(errp, "Duplicate node name"); - return -EINVAL; + return; } /* copy node name into the bs and insert it into the graph list */ pstrcpy(bs->node_name, sizeof(bs->node_name), node_name); QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs, node_list); - - return 0; } /* @@ -854,9 +863,10 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, trace_bdrv_open_common(bs, filename ?: "", flags, drv->format_name); node_name = qdict_get_try_str(options, "node-name"); - ret = bdrv_assign_node_name(bs, node_name, errp); - if (ret < 0) { - return ret; + bdrv_assign_node_name(bs, node_name, &local_err); + if (error_is_set(&local_err)) { + error_propagate(errp, local_err); + return -EINVAL; } qdict_del(options, "node-name"); @@ -1221,7 +1231,7 @@ void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp) qdict_put(snapshot_options, "file.filename", qstring_from_str(tmp_filename)); - bs_snapshot = bdrv_new(""); + bs_snapshot = bdrv_new("", &error_abort); bs_snapshot->is_temporary = 1; ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options, @@ -1288,7 +1298,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename, if (*pbs) { bs = *pbs; } else { - bs = bdrv_new(""); + bs = bdrv_new("", &error_abort); } /* NULL means an empty set of options */ @@ -2581,6 +2591,10 @@ static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset, { int64_t len; + if (size > INT_MAX) { + return -EIO; + } + if (!bdrv_is_inserted(bs)) return -ENOMEDIUM; @@ -2601,7 +2615,7 @@ static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset, static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num, int nb_sectors) { - if (nb_sectors > INT_MAX / BDRV_SECTOR_SIZE) { + if (nb_sectors < 0 || nb_sectors > INT_MAX / BDRV_SECTOR_SIZE) { return -EIO; } @@ -2686,6 +2700,10 @@ static int bdrv_rw_co(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, .iov_len = nb_sectors * BDRV_SECTOR_SIZE, }; + if (nb_sectors < 0 || nb_sectors > INT_MAX / BDRV_SECTOR_SIZE) { + return -EINVAL; + } + qemu_iovec_init_external(&qiov, &iov, 1); return bdrv_prwv_co(bs, sector_num << BDRV_SECTOR_BITS, &qiov, is_write, flags); @@ -2741,10 +2759,16 @@ int bdrv_write_zeroes(BlockDriverState *bs, int64_t sector_num, */ int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags) { - int64_t target_size = bdrv_getlength(bs) / BDRV_SECTOR_SIZE; + int64_t target_size; int64_t ret, nb_sectors, sector_num = 0; int n; + target_size = bdrv_getlength(bs); + if (target_size < 0) { + return target_size; + } + target_size /= BDRV_SECTOR_SIZE; + for (;;) { nb_sectors = target_size - sector_num; if (nb_sectors <= 0) { @@ -5096,7 +5120,8 @@ bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov) return true; } -BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity) +BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity, + Error **errp) { int64_t bitmap_size; BdrvDirtyBitmap *bitmap; @@ -5105,7 +5130,13 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity) granularity >>= BDRV_SECTOR_BITS; assert(granularity); - bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS); + bitmap_size = bdrv_getlength(bs); + if (bitmap_size < 0) { + error_setg_errno(errp, -bitmap_size, "could not get length of device"); + errno = -bitmap_size; + return NULL; + } + bitmap_size >>= BDRV_SECTOR_BITS; bitmap = g_malloc0(sizeof(BdrvDirtyBitmap)); bitmap->bitmap = hbitmap_alloc(bitmap_size, ffs(granularity) - 1); QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list); diff --git a/block/cloop.c b/block/cloop.c index b6ad50f..8457737 100644 --- a/block/cloop.c +++ b/block/cloop.c @@ -72,7 +72,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags, } s->block_size = be32_to_cpu(s->block_size); if (s->block_size % 512) { - error_setg(errp, "block_size %u must be a multiple of 512", + error_setg(errp, "block_size %" PRIu32 " must be a multiple of 512", s->block_size); return -EINVAL; } @@ -86,7 +86,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags, * need a buffer this big. */ if (s->block_size > MAX_BLOCK_SIZE) { - error_setg(errp, "block_size %u must be %u MB or less", + error_setg(errp, "block_size %" PRIu32 " must be %u MB or less", s->block_size, MAX_BLOCK_SIZE / (1024 * 1024)); return -EINVAL; @@ -101,7 +101,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags, /* read offsets */ if (s->n_blocks > (UINT32_MAX - 1) / sizeof(uint64_t)) { /* Prevent integer overflow */ - error_setg(errp, "n_blocks %u must be %zu or less", + error_setg(errp, "n_blocks %" PRIu32 " must be %zu or less", s->n_blocks, (UINT32_MAX - 1) / sizeof(uint64_t)); return -EINVAL; @@ -133,7 +133,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags, if (s->offsets[i] < s->offsets[i - 1]) { error_setg(errp, "offsets not monotonically increasing at " - "index %u, image file is corrupt", i); + "index %" PRIu32 ", image file is corrupt", i); ret = -EINVAL; goto fail; } @@ -146,8 +146,8 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags, * ridiculous s->compressed_block allocation. */ if (size > 2 * MAX_BLOCK_SIZE) { - error_setg(errp, "invalid compressed block size at index %u, " - "image file is corrupt", i); + error_setg(errp, "invalid compressed block size at index %" PRIu32 + ", image file is corrupt", i); ret = -EINVAL; goto fail; } diff --git a/block/curl.c b/block/curl.c index 1b9b1f6..6731d28 100644 --- a/block/curl.c +++ b/block/curl.c @@ -543,7 +543,7 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags, return 0; out: - fprintf(stderr, "CURL: Error opening file: %s\n", state->errmsg); + error_setg(errp, "CURL: Error opening file: %s", state->errmsg); curl_easy_cleanup(state->curl); state->curl = NULL; out_noclean: diff --git a/block/iscsi.c b/block/iscsi.c index f425573..a636ea4 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -1401,7 +1401,7 @@ static int iscsi_create(const char *filename, QEMUOptionParameter *options, IscsiLun *iscsilun = NULL; QDict *bs_options; - bs = bdrv_new(""); + bs = bdrv_new("", &error_abort); /* Read out options */ while (options && options->name) { diff --git a/block/mirror.c b/block/mirror.c index 0ef41f9..2618c37 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -605,7 +605,10 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target, s->granularity = granularity; s->buf_size = MAX(buf_size, granularity); - s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity); + s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, errp); + if (!s->dirty_bitmap) { + return; + } bdrv_set_enable_write_cache(s->target, true); bdrv_set_on_error(s->target, on_target_error, on_target_error); bdrv_iostatus_enable(s->target); diff --git a/block/qed.c b/block/qed.c index 3bd9db9..c130e42 100644 --- a/block/qed.c +++ b/block/qed.c @@ -650,19 +650,21 @@ static int bdrv_qed_create(const char *filename, QEMUOptionParameter *options, } if (!qed_is_cluster_size_valid(cluster_size)) { - fprintf(stderr, "QED cluster size must be within range [%u, %u] and power of 2\n", - QED_MIN_CLUSTER_SIZE, QED_MAX_CLUSTER_SIZE); + error_setg(errp, "QED cluster size must be within range [%u, %u] " + "and power of 2", + QED_MIN_CLUSTER_SIZE, QED_MAX_CLUSTER_SIZE); return -EINVAL; } if (!qed_is_table_size_valid(table_size)) { - fprintf(stderr, "QED table size must be within range [%u, %u] and power of 2\n", - QED_MIN_TABLE_SIZE, QED_MAX_TABLE_SIZE); + error_setg(errp, "QED table size must be within range [%u, %u] " + "and power of 2", + QED_MIN_TABLE_SIZE, QED_MAX_TABLE_SIZE); return -EINVAL; } if (!qed_is_image_size_valid(image_size, cluster_size, table_size)) { - fprintf(stderr, "QED image size must be a non-zero multiple of " - "cluster size and less than %" PRIu64 " bytes\n", - qed_max_image_size(cluster_size, table_size)); + error_setg(errp, "QED image size must be a non-zero multiple of " + "cluster size and less than %" PRIu64 " bytes", + qed_max_image_size(cluster_size, table_size)); return -EINVAL; } diff --git a/block/vmdk.c b/block/vmdk.c index b69988d..06a1f9f 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -262,7 +262,7 @@ static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent) p_name = strstr(desc, cid_str); if (p_name != NULL) { p_name += cid_str_size; - sscanf(p_name, "%x", &cid); + sscanf(p_name, "%" SCNx32, &cid); } return cid; @@ -290,7 +290,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid) p_name = strstr(desc, "CID"); if (p_name != NULL) { p_name += sizeof("CID"); - snprintf(p_name, sizeof(desc) - (p_name - desc), "%x\n", cid); + snprintf(p_name, sizeof(desc) - (p_name - desc), "%" PRIx32 "\n", cid); pstrcat(desc, sizeof(desc), tmp_desc); } @@ -640,7 +640,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, if (le32_to_cpu(header.version) > 3) { char buf[64]; - snprintf(buf, sizeof(buf), "VMDK version %d", + snprintf(buf, sizeof(buf), "VMDK version %" PRId32, le32_to_cpu(header.version)); error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, bs->device_name, "vmdk", buf); @@ -671,8 +671,9 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, } if (bdrv_getlength(file) < le64_to_cpu(header.grain_offset) * BDRV_SECTOR_SIZE) { - error_setg(errp, "File truncated, expecting at least %lld bytes", - le64_to_cpu(header.grain_offset) * BDRV_SECTOR_SIZE); + error_setg(errp, "File truncated, expecting at least %" PRId64 " bytes", + (int64_t)(le64_to_cpu(header.grain_offset) + * BDRV_SECTOR_SIZE)); return -EINVAL; } @@ -1707,8 +1708,8 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, const char desc_template[] = "# Disk DescriptorFile\n" "version=1\n" - "CID=%x\n" - "parentCID=%x\n" + "CID=%" PRIx32 "\n" + "parentCID=%" PRIx32 "\n" "createType=\"%s\"\n" "%s" "\n" @@ -1720,7 +1721,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, "\n" "ddb.virtualHWVersion = \"%d\"\n" "ddb.geometry.cylinders = \"%" PRId64 "\"\n" - "ddb.geometry.heads = \"%d\"\n" + "ddb.geometry.heads = \"%" PRIu32 "\"\n" "ddb.geometry.sectors = \"63\"\n" "ddb.adapterType = \"%s\"\n"; @@ -1780,9 +1781,9 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, strcmp(fmt, "twoGbMaxExtentFlat")); compress = !strcmp(fmt, "streamOptimized"); if (flat) { - desc_extent_line = "RW %lld FLAT \"%s\" 0\n"; + desc_extent_line = "RW %" PRId64 " FLAT \"%s\" 0\n"; } else { - desc_extent_line = "RW %lld SPARSE \"%s\"\n"; + desc_extent_line = "RW %" PRId64 " SPARSE \"%s\"\n"; } if (flat && backing_file) { error_setg(errp, "Flat image can't have backing file"); @@ -1850,7 +1851,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, } /* generate descriptor file */ desc = g_strdup_printf(desc_template, - (unsigned int)time(NULL), + (uint32_t)time(NULL), parent_cid, fmt, parent_desc_line, diff --git a/block/vvfat.c b/block/vvfat.c index 1978c9e..c3af7ff 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -2947,7 +2947,7 @@ static int enable_write_target(BDRVVVFATState *s) unlink(s->qcow_filename); #endif - s->bs->backing_hd = bdrv_new(""); + s->bs->backing_hd = bdrv_new("", &error_abort); s->bs->backing_hd->drv = &vvfat_write_target; s->bs->backing_hd->opaque = g_malloc(sizeof(void*)); *(void**)s->bs->backing_hd->opaque = s; @@ -452,16 +452,14 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts, } } - if (bdrv_find_node(qemu_opts_id(opts))) { - error_setg(errp, "device id=%s is conflicting with a node-name", - qemu_opts_id(opts)); - goto early_err; - } - /* init */ dinfo = g_malloc0(sizeof(*dinfo)); dinfo->id = g_strdup(qemu_opts_id(opts)); - dinfo->bdrv = bdrv_new(dinfo->id); + dinfo->bdrv = bdrv_new(dinfo->id, &error); + if (error) { + error_propagate(errp, error); + goto bdrv_new_err; + } dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0; dinfo->bdrv->read_only = ro; dinfo->refcount = 1; @@ -523,8 +521,9 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts, err: bdrv_unref(dinfo->bdrv); - g_free(dinfo->id); QTAILQ_REMOVE(&drives, dinfo, next); +bdrv_new_err: + g_free(dinfo->id); g_free(dinfo); early_err: QDECREF(bs_opts); diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c index bc061e6..a8fea72 100644 --- a/hw/block/xen_disk.c +++ b/hw/block/xen_disk.c @@ -817,11 +817,14 @@ static int blk_connect(struct XenDevice *xendev) index = (blkdev->xendev.dev - 202 * 256) / 16; blkdev->dinfo = drive_get(IF_XEN, 0, index); if (!blkdev->dinfo) { + Error *local_err = NULL; /* setup via xenbus -> create new block driver instance */ xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n"); - blkdev->bs = bdrv_new(blkdev->dev); + blkdev->bs = bdrv_new(blkdev->dev, &local_err); + if (local_err) { + blkdev->bs = NULL; + } if (blkdev->bs) { - Error *local_err = NULL; BlockDriver *drv = bdrv_find_whitelisted_format(blkdev->fileproto, readonly); if (bdrv_open(&blkdev->bs, blkdev->filename, NULL, NULL, qflags, diff --git a/include/block/block.h b/include/block/block.h index b3230a2..c12808a 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -180,7 +180,7 @@ int bdrv_create(BlockDriver *drv, const char* filename, QEMUOptionParameter *options, Error **errp); int bdrv_create_file(const char* filename, QEMUOptionParameter *options, Error **errp); -BlockDriverState *bdrv_new(const char *device_name); +BlockDriverState *bdrv_new(const char *device_name, Error **errp); void bdrv_make_anon(BlockDriverState *bs); void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old); void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top); @@ -429,7 +429,8 @@ bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov); struct HBitmapIter; typedef struct BdrvDirtyBitmap BdrvDirtyBitmap; -BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity); +BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity, + Error **errp); void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap); BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs); int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector); @@ -57,8 +57,22 @@ static void format_print(void *opaque, const char *name) printf(" %s", name); } +static void QEMU_NORETURN GCC_FMT_ATTR(1, 2) error_exit(const char *fmt, ...) +{ + va_list ap; + + error_printf("qemu-img: "); + + va_start(ap, fmt); + error_vprintf(fmt, ap); + va_end(ap); + + error_printf("\nTry 'qemu-img --help' for more information\n"); + exit(EXIT_FAILURE); +} + /* Please keep in synch with qemu-img.texi */ -static void help(void) +static void QEMU_NORETURN help(void) { const char *help_msg = "qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n" @@ -129,7 +143,7 @@ static void help(void) printf("%s\nSupported formats:", help_msg); bdrv_iterate_format(format_print, NULL); printf("\n"); - exit(1); + exit(EXIT_SUCCESS); } static int GCC_FMT_ATTR(2, 3) qprintf(bool quiet, const char *fmt, ...) @@ -262,7 +276,8 @@ static int print_block_option_help(const char *filename, const char *fmt) return 0; } -static BlockDriverState *bdrv_new_open(const char *filename, +static BlockDriverState *bdrv_new_open(const char *id, + const char *filename, const char *fmt, int flags, bool require_io, @@ -274,7 +289,7 @@ static BlockDriverState *bdrv_new_open(const char *filename, Error *local_err = NULL; int ret; - bs = bdrv_new("image"); + bs = bdrv_new(id, &error_abort); if (fmt) { drv = bdrv_find_format(fmt); @@ -398,7 +413,7 @@ static int img_create(int argc, char **argv) } if (optind >= argc) { - help(); + error_exit("Expecting image file name"); } optind++; @@ -421,7 +436,7 @@ static int img_create(int argc, char **argv) img_size = (uint64_t)sval; } if (optind != argc) { - help(); + error_exit("Unexpected argument: %s", argv[optind]); } bdrv_img_create(filename, fmt, base_filename, base_fmt, @@ -590,7 +605,8 @@ static int img_check(int argc, char **argv) } else if (!strcmp(optarg, "all")) { fix = BDRV_FIX_LEAKS | BDRV_FIX_ERRORS; } else { - help(); + error_exit("Unknown option value for -r " + "(expecting 'leaks' or 'all'): %s", optarg); } break; case OPTION_OUTPUT: @@ -602,7 +618,7 @@ static int img_check(int argc, char **argv) } } if (optind != argc - 1) { - help(); + error_exit("Expecting one image file name"); } filename = argv[optind++]; @@ -615,7 +631,7 @@ static int img_check(int argc, char **argv) return 1; } - bs = bdrv_new_open(filename, fmt, flags, true, quiet); + bs = bdrv_new_open("image", filename, fmt, flags, true, quiet); if (!bs) { return 1; } @@ -713,7 +729,7 @@ static int img_commit(int argc, char **argv) } } if (optind != argc - 1) { - help(); + error_exit("Expecting one image file name"); } filename = argv[optind++]; @@ -724,7 +740,7 @@ static int img_commit(int argc, char **argv) return -1; } - bs = bdrv_new_open(filename, fmt, flags, true, quiet); + bs = bdrv_new_open("image", filename, fmt, flags, true, quiet); if (!bs) { return 1; } @@ -959,7 +975,7 @@ static int img_compare(int argc, char **argv) if (optind != argc - 2) { - help(); + error_exit("Expecting two image file names"); } filename1 = argv[optind++]; filename2 = argv[optind++]; @@ -967,14 +983,14 @@ static int img_compare(int argc, char **argv) /* Initialize before goto out */ qemu_progress_init(progress, 2.0); - bs1 = bdrv_new_open(filename1, fmt1, BDRV_O_FLAGS, true, quiet); + bs1 = bdrv_new_open("image 1", filename1, fmt1, BDRV_O_FLAGS, true, quiet); if (!bs1) { error_report("Can't open file %s", filename1); ret = 2; goto out3; } - bs2 = bdrv_new_open(filename2, fmt2, BDRV_O_FLAGS, true, quiet); + bs2 = bdrv_new_open("image 2", filename2, fmt2, BDRV_O_FLAGS, true, quiet); if (!bs2) { error_report("Can't open file %s", filename2); ret = 2; @@ -1275,7 +1291,7 @@ static int img_convert(int argc, char **argv) } if (bs_n < 1) { - help(); + error_exit("Must specify image file name"); } @@ -1292,8 +1308,11 @@ static int img_convert(int argc, char **argv) total_sectors = 0; for (bs_i = 0; bs_i < bs_n; bs_i++) { - bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, BDRV_O_FLAGS, true, - quiet); + char *id = bs_n > 1 ? g_strdup_printf("source %d", bs_i) + : g_strdup("source"); + bs[bs_i] = bdrv_new_open(id, argv[optind + bs_i], fmt, BDRV_O_FLAGS, + true, quiet); + g_free(id); if (!bs[bs_i]) { error_report("Could not open '%s'", argv[optind + bs_i]); ret = -1; @@ -1416,7 +1435,7 @@ static int img_convert(int argc, char **argv) return -1; } - out_bs = bdrv_new_open(out_filename, out_fmt, flags, true, quiet); + out_bs = bdrv_new_open("target", out_filename, out_fmt, flags, true, quiet); if (!out_bs) { ret = -1; goto out; @@ -1799,8 +1818,8 @@ static ImageInfoList *collect_image_info_list(const char *filename, } g_hash_table_insert(filenames, (gpointer)filename, NULL); - bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING, - false, false); + bs = bdrv_new_open("image", filename, fmt, + BDRV_O_FLAGS | BDRV_O_NO_BACKING, false, false); if (!bs) { goto err; } @@ -1882,7 +1901,7 @@ static int img_info(int argc, char **argv) } } if (optind != argc - 1) { - help(); + error_exit("Expecting one image file name"); } filename = argv[optind++]; @@ -2046,10 +2065,10 @@ static int img_map(int argc, char **argv) break; } } - if (optind >= argc) { - help(); + if (optind != argc - 1) { + error_exit("Expecting one image file name"); } - filename = argv[optind++]; + filename = argv[optind]; if (output && !strcmp(output, "json")) { output_format = OFORMAT_JSON; @@ -2060,7 +2079,7 @@ static int img_map(int argc, char **argv) return 1; } - bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS, true, false); + bs = bdrv_new_open("image", filename, fmt, BDRV_O_FLAGS, true, false); if (!bs) { return 1; } @@ -2138,7 +2157,7 @@ static int img_snapshot(int argc, char **argv) return 0; case 'l': if (action) { - help(); + error_exit("Cannot mix '-l', '-a', '-c', '-d'"); return 0; } action = SNAPSHOT_LIST; @@ -2146,7 +2165,7 @@ static int img_snapshot(int argc, char **argv) break; case 'a': if (action) { - help(); + error_exit("Cannot mix '-l', '-a', '-c', '-d'"); return 0; } action = SNAPSHOT_APPLY; @@ -2154,7 +2173,7 @@ static int img_snapshot(int argc, char **argv) break; case 'c': if (action) { - help(); + error_exit("Cannot mix '-l', '-a', '-c', '-d'"); return 0; } action = SNAPSHOT_CREATE; @@ -2162,7 +2181,7 @@ static int img_snapshot(int argc, char **argv) break; case 'd': if (action) { - help(); + error_exit("Cannot mix '-l', '-a', '-c', '-d'"); return 0; } action = SNAPSHOT_DELETE; @@ -2175,12 +2194,12 @@ static int img_snapshot(int argc, char **argv) } if (optind != argc - 1) { - help(); + error_exit("Expecting one image file name"); } filename = argv[optind++]; /* Open the image */ - bs = bdrv_new_open(filename, NULL, bdrv_oflags, true, quiet); + bs = bdrv_new_open("image", filename, NULL, bdrv_oflags, true, quiet); if (!bs) { return 1; } @@ -2288,8 +2307,11 @@ static int img_rebase(int argc, char **argv) progress = 0; } - if ((optind != argc - 1) || (!unsafe && !out_baseimg)) { - help(); + if (optind != argc - 1) { + error_exit("Expecting one image file name"); + } + if (!unsafe && !out_baseimg) { + error_exit("Must specify backing file (-b) or use unsafe mode (-u)"); } filename = argv[optind++]; @@ -2309,7 +2331,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. */ - bs = bdrv_new_open(filename, fmt, flags, true, quiet); + bs = bdrv_new_open("image", filename, fmt, flags, true, quiet); if (!bs) { return 1; } @@ -2344,7 +2366,7 @@ static int img_rebase(int argc, char **argv) } else { char backing_name[1024]; - bs_old_backing = bdrv_new("old_backing"); + bs_old_backing = bdrv_new("old_backing", &error_abort); bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name)); ret = bdrv_open(&bs_old_backing, backing_name, NULL, NULL, BDRV_O_FLAGS, old_backing_drv, &local_err); @@ -2355,7 +2377,7 @@ static int img_rebase(int argc, char **argv) goto out; } if (out_baseimg[0]) { - bs_new_backing = bdrv_new("new_backing"); + bs_new_backing = bdrv_new("new_backing", &error_abort); ret = bdrv_open(&bs_new_backing, out_baseimg, NULL, NULL, BDRV_O_FLAGS, new_backing_drv, &local_err); if (ret) { @@ -2549,7 +2571,7 @@ static int img_resize(int argc, char **argv) /* Remove size from argv manually so that negative numbers are not treated * as options by getopt. */ if (argc < 3) { - help(); + error_exit("Not enough arguments"); return 1; } @@ -2576,7 +2598,7 @@ static int img_resize(int argc, char **argv) } } if (optind != argc - 1) { - help(); + error_exit("Expecting one image file name"); } filename = argv[optind++]; @@ -2606,7 +2628,8 @@ static int img_resize(int argc, char **argv) n = qemu_opt_get_size(param, BLOCK_OPT_SIZE, 0); qemu_opts_del(param); - bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR, true, quiet); + bs = bdrv_new_open("image", filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR, + true, quiet); if (!bs) { ret = -1; goto out; @@ -2692,7 +2715,7 @@ static int img_amend(int argc, char **argv) } if (!options) { - help(); + error_exit("Must specify options (-o)"); } filename = (optind == argc - 1) ? argv[argc - 1] : NULL; @@ -2704,10 +2727,11 @@ static int img_amend(int argc, char **argv) } if (optind != argc - 1) { - help(); + error_exit("Expecting one image file name"); } - bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR, true, quiet); + bs = bdrv_new_open("image", filename, fmt, + BDRV_O_FLAGS | BDRV_O_RDWR, true, quiet); if (!bs) { error_report("Could not open image '%s'", filename); ret = -1; @@ -2775,8 +2799,9 @@ int main(int argc, char **argv) qemu_init_main_loop(); bdrv_init(); - if (argc < 2) - help(); + if (argc < 2) { + error_exit("Not enough arguments"); + } cmdname = argv[1]; argc--; argv++; @@ -2788,6 +2813,5 @@ int main(int argc, char **argv) } /* not found */ - help(); - return 0; + error_exit("Command not found: %s", cmdname); } @@ -67,7 +67,7 @@ static int openfile(char *name, int flags, int growable, QDict *opts) return 1; } } else { - qemuio_bs = bdrv_new("hda"); + qemuio_bs = bdrv_new("hda", &error_abort); if (bdrv_open(&qemuio_bs, name, NULL, opts, flags, NULL, &local_err) < 0) @@ -657,7 +657,8 @@ int main(int argc, char **argv) drv = NULL; } - bs = bdrv_new("hda"); + bs = bdrv_new("hda", &error_abort); + srcpath = argv[optind]; ret = bdrv_open(&bs, srcpath, NULL, NULL, flags, drv, &local_err); if (ret < 0) { diff --git a/tests/qemu-iotests/084.out b/tests/qemu-iotests/084.out index e681924..c7120d9 100644 --- a/tests/qemu-iotests/084.out +++ b/tests/qemu-iotests/084.out @@ -4,10 +4,7 @@ QA output created by 084 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 Test 1: Maximum size (1024 TB): -image: TEST_DIR/t.IMGFMT -file format: IMGFMT -virtual size: 1024T (1125899905794048 bytes) -cluster_size: 1048576 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Could not open 'TEST_DIR/t.IMGFMT': Invalid argument Test 2: Size too large (1024TB + 1) qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported VDI image size (size is 0x3fffffff10000, max supported is 0x3fffffff00000) diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087 index a38bb70..82c56b1 100755 --- a/tests/qemu-iotests/087 +++ b/tests/qemu-iotests/087 @@ -73,6 +73,91 @@ run_qemu <<EOF EOF echo +echo === Duplicate ID === +echo + +run_qemu <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "blockdev-add", + "arguments": { + "options": { + "driver": "$IMGFMT", + "id": "disk", + "node-name": "test-node", + "file": { + "driver": "file", + "filename": "$TEST_IMG" + } + } + } + } +{ "execute": "blockdev-add", + "arguments": { + "options": { + "driver": "$IMGFMT", + "id": "disk", + "file": { + "driver": "file", + "filename": "$TEST_IMG" + } + } + } + } +{ "execute": "blockdev-add", + "arguments": { + "options": { + "driver": "$IMGFMT", + "id": "test-node", + "file": { + "driver": "file", + "filename": "$TEST_IMG" + } + } + } + } +{ "execute": "blockdev-add", + "arguments": { + "options": { + "driver": "$IMGFMT", + "id": "disk2", + "node-name": "disk", + "file": { + "driver": "file", + "filename": "$TEST_IMG" + } + } + } + } +{ "execute": "blockdev-add", + "arguments": { + "options": { + "driver": "$IMGFMT", + "id": "disk2", + "node-name": "test-node", + "file": { + "driver": "file", + "filename": "$TEST_IMG" + } + } + } + } +{ "execute": "blockdev-add", + "arguments": { + "options": { + "driver": "$IMGFMT", + "id": "disk3", + "node-name": "disk3", + "file": { + "driver": "file", + "filename": "$TEST_IMG" + } + } + } + } +{ "execute": "quit" } +EOF + +echo echo === aio=native without O_DIRECT === echo diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out index e65dcdf..7fbee3f 100644 --- a/tests/qemu-iotests/087.out +++ b/tests/qemu-iotests/087.out @@ -13,6 +13,24 @@ QMP_VERSION {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}} +=== Duplicate ID === + +Testing: +QMP_VERSION +{"return": {}} +{"return": {}} +{"error": {"class": "GenericError", "desc": "Device with id 'disk' already exists"}} +{"error": {"class": "GenericError", "desc": "Device with node-name 'test-node' already exists"}} +main-loop: WARNING: I/O thread spun for 1000 iterations +{"error": {"class": "GenericError", "desc": "could not open disk image disk2: node-name=disk is conflicting with a device id"}} +{"error": {"class": "GenericError", "desc": "could not open disk image disk2: Duplicate node name"}} +{"error": {"class": "GenericError", "desc": "could not open disk image disk3: node-name=disk3 is conflicting with a device id"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}} + + === aio=native without O_DIRECT === Testing: |