[submodule "roms/vgabios"]
path = roms/vgabios
- url = git://git.qemu.org/vgabios.git/
+ url = git://git.qemu-project.org/vgabios.git/
[submodule "roms/seabios"]
path = roms/seabios
- url = git://git.qemu.org/seabios.git/
+ url = git://git.qemu-project.org/seabios.git/
[submodule "roms/SLOF"]
path = roms/SLOF
- url = git://git.qemu.org/SLOF.git
+ url = git://git.qemu-project.org/SLOF.git
[submodule "roms/ipxe"]
path = roms/ipxe
- url = git://git.qemu.org/ipxe.git
+ url = git://git.qemu-project.org/ipxe.git
[submodule "roms/openbios"]
path = roms/openbios
- url = git://git.qemu.org/openbios.git
+ url = git://git.qemu-project.org/openbios.git
[submodule "roms/qemu-palcode"]
path = roms/qemu-palcode
url = git://github.com/rth7680/qemu-palcode.git
[submodule "roms/sgabios"]
path = roms/sgabios
- url = git://git.qemu.org/sgabios.git
+ url = git://git.qemu-project.org/sgabios.git
[submodule "pixman"]
path = pixman
url = git://anongit.freedesktop.org/pixman
[submodule "dtc"]
path = dtc
- url = git://git.qemu.org/dtc.git
+ url = git://git.qemu-project.org/dtc.git
This file documents changes for QEMU releases 0.12 and earlier.
For changelog information for later releases, see
-http://wiki.qemu.org/ChangeLog or look at the git history for
+http://wiki.qemu-project.org/ChangeLog or look at the git history for
more detailed information.
General Project Administration
------------------------------
-M: Anthony Liguori <anthony@codemonkey.ws>
+M: Anthony Liguori <aliguori@amazon.com>
Guest CPU cores (TCG):
----------------------
X86 Machines
------------
PC
-M: Anthony Liguori <anthony@codemonkey.ws>
+M: Anthony Liguori <aliguori@amazon.com>
S: Supported
F: hw/i386/pc.[ch]
F: hw/i386/pc_piix.c
F: hw/*/*vhost*
virtio
-M: Anthony Liguori <anthony@codemonkey.ws>
+M: Anthony Liguori <aliguori@amazon.com>
S: Supported
F: hw/*/virtio*
F: hw/block/
Character Devices
-M: Anthony Liguori <anthony@codemonkey.ws>
+M: Anthony Liguori <aliguori@amazon.com>
S: Maintained
F: qemu-char.c
F: hw/display/qxl*
Graphics
-M: Anthony Liguori <anthony@codemonkey.ws>
+M: Anthony Liguori <aliguori@amazon.com>
S: Maintained
F: ui/
F: ui/cocoa.m
Main loop
-M: Anthony Liguori <anthony@codemonkey.ws>
+M: Anthony Liguori <aliguori@amazon.com>
S: Supported
F: vl.c
F: hmp-commands.hx
Network device layer
-M: Anthony Liguori <anthony@codemonkey.ws>
+M: Anthony Liguori <aliguori@amazon.com>
M: Stefan Hajnoczi <stefanha@redhat.com>
S: Maintained
F: net/
---------------
Stable 1.0
L: qemu-stable@nongnu.org
-T: git git://git.qemu.org/qemu-stable-1.0.git
+T: git git://git.qemu-project.org/qemu-stable-1.0.git
S: Orphan
Stable 0.15
L: qemu-stable@nongnu.org
M: Andreas Färber <afaerber@suse.de>
-T: git git://git.qemu.org/qemu-stable-0.15.git
+T: git git://git.qemu-project.org/qemu-stable-0.15.git
S: Supported
Stable 0.14
L: qemu-stable@nongnu.org
-T: git git://git.qemu.org/qemu-stable-0.14.git
+T: git git://git.qemu-project.org/qemu-stable-0.14.git
S: Orphan
Stable 0.10
L: qemu-stable@nongnu.org
-T: git git://git.qemu.org/qemu-stable-0.10.git
+T: git git://git.qemu-project.org/qemu-stable-0.10.git
S: Orphan
rm -f $(foreach f,$(GENERATED_SOURCES),$(f) $(f)-timestamp)
rm -rf qapi-generated
rm -rf qga/qapi-generated
- $(MAKE) -C tests/tcg clean
for d in $(ALL_SUBDIRS); do \
if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
rm -f $$d/qemu-options.def; \
-Read the documentation in qemu-doc.html or on http://wiki.qemu.org
+Read the documentation in qemu-doc.html or on http://wiki.qemu-project.org
- QEMU team
bs->read_only = !(open_flags & BDRV_O_RDWR);
if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, bs->read_only)) {
- error_setg(errp, "Driver '%s' is not whitelisted", drv->format_name);
+ error_setg(errp,
+ !bs->read_only && bdrv_is_whitelisted(drv, true)
+ ? "Driver '%s' can only be used for read-only devices"
+ : "Driver '%s' is not whitelisted",
+ drv->format_name);
return -ENOTSUP;
}
assert(bs->copy_on_read == 0); /* bdrv_new() and bdrv_close() make it so */
- if (!bs->read_only && (flags & BDRV_O_COPY_ON_READ)) {
- bdrv_enable_copy_on_read(bs);
+ if (flags & BDRV_O_COPY_ON_READ) {
+ if (!bs->read_only) {
+ bdrv_enable_copy_on_read(bs);
+ } else {
+ error_setg(errp, "Can't use copy-on-read on read-only device");
+ return -EINVAL;
+ }
}
if (filename != NULL) {
/* Find the right block driver */
drvname = qdict_get_try_str(options, "driver");
if (drvname) {
- drv = bdrv_find_whitelisted_format(drvname, !(flags & BDRV_O_RDWR));
+ drv = bdrv_find_format(drvname);
if (!drv) {
error_setg(errp, "Unknown driver '%s'", drvname);
}
/* Find the right image format driver */
drvname = qdict_get_try_str(options, "driver");
if (drvname) {
- drv = bdrv_find_whitelisted_format(drvname, !(flags & BDRV_O_RDWR));
+ drv = bdrv_find_format(drvname);
qdict_del(options, "driver");
}
return ret;
}
+ if (ret & BDRV_BLOCK_RAW) {
+ assert(ret & BDRV_BLOCK_OFFSET_VALID);
+ return bdrv_get_block_status(bs->file, ret >> BDRV_SECTOR_BITS,
+ *pnum, pnum);
+ }
+
if (!(ret & BDRV_BLOCK_DATA)) {
if (bdrv_has_zero_init(bs)) {
ret |= BDRV_BLOCK_ZERO;
return drv->bdrv_get_info(bs, bdi);
}
+ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs)
+{
+ BlockDriver *drv = bs->drv;
+ if (drv && drv->bdrv_get_specific_info) {
+ return drv->bdrv_get_specific_info(bs);
+ }
+ return NULL;
+}
+
int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
int64_t pos, int size)
{
}
return bs->drv->bdrv_amend_options(bs, options);
}
+
+ExtSnapshotPerm bdrv_check_ext_snapshot(BlockDriverState *bs)
+{
+ if (bs->drv->bdrv_check_ext_snapshot) {
+ return bs->drv->bdrv_check_ext_snapshot(bs);
+ }
+
+ if (bs->file && bs->file->drv && bs->file->drv->bdrv_check_ext_snapshot) {
+ return bs->file->drv->bdrv_check_ext_snapshot(bs);
+ }
+
+ /* external snapshots are allowed by default */
+ return EXT_SNAPSHOT_ALLOWED;
+}
+
+ExtSnapshotPerm bdrv_check_ext_snapshot_forbidden(BlockDriverState *bs)
+{
+ return EXT_SNAPSHOT_FORBIDDEN;
+}
bdrv_iostatus_reset(s->target);
}
-static const BlockJobType backup_job_type = {
+static const BlockJobDriver backup_job_driver = {
.instance_size = sizeof(BackupBlockJob),
- .job_type = "backup",
+ .job_type = BLOCK_JOB_TYPE_BACKUP,
.set_speed = backup_set_speed,
.iostatus_reset = backup_iostatus_reset,
};
return;
}
- BackupBlockJob *job = block_job_create(&backup_job_type, bs, speed,
+ BackupBlockJob *job = block_job_create(&backup_job_driver, bs, speed,
cb, opaque, errp);
if (!job) {
return;
opts = qemu_opts_create_nofail(&runtime_opts);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (error_is_set(&local_err)) {
- qerror_report_err(local_err);
- error_free(local_err);
+ error_propagate(errp, local_err);
ret = -EINVAL;
goto fail;
}
if (config) {
ret = read_config(s, config);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Could not read blkdebug config file");
goto fail;
}
}
/* Open the backing file */
filename = qemu_opt_get(opts, "x-image");
if (filename == NULL) {
+ error_setg(errp, "Could not retrieve image file name");
ret = -EINVAL;
goto fail;
}
ret = bdrv_file_open(&bs->file, filename, NULL, flags, &local_err);
if (ret < 0) {
- qerror_report_err(local_err);
- error_free(local_err);
+ error_propagate(errp, local_err);
goto fail;
}
opts = qemu_opts_create_nofail(&runtime_opts);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (error_is_set(&local_err)) {
- qerror_report_err(local_err);
- error_free(local_err);
+ error_propagate(errp, local_err);
ret = -EINVAL;
goto fail;
}
/* Parse the raw image filename */
raw = qemu_opt_get(opts, "x-raw");
if (raw == NULL) {
+ error_setg(errp, "Could not retrieve raw image filename");
ret = -EINVAL;
goto fail;
}
ret = bdrv_file_open(&bs->file, raw, NULL, flags, &local_err);
if (ret < 0) {
- qerror_report_err(local_err);
- error_free(local_err);
+ error_propagate(errp, local_err);
goto fail;
}
/* Open the test file */
filename = qemu_opt_get(opts, "x-image");
if (filename == NULL) {
+ error_setg(errp, "Could not retrieve test image filename");
ret = -EINVAL;
goto fail;
}
s->test_file = bdrv_new("");
ret = bdrv_open(s->test_file, filename, NULL, flags, NULL, &local_err);
if (ret < 0) {
- qerror_report_err(local_err);
- error_free(local_err);
+ error_propagate(errp, local_err);
bdrv_unref(s->test_file);
s->test_file = NULL;
goto fail;
.bdrv_aio_readv = blkverify_aio_readv,
.bdrv_aio_writev = blkverify_aio_writev,
.bdrv_aio_flush = blkverify_aio_flush,
+
+ .bdrv_check_ext_snapshot = bdrv_check_ext_snapshot_forbidden,
};
static void bdrv_blkverify_init(void)
ratelimit_set_speed(&s->limit, speed / BDRV_SECTOR_SIZE, SLICE_TIME);
}
-static const BlockJobType commit_job_type = {
+static const BlockJobDriver commit_job_driver = {
.instance_size = sizeof(CommitBlockJob),
- .job_type = "commit",
+ .job_type = BLOCK_JOB_TYPE_COMMIT,
.set_speed = commit_set_speed,
};
}
- s = block_job_create(&commit_job_type, bs, speed, cb, opaque, errp);
+ s = block_job_create(&commit_job_driver, bs, speed, cb, opaque, errp);
if (!s) {
return;
}
return len;
}
-#if defined(SCSI_PROVISIONING_TYPE_DEALLOCATED)
+#if defined(LIBISCSI_FEATURE_IOVECTOR)
static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
int64_t sector_num,
return ret;
}
-#endif /* SCSI_PROVISIONING_TYPE_DEALLOCATED */
+#endif /* LIBISCSI_FEATURE_IOVECTOR */
static int
coroutine_fn iscsi_co_discard(BlockDriverState *bs, int64_t sector_num,
.bdrv_getlength = iscsi_getlength,
.bdrv_truncate = iscsi_truncate,
-#if defined(SCSI_PROVISIONING_TYPE_DEALLOCATED)
+#if defined(LIBISCSI_FEATURE_IOVECTOR)
.bdrv_co_get_block_status = iscsi_co_get_block_status,
#endif
.bdrv_co_discard = iscsi_co_discard,
block_job_resume(job);
}
-static const BlockJobType mirror_job_type = {
+static const BlockJobDriver mirror_job_driver = {
.instance_size = sizeof(MirrorBlockJob),
- .job_type = "mirror",
+ .job_type = BLOCK_JOB_TYPE_MIRROR,
.set_speed = mirror_set_speed,
.iostatus_reset= mirror_iostatus_reset,
.complete = mirror_complete,
return;
}
- s = block_job_create(&mirror_job_type, bs, speed, cb, opaque, errp);
+ s = block_job_create(&mirror_job_driver, bs, speed, cb, opaque, errp);
if (!s) {
return;
}
#include "block/qapi.h"
#include "block/block_int.h"
#include "qmp-commands.h"
+#include "qapi-visit.h"
+#include "qapi/qmp-output-visitor.h"
+#include "qapi/qmp/types.h"
/*
* Returns 0 on success, with *p_list either set to describe snapshot
info->dirty_flag = bdi.is_dirty;
info->has_dirty_flag = true;
}
+ info->format_specific = bdrv_get_specific_info(bs);
+ info->has_format_specific = info->format_specific != NULL;
+
backing_filename = bs->backing_file;
if (backing_filename[0] != '\0') {
info->backing_filename = g_strdup(backing_filename);
}
}
+static void dump_qdict(fprintf_function func_fprintf, void *f, int indentation,
+ QDict *dict);
+static void dump_qlist(fprintf_function func_fprintf, void *f, int indentation,
+ QList *list);
+
+static void dump_qobject(fprintf_function func_fprintf, void *f,
+ int comp_indent, QObject *obj)
+{
+ switch (qobject_type(obj)) {
+ case QTYPE_QINT: {
+ QInt *value = qobject_to_qint(obj);
+ func_fprintf(f, "%" PRId64, qint_get_int(value));
+ break;
+ }
+ case QTYPE_QSTRING: {
+ QString *value = qobject_to_qstring(obj);
+ func_fprintf(f, "%s", qstring_get_str(value));
+ break;
+ }
+ case QTYPE_QDICT: {
+ QDict *value = qobject_to_qdict(obj);
+ dump_qdict(func_fprintf, f, comp_indent, value);
+ break;
+ }
+ case QTYPE_QLIST: {
+ QList *value = qobject_to_qlist(obj);
+ dump_qlist(func_fprintf, f, comp_indent, value);
+ break;
+ }
+ case QTYPE_QFLOAT: {
+ QFloat *value = qobject_to_qfloat(obj);
+ func_fprintf(f, "%g", qfloat_get_double(value));
+ break;
+ }
+ case QTYPE_QBOOL: {
+ QBool *value = qobject_to_qbool(obj);
+ func_fprintf(f, "%s", qbool_get_int(value) ? "true" : "false");
+ break;
+ }
+ case QTYPE_QERROR: {
+ QString *value = qerror_human((QError *)obj);
+ func_fprintf(f, "%s", qstring_get_str(value));
+ break;
+ }
+ case QTYPE_NONE:
+ break;
+ case QTYPE_MAX:
+ default:
+ abort();
+ }
+}
+
+static void dump_qlist(fprintf_function func_fprintf, void *f, int indentation,
+ QList *list)
+{
+ const QListEntry *entry;
+ int i = 0;
+
+ for (entry = qlist_first(list); entry; entry = qlist_next(entry), i++) {
+ qtype_code type = qobject_type(entry->value);
+ bool composite = (type == QTYPE_QDICT || type == QTYPE_QLIST);
+ const char *format = composite ? "%*s[%i]:\n" : "%*s[%i]: ";
+
+ func_fprintf(f, format, indentation * 4, "", i);
+ dump_qobject(func_fprintf, f, indentation + 1, entry->value);
+ if (!composite) {
+ func_fprintf(f, "\n");
+ }
+ }
+}
+
+static void dump_qdict(fprintf_function func_fprintf, void *f, int indentation,
+ QDict *dict)
+{
+ const QDictEntry *entry;
+
+ for (entry = qdict_first(dict); entry; entry = qdict_next(dict, entry)) {
+ qtype_code type = qobject_type(entry->value);
+ bool composite = (type == QTYPE_QDICT || type == QTYPE_QLIST);
+ const char *format = composite ? "%*s%s:\n" : "%*s%s: ";
+ char key[strlen(entry->key) + 1];
+ int i;
+
+ /* replace dashes with spaces in key (variable) names */
+ for (i = 0; entry->key[i]; i++) {
+ key[i] = entry->key[i] == '-' ? ' ' : entry->key[i];
+ }
+ key[i] = 0;
+
+ func_fprintf(f, format, indentation * 4, "", key);
+ dump_qobject(func_fprintf, f, indentation + 1, entry->value);
+ if (!composite) {
+ func_fprintf(f, "\n");
+ }
+ }
+}
+
+void bdrv_image_info_specific_dump(fprintf_function func_fprintf, void *f,
+ ImageInfoSpecific *info_spec)
+{
+ Error *local_err = NULL;
+ QmpOutputVisitor *ov = qmp_output_visitor_new();
+ QObject *obj, *data;
+
+ visit_type_ImageInfoSpecific(qmp_output_get_visitor(ov), &info_spec, NULL,
+ &local_err);
+ obj = qmp_output_get_qobject(ov);
+ assert(qobject_type(obj) == QTYPE_QDICT);
+ data = qdict_get(qobject_to_qdict(obj), "data");
+ dump_qobject(func_fprintf, f, 1, data);
+ qmp_output_visitor_cleanup(ov);
+}
+
void bdrv_image_info_dump(fprintf_function func_fprintf, void *f,
ImageInfo *info)
{
func_fprintf(f, "\n");
}
}
+
+ if (info->has_format_specific) {
+ func_fprintf(f, "Format specific information:\n");
+ bdrv_image_info_specific_dump(func_fprintf, f, info->format_specific);
+ }
}
}
if (c == s->refcount_block_cache) {
- ret = qcow2_pre_write_overlap_check(bs,
- QCOW2_OL_DEFAULT & ~QCOW2_OL_REFCOUNT_BLOCK,
+ ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_REFCOUNT_BLOCK,
c->entries[i].offset, s->cluster_size);
} else if (c == s->l2_table_cache) {
- ret = qcow2_pre_write_overlap_check(bs,
- QCOW2_OL_DEFAULT & ~QCOW2_OL_ACTIVE_L2,
+ ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L2,
c->entries[i].offset, s->cluster_size);
} else {
- ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT,
+ ret = qcow2_pre_write_overlap_check(bs, 0,
c->entries[i].offset, s->cluster_size);
}
/* the L1 position has not yet been updated, so these clusters must
* indeed be completely free */
- ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT,
- new_l1_table_offset, new_l1_size2);
+ ret = qcow2_pre_write_overlap_check(bs, 0, new_l1_table_offset,
+ new_l1_size2);
if (ret < 0) {
goto fail;
}
buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]);
}
- ret = qcow2_pre_write_overlap_check(bs,
- QCOW2_OL_DEFAULT & ~QCOW2_OL_ACTIVE_L1,
+ ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L1,
s->l1_table_offset + 8 * l1_start_index, sizeof(buf));
if (ret < 0) {
return ret;
&s->aes_encrypt_key);
}
- ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT,
+ ret = qcow2_pre_write_overlap_check(bs, 0,
cluster_offset + n_start * BDRV_SECTOR_SIZE, n * BDRV_SECTOR_SIZE);
if (ret < 0) {
goto out;
}
}
- ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT,
- offset, s->cluster_size);
+ ret = qcow2_pre_write_overlap_check(bs, 0, offset, s->cluster_size);
if (ret < 0) {
if (!preallocated) {
qcow2_free_clusters(bs, offset, s->cluster_size,
}
} else {
if (l2_dirty) {
- ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT &
- ~(QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2), l2_offset,
+ ret = qcow2_pre_write_overlap_check(bs,
+ QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2, l2_offset,
s->cluster_size);
if (ret < 0) {
goto fail;
}
break;
case QCOW2_CLUSTER_NORMAL:
- qcow2_free_clusters(bs, l2_entry & L2E_OFFSET_MASK,
- nb_clusters << s->cluster_bits, type);
+ case QCOW2_CLUSTER_ZERO:
+ if (l2_entry & L2E_OFFSET_MASK) {
+ qcow2_free_clusters(bs, l2_entry & L2E_OFFSET_MASK,
+ nb_clusters << s->cluster_bits, type);
+ }
break;
case QCOW2_CLUSTER_UNALLOCATED:
- case QCOW2_CLUSTER_ZERO:
break;
default:
abort();
}
if (l2_dirty) {
- ret = qcow2_pre_write_overlap_check(bs,
- QCOW2_OL_DEFAULT & ~QCOW2_OL_ACTIVE_L2, l2_offset,
- s->cluster_size);
+ ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L2,
+ l2_offset, s->cluster_size);
if (ret < 0) {
fprintf(stderr, "ERROR: Could not write L2 table; metadata "
"overlap check failed: %s\n", strerror(-ret));
buf[i] = cpu_to_be64(s->refcount_table[rt_start_index + i]);
}
- ret = qcow2_pre_write_overlap_check(bs,
- QCOW2_OL_DEFAULT & ~QCOW2_OL_REFCOUNT_TABLE,
+ ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_REFCOUNT_TABLE,
s->refcount_table_offset + rt_start_index * sizeof(uint64_t),
sizeof(buf));
if (ret < 0) {
/* new block has not yet been entered into refcount table, therefore it is
* no refcount block yet (regarding this check) */
- ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT, new_offset,
- s->cluster_size);
+ ret = qcow2_pre_write_overlap_check(bs, 0, new_offset, s->cluster_size);
if (ret < 0) {
fprintf(stderr, "Could not write refcount block; metadata overlap "
"check failed: %s\n", strerror(-ret));
* looking for overlaps with important metadata sections (L1/L2 tables etc.),
* i.e. a sanity check without relying on the refcount tables.
*
- * The chk parameter specifies exactly what checks to perform (being a bitmask
- * of QCow2MetadataOverlap values).
+ * The ign parameter specifies what checks not to perform (being a bitmask of
+ * QCow2MetadataOverlap values), i.e., what sections to ignore.
*
* Returns:
* - 0 if writing to this offset will not affect the mentioned metadata
* - a negative value (-errno) indicating an error while performing a check,
* e.g. when bdrv_read failed on QCOW2_OL_INACTIVE_L2
*/
-int qcow2_check_metadata_overlap(BlockDriverState *bs, int chk, int64_t offset,
+int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
int64_t size)
{
BDRVQcowState *s = bs->opaque;
+ int chk = s->overlap_check & ~ign;
int i, j;
if (!size) {
for (i = 0; i < s->nb_snapshots; i++) {
uint64_t l1_ofs = s->snapshots[i].l1_table_offset;
uint32_t l1_sz = s->snapshots[i].l1_size;
- uint64_t *l1 = g_malloc(l1_sz * sizeof(uint64_t));
+ uint64_t l1_sz2 = l1_sz * sizeof(uint64_t);
+ uint64_t *l1 = g_malloc(l1_sz2);
int ret;
- ret = bdrv_read(bs->file, l1_ofs / BDRV_SECTOR_SIZE, (uint8_t *)l1,
- l1_sz * sizeof(uint64_t) / BDRV_SECTOR_SIZE);
-
+ ret = bdrv_pread(bs->file, l1_ofs, l1, l1_sz2);
if (ret < 0) {
g_free(l1);
return ret;
* Returns 0 if there were neither overlaps nor errors while checking for
* overlaps; or a negative value (-errno) on error.
*/
-int qcow2_pre_write_overlap_check(BlockDriverState *bs, int chk, int64_t offset,
+int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
int64_t size)
{
- int ret = qcow2_check_metadata_overlap(bs, chk, offset, size);
+ int ret = qcow2_check_metadata_overlap(bs, ign, offset, size);
if (ret < 0) {
return ret;
snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size);
offset = snapshots_offset;
if (offset < 0) {
- return offset;
+ ret = offset;
+ goto fail;
}
ret = bdrv_flush(bs);
if (ret < 0) {
- return ret;
+ goto fail;
}
/* The snapshot list position has not yet been updated, so these clusters
* must indeed be completely free */
- ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT, offset,
- snapshots_size);
+ ret = qcow2_pre_write_overlap_check(bs, 0, offset, snapshots_size);
if (ret < 0) {
- return ret;
+ goto fail;
}
id_str_size = strlen(sn->id_str);
name_size = strlen(sn->name);
+ assert(id_str_size <= UINT16_MAX && name_size <= UINT16_MAX);
h.id_str_size = cpu_to_be16(id_str_size);
h.name_size = cpu_to_be16(name_size);
offset = align_offset(offset, 8);
return 0;
fail:
+ if (snapshots_offset > 0) {
+ qcow2_free_clusters(bs, snapshots_offset, snapshots_size,
+ QCOW2_DISCARD_ALWAYS);
+ }
return ret;
}
{
BDRVQcowState *s = bs->opaque;
QCowSnapshot *sn;
- int i, id, id_max = 0;
+ int i;
+ unsigned long id, id_max = 0;
for(i = 0; i < s->nb_snapshots; i++) {
sn = s->snapshots + i;
if (id > id_max)
id_max = id;
}
- snprintf(id_str, id_str_size, "%d", id_max + 1);
+ snprintf(id_str, id_str_size, "%lu", id_max + 1);
}
static int find_snapshot_by_id_and_name(BlockDriverState *bs,
l1_table[i] = cpu_to_be64(s->l1_table[i]);
}
- ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT,
- sn->l1_table_offset, s->l1_size * sizeof(uint64_t));
+ ret = qcow2_pre_write_overlap_check(bs, 0, sn->l1_table_offset,
+ s->l1_size * sizeof(uint64_t));
if (ret < 0) {
goto fail;
}
if (ret < 0) {
g_free(s->snapshots);
s->snapshots = old_snapshot_list;
+ s->nb_snapshots--;
goto fail;
}
goto fail;
}
- ret = qcow2_pre_write_overlap_check(bs,
- QCOW2_OL_DEFAULT & ~QCOW2_OL_ACTIVE_L1,
- s->l1_table_offset, cur_l1_bytes);
+ ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L1,
+ s->l1_table_offset, cur_l1_bytes);
if (ret < 0) {
goto fail;
}
.type = QEMU_OPT_BOOL,
.help = "Generate discard requests when other clusters are freed",
},
+ {
+ .name = QCOW2_OPT_OVERLAP,
+ .type = QEMU_OPT_STRING,
+ .help = "Selects which overlap checks to perform from a range of "
+ "templates (none, constant, cached, all)",
+ },
+ {
+ .name = QCOW2_OPT_OVERLAP_MAIN_HEADER,
+ .type = QEMU_OPT_BOOL,
+ .help = "Check for unintended writes into the main qcow2 header",
+ },
+ {
+ .name = QCOW2_OPT_OVERLAP_ACTIVE_L1,
+ .type = QEMU_OPT_BOOL,
+ .help = "Check for unintended writes into the active L1 table",
+ },
+ {
+ .name = QCOW2_OPT_OVERLAP_ACTIVE_L2,
+ .type = QEMU_OPT_BOOL,
+ .help = "Check for unintended writes into an active L2 table",
+ },
+ {
+ .name = QCOW2_OPT_OVERLAP_REFCOUNT_TABLE,
+ .type = QEMU_OPT_BOOL,
+ .help = "Check for unintended writes into the refcount table",
+ },
+ {
+ .name = QCOW2_OPT_OVERLAP_REFCOUNT_BLOCK,
+ .type = QEMU_OPT_BOOL,
+ .help = "Check for unintended writes into a refcount block",
+ },
+ {
+ .name = QCOW2_OPT_OVERLAP_SNAPSHOT_TABLE,
+ .type = QEMU_OPT_BOOL,
+ .help = "Check for unintended writes into the snapshot table",
+ },
+ {
+ .name = QCOW2_OPT_OVERLAP_INACTIVE_L1,
+ .type = QEMU_OPT_BOOL,
+ .help = "Check for unintended writes into an inactive L1 table",
+ },
+ {
+ .name = QCOW2_OPT_OVERLAP_INACTIVE_L2,
+ .type = QEMU_OPT_BOOL,
+ .help = "Check for unintended writes into an inactive L2 table",
+ },
{ /* end of list */ }
},
};
+static const char *overlap_bool_option_names[QCOW2_OL_MAX_BITNR] = {
+ [QCOW2_OL_MAIN_HEADER_BITNR] = QCOW2_OPT_OVERLAP_MAIN_HEADER,
+ [QCOW2_OL_ACTIVE_L1_BITNR] = QCOW2_OPT_OVERLAP_ACTIVE_L1,
+ [QCOW2_OL_ACTIVE_L2_BITNR] = QCOW2_OPT_OVERLAP_ACTIVE_L2,
+ [QCOW2_OL_REFCOUNT_TABLE_BITNR] = QCOW2_OPT_OVERLAP_REFCOUNT_TABLE,
+ [QCOW2_OL_REFCOUNT_BLOCK_BITNR] = QCOW2_OPT_OVERLAP_REFCOUNT_BLOCK,
+ [QCOW2_OL_SNAPSHOT_TABLE_BITNR] = QCOW2_OPT_OVERLAP_SNAPSHOT_TABLE,
+ [QCOW2_OL_INACTIVE_L1_BITNR] = QCOW2_OPT_OVERLAP_INACTIVE_L1,
+ [QCOW2_OL_INACTIVE_L2_BITNR] = QCOW2_OPT_OVERLAP_INACTIVE_L2,
+};
+
static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
Error *local_err = NULL;
uint64_t ext_end;
uint64_t l1_vm_state_index;
+ const char *opt_overlap_check;
+ int overlap_check_template = 0;
ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
if (ret < 0) {
s->discard_passthrough[QCOW2_DISCARD_OTHER] =
qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_OTHER, false);
+ opt_overlap_check = qemu_opt_get(opts, "overlap-check") ?: "cached";
+ if (!strcmp(opt_overlap_check, "none")) {
+ overlap_check_template = 0;
+ } else if (!strcmp(opt_overlap_check, "constant")) {
+ overlap_check_template = QCOW2_OL_CONSTANT;
+ } else if (!strcmp(opt_overlap_check, "cached")) {
+ overlap_check_template = QCOW2_OL_CACHED;
+ } else if (!strcmp(opt_overlap_check, "all")) {
+ overlap_check_template = QCOW2_OL_ALL;
+ } else {
+ error_setg(errp, "Unsupported value '%s' for qcow2 option "
+ "'overlap-check'. Allowed are either of the following: "
+ "none, constant, cached, all", opt_overlap_check);
+ qemu_opts_del(opts);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ s->overlap_check = 0;
+ for (i = 0; i < QCOW2_OL_MAX_BITNR; i++) {
+ /* overlap-check defines a template bitmask, but every flag may be
+ * overwritten through the associated boolean option */
+ s->overlap_check |=
+ qemu_opt_get_bool(opts, overlap_bool_option_names[i],
+ overlap_check_template & (1 << i)) << i;
+ }
+
qemu_opts_del(opts);
if (s->use_lazy_refcounts && s->qcow_version < 3) {
cur_nr_sectors * 512);
}
- ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT,
+ ret = qcow2_pre_write_overlap_check(bs, 0,
cluster_offset + index_in_cluster * BDRV_SECTOR_SIZE,
cur_nr_sectors * BDRV_SECTOR_SIZE);
if (ret < 0) {
if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
/* could not compress: write normal cluster */
-
- ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT,
- sector_num * BDRV_SECTOR_SIZE,
- s->cluster_sectors * BDRV_SECTOR_SIZE);
- if (ret < 0) {
- goto fail;
- }
-
ret = bdrv_write(bs, sector_num, buf, s->cluster_sectors);
if (ret < 0) {
goto fail;
}
cluster_offset &= s->cluster_offset_mask;
- ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT,
- cluster_offset, out_len);
+ ret = qcow2_pre_write_overlap_check(bs, 0, cluster_offset, out_len);
if (ret < 0) {
goto fail;
}
return 0;
}
+static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
+{
+ BDRVQcowState *s = bs->opaque;
+ ImageInfoSpecific *spec_info = g_new(ImageInfoSpecific, 1);
+
+ *spec_info = (ImageInfoSpecific){
+ .kind = IMAGE_INFO_SPECIFIC_KIND_QCOW2,
+ {
+ .qcow2 = g_new(ImageInfoSpecificQCow2, 1),
+ },
+ };
+ if (s->qcow_version == 2) {
+ *spec_info->qcow2 = (ImageInfoSpecificQCow2){
+ .compat = g_strdup("0.10"),
+ };
+ } else if (s->qcow_version == 3) {
+ *spec_info->qcow2 = (ImageInfoSpecificQCow2){
+ .compat = g_strdup("1.1"),
+ .lazy_refcounts = s->compatible_features &
+ QCOW2_COMPAT_LAZY_REFCOUNTS,
+ .has_lazy_refcounts = true,
+ };
+ }
+
+ return spec_info;
+}
+
#if 0
static void dump_refcounts(BlockDriverState *bs)
{
* support anything different than 4 anyway, there is no point in doing
* so right now; however, we should error out (if qemu supports this in
* the future and this code has not been adapted) */
- error_report("qcow2_downgrade: Image refcount orders other than 4 are"
+ error_report("qcow2_downgrade: Image refcount orders other than 4 are "
"currently not supported.");
return -ENOTSUP;
}
.bdrv_snapshot_list = qcow2_snapshot_list,
.bdrv_snapshot_load_tmp = qcow2_snapshot_load_tmp,
.bdrv_get_info = qcow2_get_info,
+ .bdrv_get_specific_info = qcow2_get_specific_info,
.bdrv_save_vmstate = qcow2_save_vmstate,
.bdrv_load_vmstate = qcow2_load_vmstate,
#define QCOW2_OPT_DISCARD_REQUEST "pass-discard-request"
#define QCOW2_OPT_DISCARD_SNAPSHOT "pass-discard-snapshot"
#define QCOW2_OPT_DISCARD_OTHER "pass-discard-other"
+#define QCOW2_OPT_OVERLAP "overlap-check"
+#define QCOW2_OPT_OVERLAP_MAIN_HEADER "overlap-check.main-header"
+#define QCOW2_OPT_OVERLAP_ACTIVE_L1 "overlap-check.active-l1"
+#define QCOW2_OPT_OVERLAP_ACTIVE_L2 "overlap-check.active-l2"
+#define QCOW2_OPT_OVERLAP_REFCOUNT_TABLE "overlap-check.refcount-table"
+#define QCOW2_OPT_OVERLAP_REFCOUNT_BLOCK "overlap-check.refcount-block"
+#define QCOW2_OPT_OVERLAP_SNAPSHOT_TABLE "overlap-check.snapshot-table"
+#define QCOW2_OPT_OVERLAP_INACTIVE_L1 "overlap-check.inactive-l1"
+#define QCOW2_OPT_OVERLAP_INACTIVE_L2 "overlap-check.inactive-l2"
typedef struct QCowHeader {
uint32_t magic;
bool discard_passthrough[QCOW2_DISCARD_MAX];
+ int overlap_check; /* bitmask of Qcow2MetadataOverlap values */
+
uint64_t incompatible_features;
uint64_t compatible_features;
uint64_t autoclear_features;
QCOW2_OL_INACTIVE_L2 = (1 << QCOW2_OL_INACTIVE_L2_BITNR),
} QCow2MetadataOverlap;
+/* Perform all overlap checks which can be done in constant time */
+#define QCOW2_OL_CONSTANT \
+ (QCOW2_OL_MAIN_HEADER | QCOW2_OL_ACTIVE_L1 | QCOW2_OL_REFCOUNT_TABLE | \
+ QCOW2_OL_SNAPSHOT_TABLE)
+
/* Perform all overlap checks which don't require disk access */
#define QCOW2_OL_CACHED \
- (QCOW2_OL_MAIN_HEADER | QCOW2_OL_ACTIVE_L1 | QCOW2_OL_ACTIVE_L2 | \
- QCOW2_OL_REFCOUNT_TABLE | QCOW2_OL_REFCOUNT_BLOCK | \
- QCOW2_OL_SNAPSHOT_TABLE | QCOW2_OL_INACTIVE_L1)
+ (QCOW2_OL_CONSTANT | QCOW2_OL_ACTIVE_L2 | QCOW2_OL_REFCOUNT_BLOCK | \
+ QCOW2_OL_INACTIVE_L1)
-/* The default checks to perform */
-#define QCOW2_OL_DEFAULT QCOW2_OL_CACHED
+/* Perform all overlap checks */
+#define QCOW2_OL_ALL \
+ (QCOW2_OL_CACHED | QCOW2_OL_INACTIVE_L2)
#define L1E_OFFSET_MASK 0x00ffffffffffff00ULL
#define L2E_OFFSET_MASK 0x00ffffffffffff00ULL
void qcow2_process_discards(BlockDriverState *bs, int ret);
-int qcow2_check_metadata_overlap(BlockDriverState *bs, int chk, int64_t offset,
+int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
int64_t size);
-int qcow2_pre_write_overlap_check(BlockDriverState *bs, int chk, int64_t offset,
+int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
int64_t size);
/* qcow2-cluster.c functions */
};
static int raw_open_common(BlockDriverState *bs, QDict *options,
- int bdrv_flags, int open_flags)
+ int bdrv_flags, int open_flags, Error **errp)
{
BDRVRawState *s = bs->opaque;
QemuOpts *opts;
opts = qemu_opts_create_nofail(&raw_runtime_opts);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (error_is_set(&local_err)) {
- qerror_report_err(local_err);
- error_free(local_err);
+ error_propagate(errp, local_err);
ret = -EINVAL;
goto fail;
}
ret = raw_normalize_devicepath(&filename);
if (ret != 0) {
+ error_setg_errno(errp, -ret, "Could not normalize device path");
goto fail;
}
if (ret == -EROFS) {
ret = -EACCES;
}
+ error_setg_errno(errp, -ret, "Could not open file");
goto fail;
}
s->fd = fd;
if (raw_set_aio(&s->aio_ctx, &s->use_aio, bdrv_flags)) {
qemu_close(fd);
ret = -errno;
+ error_setg_errno(errp, -ret, "Could not set AIO state");
goto fail;
}
#endif
Error **errp)
{
BDRVRawState *s = bs->opaque;
+ Error *local_err = NULL;
+ int ret;
s->type = FTYPE_FILE;
- return raw_open_common(bs, options, flags, 0);
+ ret = raw_open_common(bs, options, flags, 0, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ }
+ return ret;
}
static int raw_reopen_prepare(BDRVReopenState *state,
* valid in the 'false' condition even if aio_ctx is set, and raw_set_aio()
* won't override aio_ctx if aio_ctx is non-NULL */
if (raw_set_aio(&s->aio_ctx, &raw_s->use_aio, state->flags)) {
+ error_setg(errp, "Could not set AIO state");
return -1;
}
#endif
assert(!(raw_s->open_flags & O_CREAT));
raw_s->fd = qemu_open(state->bs->filename, raw_s->open_flags);
if (raw_s->fd == -1) {
+ error_setg_errno(errp, errno, "Could not reopen file");
ret = -1;
}
}
0644);
if (fd < 0) {
result = -errno;
+ error_setg_errno(errp, -result, "Could not create file");
} else {
if (ftruncate(fd, total_size * BDRV_SECTOR_SIZE) != 0) {
result = -errno;
+ error_setg_errno(errp, -result, "Could not resize file");
}
if (qemu_close(fd) != 0) {
result = -errno;
+ error_setg_errno(errp, -result, "Could not close the new file");
}
}
return result;
Error **errp)
{
BDRVRawState *s = bs->opaque;
+ Error *local_err = NULL;
int ret;
const char *filename = qdict_get_str(options, "filename");
}
#endif
- ret = raw_open_common(bs, options, flags, 0);
+ ret = raw_open_common(bs, options, flags, 0, &local_err);
if (ret < 0) {
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ }
return ret;
}
ret = check_hdev_writable(s);
if (ret < 0) {
raw_close(bs);
+ error_setg_errno(errp, -ret, "The device is not writable");
return ret;
}
}
}
fd = qemu_open(filename, O_WRONLY | O_BINARY);
- if (fd < 0)
- return -errno;
+ if (fd < 0) {
+ ret = -errno;
+ error_setg_errno(errp, -ret, "Could not open device");
+ return ret;
+ }
- if (fstat(fd, &stat_buf) < 0)
+ if (fstat(fd, &stat_buf) < 0) {
ret = -errno;
- else if (!S_ISBLK(stat_buf.st_mode) && !S_ISCHR(stat_buf.st_mode))
+ error_setg_errno(errp, -ret, "Could not stat device");
+ } else if (!S_ISBLK(stat_buf.st_mode) && !S_ISCHR(stat_buf.st_mode)) {
+ error_setg(errp,
+ "The given file is neither a block nor a character device");
ret = -ENODEV;
- else if (lseek(fd, 0, SEEK_END) < total_size * BDRV_SECTOR_SIZE)
+ } else if (lseek(fd, 0, SEEK_END) < total_size * BDRV_SECTOR_SIZE) {
+ error_setg(errp, "Device is too small");
ret = -ENOSPC;
+ }
qemu_close(fd);
return ret;
Error **errp)
{
BDRVRawState *s = bs->opaque;
+ Error *local_err = NULL;
int ret;
s->type = FTYPE_FD;
/* open will not fail even if no floppy is inserted, so add O_NONBLOCK */
- ret = raw_open_common(bs, options, flags, O_NONBLOCK);
- if (ret)
+ ret = raw_open_common(bs, options, flags, O_NONBLOCK, &local_err);
+ if (ret) {
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ }
return ret;
+ }
/* close fd so that we can reopen it as needed */
qemu_close(s->fd);
Error **errp)
{
BDRVRawState *s = bs->opaque;
+ Error *local_err = NULL;
+ int ret;
s->type = FTYPE_CD;
/* open will not fail even if no CD is inserted, so add O_NONBLOCK */
- return raw_open_common(bs, options, flags, O_NONBLOCK);
+ ret = raw_open_common(bs, options, flags, O_NONBLOCK, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ }
+ return ret;
}
static int cdrom_probe_device(const char *filename)
static int cdrom_open(BlockDriverState *bs, QDict *options, int flags)
{
BDRVRawState *s = bs->opaque;
+ Error *local_err = NULL;
int ret;
s->type = FTYPE_CD;
- ret = raw_open_common(bs, options, flags, 0);
- if (ret)
+ ret = raw_open_common(bs, options, flags, 0, &local_err);
+ if (ret) {
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ }
return ret;
+ }
/* make sure the door isn't locked at this time */
ioctl(s->fd, CDIOCALLOW);
opts = qemu_opts_create_nofail(&raw_runtime_opts);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (error_is_set(&local_err)) {
- qerror_report_err(local_err);
- error_free(local_err);
+ error_propagate(errp, local_err);
ret = -EINVAL;
goto fail;
}
if ((flags & BDRV_O_NATIVE_AIO) && aio == NULL) {
aio = win32_aio_init();
if (aio == NULL) {
+ error_setg(errp, "Could not initialize AIO");
ret = -EINVAL;
goto fail;
}
} else {
ret = -EINVAL;
}
+ error_setg_errno(errp, -ret, "Could not open file");
goto fail;
}
ret = win32_aio_attach(aio, s->hfile);
if (ret < 0) {
CloseHandle(s->hfile);
+ error_setg_errno(errp, -ret, "Could not enable AIO");
goto fail;
}
s->aio = aio;
fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
0644);
- if (fd < 0)
+ if (fd < 0) {
+ error_setg_errno(errp, errno, "Could not create file");
return -EIO;
+ }
set_sparse(fd);
ftruncate(fd, total_size * 512);
qemu_close(fd);
QemuOpts *opts = qemu_opts_create_nofail(&raw_runtime_opts);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (error_is_set(&local_err)) {
- qerror_report_err(local_err);
- error_free(local_err);
+ error_propagate(errp, local_err);
ret = -EINVAL;
goto done;
}
if (strstart(filename, "/dev/cdrom", NULL)) {
if (find_cdrom(device_name, sizeof(device_name)) < 0) {
+ error_setg(errp, "Could not open CD-ROM drive");
ret = -ENOENT;
goto done;
}
int err = GetLastError();
if (err == ERROR_ACCESS_DENIED) {
+ error_setg_errno(errp, EACCES, "Could not open device");
ret = -EACCES;
} else {
+ error_setg(errp, "Could not open device");
ret = -1;
}
goto done;
int64_t sector_num,
int nb_sectors, int *pnum)
{
- return bdrv_get_block_status(bs->file, sector_num, nb_sectors, pnum);
+ *pnum = nb_sectors;
+ return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | BDRV_BLOCK_DATA |
+ (sector_num << BDRV_SECTOR_BITS);
}
static int coroutine_fn raw_co_write_zeroes(BlockDriverState *bs,
ret = bdrv_create_file(filename, options, &local_err);
if (error_is_set(&local_err)) {
- qerror_report_err(local_err);
- error_free(local_err);
+ error_propagate(errp, local_err);
}
return ret;
}
ratelimit_set_speed(&s->limit, speed / BDRV_SECTOR_SIZE, SLICE_TIME);
}
-static const BlockJobType stream_job_type = {
+static const BlockJobDriver stream_job_driver = {
.instance_size = sizeof(StreamBlockJob),
- .job_type = "stream",
+ .job_type = BLOCK_JOB_TYPE_STREAM,
.set_speed = stream_set_speed,
};
return;
}
- s = block_job_create(&stream_job_type, bs, speed, cb, opaque, errp);
+ s = block_job_create(&stream_job_driver, bs, speed, cb, opaque, errp);
if (!s) {
return;
}
assert(state->bs != NULL);
if (queue == NULL) {
- error_set(errp, ERROR_CLASS_GENERIC_ERROR,
- "No reopen queue for VMDK extents");
+ error_setg(errp, "No reopen queue for VMDK extents");
goto exit;
}
int64_t l1_offset, int64_t l1_backup_offset,
uint32_t l1_size,
int l2_size, uint64_t cluster_sectors,
- VmdkExtent **new_extent)
+ VmdkExtent **new_extent,
+ Error **errp)
{
VmdkExtent *extent;
BDRVVmdkState *s = bs->opaque;
if (cluster_sectors > 0x200000) {
/* 0x200000 * 512Bytes = 1GB for one cluster is unrealistic */
- error_report("invalid granularity, image may be corrupt");
- return -EINVAL;
+ error_setg(errp, "Invalid granularity, image may be corrupt");
+ return -EFBIG;
}
if (l1_size > 512 * 1024 * 1024) {
/* Although with big capacity and small l1_entry_sectors, we can get a
* big l1_size, we don't want unbounded value to allocate the table.
* Limit it to 512M, which is 16PB for default cluster and L2 table
* size */
- error_report("L1 size too big");
+ error_setg(errp, "L1 size too big");
return -EFBIG;
}
return 0;
}
-static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent)
+static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
+ Error **errp)
{
int ret;
int l1_size, i;
l1_size = extent->l1_size * sizeof(uint32_t);
extent->l1_table = g_malloc(l1_size);
ret = bdrv_pread(extent->file,
- extent->l1_table_offset,
- extent->l1_table,
- l1_size);
+ extent->l1_table_offset,
+ extent->l1_table,
+ l1_size);
if (ret < 0) {
+ error_setg_errno(errp, -ret,
+ "Could not read l1 table from extent '%s'",
+ extent->file->filename);
goto fail_l1;
}
for (i = 0; i < extent->l1_size; i++) {
if (extent->l1_backup_table_offset) {
extent->l1_backup_table = g_malloc(l1_size);
ret = bdrv_pread(extent->file,
- extent->l1_backup_table_offset,
- extent->l1_backup_table,
- l1_size);
+ extent->l1_backup_table_offset,
+ extent->l1_backup_table,
+ l1_size);
if (ret < 0) {
+ error_setg_errno(errp, -ret,
+ "Could not read l1 backup table from extent '%s'",
+ extent->file->filename);
goto fail_l1b;
}
for (i = 0; i < extent->l1_size; i++) {
static int vmdk_open_vmfs_sparse(BlockDriverState *bs,
BlockDriverState *file,
- int flags)
+ int flags, Error **errp)
{
int ret;
uint32_t magic;
ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header));
if (ret < 0) {
+ error_setg_errno(errp, -ret,
+ "Could not read header from file '%s'",
+ file->filename);
return ret;
}
ret = vmdk_add_extent(bs, file, false,
le32_to_cpu(header.l1dir_size),
4096,
le32_to_cpu(header.granularity),
- &extent);
+ &extent,
+ errp);
if (ret < 0) {
return ret;
}
- ret = vmdk_init_tables(bs, extent);
+ ret = vmdk_init_tables(bs, extent, errp);
if (ret) {
/* free extent allocated by vmdk_add_extent */
vmdk_free_last_extent(bs);
}
static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
- uint64_t desc_offset);
+ uint64_t desc_offset, Error **errp);
static int vmdk_open_vmdk4(BlockDriverState *bs,
BlockDriverState *file,
- int flags)
+ int flags, Error **errp)
{
int ret;
uint32_t magic;
ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header));
if (ret < 0) {
- return ret;
+ error_setg_errno(errp, -ret,
+ "Could not read header from file '%s'",
+ file->filename);
}
if (header.capacity == 0) {
uint64_t desc_offset = le64_to_cpu(header.desc_offset);
if (desc_offset) {
- return vmdk_open_desc_file(bs, flags, desc_offset << 9);
+ return vmdk_open_desc_file(bs, flags, desc_offset << 9, errp);
}
}
l1_size,
le32_to_cpu(header.num_gtes_per_gt),
le64_to_cpu(header.granularity),
- &extent);
+ &extent,
+ errp);
if (ret < 0) {
return ret;
}
extent->has_marker = le32_to_cpu(header.flags) & VMDK4_FLAG_MARKER;
extent->version = le32_to_cpu(header.version);
extent->has_zero_grain = le32_to_cpu(header.flags) & VMDK4_FLAG_ZERO_GRAIN;
- ret = vmdk_init_tables(bs, extent);
+ ret = vmdk_init_tables(bs, extent, errp);
if (ret) {
/* free extent allocated by vmdk_add_extent */
vmdk_free_last_extent(bs);
/* Open an extent file and append to bs array */
static int vmdk_open_sparse(BlockDriverState *bs,
BlockDriverState *file,
- int flags)
+ int flags, Error **errp)
{
uint32_t magic;
magic = be32_to_cpu(magic);
switch (magic) {
case VMDK3_MAGIC:
- return vmdk_open_vmfs_sparse(bs, file, flags);
+ return vmdk_open_vmfs_sparse(bs, file, flags, errp);
break;
case VMDK4_MAGIC:
- return vmdk_open_vmdk4(bs, file, flags);
+ return vmdk_open_vmdk4(bs, file, flags, errp);
break;
default:
return -EMEDIUMTYPE;
}
static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
- const char *desc_file_path)
+ const char *desc_file_path, Error **errp)
{
int ret;
char access[11];
int64_t flat_offset;
char extent_path[PATH_MAX];
BlockDriverState *extent_file;
- Error *local_err = NULL;
while (*p) {
/* parse extent line:
goto next_line;
} else if (!strcmp(type, "FLAT")) {
if (ret != 5 || flat_offset < 0) {
+ error_setg(errp, "Invalid extent lines: \n%s", p);
return -EINVAL;
}
} else if (ret != 4) {
+ error_setg(errp, "Invalid extent lines: \n%s", p);
return -EINVAL;
}
path_combine(extent_path, sizeof(extent_path),
desc_file_path, fname);
ret = bdrv_file_open(&extent_file, extent_path, NULL, bs->open_flags,
- &local_err);
+ errp);
if (ret) {
- qerror_report_err(local_err);
- error_free(local_err);
return ret;
}
VmdkExtent *extent;
ret = vmdk_add_extent(bs, extent_file, true, sectors,
- 0, 0, 0, 0, 0, &extent);
+ 0, 0, 0, 0, 0, &extent, errp);
if (ret < 0) {
return ret;
}
extent->flat_start_offset = flat_offset << 9;
} else if (!strcmp(type, "SPARSE") || !strcmp(type, "VMFSSPARSE")) {
/* SPARSE extent and VMFSSPARSE extent are both "COWD" sparse file*/
- ret = vmdk_open_sparse(bs, extent_file, bs->open_flags);
+ ret = vmdk_open_sparse(bs, extent_file, bs->open_flags, errp);
if (ret) {
bdrv_unref(extent_file);
return ret;
}
} else {
- fprintf(stderr,
- "VMDK: Not supported extent type \"%s\""".\n", type);
+ error_setg(errp, "Unsupported extent type '%s'", type);
return -ENOTSUP;
}
next_line:
/* move to next line */
- while (*p && *p != '\n') {
+ while (*p) {
+ if (*p == '\n') {
+ p++;
+ break;
+ }
p++;
}
- p++;
}
return 0;
}
static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
- uint64_t desc_offset)
+ uint64_t desc_offset, Error **errp)
{
int ret;
char *buf = NULL;
strcmp(ct, "vmfsSparse") &&
strcmp(ct, "twoGbMaxExtentSparse") &&
strcmp(ct, "twoGbMaxExtentFlat")) {
- fprintf(stderr,
- "VMDK: Not supported image type \"%s\""".\n", ct);
+ error_setg(errp, "Unsupported image type '%s'", ct);
ret = -ENOTSUP;
goto exit;
}
s->desc_offset = 0;
- ret = vmdk_parse_extents(buf, bs, bs->file->filename);
+ ret = vmdk_parse_extents(buf, bs, bs->file->filename, errp);
exit:
g_free(buf);
return ret;
int ret;
BDRVVmdkState *s = bs->opaque;
- if (vmdk_open_sparse(bs, bs->file, flags) == 0) {
+ if (vmdk_open_sparse(bs, bs->file, flags, errp) == 0) {
s->desc_offset = 0x200;
} else {
- ret = vmdk_open_desc_file(bs, flags, 0);
+ ret = vmdk_open_desc_file(bs, flags, 0, errp);
if (ret) {
goto fail;
}
VmdkMetaData m_data;
if (sector_num > bs->total_sectors) {
- fprintf(stderr,
- "(VMDK) Wrong offset: sector_num=0x%" PRIx64
+ error_report("Wrong offset: sector_num=0x%" PRIx64
" total_sectors=0x%" PRIx64 "\n",
sector_num, bs->total_sectors);
return -EIO;
if (extent->compressed) {
if (ret == VMDK_OK) {
/* Refuse write to allocated cluster for streamOptimized */
- fprintf(stderr,
- "VMDK: can't write to allocated cluster"
- " for streamOptimized\n");
+ error_report("Could not write to allocated cluster"
+ " for streamOptimized");
return -EIO;
} else {
/* allocate */
}
static int filename_decompose(const char *filename, char *path, char *prefix,
- char *postfix, size_t buf_len)
+ char *postfix, size_t buf_len, Error **errp)
{
const char *p, *q;
if (filename == NULL || !strlen(filename)) {
- fprintf(stderr, "Vmdk: no filename provided.\n");
+ error_setg(errp, "No filename provided");
return VMDK_ERROR;
}
p = strrchr(filename, '/');
"ddb.geometry.heads = \"%d\"\n"
"ddb.geometry.sectors = \"63\"\n"
"ddb.adapterType = \"%s\"\n";
- Error *local_err = NULL;
- if (filename_decompose(filename, path, prefix, postfix, PATH_MAX)) {
+ if (filename_decompose(filename, path, prefix, postfix, PATH_MAX, errp)) {
return -EINVAL;
}
/* Read out options */
strcmp(adapter_type, "buslogic") &&
strcmp(adapter_type, "lsilogic") &&
strcmp(adapter_type, "legacyESX")) {
- fprintf(stderr, "VMDK: Unknown adapter type: '%s'.\n", adapter_type);
+ error_setg(errp, "Unknown adapter type: '%s'", adapter_type);
return -EINVAL;
}
if (strcmp(adapter_type, "ide") != 0) {
strcmp(fmt, "twoGbMaxExtentSparse") &&
strcmp(fmt, "twoGbMaxExtentFlat") &&
strcmp(fmt, "streamOptimized")) {
- fprintf(stderr, "VMDK: Unknown subformat: %s\n", fmt);
+ error_setg(errp, "Unknown subformat: '%s'", fmt);
return -EINVAL;
}
split = !(strcmp(fmt, "twoGbMaxExtentFlat") &&
desc_extent_line = "RW %lld SPARSE \"%s\"\n";
}
if (flat && backing_file) {
- /* not supporting backing file for flat image */
+ error_setg(errp, "Flat image can't have backing file");
+ return -ENOTSUP;
+ }
+ if (flat && zeroed_grain) {
+ error_setg(errp, "Flat image can't enable zeroed grain");
return -ENOTSUP;
}
if (backing_file) {
BlockDriverState *bs = bdrv_new("");
- ret = bdrv_open(bs, backing_file, NULL, 0, NULL, &local_err);
+ ret = bdrv_open(bs, backing_file, NULL, 0, NULL, errp);
if (ret != 0) {
- qerror_report_err(local_err);
- error_free(local_err);
bdrv_unref(bs);
return ret;
}
#include "qemu/option.h"
#include "qemu/config-file.h"
#include "qapi/qmp/types.h"
+#include "qapi-visit.h"
+#include "qapi/qmp-output-visitor.h"
#include "sysemu/sysemu.h"
#include "block/block_int.h"
#include "qmp-commands.h"
{
DriveInfo *dinfo = drive_get_by_blockdev(bs);
+ if (dinfo && !dinfo->enable_auto_del) {
+ return;
+ }
+
if (bs->job) {
block_job_cancel(bs->job);
}
static void drive_uninit(DriveInfo *dinfo)
{
- qemu_opts_del(dinfo->opts);
+ if (dinfo->opts) {
+ qemu_opts_del(dinfo->opts);
+ }
+
bdrv_unref(dinfo->bdrv);
g_free(dinfo->id);
QTAILQ_REMOVE(&drives, dinfo, next);
qemu_bh_schedule(s->bh);
}
-static int parse_block_error_action(const char *buf, bool is_read)
+static int parse_block_error_action(const char *buf, bool is_read, Error **errp)
{
if (!strcmp(buf, "ignore")) {
return BLOCKDEV_ON_ERROR_IGNORE;
} else if (!strcmp(buf, "report")) {
return BLOCKDEV_ON_ERROR_REPORT;
} else {
- error_report("'%s' invalid %s error action",
- buf, is_read ? "read" : "write");
+ error_setg(errp, "'%s' invalid %s error action",
+ buf, is_read ? "read" : "write");
return -1;
}
}
return true;
}
-static DriveInfo *blockdev_init(QemuOpts *all_opts,
- BlockInterfaceType block_default_type)
+typedef enum { MEDIA_DISK, MEDIA_CDROM } DriveMediaType;
+
+/* Takes the ownership of bs_opts */
+static DriveInfo *blockdev_init(QDict *bs_opts,
+ BlockInterfaceType type,
+ Error **errp)
{
const char *buf;
const char *file = NULL;
const char *serial;
- const char *mediastr = "";
- BlockInterfaceType type;
- enum { MEDIA_DISK, MEDIA_CDROM } media;
- int bus_id, unit_id;
- int cyls, heads, secs, translation;
- int max_devs;
- int index;
int ro = 0;
int bdrv_flags = 0;
int on_read_error, on_write_error;
- const char *devaddr;
DriveInfo *dinfo;
ThrottleConfig cfg;
int snapshot = 0;
int ret;
Error *error = NULL;
QemuOpts *opts;
- QDict *bs_opts;
const char *id;
bool has_driver_specific_opts;
BlockDriver *drv = NULL;
- translation = BIOS_ATA_TRANSLATION_AUTO;
- media = MEDIA_DISK;
-
- /* Check common options by copying from all_opts to opts, all other options
- * are stored in bs_opts. */
- id = qemu_opts_id(all_opts);
+ /* Check common options by copying from bs_opts to opts, all other options
+ * stay in bs_opts for processing by bdrv_open(). */
+ id = qdict_get_try_str(bs_opts, "id");
opts = qemu_opts_create(&qemu_common_drive_opts, id, 1, &error);
if (error_is_set(&error)) {
- qerror_report_err(error);
- error_free(error);
+ error_propagate(errp, error);
return NULL;
}
- bs_opts = qdict_new();
- qemu_opts_to_qdict(all_opts, bs_opts);
qemu_opts_absorb_qdict(opts, bs_opts, &error);
if (error_is_set(&error)) {
- qerror_report_err(error);
- error_free(error);
+ error_propagate(errp, error);
return NULL;
}
has_driver_specific_opts = !!qdict_size(bs_opts);
/* extract parameters */
- bus_id = qemu_opt_get_number(opts, "bus", 0);
- unit_id = qemu_opt_get_number(opts, "unit", -1);
- index = qemu_opt_get_number(opts, "index", -1);
-
- cyls = qemu_opt_get_number(opts, "cyls", 0);
- heads = qemu_opt_get_number(opts, "heads", 0);
- secs = qemu_opt_get_number(opts, "secs", 0);
-
snapshot = qemu_opt_get_bool(opts, "snapshot", 0);
ro = qemu_opt_get_bool(opts, "read-only", 0);
copy_on_read = qemu_opt_get_bool(opts, "copy-on-read", false);
file = qemu_opt_get(opts, "file");
serial = qemu_opt_get(opts, "serial");
- if ((buf = qemu_opt_get(opts, "if")) != NULL) {
- for (type = 0; type < IF_COUNT && strcmp(buf, if_name[type]); type++)
- ;
- if (type == IF_COUNT) {
- error_report("unsupported bus type '%s'", buf);
- return NULL;
- }
- } else {
- type = block_default_type;
- }
-
- max_devs = if_max_devs[type];
-
- if (cyls || heads || secs) {
- if (cyls < 1) {
- error_report("invalid physical cyls number");
- return NULL;
- }
- if (heads < 1) {
- error_report("invalid physical heads number");
- return NULL;
- }
- if (secs < 1) {
- error_report("invalid physical secs number");
- return NULL;
- }
- }
-
- if ((buf = qemu_opt_get(opts, "trans")) != NULL) {
- if (!cyls) {
- error_report("'%s' trans must be used with cyls, heads and secs",
- buf);
- return NULL;
- }
- if (!strcmp(buf, "none"))
- translation = BIOS_ATA_TRANSLATION_NONE;
- else if (!strcmp(buf, "lba"))
- translation = BIOS_ATA_TRANSLATION_LBA;
- else if (!strcmp(buf, "auto"))
- translation = BIOS_ATA_TRANSLATION_AUTO;
- else {
- error_report("'%s' invalid translation type", buf);
- return NULL;
- }
- }
-
- if ((buf = qemu_opt_get(opts, "media")) != NULL) {
- if (!strcmp(buf, "disk")) {
- media = MEDIA_DISK;
- } else if (!strcmp(buf, "cdrom")) {
- if (cyls || secs || heads) {
- error_report("CHS can't be set with media=%s", buf);
- return NULL;
- }
- media = MEDIA_CDROM;
- } else {
- error_report("'%s' invalid media", buf);
- return NULL;
- }
- }
-
if ((buf = qemu_opt_get(opts, "discard")) != NULL) {
if (bdrv_parse_discard_flags(buf, &bdrv_flags) != 0) {
- error_report("invalid discard option");
+ error_setg(errp, "invalid discard option");
return NULL;
}
}
} else if (!strcmp(buf, "threads")) {
/* this is the default */
} else {
- error_report("invalid aio option");
+ error_setg(errp, "invalid aio option");
return NULL;
}
}
return NULL;
}
- drv = bdrv_find_whitelisted_format(buf, ro);
+ drv = bdrv_find_format(buf);
if (!drv) {
- if (!ro && bdrv_find_whitelisted_format(buf, !ro)) {
- error_report("'%s' can be only used as read-only device.", buf);
- } else {
- error_report("'%s' invalid format", buf);
- }
+ error_setg(errp, "'%s' invalid format", buf);
return NULL;
}
}
cfg.op_size = qemu_opt_get_number(opts, "throttling.iops-size", 0);
if (!check_throttle_config(&cfg, &error)) {
- error_report("%s", error_get_pretty(error));
- error_free(error);
+ error_propagate(errp, error);
return NULL;
}
- if (qemu_opt_get(opts, "boot") != NULL) {
- fprintf(stderr, "qemu-kvm: boot=on|off is deprecated and will be "
- "ignored. Future versions will reject this parameter. Please "
- "update your scripts.\n");
- }
-
on_write_error = BLOCKDEV_ON_ERROR_ENOSPC;
if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) {
- error_report("werror is not supported by this bus type");
+ error_setg(errp, "werror is not supported by this bus type");
return NULL;
}
- on_write_error = parse_block_error_action(buf, 0);
- if (on_write_error < 0) {
+ on_write_error = parse_block_error_action(buf, 0, &error);
+ if (error_is_set(&error)) {
+ error_propagate(errp, error);
return NULL;
}
}
return NULL;
}
- on_read_error = parse_block_error_action(buf, 1);
- if (on_read_error < 0) {
- return NULL;
- }
- }
-
- if ((devaddr = qemu_opt_get(opts, "addr")) != NULL) {
- if (type != IF_VIRTIO) {
- error_report("addr is not supported by this bus type");
+ on_read_error = parse_block_error_action(buf, 1, &error);
+ if (error_is_set(&error)) {
+ error_propagate(errp, error);
return NULL;
}
}
- /* compute bus and unit according index */
-
- if (index != -1) {
- if (bus_id != 0 || unit_id != -1) {
- error_report("index cannot be used with bus and unit");
- return NULL;
- }
- bus_id = drive_index_to_bus_id(type, index);
- unit_id = drive_index_to_unit_id(type, index);
- }
-
- /* if user doesn't specify a unit_id,
- * try to find the first free
- */
-
- if (unit_id == -1) {
- unit_id = 0;
- while (drive_get(type, bus_id, unit_id) != NULL) {
- unit_id++;
- if (max_devs && unit_id >= max_devs) {
- unit_id -= max_devs;
- bus_id++;
- }
- }
- }
-
- /* check unit id */
-
- if (max_devs && unit_id >= max_devs) {
- error_report("unit %d too big (max is %d)",
- unit_id, max_devs - 1);
- return NULL;
- }
-
- /*
- * catch multiple definitions
- */
-
- if (drive_get(type, bus_id, unit_id) != NULL) {
- error_report("drive with bus=%d, unit=%d (index=%d) exists",
- bus_id, unit_id, index);
- return NULL;
- }
-
/* init */
-
dinfo = g_malloc0(sizeof(*dinfo));
- if ((buf = qemu_opts_id(opts)) != NULL) {
- dinfo->id = g_strdup(buf);
- } else {
- /* no id supplied -> create one */
- dinfo->id = g_malloc0(32);
- if (type == IF_IDE || type == IF_SCSI)
- mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd";
- if (max_devs)
- snprintf(dinfo->id, 32, "%s%i%s%i",
- if_name[type], bus_id, mediastr, unit_id);
- else
- snprintf(dinfo->id, 32, "%s%s%i",
- if_name[type], mediastr, unit_id);
- }
+ dinfo->id = g_strdup(qemu_opts_id(opts));
dinfo->bdrv = bdrv_new(dinfo->id);
dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
dinfo->bdrv->read_only = ro;
- dinfo->devaddr = devaddr;
dinfo->type = type;
- dinfo->bus = bus_id;
- dinfo->unit = unit_id;
- dinfo->cyls = cyls;
- dinfo->heads = heads;
- dinfo->secs = secs;
- dinfo->trans = translation;
- dinfo->opts = all_opts;
dinfo->refcount = 1;
if (serial != NULL) {
dinfo->serial = g_strdup(serial);
bdrv_set_io_limits(dinfo->bdrv, &cfg);
}
- switch(type) {
- case IF_IDE:
- case IF_SCSI:
- case IF_XEN:
- case IF_NONE:
- dinfo->media_cd = media == MEDIA_CDROM;
- break;
- case IF_SD:
- case IF_FLOPPY:
- case IF_PFLASH:
- case IF_MTD:
- break;
- case IF_VIRTIO:
- {
- /* add virtio block device */
- QemuOpts *devopts;
- devopts = qemu_opts_create_nofail(qemu_find_opts("device"));
- if (arch_type == QEMU_ARCH_S390X) {
- qemu_opt_set(devopts, "driver", "virtio-blk-s390");
- } else {
- qemu_opt_set(devopts, "driver", "virtio-blk-pci");
- }
- qemu_opt_set(devopts, "drive", dinfo->id);
- if (devaddr)
- qemu_opt_set(devopts, "addr", devaddr);
- break;
- }
- default:
- abort();
- }
if (!file || !*file) {
if (has_driver_specific_opts) {
file = NULL;
bdrv_flags |= BDRV_O_INCOMING;
}
- if (media == MEDIA_CDROM) {
- /* CDROM is fine for any interface, don't check. */
- ro = 1;
- } else if (ro == 1) {
- if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY &&
- type != IF_NONE && type != IF_PFLASH) {
- error_report("read-only not supported by this bus type");
- goto err;
- }
- }
-
bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
- if (ro && copy_on_read) {
- error_report("warning: disabling copy_on_read on read-only drive");
- }
-
QINCREF(bs_opts);
ret = bdrv_open(dinfo->bdrv, file, bs_opts, bdrv_flags, drv, &error);
if (ret < 0) {
- error_report("could not open disk image %s: %s",
- file ?: dinfo->id, error_get_pretty(error));
+ error_setg(errp, "could not open disk image %s: %s",
+ file ?: dinfo->id, error_get_pretty(error));
+ error_free(error);
goto err;
}
}
}
+QemuOptsList qemu_legacy_drive_opts = {
+ .name = "drive",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_legacy_drive_opts.head),
+ .desc = {
+ {
+ .name = "bus",
+ .type = QEMU_OPT_NUMBER,
+ .help = "bus number",
+ },{
+ .name = "unit",
+ .type = QEMU_OPT_NUMBER,
+ .help = "unit number (i.e. lun for scsi)",
+ },{
+ .name = "index",
+ .type = QEMU_OPT_NUMBER,
+ .help = "index number",
+ },{
+ .name = "media",
+ .type = QEMU_OPT_STRING,
+ .help = "media type (disk, cdrom)",
+ },{
+ .name = "if",
+ .type = QEMU_OPT_STRING,
+ .help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
+ },{
+ .name = "cyls",
+ .type = QEMU_OPT_NUMBER,
+ .help = "number of cylinders (ide disk geometry)",
+ },{
+ .name = "heads",
+ .type = QEMU_OPT_NUMBER,
+ .help = "number of heads (ide disk geometry)",
+ },{
+ .name = "secs",
+ .type = QEMU_OPT_NUMBER,
+ .help = "number of sectors (ide disk geometry)",
+ },{
+ .name = "trans",
+ .type = QEMU_OPT_STRING,
+ .help = "chs translation (auto, lba, none)",
+ },{
+ .name = "boot",
+ .type = QEMU_OPT_BOOL,
+ .help = "(deprecated, ignored)",
+ },{
+ .name = "addr",
+ .type = QEMU_OPT_STRING,
+ .help = "pci address (virtio only)",
+ },
+
+ /* Options that are passed on, but have special semantics with -drive */
+ {
+ .name = "read-only",
+ .type = QEMU_OPT_BOOL,
+ .help = "open drive file as read-only",
+ },{
+ .name = "copy-on-read",
+ .type = QEMU_OPT_BOOL,
+ .help = "copy read data from backing file into image file",
+ },
+
+ { /* end of list */ }
+ },
+};
+
DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
{
const char *value;
+ DriveInfo *dinfo = NULL;
+ QDict *bs_opts;
+ QemuOpts *legacy_opts;
+ DriveMediaType media = MEDIA_DISK;
+ BlockInterfaceType type;
+ int cyls, heads, secs, translation;
+ int max_devs, bus_id, unit_id, index;
+ const char *devaddr;
+ bool read_only, copy_on_read;
+ Error *local_err = NULL;
/* Change legacy command line options into QMP ones */
qemu_opt_rename(all_opts, "iops", "throttling.iops-total");
qemu_opt_unset(all_opts, "cache");
}
- return blockdev_init(all_opts, block_default_type);
+ /* Get a QDict for processing the options */
+ bs_opts = qdict_new();
+ qemu_opts_to_qdict(all_opts, bs_opts);
+
+ legacy_opts = qemu_opts_create_nofail(&qemu_legacy_drive_opts);
+ qemu_opts_absorb_qdict(legacy_opts, bs_opts, &local_err);
+ if (error_is_set(&local_err)) {
+ qerror_report_err(local_err);
+ error_free(local_err);
+ goto fail;
+ }
+
+ /* Deprecated option boot=[on|off] */
+ if (qemu_opt_get(legacy_opts, "boot") != NULL) {
+ fprintf(stderr, "qemu-kvm: boot=on|off is deprecated and will be "
+ "ignored. Future versions will reject this parameter. Please "
+ "update your scripts.\n");
+ }
+
+ /* Media type */
+ value = qemu_opt_get(legacy_opts, "media");
+ if (value) {
+ if (!strcmp(value, "disk")) {
+ media = MEDIA_DISK;
+ } else if (!strcmp(value, "cdrom")) {
+ media = MEDIA_CDROM;
+ qdict_put(bs_opts, "read-only", qstring_from_str("on"));
+ } else {
+ error_report("'%s' invalid media", value);
+ goto fail;
+ }
+ }
+
+ /* copy-on-read is disabled with a warning for read-only devices */
+ read_only = qemu_opt_get_bool(legacy_opts, "read-only", false);
+ copy_on_read = qemu_opt_get_bool(legacy_opts, "copy-on-read", false);
+
+ if (read_only && copy_on_read) {
+ error_report("warning: disabling copy-on-read on read-only drive");
+ copy_on_read = false;
+ }
+
+ qdict_put(bs_opts, "read-only",
+ qstring_from_str(read_only ? "on" : "off"));
+ qdict_put(bs_opts, "copy-on-read",
+ qstring_from_str(copy_on_read ? "on" :"off"));
+
+ /* Controller type */
+ value = qemu_opt_get(legacy_opts, "if");
+ if (value) {
+ for (type = 0;
+ type < IF_COUNT && strcmp(value, if_name[type]);
+ type++) {
+ }
+ if (type == IF_COUNT) {
+ error_report("unsupported bus type '%s'", value);
+ goto fail;
+ }
+ } else {
+ type = block_default_type;
+ }
+
+ /* Geometry */
+ cyls = qemu_opt_get_number(legacy_opts, "cyls", 0);
+ heads = qemu_opt_get_number(legacy_opts, "heads", 0);
+ secs = qemu_opt_get_number(legacy_opts, "secs", 0);
+
+ if (cyls || heads || secs) {
+ if (cyls < 1) {
+ error_report("invalid physical cyls number");
+ goto fail;
+ }
+ if (heads < 1) {
+ error_report("invalid physical heads number");
+ goto fail;
+ }
+ if (secs < 1) {
+ error_report("invalid physical secs number");
+ goto fail;
+ }
+ }
+
+ translation = BIOS_ATA_TRANSLATION_AUTO;
+ value = qemu_opt_get(legacy_opts, "trans");
+ if (value != NULL) {
+ if (!cyls) {
+ error_report("'%s' trans must be used with cyls, heads and secs",
+ value);
+ goto fail;
+ }
+ if (!strcmp(value, "none")) {
+ translation = BIOS_ATA_TRANSLATION_NONE;
+ } else if (!strcmp(value, "lba")) {
+ translation = BIOS_ATA_TRANSLATION_LBA;
+ } else if (!strcmp(value, "auto")) {
+ translation = BIOS_ATA_TRANSLATION_AUTO;
+ } else {
+ error_report("'%s' invalid translation type", value);
+ goto fail;
+ }
+ }
+
+ if (media == MEDIA_CDROM) {
+ if (cyls || secs || heads) {
+ error_report("CHS can't be set with media=cdrom");
+ goto fail;
+ }
+ }
+
+ /* Device address specified by bus/unit or index.
+ * If none was specified, try to find the first free one. */
+ bus_id = qemu_opt_get_number(legacy_opts, "bus", 0);
+ unit_id = qemu_opt_get_number(legacy_opts, "unit", -1);
+ index = qemu_opt_get_number(legacy_opts, "index", -1);
+
+ max_devs = if_max_devs[type];
+
+ if (index != -1) {
+ if (bus_id != 0 || unit_id != -1) {
+ error_report("index cannot be used with bus and unit");
+ goto fail;
+ }
+ bus_id = drive_index_to_bus_id(type, index);
+ unit_id = drive_index_to_unit_id(type, index);
+ }
+
+ if (unit_id == -1) {
+ unit_id = 0;
+ while (drive_get(type, bus_id, unit_id) != NULL) {
+ unit_id++;
+ if (max_devs && unit_id >= max_devs) {
+ unit_id -= max_devs;
+ bus_id++;
+ }
+ }
+ }
+
+ if (max_devs && unit_id >= max_devs) {
+ error_report("unit %d too big (max is %d)", unit_id, max_devs - 1);
+ goto fail;
+ }
+
+ if (drive_get(type, bus_id, unit_id) != NULL) {
+ error_report("drive with bus=%d, unit=%d (index=%d) exists",
+ bus_id, unit_id, index);
+ goto fail;
+ }
+
+ /* no id supplied -> create one */
+ if (qemu_opts_id(all_opts) == NULL) {
+ char *new_id;
+ const char *mediastr = "";
+ if (type == IF_IDE || type == IF_SCSI) {
+ mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd";
+ }
+ if (max_devs) {
+ new_id = g_strdup_printf("%s%i%s%i", if_name[type], bus_id,
+ mediastr, unit_id);
+ } else {
+ new_id = g_strdup_printf("%s%s%i", if_name[type],
+ mediastr, unit_id);
+ }
+ qdict_put(bs_opts, "id", qstring_from_str(new_id));
+ g_free(new_id);
+ }
+
+ /* Add virtio block device */
+ devaddr = qemu_opt_get(legacy_opts, "addr");
+ if (devaddr && type != IF_VIRTIO) {
+ error_report("addr is not supported by this bus type");
+ goto fail;
+ }
+
+ if (type == IF_VIRTIO) {
+ QemuOpts *devopts;
+ devopts = qemu_opts_create_nofail(qemu_find_opts("device"));
+ if (arch_type == QEMU_ARCH_S390X) {
+ qemu_opt_set(devopts, "driver", "virtio-blk-s390");
+ } else {
+ qemu_opt_set(devopts, "driver", "virtio-blk-pci");
+ }
+ qemu_opt_set(devopts, "drive", qdict_get_str(bs_opts, "id"));
+ if (devaddr) {
+ qemu_opt_set(devopts, "addr", devaddr);
+ }
+ }
+
+ /* Actual block device init: Functionality shared with blockdev-add */
+ dinfo = blockdev_init(bs_opts, type, &local_err);
+ if (dinfo == NULL) {
+ if (error_is_set(&local_err)) {
+ qerror_report_err(local_err);
+ error_free(local_err);
+ }
+ goto fail;
+ } else {
+ assert(!error_is_set(&local_err));
+ }
+
+ /* Set legacy DriveInfo fields */
+ dinfo->enable_auto_del = true;
+ dinfo->opts = all_opts;
+
+ dinfo->cyls = cyls;
+ dinfo->heads = heads;
+ dinfo->secs = secs;
+ dinfo->trans = translation;
+
+ dinfo->bus = bus_id;
+ dinfo->unit = unit_id;
+ dinfo->devaddr = devaddr;
+
+ switch(type) {
+ case IF_IDE:
+ case IF_SCSI:
+ case IF_XEN:
+ case IF_NONE:
+ dinfo->media_cd = media == MEDIA_CDROM;
+ break;
+ default:
+ break;
+ }
+
+fail:
+ qemu_opts_del(legacy_opts);
+ return dinfo;
}
void do_commit(Monitor *mon, const QDict *qdict)
}
}
+ if (bdrv_check_ext_snapshot(state->old_bs) != EXT_SNAPSHOT_ALLOWED) {
+ error_set(errp, QERR_FEATURE_DISABLED, "snapshot");
+ return;
+ }
+
flags = state->old_bs->open_flags;
/* create new image w/backing file */
block_job_complete(job, errp);
}
+void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
+{
+ QmpOutputVisitor *ov = qmp_output_visitor_new();
+ QObject *obj;
+ QDict *qdict;
+ Error *local_err = NULL;
+
+ /* Require an ID in the top level */
+ if (!options->has_id) {
+ error_setg(errp, "Block device needs an ID");
+ goto fail;
+ }
+
+ /* TODO Sort it out in raw-posix and drive_init: Reject aio=native with
+ * cache.direct=false instead of silently switching to aio=threads, except
+ * if called from drive_init.
+ *
+ * For now, simply forbidding the combination for all drivers will do. */
+ if (options->has_aio && options->aio == BLOCKDEV_AIO_OPTIONS_NATIVE) {
+ bool direct = options->cache->has_direct && options->cache->direct;
+ if (!options->has_cache && !direct) {
+ error_setg(errp, "aio=native requires cache.direct=true");
+ goto fail;
+ }
+ }
+
+ visit_type_BlockdevOptions(qmp_output_get_visitor(ov),
+ &options, NULL, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ goto fail;
+ }
+
+ obj = qmp_output_get_qobject(ov);
+ qdict = qobject_to_qdict(obj);
+
+ qdict_flatten(qdict);
+
+ blockdev_init(qdict, IF_NONE, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ goto fail;
+ }
+
+fail:
+ qmp_output_visitor_cleanup(ov);
+}
+
static void do_qmp_query_block_jobs_one(void *opaque, BlockDriverState *bs)
{
BlockJobInfoList **prev = opaque;
.head = QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head),
.desc = {
{
- .name = "bus",
- .type = QEMU_OPT_NUMBER,
- .help = "bus number",
- },{
- .name = "unit",
- .type = QEMU_OPT_NUMBER,
- .help = "unit number (i.e. lun for scsi)",
- },{
- .name = "if",
- .type = QEMU_OPT_STRING,
- .help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
- },{
- .name = "index",
- .type = QEMU_OPT_NUMBER,
- .help = "index number",
- },{
- .name = "cyls",
- .type = QEMU_OPT_NUMBER,
- .help = "number of cylinders (ide disk geometry)",
- },{
- .name = "heads",
- .type = QEMU_OPT_NUMBER,
- .help = "number of heads (ide disk geometry)",
- },{
- .name = "secs",
- .type = QEMU_OPT_NUMBER,
- .help = "number of sectors (ide disk geometry)",
- },{
- .name = "trans",
- .type = QEMU_OPT_STRING,
- .help = "chs translation (auto, lba. none)",
- },{
- .name = "media",
- .type = QEMU_OPT_STRING,
- .help = "media type (disk, cdrom)",
- },{
.name = "snapshot",
.type = QEMU_OPT_BOOL,
.help = "enable/disable snapshot mode",
.name = "werror",
.type = QEMU_OPT_STRING,
.help = "write error action",
- },{
- .name = "addr",
- .type = QEMU_OPT_STRING,
- .help = "pci address (virtio only)",
},{
.name = "read-only",
.type = QEMU_OPT_BOOL,
.name = "copy-on-read",
.type = QEMU_OPT_BOOL,
.help = "copy read data from backing file into image file",
- },{
- .name = "boot",
- .type = QEMU_OPT_BOOL,
- .help = "(deprecated, ignored)",
},
{ /* end of list */ }
},
#include "qmp-commands.h"
#include "qemu/timer.h"
-void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs,
+void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
int64_t speed, BlockDriverCompletionFunc *cb,
void *opaque, Error **errp)
{
bdrv_ref(bs);
bdrv_set_in_use(bs, 1);
- job = g_malloc0(job_type->instance_size);
- job->job_type = job_type;
+ job = g_malloc0(driver->instance_size);
+ job->driver = driver;
job->bs = bs;
job->cb = cb;
job->opaque = opaque;
{
Error *local_err = NULL;
- if (!job->job_type->set_speed) {
+ if (!job->driver->set_speed) {
error_set(errp, QERR_NOT_SUPPORTED);
return;
}
- job->job_type->set_speed(job, speed, &local_err);
+ job->driver->set_speed(job, speed, &local_err);
if (error_is_set(&local_err)) {
error_propagate(errp, local_err);
return;
void block_job_complete(BlockJob *job, Error **errp)
{
- if (job->paused || job->cancelled || !job->job_type->complete) {
+ if (job->paused || job->cancelled || !job->driver->complete) {
error_set(errp, QERR_BLOCK_JOB_NOT_READY, job->bs->device_name);
return;
}
- job->job_type->complete(job, errp);
+ job->driver->complete(job, errp);
}
void block_job_pause(BlockJob *job)
void block_job_iostatus_reset(BlockJob *job)
{
job->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
- if (job->job_type->iostatus_reset) {
- job->job_type->iostatus_reset(job);
+ if (job->driver->iostatus_reset) {
+ job->driver->iostatus_reset(job);
}
}
BlockJobInfo *block_job_query(BlockJob *job)
{
BlockJobInfo *info = g_new0(BlockJobInfo, 1);
- info->type = g_strdup(job->job_type->job_type);
+ info->type = g_strdup(BlockJobType_lookup[job->driver->job_type]);
info->device = g_strdup(bdrv_get_device_name(job->bs));
info->len = job->len;
info->busy = job->busy;
"'len': %" PRId64 ","
"'offset': %" PRId64 ","
"'speed': %" PRId64 " }",
- job->job_type->job_type,
+ BlockJobType_lookup[job->driver->job_type],
bdrv_get_device_name(job->bs),
job->len,
job->offset,
* local variables as longjmp is marked 'noreturn'. */
cpu = current_cpu;
env = cpu->env_ptr;
+#if !(defined(CONFIG_USER_ONLY) && \
+ (defined(TARGET_M68K) || defined(TARGET_PPC) || defined(TARGET_S390X)))
+ cc = CPU_GET_CLASS(cpu);
+#endif
}
} /* for(;;) */
return ram_addr;
}
-static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
-{
- ram_addr_t ram_addr;
- void *p;
-
- if (tlb_is_dirty_ram(tlb_entry)) {
- p = (void *)(uintptr_t)((tlb_entry->addr_write & TARGET_PAGE_MASK)
- + tlb_entry->addend);
- ram_addr = qemu_ram_addr_from_host_nofail(p);
- if (!cpu_physical_memory_is_dirty(ram_addr)) {
- tlb_entry->addr_write |= TLB_NOTDIRTY;
- }
- }
-}
-
void cpu_tlb_reset_dirty_all(ram_addr_t start1, ram_addr_t length)
{
CPUState *cpu;
members should always be added to the end of the dictionary to preserve
backwards compatibility.
+
+A complex type definition can specify another complex type as its base.
+In this case, the fields of the base type are included as top-level fields
+of the new complex type's dictionary in the QMP wire format. An example
+definition is:
+
+ { 'type': 'BlockdevOptionsGenericFormat', 'data': { 'file': 'str' } }
+ { 'type': 'BlockdevOptionsGenericCOWFormat',
+ 'base': 'BlockdevOptionsGenericFormat',
+ 'data': { '*backing': 'str' } }
+
+An example BlockdevOptionsGenericCOWFormat object on the wire could use
+both fields like this:
+
+ { "file": "/some/place/my-image",
+ "backing": "/some/place/my-backing-file" }
+
=== Enumeration types ===
An enumeration type is a dictionary containing a single key whose value is a
QMP wiki page
-------------
-http://wiki.qemu.org/QMP
+http://wiki.qemu-project.org/QMP
(RDMA: Remote Direct Memory Access)
RDMA Live Migration Specification, Version # 1
==============================================
-Wiki: http://wiki.qemu.org/Features/RDMALiveMigration
+Wiki: http://wiki.qemu-project.org/Features/RDMALiveMigration
Github: git@github.com:hinesmr/qemu.git, 'rdma' branch
Copyright (C) 2013 Michael R. Hines <mrhines@us.ibm.com>
variable: Unique ID string for the snapshot (not null terminated)
variable: Name of the snapshot (not null terminated)
+
+ variable: Padding to round up the snapshot table entry size to the
+ next multiple of 8.
abort();
}
-CPUArchState *cpu_copy(CPUArchState *env)
-{
- CPUArchState *new_env = cpu_init(env->cpu_model_str);
-#if defined(TARGET_HAS_ICE)
- CPUBreakpoint *bp;
- CPUWatchpoint *wp;
-#endif
-
- /* Reset non arch specific state */
- cpu_reset(ENV_GET_CPU(new_env));
-
- /* Copy arch specific state into the new CPU */
- memcpy(new_env, env, sizeof(CPUArchState));
-
- /* Clone all break/watchpoints.
- Note: Once we support ptrace with hw-debug register access, make sure
- BP_CPU break/watchpoints are handled correctly on clone. */
- QTAILQ_INIT(&env->breakpoints);
- QTAILQ_INIT(&env->watchpoints);
-#if defined(TARGET_HAS_ICE)
- QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
- cpu_breakpoint_insert(new_env, bp->pc, bp->flags, NULL);
- }
- QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
- cpu_watchpoint_insert(new_env, wp->vaddr, (~wp->len_mask) + 1,
- wp->flags, NULL);
- }
-#endif
-
- return new_env;
-}
-
#if !defined(CONFIG_USER_ONLY)
static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t end,
uintptr_t length)
if (dinfo && dinfo->bdrv) {
DB_PRINT_L(0, "Binding to IF_MTD drive\n");
s->bdrv = dinfo->bdrv;
+ if (bdrv_is_read_only(s->bdrv)) {
+ fprintf(stderr, "Can't use a read-only drive");
+ return 1;
+ }
+
/* FIXME: Move to late init */
if (bdrv_read(s->bdrv, 0, s->storage, DIV_ROUND_UP(s->size,
BDRV_SECTOR_SIZE))) {
xen_be_printf(&ioreq->blkdev->xendev, 0,
"can't map grant ref %d (%s, %d maps)\n",
refs[i], strerror(errno), ioreq->blkdev->cnt_map);
+ ioreq->mapped = 1;
ioreq_unmap(ioreq);
return -1;
}
/* setup via qemu cmdline -> already setup for us */
xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n");
blkdev->bs = blkdev->dinfo->bdrv;
+ if (bdrv_is_read_only(blkdev->bs) && !readonly) {
+ xen_be_printf(&blkdev->xendev, 0, "Unexpected read-only drive");
+ blkdev->bs = NULL;
+ return -1;
+ }
/* blkdev->bs is not create by us, we get a reference
* so we can bdrv_unref() unconditionally */
bdrv_ref(blkdev->bs);
int i;
s->control_regs.irqstatus = 0;
- s->control_regs.ghc = 0;
+ /* AHCI Enable (AE)
+ * The implementation of this bit is dependent upon the value of the
+ * CAP.SAM bit. If CAP.SAM is '0', then GHC.AE shall be read-write and
+ * shall have a reset value of '0'. If CAP.SAM is '1', then AE shall be
+ * read-only and shall have a reset value of '1'.
+ *
+ * We set HOST_CAP_AHCI so we must enable AHCI at reset.
+ */
+ s->control_regs.ghc = HOST_CTL_AHCI_EN;
for (i = 0; i < s->ports; i++) {
pr = &s->dev[i].port_regs;
static char *scsibus_get_fw_dev_path(DeviceState *dev);
static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf);
static void scsi_req_dequeue(SCSIRequest *req);
+static uint8_t *scsi_target_alloc_buf(SCSIRequest *req, size_t len);
+static void scsi_target_free_buf(SCSIRequest *req);
static Property scsi_props[] = {
DEFINE_PROP_UINT32("channel", SCSIDevice, channel, 0),
struct SCSITargetReq {
SCSIRequest req;
int len;
- uint8_t buf[2056];
+ uint8_t *buf;
+ int buf_len;
};
static void store_lun(uint8_t *outbuf, int lun)
if (!found_lun0) {
n += 8;
}
- len = MIN(n + 8, r->req.cmd.xfer & ~7);
- if (len > sizeof(r->buf)) {
- /* TODO: > 256 LUNs? */
- return false;
- }
+ scsi_target_alloc_buf(&r->req, n + 8);
+
+ len = MIN(n + 8, r->req.cmd.xfer & ~7);
memset(r->buf, 0, len);
- stl_be_p(&r->buf, n);
+ stl_be_p(&r->buf[0], n);
i = found_lun0 ? 8 : 16;
QTAILQ_FOREACH(kid, &r->req.bus->qbus.children, sibling) {
DeviceState *qdev = kid->child;
static bool scsi_target_emulate_inquiry(SCSITargetReq *r)
{
assert(r->req.dev->lun != r->req.lun);
+
+ scsi_target_alloc_buf(&r->req, SCSI_INQUIRY_LEN);
+
if (r->req.cmd.buf[1] & 0x2) {
/* Command support data - optional, not implemented */
return false;
return false;
}
/* done with EVPD */
- assert(r->len < sizeof(r->buf));
+ assert(r->len < r->buf_len);
r->len = MIN(r->req.cmd.xfer, r->len);
return true;
}
}
/* PAGE CODE == 0 */
- r->len = MIN(r->req.cmd.xfer, 36);
+ r->len = MIN(r->req.cmd.xfer, SCSI_INQUIRY_LEN);
memset(r->buf, 0, r->len);
if (r->req.lun != 0) {
r->buf[0] = TYPE_NO_LUN;
}
break;
case REQUEST_SENSE:
+ scsi_target_alloc_buf(&r->req, SCSI_SENSE_LEN);
r->len = scsi_device_get_sense(r->req.dev, r->buf,
- MIN(req->cmd.xfer, sizeof r->buf),
+ MIN(req->cmd.xfer, r->buf_len),
(req->cmd.buf[1] & 1) == 0);
if (r->req.dev->sense_is_ua) {
scsi_device_unit_attention_reported(req->dev);
return r->buf;
}
+static uint8_t *scsi_target_alloc_buf(SCSIRequest *req, size_t len)
+{
+ SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
+
+ r->buf = g_malloc(len);
+ r->buf_len = len;
+
+ return r->buf;
+}
+
+static void scsi_target_free_buf(SCSIRequest *req)
+{
+ SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
+
+ g_free(r->buf);
+}
+
static const struct SCSIReqOps reqops_target_command = {
.size = sizeof(SCSITargetReq),
.send_command = scsi_target_send_command,
.read_data = scsi_target_read_data,
.get_buf = scsi_target_get_buf,
+ .free_req = scsi_target_free_buf,
};
buf[7] = 10;
buf[12] = sense.asc;
buf[13] = sense.ascq;
- return MIN(len, 18);
+ return MIN(len, SCSI_SENSE_LEN);
} else {
/* Return descriptor format sense buffer */
buf[0] = 0x72;
dinfo = drive_get_next(IF_SD);
s->card = sd_init(dinfo ? dinfo->bdrv : NULL, false);
+ if (s->card == NULL) {
+ return -1;
+ }
+
s->enabled = dinfo ? bdrv_is_inserted(dinfo->bdrv) : 0;
memory_region_init_io(&s->regs_region, OBJECT(s), &memcard_mmio_ops, s,
/* Instantiate the storage */
s->card = sd_init(bd, false);
+ if (s->card == NULL) {
+ exit(1);
+ }
return s;
}
/* Instantiate the storage */
s->card = sd_init(bd, false);
+ if (s->card == NULL) {
+ exit(1);
+ }
s->cdet = qemu_allocate_irqs(omap_mmc_cover_cb, s, 1)[0];
sd_set_cb(s->card, NULL, s->cdet);
qdev_init_gpio_out(dev, s->cardstatus, 2);
dinfo = drive_get_next(IF_SD);
s->card = sd_init(dinfo ? dinfo->bdrv : NULL, false);
+ if (s->card == NULL) {
+ return -1;
+ }
+
return 0;
}
/* Instantiate the actual storage */
s->card = sd_init(bd, false);
+ if (s->card == NULL) {
+ exit(1);
+ }
register_savevm(NULL, "pxa2xx_mmci", 0, 0,
pxa2xx_mmci_save, pxa2xx_mmci_load, s);
{
SDState *sd;
+ if (bdrv_is_read_only(bs)) {
+ fprintf(stderr, "sd_init: Cannot use read-only drive\n");
+ return NULL;
+ }
+
sd = (SDState *) g_malloc0(sizeof(SDState));
sd->buf = qemu_blockalign(bs, 512);
sd->spi = is_spi;
di = drive_get_next(IF_SD);
s->card = sd_init(di ? di->bdrv : NULL, false);
+ if (s->card == NULL) {
+ exit(1);
+ }
s->eject_cb = qemu_allocate_irqs(sdhci_insert_eject_cb, s, 1)[0];
s->ro_cb = qemu_allocate_irqs(sdhci_card_readonly_cb, s, 1)[0];
sd_set_cb(s->card, s->ro_cb, s->eject_cb);
s->mode = SSI_SD_CMD;
dinfo = drive_get_next(IF_SD);
s->sd = sd_init(dinfo ? dinfo->bdrv : NULL, true);
+ if (s->sd == NULL) {
+ return -1;
+ }
register_savevm(&dev->qdev, "ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s);
return 0;
}
struct XenDevOps *ops)
{
struct XenDevice *xendev;
- char *dom0;
xendev = xen_be_find_xendev(type, dom, dev);
if (xendev) {
xendev->dev = dev;
xendev->ops = ops;
- dom0 = xs_get_domain_path(xenstore, 0);
- snprintf(xendev->be, sizeof(xendev->be), "%s/backend/%s/%d/%d",
- dom0, xendev->type, xendev->dom, xendev->dev);
+ snprintf(xendev->be, sizeof(xendev->be), "backend/%s/%d/%d",
+ xendev->type, xendev->dom, xendev->dev);
snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
xendev->type, xendev->dev);
- free(dom0);
xendev->debug = debug;
xendev->local_port = -1;
{
struct XenDevice *xendev;
char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
- char **dev = NULL, *dom0;
+ char **dev = NULL;
unsigned int cdev, j;
/* setup watch */
- dom0 = xs_get_domain_path(xenstore, 0);
snprintf(token, sizeof(token), "be:%p:%d:%p", type, dom, ops);
- snprintf(path, sizeof(path), "%s/backend/%s/%d", dom0, type, dom);
- free(dom0);
+ snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
if (!xs_watch(xenstore, path, token)) {
xen_be_printf(NULL, 0, "xen be: watching backend path (%s) failed\n", path);
return -1;
struct XenDevOps *ops)
{
struct XenDevice *xendev;
- char path[XEN_BUFSIZE], *dom0, *bepath;
+ char path[XEN_BUFSIZE], *bepath;
unsigned int len, dev;
- dom0 = xs_get_domain_path(xenstore, 0);
- len = snprintf(path, sizeof(path), "%s/backend/%s/%d", dom0, type, dom);
- free(dom0);
+ len = snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
if (strncmp(path, watch, len) != 0) {
return;
}
/* BDRV_BLOCK_DATA: data is read from bs->file or another file
* BDRV_BLOCK_ZERO: sectors read as zero
* BDRV_BLOCK_OFFSET_VALID: sector stored in bs->file as raw data
+ * BDRV_BLOCK_RAW: used internally to indicate that the request
+ * was answered by the raw driver and that one
+ * should look in bs->file directly.
*
* If BDRV_BLOCK_OFFSET_VALID is set, bits 9-62 represent the offset in
* bs->file where sector data can be read from as raw data.
#define BDRV_BLOCK_DATA 1
#define BDRV_BLOCK_ZERO 2
#define BDRV_BLOCK_OFFSET_VALID 4
+#define BDRV_BLOCK_RAW 8
#define BDRV_BLOCK_OFFSET_MASK BDRV_SECTOR_MASK
typedef enum {
int bdrv_amend_options(BlockDriverState *bs_new, QEMUOptionParameter *options);
+/* external snapshots */
+
+typedef enum {
+ EXT_SNAPSHOT_ALLOWED,
+ EXT_SNAPSHOT_FORBIDDEN,
+} ExtSnapshotPerm;
+
+/* return EXT_SNAPSHOT_ALLOWED if external snapshot is allowed
+ * return EXT_SNAPSHOT_FORBIDDEN if external snapshot is forbidden
+ */
+ExtSnapshotPerm bdrv_check_ext_snapshot(BlockDriverState *bs);
+/* helper used to forbid external snapshots like in blkverify */
+ExtSnapshotPerm bdrv_check_ext_snapshot_forbidden(BlockDriverState *bs);
+
/* async block I/O */
typedef void BlockDriverDirtyHandler(BlockDriverState *bs, int64_t sector,
int sector_num);
int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors);
int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
+ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs);
void bdrv_round_to_clusters(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
int64_t *cluster_sector_num,
struct BlockDriver {
const char *format_name;
int instance_size;
+
+ /* if not defined external snapshots are allowed
+ * future block filters will query their children to build the response
+ */
+ ExtSnapshotPerm (*bdrv_check_ext_snapshot)(BlockDriverState *bs);
+
int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
int (*bdrv_probe_device)(const char *filename);
int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs,
const char *snapshot_name);
int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
+ ImageInfoSpecific *(*bdrv_get_specific_info)(BlockDriverState *bs);
int (*bdrv_save_vmstate)(BlockDriverState *bs, QEMUIOVector *qiov,
int64_t pos);
#include "block/block.h"
/**
- * BlockJobType:
+ * BlockJobDriver:
*
- * A class type for block job objects.
+ * A class type for block job driver.
*/
-typedef struct BlockJobType {
+typedef struct BlockJobDriver {
/** Derived BlockJob struct size */
size_t instance_size;
/** String describing the operation, part of query-block-jobs QMP API */
- const char *job_type;
+ BlockJobType job_type;
/** Optional callback for job types that support setting a speed limit */
void (*set_speed)(BlockJob *job, int64_t speed, Error **errp);
* manually.
*/
void (*complete)(BlockJob *job, Error **errp);
-} BlockJobType;
+} BlockJobDriver;
/**
* BlockJob:
*/
struct BlockJob {
/** The job type, including the job vtable. */
- const BlockJobType *job_type;
+ const BlockJobDriver *driver;
/** The block device on which the job is operating. */
BlockDriverState *bs;
* This function is not part of the public job interface; it should be
* called from a wrapper that is specific to the job type.
*/
-void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs,
+void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
int64_t speed, BlockDriverCompletionFunc *cb,
void *opaque, Error **errp);
void bdrv_snapshot_dump(fprintf_function func_fprintf, void *f,
QEMUSnapshotInfo *sn);
+void bdrv_image_info_specific_dump(fprintf_function func_fprintf, void *f,
+ ImageInfoSpecific *info_spec);
void bdrv_image_info_dump(fprintf_function func_fprintf, void *f,
ImageInfo *info);
#endif
\
/* user data */ \
void *opaque; \
- \
- const char *cpu_model_str;
#endif
.driver = "e1000",\
.property = "mitigation",\
.value = "off",\
+ },{\
+ .driver = "qemu64-" TYPE_X86_CPU,\
+ .property = "model",\
+ .value = stringify(2),\
+ },{\
+ .driver = "qemu32-" TYPE_X86_CPU,\
+ .property = "model",\
+ .value = stringify(3),\
}
#define PC_COMPAT_1_5 \
DEVICE_CATEGORY_MAX
} DeviceCategory;
-static inline const char *qdev_category_get_name(DeviceCategory category)
-{
- static const char *category_names[DEVICE_CATEGORY_MAX] = {
- [DEVICE_CATEGORY_BRIDGE] = "Controller/Bridge/Hub",
- [DEVICE_CATEGORY_USB] = "USB",
- [DEVICE_CATEGORY_STORAGE] = "Storage",
- [DEVICE_CATEGORY_NETWORK] = "Network",
- [DEVICE_CATEGORY_INPUT] = "Input",
- [DEVICE_CATEGORY_DISPLAY] = "Display",
- [DEVICE_CATEGORY_SOUND] = "Sound",
- [DEVICE_CATEGORY_MISC] = "Misc",
- };
-
- return category_names[category];
-};
-
typedef int (*qdev_initfn)(DeviceState *dev);
typedef int (*qdev_event)(DeviceState *dev);
typedef void (*qdev_resetfn)(DeviceState *dev);
#define MAX_SCSI_DEVS 255
#define SCSI_CMD_BUF_SIZE 16
+#define SCSI_SENSE_LEN 18
+#define SCSI_INQUIRY_LEN 36
typedef struct SCSIBus SCSIBus;
typedef struct SCSIBusInfo SCSIBusInfo;
int qemu_opts_set(QemuOptsList *list, const char *id,
const char *name, const char *value);
const char *qemu_opts_id(QemuOpts *opts);
+void qemu_opts_set_id(QemuOpts *opts, char *id);
void qemu_opts_del(QemuOpts *opts);
void qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp);
int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname);
int bus;
int unit;
int auto_del; /* see blockdev_mark_auto_del() */
+ bool enable_auto_del; /* Only for legacy drive_init() */
int media_cd;
int cyls, heads, secs, trans;
QemuOpts *opts;
int explicit_be_open;
int avail_connections;
int is_mux;
+ guint fd_in_tag;
QemuOpts *opts;
QTAILQ_ENTRY(CharDriverState) next;
};
const char *argv0;
int gdbstub_port;
envlist_t *envlist;
-const char *cpu_model;
+static const char *cpu_model;
unsigned long mmap_min_addr;
#if defined(CONFIG_USE_GUEST_BASE)
unsigned long guest_base;
ts->sigqueue_table[i].next = NULL;
}
+CPUArchState *cpu_copy(CPUArchState *env)
+{
+ CPUArchState *new_env = cpu_init(cpu_model);
+#if defined(TARGET_HAS_ICE)
+ CPUBreakpoint *bp;
+ CPUWatchpoint *wp;
+#endif
+
+ /* Reset non arch specific state */
+ cpu_reset(ENV_GET_CPU(new_env));
+
+ memcpy(new_env, env, sizeof(CPUArchState));
+
+ /* Clone all break/watchpoints.
+ Note: Once we support ptrace with hw-debug register access, make sure
+ BP_CPU break/watchpoints are handled correctly on clone. */
+ QTAILQ_INIT(&env->breakpoints);
+ QTAILQ_INIT(&env->watchpoints);
+#if defined(TARGET_HAS_ICE)
+ QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+ cpu_breakpoint_insert(new_env, bp->pc, bp->flags, NULL);
+ }
+ QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
+ cpu_watchpoint_insert(new_env, wp->vaddr, (~wp->len_mask) + 1,
+ wp->flags, NULL);
+ }
+#endif
+
+ return new_env;
+}
+
static void handle_arg_help(const char *arg)
{
usage();
1275-1994 (referred to as Open Firmware) compliant firmware.
The included images for PowerPC (for 32 and 64 bit PPC CPUs),
Sparc32 and Sparc64 are built from OpenBIOS SVN revision
- 1198.
+ 1229.
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
implementation for certain IBM POWER hardware. The sources are at
legacy x86 software to communicate with an attached serial console as
if a video card were attached. The master sources reside in a subversion
repository at http://sgabios.googlecode.com/svn/trunk. A git mirror is
- available at git://git.qemu.org/sgabios.git.
+ available at git://git.qemu-project.org/sgabios.git.
- The PXE roms come from the iPXE project. Built with BANNER_TIME 0.
Sources available at http://ipxe.org. Vendor:Device ID -> ROM mapping:
'date-sec': 'int', 'date-nsec': 'int',
'vm-clock-sec': 'int', 'vm-clock-nsec': 'int' } }
+##
+# @ImageInfoSpecificQCow2:
+#
+# @compat: compatibility level
+#
+# @lazy-refcounts: #optional on or off; only valid for compat >= 1.1
+#
+# Since: 1.7
+##
+{ 'type': 'ImageInfoSpecificQCow2',
+ 'data': {
+ 'compat': 'str',
+ '*lazy-refcounts': 'bool'
+ } }
+
+##
+# @ImageInfoSpecific:
+#
+# A discriminated record of image format specific information structures.
+#
+# Since: 1.7
+##
+
+{ 'union': 'ImageInfoSpecific',
+ 'data': {
+ 'qcow2': 'ImageInfoSpecificQCow2'
+ } }
+
##
# @ImageInfo:
#
#
# @backing-image: #optional info of the backing image (since 1.6)
#
+# @format-specific: #optional structure supplying additional format-specific
+# information (since 1.7)
+#
# Since: 1.3
#
##
'*cluster-size': 'int', '*encrypted': 'bool',
'*backing-filename': 'str', '*full-backing-filename': 'str',
'*backing-filename-format': 'str', '*snapshots': ['SnapshotInfo'],
- '*backing-image': 'ImageInfo' } }
+ '*backing-image': 'ImageInfo',
+ '*format-specific': 'ImageInfoSpecific' } }
##
# @ImageCheck:
{ 'enum': 'MirrorSyncMode',
'data': ['top', 'full', 'none'] }
+##
+# @BlockJobType:
+#
+# Type of a block job.
+#
+# @commit: block commit job type, see "block-commit"
+#
+# @stream: block stream job type, see "block-stream"
+#
+# @mirror: drive mirror job type, see "drive-mirror"
+#
+# @backup: drive backup job type, see "drive-backup"
+#
+# Since: 1.7
+##
+{ 'enum': 'BlockJobType',
+ 'data': ['commit', 'stream', 'mirror', 'backup'] }
+
##
# @BlockJobInfo:
#
##
{ 'command': 'query-rx-filter', 'data': { '*name': 'str' },
'returns': ['RxFilterInfo'] }
+
+
+##
+# @BlockdevDiscardOptions
+#
+# Determines how to handle discard requests.
+#
+# @ignore: Ignore the request
+# @unmap: Forward as an unmap request
+#
+# Since: 1.7
+##
+{ 'enum': 'BlockdevDiscardOptions',
+ 'data': [ 'ignore', 'unmap' ] }
+
+##
+# @BlockdevAioOptions
+#
+# Selects the AIO backend to handle I/O requests
+#
+# @threads: Use qemu's thread pool
+# @native: Use native AIO backend (only Linux and Windows)
+#
+# Since: 1.7
+##
+{ 'enum': 'BlockdevAioOptions',
+ 'data': [ 'threads', 'native' ] }
+
+##
+# @BlockdevCacheOptions
+#
+# Includes cache-related options for block devices
+#
+# @writeback: #optional enables writeback mode for any caches (default: true)
+# @direct: #optional enables use of O_DIRECT (bypass the host page cache;
+# default: false)
+# @no-flush: #optional ignore any flush requests for the device (default:
+# false)
+#
+# Since: 1.7
+##
+{ 'type': 'BlockdevCacheOptions',
+ 'data': { '*writeback': 'bool',
+ '*direct': 'bool',
+ '*no-flush': 'bool' } }
+
+##
+# @BlockdevOptionsBase
+#
+# Options that are available for all block devices, independent of the block
+# driver.
+#
+# @driver: block driver name
+# @id: #optional id by which the new block device can be referred to.
+# This is a required option on the top level of blockdev-add, and
+# currently not allowed on any other level.
+# @discard: #optional discard-related options (default: ignore)
+# @cache: #optional cache-related options
+# @aio: #optional AIO backend (default: threads)
+# @rerror: #optional how to handle read errors on the device
+# (default: report)
+# @werror: #optional how to handle write errors on the device
+# (default: enospc)
+# @read-only: #optional whether the block device should be read-only
+# (default: false)
+#
+# Since: 1.7
+##
+{ 'type': 'BlockdevOptionsBase',
+ 'data': { 'driver': 'str',
+ '*id': 'str',
+ '*discard': 'BlockdevDiscardOptions',
+ '*cache': 'BlockdevCacheOptions',
+ '*aio': 'BlockdevAioOptions',
+ '*rerror': 'BlockdevOnError',
+ '*werror': 'BlockdevOnError',
+ '*read-only': 'bool' } }
+
+##
+# @BlockdevOptionsFile
+#
+# Driver specific block device options for the file backend and similar
+# protocols.
+#
+# @filename: path to the image file
+#
+# Since: 1.7
+##
+{ 'type': 'BlockdevOptionsFile',
+ 'data': { 'filename': 'str' } }
+
+##
+# @BlockdevOptionsVVFAT
+#
+# Driver specific block device options for the vvfat protocol.
+#
+# @dir: directory to be exported as FAT image
+# @fat-type: #optional FAT type: 12, 16 or 32
+# @floppy: #optional whether to export a floppy image (true) or
+# partitioned hard disk (false; default)
+# @rw: #optional whether to allow write operations (default: false)
+#
+# Since: 1.7
+##
+{ 'type': 'BlockdevOptionsVVFAT',
+ 'data': { 'dir': 'str', '*fat-type': 'int', '*floppy': 'bool',
+ '*rw': 'bool' } }
+
+##
+# @BlockdevOptionsGenericFormat
+#
+# Driver specific block device options for image format that have no option
+# besides their data source.
+#
+# @file: reference to or definition of the data source block device
+#
+# Since: 1.7
+##
+{ 'type': 'BlockdevOptionsGenericFormat',
+ 'data': { 'file': 'BlockdevRef' } }
+
+##
+# @BlockdevOptionsGenericCOWFormat
+#
+# Driver specific block device options for image format that have no option
+# besides their data source and an optional backing file.
+#
+# @backing: #optional reference to or definition of the backing file block
+# device (if missing, taken from the image file content). It is
+# allowed to pass an empty string here in order to disable the
+# default backing file.
+#
+# Since: 1.7
+##
+{ 'type': 'BlockdevOptionsGenericCOWFormat',
+ 'base': 'BlockdevOptionsGenericFormat',
+ 'data': { '*backing': 'BlockdevRef' } }
+
+##
+# @BlockdevOptionsQcow2
+#
+# Driver specific block device options for qcow2.
+#
+# @lazy-refcounts: #optional whether to enable the lazy refcounts
+# feature (default is taken from the image file)
+#
+# @pass-discard-request: #optional whether discard requests to the qcow2
+# device should be forwarded to the data source
+#
+# @pass-discard-snapshot: #optional whether discard requests for the data source
+# should be issued when a snapshot operation (e.g.
+# deleting a snapshot) frees clusters in the qcow2 file
+#
+# @pass-discard-other: #optional whether discard requests for the data source
+# should be issued on other occasions where a cluster
+# gets freed
+#
+# Since: 1.7
+##
+{ 'type': 'BlockdevOptionsQcow2',
+ 'base': 'BlockdevOptionsGenericCOWFormat',
+ 'data': { '*lazy-refcounts': 'bool',
+ '*pass-discard-request': 'bool',
+ '*pass-discard-snapshot': 'bool',
+ '*pass-discard-other': 'bool' } }
+
+##
+# @BlockdevOptions
+#
+# Options for creating a block device.
+#
+# Since: 1.7
+##
+{ 'union': 'BlockdevOptions',
+ 'base': 'BlockdevOptionsBase',
+ 'discriminator': 'driver',
+ 'data': {
+ 'file': 'BlockdevOptionsFile',
+ 'http': 'BlockdevOptionsFile',
+ 'https': 'BlockdevOptionsFile',
+ 'ftp': 'BlockdevOptionsFile',
+ 'ftps': 'BlockdevOptionsFile',
+ 'tftp': 'BlockdevOptionsFile',
+# TODO gluster: Wait for structured options
+# TODO iscsi: Wait for structured options
+# TODO nbd: Should take InetSocketAddress for 'host'?
+# TODO rbd: Wait for structured options
+# TODO sheepdog: Wait for structured options
+# TODO ssh: Should take InetSocketAddress for 'host'?
+ 'vvfat': 'BlockdevOptionsVVFAT',
+
+# TODO blkdebug: Wait for structured options
+# TODO blkverify: Wait for structured options
+
+ 'bochs': 'BlockdevOptionsGenericFormat',
+ 'cloop': 'BlockdevOptionsGenericFormat',
+ 'cow': 'BlockdevOptionsGenericCOWFormat',
+ 'dmg': 'BlockdevOptionsGenericFormat',
+ 'parallels': 'BlockdevOptionsGenericFormat',
+ 'qcow': 'BlockdevOptionsGenericCOWFormat',
+ 'qcow2': 'BlockdevOptionsQcow2',
+ 'qed': 'BlockdevOptionsGenericCOWFormat',
+ 'raw': 'BlockdevOptionsGenericFormat',
+ 'vdi': 'BlockdevOptionsGenericFormat',
+ 'vhdx': 'BlockdevOptionsGenericFormat',
+ 'vmdk': 'BlockdevOptionsGenericCOWFormat',
+ 'vpc': 'BlockdevOptionsGenericFormat'
+ } }
+
+##
+# @BlockdevRef
+#
+# Reference to a block device.
+#
+# @definition: defines a new block device inline
+# @reference: references the ID of an existing block device. An
+# empty string means that no block device should be
+# referenced.
+#
+# Since: 1.7
+##
+{ 'union': 'BlockdevRef',
+ 'discriminator': {},
+ 'data': { 'definition': 'BlockdevOptions',
+ 'reference': 'str' } }
+
+##
+# @blockdev-add:
+#
+# Creates a new block device.
+#
+# @options: block device options for the new device
+#
+# Since: 1.7
+##
+{ 'command': 'blockdev-add', 'data': { 'options': 'BlockdevOptions' } }
return (qdev_class_get_alias(dc) != NULL);
}
-static void qdev_print_class_devinfo(DeviceClass *dc)
+static void qdev_print_devinfo(DeviceClass *dc)
{
- DeviceCategory category;
-
- if (!dc) {
- return;
- }
-
error_printf("name \"%s\"", object_class_get_name(OBJECT_CLASS(dc)));
if (dc->bus_type) {
error_printf(", bus %s", dc->bus_type);
if (qdev_class_has_alias(dc)) {
error_printf(", alias \"%s\"", qdev_class_get_alias(dc));
}
- error_printf(", categories");
- for (category = 0; category < DEVICE_CATEGORY_MAX; ++category) {
- if (test_bit(category, dc->categories)) {
- error_printf(" \"%s\"", qdev_category_get_name(category));
- }
- }
if (dc->desc) {
error_printf(", desc \"%s\"", dc->desc);
}
error_printf("\n");
}
-static void qdev_print_devinfo(ObjectClass *klass, void *opaque)
+static gint devinfo_cmp(gconstpointer a, gconstpointer b)
{
- DeviceClass *dc;
+ return strcasecmp(object_class_get_name((ObjectClass *)a),
+ object_class_get_name((ObjectClass *)b));
+}
- dc = (DeviceClass *)object_class_dynamic_cast(klass, TYPE_DEVICE);
+static void qdev_print_devinfos(bool show_no_user)
+{
+ static const char *cat_name[DEVICE_CATEGORY_MAX + 1] = {
+ [DEVICE_CATEGORY_BRIDGE] = "Controller/Bridge/Hub",
+ [DEVICE_CATEGORY_USB] = "USB",
+ [DEVICE_CATEGORY_STORAGE] = "Storage",
+ [DEVICE_CATEGORY_NETWORK] = "Network",
+ [DEVICE_CATEGORY_INPUT] = "Input",
+ [DEVICE_CATEGORY_DISPLAY] = "Display",
+ [DEVICE_CATEGORY_SOUND] = "Sound",
+ [DEVICE_CATEGORY_MISC] = "Misc",
+ [DEVICE_CATEGORY_MAX] = "Uncategorized",
+ };
+ GSList *list, *elt;
+ int i;
+ bool cat_printed;
+
+ list = g_slist_sort(object_class_get_list(TYPE_DEVICE, false),
+ devinfo_cmp);
+
+ for (i = 0; i <= DEVICE_CATEGORY_MAX; i++) {
+ cat_printed = false;
+ for (elt = list; elt; elt = elt->next) {
+ DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, elt->data,
+ TYPE_DEVICE);
+ if ((i < DEVICE_CATEGORY_MAX
+ ? !test_bit(i, dc->categories)
+ : !bitmap_empty(dc->categories, DEVICE_CATEGORY_MAX))
+ || (!show_no_user && dc->no_user)) {
+ continue;
+ }
+ if (!cat_printed) {
+ error_printf("%s%s devices:\n", i ? "\n" : "",
+ cat_name[i]);
+ cat_printed = true;
+ }
+ qdev_print_devinfo(dc);
+ }
+ }
- qdev_print_class_devinfo(dc);
+ g_slist_free(list);
}
static int set_property(const char *name, const char *value, void *opaque)
return NULL;
}
-static void qdev_print_category_devices(DeviceCategory category)
-{
- DeviceClass *dc;
- GSList *list, *curr;
-
- list = object_class_get_list(TYPE_DEVICE, false);
- for (curr = list; curr; curr = g_slist_next(curr)) {
- dc = (DeviceClass *)object_class_dynamic_cast(curr->data, TYPE_DEVICE);
- if (!dc->no_user && test_bit(category, dc->categories)) {
- qdev_print_class_devinfo(dc);
- }
- }
- g_slist_free(list);
-}
-
int qdev_device_help(QemuOpts *opts)
{
const char *driver;
driver = qemu_opt_get(opts, "driver");
if (driver && is_help_option(driver)) {
- DeviceCategory category;
- for (category = 0; category < DEVICE_CATEGORY_MAX; ++category) {
- qdev_print_category_devices(category);
- }
-
+ qdev_print_devinfos(false);
return 1;
}
void do_info_qdm(Monitor *mon, const QDict *qdict)
{
- object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, NULL);
+ qdev_print_devinfos(true);
}
int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
va_end(ap);
}
+static void remove_fd_in_watch(CharDriverState *chr);
+
void qemu_chr_add_handlers(CharDriverState *s,
IOCanReadHandler *fd_can_read,
IOReadHandler *fd_read,
if (!opaque && !fd_can_read && !fd_read && !fd_event) {
fe_open = 0;
+ remove_fd_in_watch(s);
} else {
fe_open = 1;
}
g_source_destroy(&iwp->parent);
}
+static void remove_fd_in_watch(CharDriverState *chr)
+{
+ if (chr->fd_in_tag) {
+ io_remove_watch_poll(chr->fd_in_tag);
+ chr->fd_in_tag = 0;
+ }
+}
+
#ifndef _WIN32
static GIOChannel *io_channel_from_fd(int fd)
{
typedef struct FDCharDriver {
CharDriverState *chr;
GIOChannel *fd_in, *fd_out;
- guint fd_in_tag;
int max_size;
QTAILQ_ENTRY(FDCharDriver) node;
} FDCharDriver;
status = g_io_channel_read_chars(chan, (gchar *)buf,
len, &bytes_read, NULL);
if (status == G_IO_STATUS_EOF) {
- if (s->fd_in_tag) {
- io_remove_watch_poll(s->fd_in_tag);
- s->fd_in_tag = 0;
- }
+ remove_fd_in_watch(chr);
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
return FALSE;
}
{
FDCharDriver *s = chr->opaque;
- if (s->fd_in_tag) {
- io_remove_watch_poll(s->fd_in_tag);
- s->fd_in_tag = 0;
- }
-
+ remove_fd_in_watch(chr);
if (s->fd_in) {
- s->fd_in_tag = io_add_watch_poll(s->fd_in, fd_chr_read_poll, fd_chr_read, chr);
+ chr->fd_in_tag = io_add_watch_poll(s->fd_in, fd_chr_read_poll,
+ fd_chr_read, chr);
}
}
{
FDCharDriver *s = chr->opaque;
- if (s->fd_in_tag) {
- io_remove_watch_poll(s->fd_in_tag);
- s->fd_in_tag = 0;
- }
-
+ remove_fd_in_watch(chr);
if (s->fd_in) {
g_io_channel_unref(s->fd_in);
}
typedef struct {
GIOChannel *fd;
- guint fd_tag;
int connected;
int read_bytes;
guint timer_tag;
PtyCharDriver *s = chr->opaque;
if (!connected) {
- if (s->fd_tag) {
- io_remove_watch_poll(s->fd_tag);
- s->fd_tag = 0;
- }
+ remove_fd_in_watch(chr);
s->connected = 0;
/* (re-)connect poll interval for idle guests: once per second.
* We check more frequently in case the guests sends data to
if (!s->connected) {
s->connected = 1;
qemu_chr_be_generic_open(chr);
- s->fd_tag = io_add_watch_poll(s->fd, pty_chr_read_poll, pty_chr_read, chr);
+ chr->fd_in_tag = io_add_watch_poll(s->fd, pty_chr_read_poll,
+ pty_chr_read, chr);
}
}
}
PtyCharDriver *s = chr->opaque;
int fd;
- if (s->fd_tag) {
- io_remove_watch_poll(s->fd_tag);
- s->fd_tag = 0;
- }
+ remove_fd_in_watch(chr);
fd = g_io_channel_unix_get_fd(s->fd);
g_io_channel_unref(s->fd);
close(fd);
typedef struct {
int fd;
GIOChannel *chan;
- guint tag;
uint8_t buf[READ_BUF_LEN];
int bufcnt;
int bufptr;
s->bufcnt = bytes_read;
s->bufptr = s->bufcnt;
if (status != G_IO_STATUS_NORMAL) {
- if (s->tag) {
- io_remove_watch_poll(s->tag);
- s->tag = 0;
- }
+ remove_fd_in_watch(chr);
return FALSE;
}
{
NetCharDriver *s = chr->opaque;
- if (s->tag) {
- io_remove_watch_poll(s->tag);
- s->tag = 0;
- }
-
+ remove_fd_in_watch(chr);
if (s->chan) {
- s->tag = io_add_watch_poll(s->chan, udp_chr_read_poll, udp_chr_read, chr);
+ chr->fd_in_tag = io_add_watch_poll(s->chan, udp_chr_read_poll,
+ udp_chr_read, chr);
}
}
static void udp_chr_close(CharDriverState *chr)
{
NetCharDriver *s = chr->opaque;
- if (s->tag) {
- io_remove_watch_poll(s->tag);
- s->tag = 0;
- }
+
+ remove_fd_in_watch(chr);
if (s->chan) {
g_io_channel_unref(s->chan);
closesocket(s->fd);
typedef struct {
GIOChannel *chan, *listen_chan;
- guint tag, listen_tag;
+ guint listen_tag;
int fd, listen_fd;
int connected;
int max_size;
if (s->listen_chan) {
s->listen_tag = g_io_add_watch(s->listen_chan, G_IO_IN, tcp_chr_accept, chr);
}
- if (s->tag) {
- io_remove_watch_poll(s->tag);
- s->tag = 0;
- }
+ remove_fd_in_watch(chr);
g_io_channel_unref(s->chan);
s->chan = NULL;
closesocket(s->fd);
s->connected = 1;
if (s->chan) {
- s->tag = io_add_watch_poll(s->chan, tcp_chr_read_poll, tcp_chr_read, chr);
+ chr->fd_in_tag = io_add_watch_poll(s->chan, tcp_chr_read_poll,
+ tcp_chr_read, chr);
}
qemu_chr_be_generic_open(chr);
}
{
TCPCharDriver *s = chr->opaque;
if (s->fd >= 0) {
- if (s->tag) {
- io_remove_watch_poll(s->tag);
- s->tag = 0;
- }
+ remove_fd_in_watch(chr);
if (s->chan) {
g_io_channel_unref(s->chan);
}
#include "qemu-io.h"
#include "block/block_int.h"
+#include "block/qapi.h"
#include "qemu/main-loop.h"
#define CMD_NOFILE_OK 0x01
static int info_f(BlockDriverState *bs, int argc, char **argv)
{
BlockDriverInfo bdi;
+ ImageInfoSpecific *spec_info;
char s1[64], s2[64];
int ret;
printf("cluster size: %s\n", s1);
printf("vm state offset: %s\n", s2);
+ spec_info = bdrv_get_specific_info(bs);
+ if (spec_info) {
+ printf("Format specific information:\n");
+ bdrv_image_info_specific_dump(fprintf, stdout, spec_info);
+ qapi_free_ImageInfoSpecific(spec_info);
+ }
+
return 0;
}
#include "qemu-io.h"
#include "qemu/main-loop.h"
+#include "qemu/option.h"
+#include "qemu/config-file.h"
#include "block/block_int.h"
#include "trace/control.h"
.oneline = "close the current open file",
};
-static int openfile(char *name, int flags, int growable)
+static int openfile(char *name, int flags, int growable, QDict *opts)
{
Error *local_err = NULL;
}
if (growable) {
- if (bdrv_file_open(&qemuio_bs, name, NULL, flags, &local_err)) {
+ if (bdrv_file_open(&qemuio_bs, name, opts, flags, &local_err)) {
fprintf(stderr, "%s: can't open device %s: %s\n", progname, name,
error_get_pretty(local_err));
error_free(local_err);
} else {
qemuio_bs = bdrv_new("hda");
- if (bdrv_open(qemuio_bs, name, NULL, flags, NULL, &local_err) < 0) {
+ if (bdrv_open(qemuio_bs, name, 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);
" -r, -- open file read-only\n"
" -s, -- use snapshot file\n"
" -n, -- disable host cache\n"
-" -g, -- allow file to grow (only applies to protocols)"
+" -g, -- allow file to grow (only applies to protocols)\n"
+" -o, -- options to be given to the block driver"
"\n");
}
.argmin = 1,
.argmax = -1,
.flags = CMD_NOFILE_OK,
- .args = "[-Crsn] [path]",
+ .args = "[-Crsn] [-o options] [path]",
.oneline = "open the file specified by path",
.help = open_help,
};
+static QemuOptsList empty_opts = {
+ .name = "drive",
+ .head = QTAILQ_HEAD_INITIALIZER(empty_opts.head),
+ .desc = {
+ /* no elements => accept any params */
+ { /* end of list */ }
+ },
+};
+
static int open_f(BlockDriverState *bs, int argc, char **argv)
{
int flags = 0;
int readonly = 0;
int growable = 0;
int c;
+ QemuOpts *qopts;
+ QDict *opts = NULL;
- while ((c = getopt(argc, argv, "snrg")) != EOF) {
+ while ((c = getopt(argc, argv, "snrgo:")) != EOF) {
switch (c) {
case 's':
flags |= BDRV_O_SNAPSHOT;
case 'g':
growable = 1;
break;
+ case 'o':
+ qopts = qemu_opts_parse(&empty_opts, optarg, 0);
+ if (qopts == NULL) {
+ printf("could not parse option list -- %s\n", optarg);
+ return 0;
+ }
+ opts = qemu_opts_to_qdict(qopts, opts);
+ qemu_opts_del(qopts);
+ break;
default:
return qemuio_command_usage(&open_cmd);
}
return qemuio_command_usage(&open_cmd);
}
- return openfile(argv[optind], flags, growable);
+ return openfile(argv[optind], flags, growable, opts);
}
static int quit_f(BlockDriverState *bs, int argc, char **argv)
}
if ((argc - optind) == 1) {
- openfile(argv[optind], flags, growable);
+ openfile(argv[optind], flags, growable, NULL);
}
command_loop();
{ SCMP_SYS(getuid), 245 },
{ SCMP_SYS(geteuid), 245 },
{ SCMP_SYS(timer_create), 245 },
+ { SCMP_SYS(times), 245 },
{ SCMP_SYS(exit), 245 },
{ SCMP_SYS(clock_gettime), 245 },
{ SCMP_SYS(time), 245 },
; NSIS_WIN32_MAKENSIS
!define PRODUCT "QEMU"
-!define URL "http://www.qemu.org/"
+!define URL "http://www.qemu-project.org/"
!define UNINST_EXE "$INSTDIR\qemu-uninstall.exe"
!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT}"
]
}
+EQMP
+
+ {
+ .name = "blockdev-add",
+ .args_type = "options:q",
+ .mhandler.cmd_new = qmp_marshal_input_blockdev_add,
+ },
+
+SQMP
+blockdev-add
+------------
+
+Add a block device.
+
+Arguments:
+
+- "options": block driver options
+
+Example (1):
+
+-> { "execute": "blockdev-add",
+ "arguments": { "options" : { "driver": "qcow2",
+ "file": { "driver": "file",
+ "filename": "test.qcow2" } } } }
+<- { "return": {} }
+
+Example (2):
+
+-> { "execute": "blockdev-add",
+ "arguments": {
+ "options": {
+ "driver": "qcow2",
+ "id": "my_disk",
+ "discard": "unmap",
+ "cache": {
+ "direct": true,
+ "writeback": true
+ },
+ "file": {
+ "driver": "file",
+ "filename": "/tmp/test.qcow2"
+ },
+ "backing": {
+ "driver": "raw",
+ "file": {
+ "driver": "file",
+ "filename": "/dev/fdset/4"
+ }
+ }
+ }
+ }
+ }
+
+<- { "return": {} }
+
EQMP
-Subproject commit 0f3d51ef22ec9166beb3ed434d253029ed7cfe84
+Subproject commit d363cf50c50c268da7e6d0bf707adde1893d1ab9
warn("$P: No supported VCS found. Add --nogit to options?\n");
warn("Using a git repository produces better results.\n");
warn("Try latest git repository using:\n");
- warn("git clone git://git.qemu.org/qemu.git\n");
+ warn("git clone git://git.qemu-project.org/qemu.git\n");
$printed_novcs = 1;
}
return 0;
c_name=c_var(argname))
if structured:
push_indent()
- ret += generate_struct("", argname, argentry)
+ ret += generate_struct({ "field": argname, "data": argentry})
pop_indent()
else:
ret += mcgen('''
return ret
-def generate_struct(structname, fieldname, members):
+def generate_struct(expr):
+
+ structname = expr.get('type', "")
+ fieldname = expr.get('field', "")
+ members = expr['data']
+ base = expr.get('base')
+
ret = mcgen('''
struct %(name)s
{
''',
name=structname)
+ if base:
+ ret += generate_struct_fields({'base': base})
+
ret += generate_struct_fields(members)
if len(fieldname):
for expr in exprs:
ret = "\n"
if expr.has_key('type'):
- ret += generate_struct(expr['type'], "", expr['data']) + "\n"
+ ret += generate_struct(expr) + "\n"
ret += generate_type_cleanup_decl(expr['type'] + "List")
fdef.write(generate_type_cleanup(expr['type'] + "List") + "\n")
ret += generate_type_cleanup_decl(expr['type'])
import getopt
import errno
-def generate_visit_struct_fields(name, field_prefix, fn_prefix, members):
+def generate_visit_struct_fields(name, field_prefix, fn_prefix, members, base = None):
substructs = []
ret = ''
full_name = name if not fn_prefix else "%s_%s" % (name, fn_prefix)
name=name, full_name=full_name)
push_indent()
+ if base:
+ ret += mcgen('''
+visit_start_implicit_struct(m, obj ? (void**) &(*obj)->%(c_name)s : NULL, sizeof(%(type)s), &err);
+if (!err) {
+ visit_type_%(type)s_fields(m, obj ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, &err);
+ error_propagate(errp, err);
+ err = NULL;
+ visit_end_implicit_struct(m, &err);
+}
+''',
+ c_prefix=c_var(field_prefix),
+ type=type_name(base), c_name=c_var('base'))
+
for argname, argentry, optional, structured in parse_args(members):
if optional:
ret += mcgen('''
''')
return ret
-def generate_visit_struct(name, members):
- ret = generate_visit_struct_fields(name, "", "", members)
+def generate_visit_struct(expr):
+
+ name = expr['type']
+ members = expr['data']
+ base = expr.get('base')
+
+ ret = generate_visit_struct_fields(name, "", "", members, base)
ret += mcgen('''
for expr in exprs:
if expr.has_key('type'):
- ret = generate_visit_struct(expr['type'], expr['data'])
+ ret = generate_visit_struct(expr)
ret += generate_visit_list(expr['type'], expr['data'])
fdef.write(ret)
# $ qemu-ga-client fsfreeze freeze
# 2 filesystems frozen
#
-# See also: http://wiki.qemu.org/Features/QAPI/GuestAgent
+# See also: http://wiki.qemu-project.org/Features/QAPI/GuestAgent
#
import base64
AlphaCPU *cpu_alpha_init(const char *cpu_model)
{
AlphaCPU *cpu;
- CPUAlphaState *env;
ObjectClass *cpu_class;
cpu_class = alpha_cpu_class_by_name(cpu_model);
cpu_class = object_class_by_name(TYPE("ev67"));
}
cpu = ALPHA_CPU(object_new(object_class_get_name(cpu_class)));
- env = &cpu->env;
-
- env->cpu_model_str = cpu_model;
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
ARMCPU *cpu_arm_init(const char *cpu_model)
{
ARMCPU *cpu;
- CPUARMState *env;
ObjectClass *oc;
oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
return NULL;
}
cpu = ARM_CPU(object_new(object_class_get_name(oc)));
- env = &cpu->env;
- env->cpu_model_str = cpu_model;
/* TODO this should be set centrally, once possible */
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
.level = 4,
.vendor = CPUID_VENDOR_AMD,
.family = 6,
- .model = 2,
+ .model = 6,
.stepping = 3,
.features[FEAT_1_EDX] =
PPRO_FEATURES |
.level = 4,
.vendor = CPUID_VENDOR_INTEL,
.family = 6,
- .model = 3,
+ .model = 6,
.stepping = 3,
.features[FEAT_1_EDX] =
PPRO_FEATURES,
Error **errp)
{
X86CPU *cpu = NULL;
- CPUX86State *env;
gchar **model_pieces;
char *name, *features;
char *typename;
qdev_set_parent_bus(DEVICE(cpu), qdev_get_child_bus(icc_bridge, "icc"));
object_unref(OBJECT(cpu));
#endif
- env = &cpu->env;
- env->cpu_model_str = cpu_model;
cpu_x86_register(cpu, name, &error);
if (error) {
}
cpu = M68K_CPU(object_new(object_class_get_name(oc)));
env = &cpu->env;
- env->cpu_model_str = cpu_model;
register_m68k_insns(env);
cpu = MIPS_CPU(object_new(TYPE_MIPS_CPU));
env = &cpu->env;
env->cpu_model = def;
- env->cpu_model_str = cpu_model;
#ifndef CONFIG_USER_ONLY
mmu_init(env, def);
return NULL;
}
cpu = MOXIE_CPU(object_new(object_class_get_name(oc)));
- cpu->env.cpu_model_str = cpu_model;
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
return NULL;
}
cpu = OPENRISC_CPU(object_new(object_class_get_name(oc)));
- cpu->env.cpu_model_str = cpu_model;
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
PowerPCCPU *cpu_ppc_init(const char *cpu_model)
{
PowerPCCPU *cpu;
- CPUPPCState *env;
ObjectClass *oc;
Error *err = NULL;
}
cpu = POWERPC_CPU(object_new(object_class_get_name(oc)));
- env = &cpu->env;
- env->cpu_model_str = cpu_model;
object_property_set_bool(OBJECT(cpu), true, "realized", &err);
if (err != NULL) {
S390CPU *cpu_s390x_init(const char *cpu_model)
{
S390CPU *cpu;
- CPUS390XState *env;
cpu = S390_CPU(object_new(TYPE_S390_CPU));
- env = &cpu->env;
- env->cpu_model_str = cpu_model;
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
SuperHCPU *cpu_sh4_init(const char *cpu_model)
{
SuperHCPU *cpu;
- CPUSH4State *env;
ObjectClass *oc;
oc = superh_cpu_class_by_name(cpu_model);
return NULL;
}
cpu = SUPERH_CPU(object_new(object_class_get_name(oc)));
- env = &cpu->env;
- env->cpu_model_str = cpu_model;
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
env->def->features |= CPU_FEATURE_FLOAT128;
}
#endif
- env->cpu_model_str = cpu_model;
env->version = def->iu_version;
env->fsr = def->fpu_version;
env->nwindows = def->nwindows;
}
cpu = UNICORE32_CPU(object_new(object_class_get_name(oc)));
env = &cpu->env;
- env->cpu_model_str = cpu_model;
object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
@echo " make check-qapi-schema Run QAPI schema tests"
@echo " make check-block Run block tests"
@echo " make check-report.html Generates an HTML test report"
+ @echo " make check-clean Clean the tests"
@echo
@echo "Please note that HTML reports do not regenerate if the unit tests"
@echo "has not changed."
# Other tests
+QEMU_IOTESTS_HELPERS-$(CONFIG_LINUX) = tests/qemu-iotests/socket_scm_helper$(EXESUF)
+
.PHONY: check-tests/qemu-iotests-quick.sh
-check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF) qemu-io$(EXESUF) tests/qemu-iotests/socket_scm_helper$(EXESUF)
+check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF) qemu-io$(EXESUF) $(QEMU_IOTESTS_HELPERS-y)
$<
.PHONY: check-tests/test-qapi.py
# Consolidated targets
-.PHONY: check-qapi-schema check-qtest check-unit check
+.PHONY: check-qapi-schema check-qtest check-unit check check-clean
check-qapi-schema: $(patsubst %,check-%, $(check-qapi-schema-y))
check-qtest: $(patsubst %,check-qtest-%, $(QTEST_TARGETS))
check-unit: $(patsubst %,check-%, $(check-unit-y))
check-block: $(patsubst %,check-%, $(check-block-y))
check: check-qapi-schema check-unit check-qtest
+check-clean:
+ $(MAKE) -C tests/tcg clean
+ rm -rf $(check-unit-y) $(check-qtest-i386-y) $(check-qtest-x86_64-y) $(check-qtest-sparc64-y) $(check-qtest-sparc-y) tests/*.o $(QEMU_IOTESTS_HELPERS-y)
+
+clean: check-clean
+
+# Build the help program automatically
+
+all: $(QEMU_IOTESTS_HELPERS-y)
-include $(wildcard tests/*.d)
-include $(wildcard tests/libqos/*.d)
(qemu) q\e[K\e[Dqu\e[K\e[D\e[Dqui\e[K\e[D\e[D\e[Dquit\e[K\r
Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on: read-only not supported by this bus type
+QEMU X.Y.Z monitor - type 'help' for more information\r
+(qemu) QEMU_PROG: Can't use a read-only drive
+QEMU_PROG: Device initialization failed.
+QEMU_PROG: Initialization of device ide-hd failed
Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on
QEMU X.Y.Z monitor - type 'help' for more information\r
QEMU_PROG: -drive file=foo:bar: could not open disk image foo:bar: Unknown protocol
Testing: -drive file.filename=foo:bar
-QEMU_PROG: -drive file.filename=foo:bar: could not open disk image ide0-hd0: Could not open 'foo:bar': No such file or directory
+QEMU_PROG: -drive file.filename=foo:bar: could not open disk image ide0-hd0: Could not open file: No such file or directory
*** done
granularity_offset=20
grain_table_size_offset=44
-echo "=== Testing invalid granularity ==="
echo
+echo "=== Testing invalid granularity ==="
_make_test_img 64M
poke_file "$TEST_IMG" "$granularity_offset" "\xff\xff\xff\xff\xff\xff\xff\xff"
{ $QEMU_IO -c "read 0 512" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
-echo "=== Testing too big L2 table size ==="
echo
+echo "=== Testing too big L2 table size ==="
_make_test_img 64M
poke_file "$TEST_IMG" "$grain_table_size_offset" "\xff\xff\xff\xff"
{ $QEMU_IO -c "read 0 512" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
-echo "=== Testing too big L1 table size ==="
echo
+echo "=== Testing too big L1 table size ==="
_make_test_img 64M
poke_file "$TEST_IMG" "$capacity_offset" "\xff\xff\xff\xff"
poke_file "$TEST_IMG" "$grain_table_size_offset" "\x01\x00\x00\x00"
{ $QEMU_IO -c "read 0 512" "$TEST_IMG"; } 2>&1 | _filter_qemu_io | _filter_testdir
-echo "=== Testing monolithicFlat creation and opening ==="
echo
+echo "=== Testing monolithicFlat creation and opening ==="
IMGOPTS="subformat=monolithicFlat" _make_test_img 2G
$QEMU_IMG info $TEST_IMG | _filter_testdir
+echo
+echo "=== Testing monolithicFlat with zeroed_grain ==="
+IMGOPTS="subformat=monolithicFlat,zeroed_grain=on" _make_test_img 2G
+
# success, all done
echo "*** done"
rm -f $seq.full
QA output created by 059
-=== Testing invalid granularity ===
+=== Testing invalid granularity ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
-invalid granularity, image may be corrupt
-qemu-io: can't open device TEST_DIR/t.vmdk: Could not open 'TEST_DIR/t.vmdk': Wrong medium type
+qemu-io: can't open device TEST_DIR/t.vmdk: Invalid granularity, image may be corrupt
no file open, try 'help open'
-=== Testing too big L2 table size ===
+=== Testing too big L2 table size ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
L2 table size too big
qemu-io: can't open device TEST_DIR/t.vmdk: Could not open 'TEST_DIR/t.vmdk': Wrong medium type
no file open, try 'help open'
-=== Testing too big L1 table size ===
+=== Testing too big L1 table size ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
-L1 size too big
-qemu-io: can't open device TEST_DIR/t.vmdk: Could not open 'TEST_DIR/t.vmdk': Wrong medium type
+qemu-io: can't open device TEST_DIR/t.vmdk: L1 size too big
no file open, try 'help open'
-=== Testing monolithicFlat creation and opening ===
+=== Testing monolithicFlat creation and opening ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648
image: TEST_DIR/t.vmdk
file format: vmdk
virtual size: 2.0G (2147483648 bytes)
disk size: 4.0K
+
+=== Testing monolithicFlat with zeroed_grain ===
+qemu-img: TEST_DIR/t.IMGFMT: Flat image can't enable zeroed grain
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648
*** done
# creator
owner=mreitz@redhat.com
-seq=`basename $0`
+seq="$(basename $0)"
echo "QA output created by $seq"
-here=`pwd`
+here="$PWD"
tmp=/tmp/$$
status=1 # failure is the default!
rb_offset=131072 # 0x20000 (XXX: just an assumption)
l1_offset=196608 # 0x30000 (XXX: just an assumption)
l2_offset=262144 # 0x40000 (XXX: just an assumption)
+l2_offset_after_snapshot=524288 # 0x80000 (XXX: just an assumption)
IMGOPTS="compat=1.1"
+OPEN_RW="open -o overlap-check=all $TEST_IMG"
+# Overlap checks are done before write operations only, therefore opening an
+# image read-only makes the overlap-check option irrelevant
+OPEN_RO="open -r $TEST_IMG"
+
echo
echo "=== Testing L2 reference into L1 ==="
echo
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
# Try to write something, thereby forcing the corrupt bit to be set
-$QEMU_IO -c "write -P 0x2a 0 512" "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
# The corrupt bit must now be set
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
# Try to open the image R/W (which should fail)
-$QEMU_IO -c "read 0 512" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir | _filter_imgfmt
+$QEMU_IO -c "$OPEN_RW" -c "read 0 512" 2>&1 | _filter_qemu_io \
+ | _filter_testdir \
+ | _filter_imgfmt
# Try to open it RO (which should succeed)
-$QEMU_IO -c "read 0 512" -r "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c "$OPEN_RO" -c "read 0 512" | _filter_qemu_io
# We could now try to fix the image, but this would probably fail (how should an
# L2 table linked onto the L1 table be fixed?)
poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x02\x00\x00"
_check_test_img
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
-$QEMU_IO -c "write -P 0x2a 0 512" "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
# Try to fix it
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
# Look if it's really really fixed
-$QEMU_IO -c "write -P 0x2a 0 512" "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
+./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+
+echo
+echo "=== Testing cluster data reference into inactive L2 table ==="
+echo
+_make_test_img 64M
+$QEMU_IO -c "$OPEN_RW" -c "write -P 1 0 512" | _filter_qemu_io
+$QEMU_IMG snapshot -c foo "$TEST_IMG"
+$QEMU_IO -c "$OPEN_RW" -c "write -P 2 0 512" | _filter_qemu_io
+# The inactive L2 table remains at its old offset
+poke_file "$TEST_IMG" "$l2_offset_after_snapshot" \
+ "\x80\x00\x00\x00\x00\x04\x00\x00"
+_check_test_img
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+$QEMU_IO -c "$OPEN_RW" -c "write -P 3 0 512" | _filter_qemu_io
+./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_check_test_img -r all
+./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+$QEMU_IO -c "$OPEN_RW" -c "write -P 4 0 512" | _filter_qemu_io
+./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+
+# Check data
+$QEMU_IO -c "$OPEN_RO" -c "read -P 4 0 512" | _filter_qemu_io
+$QEMU_IMG snapshot -a foo "$TEST_IMG"
+_check_test_img
+$QEMU_IO -c "$OPEN_RO" -c "read -P 1 0 512" | _filter_qemu_io
# success, all done
echo "*** done"
write failed: Input/output error
incompatible_features 0x2
qemu-io: can't open device TEST_DIR/t.IMGFMT: IMGFMT: Image is corrupt; cannot be opened read/write
-no file open, try 'help open'
read 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
incompatible_features 0x0
+
+=== Testing cluster data reference into inactive L2 table ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+wrote 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+ERROR cluster 4 refcount=1 reference=2
+Leaked cluster 9 refcount=1 reference=0
+
+1 errors were found on the image.
+Data may be corrupted, or further writes to the image may corrupt it.
+
+1 leaked clusters were found on the image.
+This means waste of disk space, but no harm to data.
+incompatible_features 0x0
+qcow2: Preventing invalid write on metadata (overlaps with inactive L2 table); image marked as corrupt.
+write failed: Input/output error
+incompatible_features 0x2
+Repairing cluster 4 refcount=1 reference=2
+Repairing cluster 9 refcount=1 reference=0
+Repairing OFLAG_COPIED data cluster: l2_entry=8000000000040000 refcount=2
+The following inconsistencies were found and repaired:
+
+ 1 leaked clusters
+ 2 corruptions
+
+Double checking the fixed image now...
+No errors were found on the image.
+incompatible_features 0x0
+wrote 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+incompatible_features 0x0
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+No errors were found on the image.
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
*** done
--- /dev/null
+#!/bin/bash
+#
+# Test VHDX read/write from a sample image created with Hyper-V
+#
+# Copyright (C) 2013 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=jcody@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt vhdx
+_supported_proto generic
+_supported_os Linux
+
+_use_sample_img iotest-dynamic-1G.vhdx.bz2
+
+echo
+echo "=== Verify pattern 0xa5, 0 - 33MB ==="
+$QEMU_IO -r -c "read -pP 0xa5 0 33M" "$TEST_IMG" | _filter_qemu_io
+
+echo
+echo "=== Verify pattern 0x96, 33M - 66M ==="
+$QEMU_IO -r -c "read -pP 0x96 33M 33M" "$TEST_IMG" | _filter_qemu_io
+
+echo
+echo "=== Verify pattern 0x00, 66M - 1024M ==="
+$QEMU_IO -r -c "read -pP 0x00 66M 958M" "$TEST_IMG" | _filter_qemu_io
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
--- /dev/null
+QA output created by 064
+
+=== Verify pattern 0xa5, 0 - 33MB ===
+read 34603008/34603008 bytes at offset 0
+33 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== Verify pattern 0x96, 33M - 66M ===
+read 34603008/34603008 bytes at offset 34603008
+33 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== Verify pattern 0x00, 66M - 1024M ===
+read 1004535808/1004535808 bytes at offset 69206016
+958 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+*** done
--- /dev/null
+#!/usr/bin/env python2
+#
+# Test for additional information emitted by qemu-img info on qcow2
+# images
+#
+# Copyright (C) 2013 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import os
+import re
+import json
+import iotests
+from iotests import qemu_img, qemu_img_pipe
+import unittest
+
+test_img = os.path.join(iotests.test_dir, 'test.img')
+
+class TestImageInfoSpecific(iotests.QMPTestCase):
+ '''Abstract base class for ImageInfoSpecific tests'''
+
+ def setUp(self):
+ if self.img_options is None:
+ self.skipTest('Skipping abstract test class')
+ qemu_img('create', '-f', iotests.imgfmt, '-o', self.img_options,
+ test_img, '128K')
+
+ def tearDown(self):
+ os.remove(test_img)
+
+class TestQemuImgInfo(TestImageInfoSpecific):
+ '''Abstract base class for qemu-img info tests'''
+
+ img_options = None
+ json_compare = None
+ human_compare = None
+
+ def test_json(self):
+ data = json.loads(qemu_img_pipe('info', '--output=json', test_img))
+ data = data['format-specific']
+ self.assertEqual(data['type'], iotests.imgfmt)
+ self.assertEqual(data['data'], self.json_compare)
+
+ def test_human(self):
+ data = qemu_img_pipe('info', '--output=human', test_img).split('\n')
+ data = data[(data.index('Format specific information:') + 1)
+ :data.index('')]
+ for field in data:
+ self.assertTrue(re.match('^ {4}[^ ]', field) is not None)
+ data = map(lambda line: line.strip(), data)
+ self.assertEqual(data, self.human_compare)
+
+class TestQMP(TestImageInfoSpecific):
+ '''Abstract base class for qemu QMP tests'''
+
+ img_options = None
+ qemu_options = ''
+ TestImageInfoSpecific = TestImageInfoSpecific
+
+ def setUp(self):
+ self.TestImageInfoSpecific.setUp(self)
+ self.vm = iotests.VM().add_drive(test_img, self.qemu_options)
+ self.vm.launch()
+
+ def tearDown(self):
+ self.vm.shutdown()
+ self.TestImageInfoSpecific.tearDown(self)
+
+ def test_qmp(self):
+ result = self.vm.qmp('query-block')['return']
+ drive = filter(lambda drive: drive['device'] == 'drive0', result)[0]
+ data = drive['inserted']['image']['format-specific']
+ self.assertEqual(data['type'], iotests.imgfmt)
+ self.assertEqual(data['data'], self.compare)
+
+class TestQCow2(TestQemuImgInfo):
+ '''Testing a qcow2 version 2 image'''
+ img_options = 'compat=0.10'
+ json_compare = { 'compat': '0.10' }
+ human_compare = [ 'compat: 0.10' ]
+
+class TestQCow3NotLazy(TestQemuImgInfo):
+ '''Testing a qcow2 version 3 image with lazy refcounts disabled'''
+ img_options = 'compat=1.1,lazy_refcounts=off'
+ json_compare = { 'compat': '1.1', 'lazy-refcounts': False }
+ human_compare = [ 'compat: 1.1', 'lazy refcounts: false' ]
+
+class TestQCow3Lazy(TestQemuImgInfo):
+ '''Testing a qcow2 version 3 image with lazy refcounts enabled'''
+ img_options = 'compat=1.1,lazy_refcounts=on'
+ json_compare = { 'compat': '1.1', 'lazy-refcounts': True }
+ human_compare = [ 'compat: 1.1', 'lazy refcounts: true' ]
+
+class TestQCow3NotLazyQMP(TestQMP):
+ '''Testing a qcow2 version 3 image with lazy refcounts disabled, opening
+ with lazy refcounts enabled'''
+ img_options = 'compat=1.1,lazy_refcounts=off'
+ qemu_options = 'lazy-refcounts=on'
+ compare = { 'compat': '1.1', 'lazy-refcounts': False }
+
+class TestQCow3LazyQMP(TestQMP):
+ '''Testing a qcow2 version 3 image with lazy refcounts enabled, opening
+ with lazy refcounts disabled'''
+ img_options = 'compat=1.1,lazy_refcounts=on'
+ qemu_options = 'lazy-refcounts=off'
+ compare = { 'compat': '1.1', 'lazy-refcounts': True }
+
+TestImageInfoSpecific = None
+TestQemuImgInfo = None
+TestQMP = None
+
+if __name__ == '__main__':
+ iotests.main(supported_fmts=['qcow2'])
--- /dev/null
+........
+----------------------------------------------------------------------
+Ran 8 tests
+
+OK
--- /dev/null
+#!/bin/bash
+#
+# Test case for discarding preallocated zero clusters in qcow2
+#
+# Copyright (C) 2013 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=mreitz@redhat.com
+
+seq="$(basename $0)"
+echo "QA output created by $seq"
+
+here="$PWD"
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+# This tests qocw2-specific low-level functionality
+_supported_fmt qcow2
+_supported_proto generic
+_supported_os Linux
+
+IMGOPTS="compat=1.1"
+IMG_SIZE=64M
+
+echo
+echo "=== Testing snapshotting an image with zero clusters ==="
+echo
+_make_test_img $IMG_SIZE
+# Write some normal clusters, zero them (creating preallocated zero clusters)
+# and discard those
+$QEMU_IO -c "write 0 256k" -c "write -z 0 256k" -c "discard 0 256k" "$TEST_IMG" \
+ | _filter_qemu_io
+# Check the image (there shouldn't be any leaks)
+_check_test_img
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
--- /dev/null
+QA output created by 066
+
+=== Testing snapshotting an image with zero clusters ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+wrote 262144/262144 bytes at offset 0
+256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 262144/262144 bytes at offset 0
+256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+discard 262144/262144 bytes at offset 0
+256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+No errors were found on the image.
+*** done
--- /dev/null
+#!/bin/bash
+#
+# Test automatic deletion of BDSes created by -drive/drive_add
+#
+# Copyright (C) 2013 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=kwolf@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+function do_run_qemu()
+{
+ echo Testing: "$@"
+ $QEMU -nographic -qmp stdio -serial none "$@"
+ echo
+}
+
+function run_qemu()
+{
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp
+}
+
+size=128M
+
+_make_test_img $size
+
+echo
+echo === -drive/-device and device_del ===
+echo
+
+run_qemu -drive file=$TEST_IMG,format=$IMGFMT,if=none,id=disk -device virtio-blk-pci,drive=disk,id=virtio0 <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "query-block" }
+{ "execute": "device_del", "arguments": { "id": "virtio0" } }
+{ "execute": "system_reset" }
+{ "execute": "query-block" }
+{ "execute": "quit" }
+EOF
+
+echo
+echo === -drive/device_add and device_del ===
+echo
+
+run_qemu -drive file=$TEST_IMG,format=$IMGFMT,if=none,id=disk <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "query-block" }
+{ "execute": "device_add",
+ "arguments": { "driver": "virtio-blk-pci", "drive": "disk",
+ "id": "virtio0" } }
+{ "execute": "device_del", "arguments": { "id": "virtio0" } }
+{ "execute": "system_reset" }
+{ "execute": "query-block" }
+{ "execute": "quit" }
+EOF
+
+echo
+echo === drive_add/device_add and device_del ===
+echo
+
+run_qemu <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "human-monitor-command",
+ "arguments": { "command-line": "drive_add 0 file=$TEST_IMG,format=$IMGFMT,if=none,id=disk" } }
+{ "execute": "query-block" }
+{ "execute": "device_add",
+ "arguments": { "driver": "virtio-blk-pci", "drive": "disk",
+ "id": "virtio0" } }
+{ "execute": "device_del", "arguments": { "id": "virtio0" } }
+{ "execute": "system_reset" }
+{ "execute": "query-block" }
+{ "execute": "quit" }
+EOF
+
+echo
+echo === blockdev_add/device_add and device_del ===
+echo
+
+run_qemu <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "blockdev-add",
+ "arguments": {
+ "options": {
+ "driver": "$IMGFMT",
+ "id": "disk",
+ "file": {
+ "driver": "file",
+ "filename": "$TEST_IMG"
+ }
+ }
+ }
+ }
+{ "execute": "query-block" }
+{ "execute": "device_add",
+ "arguments": { "driver": "virtio-blk-pci", "drive": "disk",
+ "id": "virtio0" } }
+{ "execute": "device_del", "arguments": { "id": "virtio0" } }
+{ "execute": "system_reset" }
+{ "execute": "query-block" }
+{ "execute": "quit" }
+EOF
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
--- /dev/null
+QA output created by 067
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
+
+=== -drive/-device and device_del ===
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virtio-blk-pci,drive=disk,id=virtio0
+QMP_VERSION
+{"return": {}}
+{"return": [{"io-status": "ok", "device": "disk", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": 139264, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
+{"return": {}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"device": "virtio0", "path": "/machine/peripheral/virtio0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "RESET"}
+{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
+{"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}}
+
+
+=== -drive/device_add and device_del ===
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
+QMP_VERSION
+{"return": {}}
+{"return": [{"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": 139264, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"device": "virtio0", "path": "/machine/peripheral/virtio0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "RESET"}
+{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
+{"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}}
+
+
+=== drive_add/device_add and device_del ===
+
+Testing:
+QMP_VERSION
+{"return": {}}
+{"return": "OK\r\n"}
+{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": 139264, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"device": "virtio0", "path": "/machine/peripheral/virtio0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "RESET"}
+{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
+{"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}}
+
+
+=== blockdev_add/device_add and device_del ===
+
+Testing:
+QMP_VERSION
+{"return": {}}
+{"return": {}}
+{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": 139264, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"device": "virtio0", "path": "/machine/peripheral/virtio0"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "RESET"}
+{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": 139264, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
+{"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}}
+
+*** done
rm -f $tmp.list $tmp.tmp $tmp.sed
export IMGFMT=raw
+export IMGFMT_GENERIC=true
export IMGPROTO=file
export IMGOPTS=""
export QEMU_IO_OPTIONS=""
-qed test qed
-vdi test vdi
-vpc test vpc
+ -vhdx test vhdx
-vmdk test vmdk
-rbd test rbd
-sheepdog test sheepdog
xpand=false
;;
+ -vhdx)
+ IMGFMT=vhdx
+ xpand=false
+ IMGFMT_GENERIC=false
+ ;;
+
-rbd)
IMGPROTO=rbd
xpand=false
-e 's#^QEMU [0-9]\+\.[0-9]\+\.[0-9]\+ monitor#QEMU X.Y.Z monitor#'
}
+# replace problematic QMP output like timestamps
+_filter_qmp()
+{
+ _filter_win32 | \
+ sed -e 's#\("\(micro\)\?seconds": \)[0-9]\+#\1 TIMESTAMP#g' \
+ -e 's#^{"QMP":.*}$#QMP_VERSION#'
+}
+
# make sure this script returns success
/bin/true
_img_info()
{
+ discard=0
+ regex_json_spec_start='^ *"format-specific": \{'
$QEMU_IMG info "$@" "$TEST_IMG" 2>&1 | \
sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
-e "s#$TEST_DIR#TEST_DIR#g" \
-e "s#$IMGFMT#IMGFMT#g" \
-e "/^disk size:/ D" \
- -e "/actual-size/ D"
+ -e "/actual-size/ D" | \
+ while IFS='' read line; do
+ if [[ $line == "Format specific information:" ]]; then
+ discard=1
+ elif [[ $line =~ $regex_json_spec_start ]]; then
+ discard=2
+ regex_json_spec_end="^${line%%[^ ]*}\\},? *$"
+ fi
+ if [[ $discard == 0 ]]; then
+ echo "$line"
+ elif [[ $discard == 1 && ! $line ]]; then
+ echo
+ discard=0
+ elif [[ $discard == 2 && $line =~ $regex_json_spec_end ]]; then
+ discard=0
+ fi
+ done
}
_get_pids_by_name()
_supported_fmt()
{
for f; do
- if [ "$f" = "$IMGFMT" -o "$f" = "generic" ]; then
+ if [ "$f" = "$IMGFMT" -o "$f" = "generic" -a "$IMGFMT_GENERIC" = "true" ]; then
return
fi
done
061 rw auto
062 rw auto
063 rw auto
+064 rw auto
+065 rw auto
+066 rw auto
+067 rw auto
'''Run qemu-img without suppressing its output and return the exit code'''
return subprocess.call(qemu_img_args + list(args))
+def qemu_img_pipe(*args):
+ '''Run qemu-img and return its output'''
+ return subprocess.Popen(qemu_img_args + list(args), stdout=subprocess.PIPE).communicate()[0]
+
def qemu_io(*args):
'''Run qemu-io and return the stdout data'''
args = qemu_io_args + list(args)
return opts->id;
}
+/* The id string will be g_free()d by qemu_opts_del */
+void qemu_opts_set_id(QemuOpts *opts, char *id)
+{
+ opts->id = id;
+}
+
void qemu_opts_del(QemuOpts *opts)
{
QemuOpt *opt;
{
BLOCK "040904E4"
{
- VALUE "CompanyName", "http://www.qemu.org"
+ VALUE "CompanyName", "http://www.qemu-project.org"
VALUE "FileDescription", "QEMU machine emulators and tools"
VALUE "FileVersion", QEMU_VERSION
VALUE "LegalCopyright", "Copyright various authors. Released under the GNU General Public License."
exit(1);
}
- snprintf(path, sizeof (path), "/local/domain/0/device-model/%u/state", xen_domid);
+ snprintf(path, sizeof (path), "device-model/%u/state", xen_domid);
if (!xs_write(xs, XBT_NULL, path, state, strlen(state))) {
fprintf(stderr, "error recording dm state\n");
exit(1);