aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--block/dirty-bitmap.c18
-rw-r--r--block/gluster.c116
-rw-r--r--block/qcow2-bitmap.c12
-rw-r--r--block/qcow2-cache.c80
-rw-r--r--block/qcow2-cluster.c519
-rw-r--r--block/qcow2-refcount.c206
-rw-r--r--block/qcow2.c63
-rw-r--r--block/qcow2.h33
-rw-r--r--block/sheepdog.c56
-rw-r--r--blockdev.c15
-rw-r--r--docs/qemu-block-drivers.texi10
-rw-r--r--include/block/dirty-bitmap.h1
-rw-r--r--qapi/block-core.json12
-rw-r--r--qemu-doc.texi7
-rw-r--r--qemu-img.texi74
-rw-r--r--qemu-io.c27
-rw-r--r--target/m68k/cpu.c2
-rw-r--r--target/m68k/cpu.h1
-rw-r--r--target/m68k/translate.c46
-rw-r--r--tests/Makefile.include22
-rw-r--r--tests/ahci-test.c3
-rw-r--r--tests/bios-tables-test.c2
-rw-r--r--tests/boot-order-test.c8
-rw-r--r--tests/boot-sector.c8
-rw-r--r--tests/boot-sector.h6
-rw-r--r--tests/boot-serial-test.c16
-rw-r--r--tests/ds1338-test.c6
-rw-r--r--tests/e1000e-test.c8
-rw-r--r--tests/fw_cfg-test.c13
-rw-r--r--tests/i440fx-test.c2
-rw-r--r--tests/ide-test.c4
-rw-r--r--tests/ivshmem-test.c1
-rw-r--r--tests/libqos/ahci.c49
-rw-r--r--tests/libqos/ahci.h2
-rw-r--r--tests/libqos/fw_cfg.c14
-rw-r--r--tests/libqos/fw_cfg.h10
-rw-r--r--tests/libqos/i2c-imx.c67
-rw-r--r--tests/libqos/i2c-omap.c45
-rw-r--r--tests/libqos/i2c.h7
-rw-r--r--tests/libqos/libqos-pc.c2
-rw-r--r--tests/libqos/libqos.c40
-rw-r--r--tests/libqos/libqos.h4
-rw-r--r--tests/libqos/malloc-pc.c8
-rw-r--r--tests/libqos/malloc-pc.h4
-rw-r--r--tests/libqos/malloc-spapr.c4
-rw-r--r--tests/libqos/malloc-spapr.h2
-rw-r--r--tests/libqos/malloc.h1
-rw-r--r--tests/libqos/pci-pc.c13
-rw-r--r--tests/libqos/pci-pc.h2
-rw-r--r--tests/libqos/pci-spapr.c25
-rw-r--r--tests/libqos/pci-spapr.h2
-rw-r--r--tests/libqos/pci.h1
-rw-r--r--tests/libqos/rtas.c36
-rw-r--r--tests/libqos/rtas.h12
-rw-r--r--tests/libqtest.c19
-rw-r--r--tests/m48t59-test.c123
-rw-r--r--tests/megasas-test.c5
-rw-r--r--tests/pxe-test.c2
-rw-r--r--tests/q35-test.c4
-rw-r--r--tests/qemu-iotests/059.out2
-rwxr-xr-xtests/qemu-iotests/06116
-rw-r--r--tests/qemu-iotests/061.out61
-rwxr-xr-xtests/qemu-iotests/10317
-rw-r--r--tests/qemu-iotests/103.out3
-rwxr-xr-xtests/qemu-iotests/1375
-rw-r--r--tests/qemu-iotests/137.out2
-rwxr-xr-xtests/qemu-iotests/15514
-rwxr-xr-xtests/qemu-iotests/1652
-rwxr-xr-xtests/qemu-iotests/1762
-rw-r--r--tests/qemu-iotests/sample_images/afl9.vmdk.bz2bin178 -> 618 bytes
-rw-r--r--tests/qmp-test.c35
-rw-r--r--tests/rtas-test.c3
-rw-r--r--tests/rtl8139-test.c5
-rw-r--r--tests/sdhci-test.c2
-rw-r--r--tests/tco-test.c5
-rw-r--r--tests/tmp105-test.c6
-rw-r--r--tests/usb-hcd-ehci-test.c2
-rw-r--r--tests/usb-hcd-uhci-test.c1
-rw-r--r--tests/vhost-user-test.c4
-rw-r--r--tests/virtio-9p-test.c1
-rw-r--r--tests/virtio-blk-test.c1
-rw-r--r--tests/virtio-net-test.c15
-rw-r--r--tests/virtio-scsi-test.c16
-rw-r--r--tests/vmgenid-test.c2
-rw-r--r--tests/wdt_ib700-test.c90
85 files changed, 1281 insertions, 931 deletions
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index 7879d13ddb..909f0517f8 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -52,8 +52,6 @@ struct BdrvDirtyBitmap {
Such operations must fail and both the image
and this bitmap must remain unchanged while
this flag is set. */
- bool autoload; /* For persistent bitmaps: bitmap must be
- autoloaded on image opening */
bool persistent; /* bitmap must be saved to owner disk image */
QLIST_ENTRY(BdrvDirtyBitmap) list;
};
@@ -104,7 +102,6 @@ void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap)
g_free(bitmap->name);
bitmap->name = NULL;
bitmap->persistent = false;
- bitmap->autoload = false;
}
/* Called with BQL taken. */
@@ -261,8 +258,6 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
bitmap->successor = NULL;
successor->persistent = bitmap->persistent;
bitmap->persistent = false;
- successor->autoload = bitmap->autoload;
- bitmap->autoload = false;
bdrv_release_dirty_bitmap(bs, bitmap);
return successor;
@@ -667,19 +662,6 @@ bool bdrv_has_readonly_bitmaps(BlockDriverState *bs)
}
/* Called with BQL taken. */
-void bdrv_dirty_bitmap_set_autoload(BdrvDirtyBitmap *bitmap, bool autoload)
-{
- qemu_mutex_lock(bitmap->mutex);
- bitmap->autoload = autoload;
- qemu_mutex_unlock(bitmap->mutex);
-}
-
-bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap)
-{
- return bitmap->autoload;
-}
-
-/* Called with BQL taken. */
void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, bool persistent)
{
qemu_mutex_lock(bitmap->mutex);
diff --git a/block/gluster.c b/block/gluster.c
index d8decc41ad..3f17b7819d 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -965,12 +965,68 @@ static coroutine_fn int qemu_gluster_co_pwrite_zeroes(BlockDriverState *bs,
}
#endif
+static int qemu_gluster_do_truncate(struct glfs_fd *fd, int64_t offset,
+ PreallocMode prealloc, Error **errp)
+{
+ int64_t current_length;
+
+ current_length = glfs_lseek(fd, 0, SEEK_END);
+ if (current_length < 0) {
+ error_setg_errno(errp, errno, "Failed to determine current size");
+ return -errno;
+ }
+
+ if (current_length > offset && prealloc != PREALLOC_MODE_OFF) {
+ error_setg(errp, "Cannot use preallocation for shrinking files");
+ return -ENOTSUP;
+ }
+
+ if (current_length == offset) {
+ return 0;
+ }
+
+ switch (prealloc) {
+#ifdef CONFIG_GLUSTERFS_FALLOCATE
+ case PREALLOC_MODE_FALLOC:
+ if (glfs_fallocate(fd, 0, current_length, offset - current_length)) {
+ error_setg_errno(errp, errno, "Could not preallocate data");
+ return -errno;
+ }
+ break;
+#endif /* CONFIG_GLUSTERFS_FALLOCATE */
+#ifdef CONFIG_GLUSTERFS_ZEROFILL
+ case PREALLOC_MODE_FULL:
+ if (glfs_ftruncate(fd, offset)) {
+ error_setg_errno(errp, errno, "Could not resize file");
+ return -errno;
+ }
+ if (glfs_zerofill(fd, current_length, offset - current_length)) {
+ error_setg_errno(errp, errno, "Could not zerofill the new area");
+ return -errno;
+ }
+ break;
+#endif /* CONFIG_GLUSTERFS_ZEROFILL */
+ case PREALLOC_MODE_OFF:
+ if (glfs_ftruncate(fd, offset)) {
+ error_setg_errno(errp, errno, "Could not resize file");
+ return -errno;
+ }
+ break;
+ default:
+ error_setg(errp, "Unsupported preallocation mode: %s",
+ PreallocMode_str(prealloc));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int qemu_gluster_create(const char *filename,
QemuOpts *opts, Error **errp)
{
BlockdevOptionsGluster *gconf;
struct glfs *glfs;
- struct glfs_fd *fd;
+ struct glfs_fd *fd = NULL;
int ret = 0;
PreallocMode prealloc;
int64_t total_size = 0;
@@ -1019,45 +1075,14 @@ static int qemu_gluster_create(const char *filename,
goto out;
}
- switch (prealloc) {
-#ifdef CONFIG_GLUSTERFS_FALLOCATE
- case PREALLOC_MODE_FALLOC:
- if (glfs_fallocate(fd, 0, 0, total_size)) {
- error_setg(errp, "Could not preallocate data for the new file");
- ret = -errno;
- }
- break;
-#endif /* CONFIG_GLUSTERFS_FALLOCATE */
-#ifdef CONFIG_GLUSTERFS_ZEROFILL
- case PREALLOC_MODE_FULL:
- if (!glfs_ftruncate(fd, total_size)) {
- if (glfs_zerofill(fd, 0, total_size)) {
- error_setg(errp, "Could not zerofill the new file");
- ret = -errno;
- }
- } else {
- error_setg(errp, "Could not resize file");
- ret = -errno;
- }
- break;
-#endif /* CONFIG_GLUSTERFS_ZEROFILL */
- case PREALLOC_MODE_OFF:
- if (glfs_ftruncate(fd, total_size) != 0) {
+ ret = qemu_gluster_do_truncate(fd, total_size, prealloc, errp);
+
+out:
+ if (fd) {
+ if (glfs_close(fd) != 0 && ret == 0) {
ret = -errno;
- error_setg(errp, "Could not resize file");
}
- break;
- default:
- ret = -EINVAL;
- error_setg(errp, "Unsupported preallocation mode: %s",
- PreallocMode_str(prealloc));
- break;
- }
-
- if (glfs_close(fd) != 0) {
- ret = -errno;
}
-out:
qapi_free_BlockdevOptionsGluster(gconf);
glfs_clear_preopened(glfs);
return ret;
@@ -1097,23 +1122,8 @@ static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset,
PreallocMode prealloc, Error **errp)
{
- int ret;
BDRVGlusterState *s = bs->opaque;
-
- if (prealloc != PREALLOC_MODE_OFF) {
- error_setg(errp, "Unsupported preallocation mode '%s'",
- PreallocMode_str(prealloc));
- return -ENOTSUP;
- }
-
- ret = glfs_ftruncate(s->fd, offset);
- if (ret < 0) {
- ret = -errno;
- error_setg_errno(errp, -ret, "Failed to truncate file");
- return ret;
- }
-
- return 0;
+ return qemu_gluster_do_truncate(s->fd, offset, prealloc, errp);
}
static coroutine_fn int qemu_gluster_co_readv(BlockDriverState *bs,
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
index efa10c6663..4f6fd863ea 100644
--- a/block/qcow2-bitmap.c
+++ b/block/qcow2-bitmap.c
@@ -933,14 +933,14 @@ static void set_readonly_helper(gpointer bitmap, gpointer value)
bdrv_dirty_bitmap_set_readonly(bitmap, (bool)value);
}
-/* qcow2_load_autoloading_dirty_bitmaps()
+/* qcow2_load_dirty_bitmaps()
* Return value is a hint for caller: true means that the Qcow2 header was
* updated. (false doesn't mean that the header should be updated by the
* caller, it just means that updating was not needed or the image cannot be
* written to).
* On failure the function returns false.
*/
-bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp)
+bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, Error **errp)
{
BDRVQcow2State *s = bs->opaque;
Qcow2BitmapList *bm_list;
@@ -960,14 +960,16 @@ bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp)
}
QSIMPLEQ_FOREACH(bm, bm_list, entry) {
- if ((bm->flags & BME_FLAG_AUTO) && !(bm->flags & BME_FLAG_IN_USE)) {
+ if (!(bm->flags & BME_FLAG_IN_USE)) {
BdrvDirtyBitmap *bitmap = load_bitmap(bs, bm, errp);
if (bitmap == NULL) {
goto fail;
}
+ if (!(bm->flags & BME_FLAG_AUTO)) {
+ bdrv_disable_dirty_bitmap(bitmap);
+ }
bdrv_dirty_bitmap_set_persistance(bitmap, true);
- bdrv_dirty_bitmap_set_autoload(bitmap, true);
bm->flags |= BME_FLAG_IN_USE;
created_dirty_bitmaps =
g_slist_append(created_dirty_bitmaps, bitmap);
@@ -1369,7 +1371,7 @@ void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp)
bm->table.size = 0;
QSIMPLEQ_INSERT_TAIL(&drop_tables, tb, entry);
}
- bm->flags = bdrv_dirty_bitmap_get_autoload(bitmap) ? BME_FLAG_AUTO : 0;
+ bm->flags = bdrv_dirty_bitmap_enabled(bitmap) ? BME_FLAG_AUTO : 0;
bm->granularity_bits = ctz32(bdrv_dirty_bitmap_granularity(bitmap));
bm->dirty_bitmap = bitmap;
}
diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
index c48ffebd8f..d9dafa31e5 100644
--- a/block/qcow2-cache.c
+++ b/block/qcow2-cache.c
@@ -39,26 +39,23 @@ struct Qcow2Cache {
Qcow2CachedTable *entries;
struct Qcow2Cache *depends;
int size;
+ int table_size;
bool depends_on_flush;
void *table_array;
uint64_t lru_counter;
uint64_t cache_clean_lru_counter;
};
-static inline void *qcow2_cache_get_table_addr(BlockDriverState *bs,
- Qcow2Cache *c, int table)
+static inline void *qcow2_cache_get_table_addr(Qcow2Cache *c, int table)
{
- BDRVQcow2State *s = bs->opaque;
- return (uint8_t *) c->table_array + (size_t) table * s->cluster_size;
+ return (uint8_t *) c->table_array + (size_t) table * c->table_size;
}
-static inline int qcow2_cache_get_table_idx(BlockDriverState *bs,
- Qcow2Cache *c, void *table)
+static inline int qcow2_cache_get_table_idx(Qcow2Cache *c, void *table)
{
- BDRVQcow2State *s = bs->opaque;
ptrdiff_t table_offset = (uint8_t *) table - (uint8_t *) c->table_array;
- int idx = table_offset / s->cluster_size;
- assert(idx >= 0 && idx < c->size && table_offset % s->cluster_size == 0);
+ int idx = table_offset / c->table_size;
+ assert(idx >= 0 && idx < c->size && table_offset % c->table_size == 0);
return idx;
}
@@ -74,15 +71,13 @@ static inline const char *qcow2_cache_get_name(BDRVQcow2State *s, Qcow2Cache *c)
}
}
-static void qcow2_cache_table_release(BlockDriverState *bs, Qcow2Cache *c,
- int i, int num_tables)
+static void qcow2_cache_table_release(Qcow2Cache *c, int i, int num_tables)
{
/* Using MADV_DONTNEED to discard memory is a Linux-specific feature */
#ifdef CONFIG_LINUX
- BDRVQcow2State *s = bs->opaque;
- void *t = qcow2_cache_get_table_addr(bs, c, i);
+ void *t = qcow2_cache_get_table_addr(c, i);
int align = getpagesize();
- size_t mem_size = (size_t) s->cluster_size * num_tables;
+ size_t mem_size = (size_t) c->table_size * num_tables;
size_t offset = QEMU_ALIGN_UP((uintptr_t) t, align) - (uintptr_t) t;
size_t length = QEMU_ALIGN_DOWN(mem_size - offset, align);
if (mem_size > offset && length > 0) {
@@ -98,7 +93,7 @@ static inline bool can_clean_entry(Qcow2Cache *c, int i)
t->lru_counter <= c->cache_clean_lru_counter;
}
-void qcow2_cache_clean_unused(BlockDriverState *bs, Qcow2Cache *c)
+void qcow2_cache_clean_unused(Qcow2Cache *c)
{
int i = 0;
while (i < c->size) {
@@ -118,23 +113,30 @@ void qcow2_cache_clean_unused(BlockDriverState *bs, Qcow2Cache *c)
}
if (to_clean > 0) {
- qcow2_cache_table_release(bs, c, i - to_clean, to_clean);
+ qcow2_cache_table_release(c, i - to_clean, to_clean);
}
}
c->cache_clean_lru_counter = c->lru_counter;
}
-Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables)
+Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
+ unsigned table_size)
{
BDRVQcow2State *s = bs->opaque;
Qcow2Cache *c;
+ assert(num_tables > 0);
+ assert(is_power_of_2(table_size));
+ assert(table_size >= (1 << MIN_CLUSTER_BITS));
+ assert(table_size <= s->cluster_size);
+
c = g_new0(Qcow2Cache, 1);
c->size = num_tables;
+ c->table_size = table_size;
c->entries = g_try_new0(Qcow2CachedTable, num_tables);
c->table_array = qemu_try_blockalign(bs->file->bs,
- (size_t) num_tables * s->cluster_size);
+ (size_t) num_tables * c->table_size);
if (!c->entries || !c->table_array) {
qemu_vfree(c->table_array);
@@ -146,7 +148,7 @@ Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables)
return c;
}
-int qcow2_cache_destroy(BlockDriverState *bs, Qcow2Cache *c)
+int qcow2_cache_destroy(Qcow2Cache *c)
{
int i;
@@ -203,13 +205,13 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
if (c == s->refcount_block_cache) {
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_REFCOUNT_BLOCK,
- c->entries[i].offset, s->cluster_size);
+ c->entries[i].offset, c->table_size);
} else if (c == s->l2_table_cache) {
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L2,
- c->entries[i].offset, s->cluster_size);
+ c->entries[i].offset, c->table_size);
} else {
ret = qcow2_pre_write_overlap_check(bs, 0,
- c->entries[i].offset, s->cluster_size);
+ c->entries[i].offset, c->table_size);
}
if (ret < 0) {
@@ -223,7 +225,7 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
}
ret = bdrv_pwrite(bs->file, c->entries[i].offset,
- qcow2_cache_get_table_addr(bs, c, i), s->cluster_size);
+ qcow2_cache_get_table_addr(c, i), c->table_size);
if (ret < 0) {
return ret;
}
@@ -309,7 +311,7 @@ int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c)
c->entries[i].lru_counter = 0;
}
- qcow2_cache_table_release(bs, c, 0, c->size);
+ qcow2_cache_table_release(c, 0, c->size);
c->lru_counter = 0;
@@ -331,7 +333,7 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
trace_qcow2_cache_get(qemu_coroutine_self(), c == s->l2_table_cache,
offset, read_from_disk);
- if (offset_into_cluster(s, offset)) {
+ if (!QEMU_IS_ALIGNED(offset, c->table_size)) {
qcow2_signal_corruption(bs, true, -1, -1, "Cannot get entry from %s "
"cache: Offset %#" PRIx64 " is unaligned",
qcow2_cache_get_name(s, c), offset);
@@ -339,7 +341,7 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
}
/* Check if the table is already cached */
- i = lookup_index = (offset / s->cluster_size * 4) % c->size;
+ i = lookup_index = (offset / c->table_size * 4) % c->size;
do {
const Qcow2CachedTable *t = &c->entries[i];
if (t->offset == offset) {
@@ -379,8 +381,8 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
}
ret = bdrv_pread(bs->file, offset,
- qcow2_cache_get_table_addr(bs, c, i),
- s->cluster_size);
+ qcow2_cache_get_table_addr(c, i),
+ c->table_size);
if (ret < 0) {
return ret;
}
@@ -391,7 +393,7 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
/* And return the right table */
found:
c->entries[i].ref++;
- *table = qcow2_cache_get_table_addr(bs, c, i);
+ *table = qcow2_cache_get_table_addr(c, i);
trace_qcow2_cache_get_done(qemu_coroutine_self(),
c == s->l2_table_cache, i);
@@ -411,9 +413,9 @@ int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
return qcow2_cache_do_get(bs, c, offset, table, false);
}
-void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table)
+void qcow2_cache_put(Qcow2Cache *c, void **table)
{
- int i = qcow2_cache_get_table_idx(bs, c, *table);
+ int i = qcow2_cache_get_table_idx(c, *table);
c->entries[i].ref--;
*table = NULL;
@@ -425,30 +427,28 @@ void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table)
assert(c->entries[i].ref >= 0);
}
-void qcow2_cache_entry_mark_dirty(BlockDriverState *bs, Qcow2Cache *c,
- void *table)
+void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table)
{
- int i = qcow2_cache_get_table_idx(bs, c, table);
+ int i = qcow2_cache_get_table_idx(c, table);
assert(c->entries[i].offset != 0);
c->entries[i].dirty = true;
}
-void *qcow2_cache_is_table_offset(BlockDriverState *bs, Qcow2Cache *c,
- uint64_t offset)
+void *qcow2_cache_is_table_offset(Qcow2Cache *c, uint64_t offset)
{
int i;
for (i = 0; i < c->size; i++) {
if (c->entries[i].offset == offset) {
- return qcow2_cache_get_table_addr(bs, c, i);
+ return qcow2_cache_get_table_addr(c, i);
}
}
return NULL;
}
-void qcow2_cache_discard(BlockDriverState *bs, Qcow2Cache *c, void *table)
+void qcow2_cache_discard(Qcow2Cache *c, void *table)
{
- int i = qcow2_cache_get_table_idx(bs, c, table);
+ int i = qcow2_cache_get_table_idx(c, table);
assert(c->entries[i].ref == 0);
@@ -456,5 +456,5 @@ void qcow2_cache_discard(BlockDriverState *bs, Qcow2Cache *c, void *table)
c->entries[i].lru_counter = 0;
c->entries[i].dirty = false;
- qcow2_cache_table_release(bs, c, i, 1);
+ qcow2_cache_table_release(c, i, 1);
}
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 3a979bcd82..e406b0f3b9 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -195,20 +195,26 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
/*
* l2_load
*
- * Loads a L2 table into memory. If the table is in the cache, the cache
- * is used; otherwise the L2 table is loaded from the image file.
+ * @bs: The BlockDriverState
+ * @offset: A guest offset, used to calculate what slice of the L2
+ * table to load.
+ * @l2_offset: Offset to the L2 table in the image file.
+ * @l2_slice: Location to store the pointer to the L2 slice.
*
- * Returns a pointer to the L2 table on success, or NULL if the read from
- * the image file failed.
+ * Loads a L2 slice into memory (L2 slices are the parts of L2 tables
+ * that are loaded by the qcow2 cache). If the slice is in the cache,
+ * the cache is used; otherwise the L2 slice is loaded from the image
+ * file.
*/
-
-static int l2_load(BlockDriverState *bs, uint64_t l2_offset,
- uint64_t **l2_table)
+static int l2_load(BlockDriverState *bs, uint64_t offset,
+ uint64_t l2_offset, uint64_t **l2_slice)
{
BDRVQcow2State *s = bs->opaque;
+ int start_of_slice = sizeof(uint64_t) *
+ (offset_to_l2_index(s, offset) - offset_to_l2_slice_index(s, offset));
- return qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
- (void **)l2_table);
+ return qcow2_cache_get(bs, s->l2_table_cache, l2_offset + start_of_slice,
+ (void **)l2_slice);
}
/*
@@ -257,11 +263,12 @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
*
*/
-static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
+static int l2_allocate(BlockDriverState *bs, int l1_index)
{
BDRVQcow2State *s = bs->opaque;
uint64_t old_l2_offset;
- uint64_t *l2_table = NULL;
+ uint64_t *l2_slice = NULL;
+ unsigned slice, slice_size2, n_slices;
int64_t l2_offset;
int ret;
@@ -292,39 +299,47 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
/* allocate a new entry in the l2 cache */
+ slice_size2 = s->l2_slice_size * sizeof(uint64_t);
+ n_slices = s->cluster_size / slice_size2;
+
trace_qcow2_l2_allocate_get_empty(bs, l1_index);
- ret = qcow2_cache_get_empty(bs, s->l2_table_cache, l2_offset, (void**) table);
- if (ret < 0) {
- goto fail;
- }
+ for (slice = 0; slice < n_slices; slice++) {
+ ret = qcow2_cache_get_empty(bs, s->l2_table_cache,
+ l2_offset + slice * slice_size2,
+ (void **) &l2_slice);
+ if (ret < 0) {
+ goto fail;
+ }
- l2_table = *table;
+ if ((old_l2_offset & L1E_OFFSET_MASK) == 0) {
+ /* if there was no old l2 table, clear the new slice */
+ memset(l2_slice, 0, slice_size2);
+ } else {
+ uint64_t *old_slice;
+ uint64_t old_l2_slice_offset =
+ (old_l2_offset & L1E_OFFSET_MASK) + slice * slice_size2;
+
+ /* if there was an old l2 table, read a slice from the disk */
+ BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_COW_READ);
+ ret = qcow2_cache_get(bs, s->l2_table_cache, old_l2_slice_offset,
+ (void **) &old_slice);
+ if (ret < 0) {
+ goto fail;
+ }
- if ((old_l2_offset & L1E_OFFSET_MASK) == 0) {
- /* if there was no old l2 table, clear the new table */
- memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
- } else {
- uint64_t* old_table;
+ memcpy(l2_slice, old_slice, slice_size2);
- /* if there was an old l2 table, read it from the disk */
- BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_COW_READ);
- ret = qcow2_cache_get(bs, s->l2_table_cache,
- old_l2_offset & L1E_OFFSET_MASK,
- (void**) &old_table);
- if (ret < 0) {
- goto fail;
+ qcow2_cache_put(s->l2_table_cache, (void **) &old_slice);
}
- memcpy(l2_table, old_table, s->cluster_size);
+ /* write the l2 slice to the file */
+ BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_WRITE);
- qcow2_cache_put(bs, s->l2_table_cache, (void **) &old_table);
+ trace_qcow2_l2_allocate_write_l2(bs, l1_index);
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
}
- /* write the l2 table to the file */
- BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_WRITE);
-
- trace_qcow2_l2_allocate_write_l2(bs, l1_index);
- qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
ret = qcow2_cache_flush(bs, s->l2_table_cache);
if (ret < 0) {
goto fail;
@@ -338,14 +353,13 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
goto fail;
}
- *table = l2_table;
trace_qcow2_l2_allocate_done(bs, l1_index, 0);
return 0;
fail:
trace_qcow2_l2_allocate_done(bs, l1_index, ret);
- if (l2_table != NULL) {
- qcow2_cache_put(bs, s->l2_table_cache, (void**) table);
+ if (l2_slice != NULL) {
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
}
s->l1_table[l1_index] = old_l2_offset;
if (l2_offset > 0) {
@@ -356,19 +370,19 @@ fail:
}
/*
- * Checks how many clusters in a given L2 table are contiguous in the image
+ * Checks how many clusters in a given L2 slice are contiguous in the image
* file. As soon as one of the flags in the bitmask stop_flags changes compared
* to the first cluster, the search is stopped and the cluster is not counted
* as contiguous. (This allows it, for example, to stop at the first compressed
* cluster which may require a different handling)
*/
static int count_contiguous_clusters(int nb_clusters, int cluster_size,
- uint64_t *l2_table, uint64_t stop_flags)
+ uint64_t *l2_slice, uint64_t stop_flags)
{
int i;
QCow2ClusterType first_cluster_type;
uint64_t mask = stop_flags | L2E_OFFSET_MASK | QCOW_OFLAG_COMPRESSED;
- uint64_t first_entry = be64_to_cpu(l2_table[0]);
+ uint64_t first_entry = be64_to_cpu(l2_slice[0]);
uint64_t offset = first_entry & mask;
if (!offset) {
@@ -381,7 +395,7 @@ static int count_contiguous_clusters(int nb_clusters, int cluster_size,
first_cluster_type == QCOW2_CLUSTER_ZERO_ALLOC);
for (i = 0; i < nb_clusters; i++) {
- uint64_t l2_entry = be64_to_cpu(l2_table[i]) & mask;
+ uint64_t l2_entry = be64_to_cpu(l2_slice[i]) & mask;
if (offset + (uint64_t) i * cluster_size != l2_entry) {
break;
}
@@ -392,10 +406,10 @@ static int count_contiguous_clusters(int nb_clusters, int cluster_size,
/*
* Checks how many consecutive unallocated clusters in a given L2
- * table have the same cluster type.
+ * slice have the same cluster type.
*/
static int count_contiguous_clusters_unallocated(int nb_clusters,
- uint64_t *l2_table,
+ uint64_t *l2_slice,
QCow2ClusterType wanted_type)
{
int i;
@@ -403,7 +417,7 @@ static int count_contiguous_clusters_unallocated(int nb_clusters,
assert(wanted_type == QCOW2_CLUSTER_ZERO_PLAIN ||
wanted_type == QCOW2_CLUSTER_UNALLOCATED);
for (i = 0; i < nb_clusters; i++) {
- uint64_t entry = be64_to_cpu(l2_table[i]);
+ uint64_t entry = be64_to_cpu(l2_slice[i]);
QCow2ClusterType type = qcow2_get_cluster_type(entry);
if (type != wanted_type) {
@@ -515,8 +529,8 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
{
BDRVQcow2State *s = bs->opaque;
unsigned int l2_index;
- uint64_t l1_index, l2_offset, *l2_table;
- int l1_bits, c;
+ uint64_t l1_index, l2_offset, *l2_slice;
+ int c;
unsigned int offset_in_cluster;
uint64_t bytes_available, bytes_needed, nb_clusters;
QCow2ClusterType type;
@@ -525,12 +539,12 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
offset_in_cluster = offset_into_cluster(s, offset);
bytes_needed = (uint64_t) *bytes + offset_in_cluster;
- l1_bits = s->l2_bits + s->cluster_bits;
-
/* compute how many bytes there are between the start of the cluster
- * containing offset and the end of the l1 entry */
- bytes_available = (1ULL << l1_bits) - (offset & ((1ULL << l1_bits) - 1))
- + offset_in_cluster;
+ * containing offset and the end of the l2 slice that contains
+ * the entry pointing to it */
+ bytes_available =
+ ((uint64_t) (s->l2_slice_size - offset_to_l2_slice_index(s, offset)))
+ << s->cluster_bits;
if (bytes_needed > bytes_available) {
bytes_needed = bytes_available;
@@ -540,7 +554,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
/* seek to the l2 offset in the l1 table */
- l1_index = offset >> l1_bits;
+ l1_index = offset_to_l1_index(s, offset);
if (l1_index >= s->l1_size) {
type = QCOW2_CLUSTER_UNALLOCATED;
goto out;
@@ -559,17 +573,17 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
return -EIO;
}
- /* load the l2 table in memory */
+ /* load the l2 slice in memory */
- ret = l2_load(bs, l2_offset, &l2_table);
+ ret = l2_load(bs, offset, l2_offset, &l2_slice);
if (ret < 0) {
return ret;
}
/* find the cluster offset for the given disk offset */
- l2_index = offset_to_l2_index(s, offset);
- *cluster_offset = be64_to_cpu(l2_table[l2_index]);
+ l2_index = offset_to_l2_slice_index(s, offset);
+ *cluster_offset = be64_to_cpu(l2_slice[l2_index]);
nb_clusters = size_to_clusters(s, bytes_needed);
/* bytes_needed <= *bytes + offset_in_cluster, both of which are unsigned
@@ -596,14 +610,14 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
case QCOW2_CLUSTER_UNALLOCATED:
/* how many empty clusters ? */
c = count_contiguous_clusters_unallocated(nb_clusters,
- &l2_table[l2_index], type);
+ &l2_slice[l2_index], type);
*cluster_offset = 0;
break;
case QCOW2_CLUSTER_ZERO_ALLOC:
case QCOW2_CLUSTER_NORMAL:
/* how many allocated clusters ? */
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
- &l2_table[l2_index], QCOW_OFLAG_ZERO);
+ &l2_slice[l2_index], QCOW_OFLAG_ZERO);
*cluster_offset &= L2E_OFFSET_MASK;
if (offset_into_cluster(s, *cluster_offset)) {
qcow2_signal_corruption(bs, true, -1, -1,
@@ -619,7 +633,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
abort();
}
- qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
bytes_available = (int64_t)c * s->cluster_size;
@@ -637,7 +651,7 @@ out:
return type;
fail:
- qcow2_cache_put(bs, s->l2_table_cache, (void **)&l2_table);
+ qcow2_cache_put(s->l2_table_cache, (void **)&l2_slice);
return ret;
}
@@ -645,26 +659,25 @@ fail:
* get_cluster_table
*
* for a given disk offset, load (and allocate if needed)
- * the l2 table.
+ * the appropriate slice of its l2 table.
*
- * the l2 table offset in the qcow2 file and the cluster index
- * in the l2 table are given to the caller.
+ * the cluster index in the l2 slice is given to the caller.
*
* Returns 0 on success, -errno in failure case
*/
static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
- uint64_t **new_l2_table,
+ uint64_t **new_l2_slice,
int *new_l2_index)
{
BDRVQcow2State *s = bs->opaque;
unsigned int l2_index;
uint64_t l1_index, l2_offset;
- uint64_t *l2_table = NULL;
+ uint64_t *l2_slice = NULL;
int ret;
/* seek to the l2 offset in the l1 table */
- l1_index = offset >> (s->l2_bits + s->cluster_bits);
+ l1_index = offset_to_l1_index(s, offset);
if (l1_index >= s->l1_size) {
ret = qcow2_grow_l1_table(bs, l1_index + 1, false);
if (ret < 0) {
@@ -681,17 +694,9 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
return -EIO;
}
- /* seek the l2 table of the given l2 offset */
-
- if (s->l1_table[l1_index] & QCOW_OFLAG_COPIED) {
- /* load the l2 table in memory */
- ret = l2_load(bs, l2_offset, &l2_table);
- if (ret < 0) {
- return ret;
- }
- } else {
+ if (!(s->l1_table[l1_index] & QCOW_OFLAG_COPIED)) {
/* First allocate a new L2 table (and do COW if needed) */
- ret = l2_allocate(bs, l1_index, &l2_table);
+ ret = l2_allocate(bs, l1_index);
if (ret < 0) {
return ret;
}
@@ -701,13 +706,23 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t),
QCOW2_DISCARD_OTHER);
}
+
+ /* Get the offset of the newly-allocated l2 table */
+ l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
+ assert(offset_into_cluster(s, l2_offset) == 0);
+ }
+
+ /* load the l2 slice in memory */
+ ret = l2_load(bs, offset, l2_offset, &l2_slice);
+ if (ret < 0) {
+ return ret;
}
/* find the cluster offset for the given disk offset */
- l2_index = offset_to_l2_index(s, offset);
+ l2_index = offset_to_l2_slice_index(s, offset);
- *new_l2_table = l2_table;
+ *new_l2_slice = l2_slice;
*new_l2_index = l2_index;
return 0;
@@ -732,26 +747,26 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
{
BDRVQcow2State *s = bs->opaque;
int l2_index, ret;
- uint64_t *l2_table;
+ uint64_t *l2_slice;
int64_t cluster_offset;
int nb_csectors;
- ret = get_cluster_table(bs, offset, &l2_table, &l2_index);
+ ret = get_cluster_table(bs, offset, &l2_slice, &l2_index);
if (ret < 0) {
return 0;
}
/* Compression can't overwrite anything. Fail if the cluster was already
* allocated. */
- cluster_offset = be64_to_cpu(l2_table[l2_index]);
+ cluster_offset = be64_to_cpu(l2_slice[l2_index]);
if (cluster_offset & L2E_OFFSET_MASK) {
- qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
return 0;
}
cluster_offset = qcow2_alloc_bytes(bs, compressed_size);
if (cluster_offset < 0) {
- qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
return 0;
}
@@ -766,9 +781,9 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
/* compressed clusters never have the copied flag */
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
- qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
- l2_table[l2_index] = cpu_to_be64(cluster_offset);
- qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
+ l2_slice[l2_index] = cpu_to_be64(cluster_offset);
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
return cluster_offset;
}
@@ -907,7 +922,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
{
BDRVQcow2State *s = bs->opaque;
int i, j = 0, l2_index, ret;
- uint64_t *old_cluster, *l2_table;
+ uint64_t *old_cluster, *l2_slice;
uint64_t cluster_offset = m->alloc_offset;
trace_qcow2_cluster_link_l2(qemu_coroutine_self(), m->nb_clusters);
@@ -934,13 +949,13 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
s->refcount_block_cache);
}
- ret = get_cluster_table(bs, m->offset, &l2_table, &l2_index);
+ ret = get_cluster_table(bs, m->offset, &l2_slice, &l2_index);
if (ret < 0) {
goto err;
}
- qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
- assert(l2_index + m->nb_clusters <= s->l2_size);
+ assert(l2_index + m->nb_clusters <= s->l2_slice_size);
for (i = 0; i < m->nb_clusters; i++) {
/* if two concurrent writes happen to the same unallocated cluster
* each write allocates separate cluster and writes data concurrently.
@@ -948,16 +963,16 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
* cluster the second one has to do RMW (which is done above by
* perform_cow()), update l2 table with its cluster pointer and free
* old cluster. This is what this loop does */
- if (l2_table[l2_index + i] != 0) {
- old_cluster[j++] = l2_table[l2_index + i];
+ if (l2_slice[l2_index + i] != 0) {
+ old_cluster[j++] = l2_slice[l2_index + i];
}
- l2_table[l2_index + i] = cpu_to_be64((cluster_offset +
+ l2_slice[l2_index + i] = cpu_to_be64((cluster_offset +
(i << s->cluster_bits)) | QCOW_OFLAG_COPIED);
}
- qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
/*
* If this was a COW, we need to decrease the refcount of the old cluster.
@@ -984,12 +999,12 @@ err:
* which must copy from the backing file)
*/
static int count_cow_clusters(BDRVQcow2State *s, int nb_clusters,
- uint64_t *l2_table, int l2_index)
+ uint64_t *l2_slice, int l2_index)
{
int i;
for (i = 0; i < nb_clusters; i++) {
- uint64_t l2_entry = be64_to_cpu(l2_table[l2_index + i]);
+ uint64_t l2_entry = be64_to_cpu(l2_slice[l2_index + i]);
QCow2ClusterType cluster_type = qcow2_get_cluster_type(l2_entry);
switch(cluster_type) {
@@ -1104,7 +1119,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
BDRVQcow2State *s = bs->opaque;
int l2_index;
uint64_t cluster_offset;
- uint64_t *l2_table;
+ uint64_t *l2_slice;
uint64_t nb_clusters;
unsigned int keep_clusters;
int ret;
@@ -1116,23 +1131,23 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
== offset_into_cluster(s, *host_offset));
/*
- * Calculate the number of clusters to look for. We stop at L2 table
+ * Calculate the number of clusters to look for. We stop at L2 slice
* boundaries to keep things simple.
*/
nb_clusters =
size_to_clusters(s, offset_into_cluster(s, guest_offset) + *bytes);
- l2_index = offset_to_l2_index(s, guest_offset);
- nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
+ l2_index = offset_to_l2_slice_index(s, guest_offset);
+ nb_clusters = MIN(nb_clusters, s->l2_slice_size - l2_index);
assert(nb_clusters <= INT_MAX);
/* Find L2 entry for the first involved cluster */
- ret = get_cluster_table(bs, guest_offset, &l2_table, &l2_index);
+ ret = get_cluster_table(bs, guest_offset, &l2_slice, &l2_index);
if (ret < 0) {
return ret;
}
- cluster_offset = be64_to_cpu(l2_table[l2_index]);
+ cluster_offset = be64_to_cpu(l2_slice[l2_index]);
/* Check how many clusters are already allocated and don't need COW */
if (qcow2_get_cluster_type(cluster_offset) == QCOW2_CLUSTER_NORMAL
@@ -1160,7 +1175,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
/* We keep all QCOW_OFLAG_COPIED clusters */
keep_clusters =
count_contiguous_clusters(nb_clusters, s->cluster_size,
- &l2_table[l2_index],
+ &l2_slice[l2_index],
QCOW_OFLAG_COPIED | QCOW_OFLAG_ZERO);
assert(keep_clusters <= nb_clusters);
@@ -1175,7 +1190,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
/* Cleanup */
out:
- qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
/* Only return a host offset if we actually made progress. Otherwise we
* would make requirements for handle_alloc() that it can't fulfill */
@@ -1259,7 +1274,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
{
BDRVQcow2State *s = bs->opaque;
int l2_index;
- uint64_t *l2_table;
+ uint64_t *l2_slice;
uint64_t entry;
uint64_t nb_clusters;
int ret;
@@ -1272,29 +1287,29 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
assert(*bytes > 0);
/*
- * Calculate the number of clusters to look for. We stop at L2 table
+ * Calculate the number of clusters to look for. We stop at L2 slice
* boundaries to keep things simple.
*/
nb_clusters =
size_to_clusters(s, offset_into_cluster(s, guest_offset) + *bytes);
- l2_index = offset_to_l2_index(s, guest_offset);
- nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
+ l2_index = offset_to_l2_slice_index(s, guest_offset);
+ nb_clusters = MIN(nb_clusters, s->l2_slice_size - l2_index);
assert(nb_clusters <= INT_MAX);
/* Find L2 entry for the first involved cluster */
- ret = get_cluster_table(bs, guest_offset, &l2_table, &l2_index);
+ ret = get_cluster_table(bs, guest_offset, &l2_slice, &l2_index);
if (ret < 0) {
return ret;
}
- entry = be64_to_cpu(l2_table[l2_index]);
+ entry = be64_to_cpu(l2_slice[l2_index]);
/* For the moment, overwrite compressed clusters one by one */
if (entry & QCOW_OFLAG_COMPRESSED) {
nb_clusters = 1;
} else {
- nb_clusters = count_cow_clusters(s, nb_clusters, l2_table, l2_index);
+ nb_clusters = count_cow_clusters(s, nb_clusters, l2_slice, l2_index);
}
/* This function is only called when there were no non-COW clusters, so if
@@ -1323,7 +1338,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
* nb_clusters already to a range of COW clusters */
preallocated_nb_clusters =
count_contiguous_clusters(nb_clusters, s->cluster_size,
- &l2_table[l2_index], QCOW_OFLAG_COPIED);
+ &l2_slice[l2_index], QCOW_OFLAG_COPIED);
assert(preallocated_nb_clusters > 0);
nb_clusters = preallocated_nb_clusters;
@@ -1334,7 +1349,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
keep_old_clusters = true;
}
- qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
if (!alloc_cluster_offset) {
/* Allocate, if necessary at a given offset in the image file */
@@ -1616,32 +1631,32 @@ int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
/*
* This discards as many clusters of nb_clusters as possible at once (i.e.
- * all clusters in the same L2 table) and returns the number of discarded
+ * all clusters in the same L2 slice) and returns the number of discarded
* clusters.
*/
-static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
- uint64_t nb_clusters, enum qcow2_discard_type type,
- bool full_discard)
+static int discard_in_l2_slice(BlockDriverState *bs, uint64_t offset,
+ uint64_t nb_clusters,
+ enum qcow2_discard_type type, bool full_discard)
{
BDRVQcow2State *s = bs->opaque;
- uint64_t *l2_table;
+ uint64_t *l2_slice;
int l2_index;
int ret;
int i;
- ret = get_cluster_table(bs, offset, &l2_table, &l2_index);
+ ret = get_cluster_table(bs, offset, &l2_slice, &l2_index);
if (ret < 0) {
return ret;
}
- /* Limit nb_clusters to one L2 table */
- nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
+ /* Limit nb_clusters to one L2 slice */
+ nb_clusters = MIN(nb_clusters, s->l2_slice_size - l2_index);
assert(nb_clusters <= INT_MAX);
for (i = 0; i < nb_clusters; i++) {
uint64_t old_l2_entry;
- old_l2_entry = be64_to_cpu(l2_table[l2_index + i]);
+ old_l2_entry = be64_to_cpu(l2_slice[l2_index + i]);
/*
* If full_discard is false, make sure that a discarded area reads back
@@ -1679,18 +1694,18 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
}
/* First remove L2 entries */
- qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
if (!full_discard && s->qcow_version >= 3) {
- l2_table[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
+ l2_slice[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
} else {
- l2_table[l2_index + i] = cpu_to_be64(0);
+ l2_slice[l2_index + i] = cpu_to_be64(0);
}
/* Then decrease the refcount */
qcow2_free_any_clusters(bs, old_l2_entry, 1, type);
}
- qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
return nb_clusters;
}
@@ -1714,10 +1729,10 @@ int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset,
s->cache_discards = true;
- /* Each L2 table is handled by its own loop iteration */
+ /* Each L2 slice is handled by its own loop iteration */
while (nb_clusters > 0) {
- cleared = discard_single_l2(bs, offset, nb_clusters, type,
- full_discard);
+ cleared = discard_in_l2_slice(bs, offset, nb_clusters, type,
+ full_discard);
if (cleared < 0) {
ret = cleared;
goto fail;
@@ -1737,33 +1752,33 @@ fail:
/*
* This zeroes as many clusters of nb_clusters as possible at once (i.e.
- * all clusters in the same L2 table) and returns the number of zeroed
+ * all clusters in the same L2 slice) and returns the number of zeroed
* clusters.
*/
-static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
- uint64_t nb_clusters, int flags)
+static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
+ uint64_t nb_clusters, int flags)
{
BDRVQcow2State *s = bs->opaque;
- uint64_t *l2_table;
+ uint64_t *l2_slice;
int l2_index;
int ret;
int i;
bool unmap = !!(flags & BDRV_REQ_MAY_UNMAP);
- ret = get_cluster_table(bs, offset, &l2_table, &l2_index);
+ ret = get_cluster_table(bs, offset, &l2_slice, &l2_index);
if (ret < 0) {
return ret;
}
- /* Limit nb_clusters to one L2 table */
- nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
+ /* Limit nb_clusters to one L2 slice */
+ nb_clusters = MIN(nb_clusters, s->l2_slice_size - l2_index);
assert(nb_clusters <= INT_MAX);
for (i = 0; i < nb_clusters; i++) {
uint64_t old_offset;
QCow2ClusterType cluster_type;
- old_offset = be64_to_cpu(l2_table[l2_index + i]);
+ old_offset = be64_to_cpu(l2_slice[l2_index + i]);
/*
* Minimize L2 changes if the cluster already reads back as
@@ -1775,16 +1790,16 @@ static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
continue;
}
- qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
if (cluster_type == QCOW2_CLUSTER_COMPRESSED || unmap) {
- l2_table[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
+ l2_slice[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
qcow2_free_any_clusters(bs, old_offset, 1, QCOW2_DISCARD_REQUEST);
} else {
- l2_table[l2_index + i] |= cpu_to_be64(QCOW_OFLAG_ZERO);
+ l2_slice[l2_index + i] |= cpu_to_be64(QCOW_OFLAG_ZERO);
}
}
- qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
return nb_clusters;
}
@@ -1808,13 +1823,13 @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
return -ENOTSUP;
}
- /* Each L2 table is handled by its own loop iteration */
+ /* Each L2 slice is handled by its own loop iteration */
nb_clusters = size_to_clusters(s, bytes);
s->cache_discards = true;
while (nb_clusters > 0) {
- cleared = zero_single_l2(bs, offset, nb_clusters, flags);
+ cleared = zero_in_l2_slice(bs, offset, nb_clusters, flags);
if (cleared < 0) {
ret = cleared;
goto fail;
@@ -1848,22 +1863,25 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
{
BDRVQcow2State *s = bs->opaque;
bool is_active_l1 = (l1_table == s->l1_table);
- uint64_t *l2_table = NULL;
+ uint64_t *l2_slice = NULL;
+ unsigned slice, slice_size2, n_slices;
int ret;
int i, j;
+ slice_size2 = s->l2_slice_size * sizeof(uint64_t);
+ n_slices = s->cluster_size / slice_size2;
+
if (!is_active_l1) {
/* inactive L2 tables require a buffer to be stored in when loading
* them from disk */
- l2_table = qemu_try_blockalign(bs->file->bs, s->cluster_size);
- if (l2_table == NULL) {
+ l2_slice = qemu_try_blockalign(bs->file->bs, slice_size2);
+ if (l2_slice == NULL) {
return -ENOMEM;
}
}
for (i = 0; i < l1_size; i++) {
uint64_t l2_offset = l1_table[i] & L1E_OFFSET_MASK;
- bool l2_dirty = false;
uint64_t l2_refcount;
if (!l2_offset) {
@@ -1883,124 +1901,131 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
goto fail;
}
- if (is_active_l1) {
- /* get active L2 tables from cache */
- ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
- (void **)&l2_table);
- } else {
- /* load inactive L2 tables from disk */
- ret = bdrv_read(bs->file, l2_offset / BDRV_SECTOR_SIZE,
- (void *)l2_table, s->cluster_sectors);
- }
- if (ret < 0) {
- goto fail;
- }
-
ret = qcow2_get_refcount(bs, l2_offset >> s->cluster_bits,
&l2_refcount);
if (ret < 0) {
goto fail;
}
- for (j = 0; j < s->l2_size; j++) {
- uint64_t l2_entry = be64_to_cpu(l2_table[j]);
- int64_t offset = l2_entry & L2E_OFFSET_MASK;
- QCow2ClusterType cluster_type = qcow2_get_cluster_type(l2_entry);
-
- if (cluster_type != QCOW2_CLUSTER_ZERO_PLAIN &&
- cluster_type != QCOW2_CLUSTER_ZERO_ALLOC) {
- continue;
+ for (slice = 0; slice < n_slices; slice++) {
+ uint64_t slice_offset = l2_offset + slice * slice_size2;
+ bool l2_dirty = false;
+ if (is_active_l1) {
+ /* get active L2 tables from cache */
+ ret = qcow2_cache_get(bs, s->l2_table_cache, slice_offset,
+ (void **)&l2_slice);
+ } else {
+ /* load inactive L2 tables from disk */
+ ret = bdrv_pread(bs->file, slice_offset, l2_slice, slice_size2);
+ }
+ if (ret < 0) {
+ goto fail;
}
- if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
- if (!bs->backing) {
- /* not backed; therefore we can simply deallocate the
- * cluster */
- l2_table[j] = 0;
- l2_dirty = true;
+ for (j = 0; j < s->l2_slice_size; j++) {
+ uint64_t l2_entry = be64_to_cpu(l2_slice[j]);
+ int64_t offset = l2_entry & L2E_OFFSET_MASK;
+ QCow2ClusterType cluster_type =
+ qcow2_get_cluster_type(l2_entry);
+
+ if (cluster_type != QCOW2_CLUSTER_ZERO_PLAIN &&
+ cluster_type != QCOW2_CLUSTER_ZERO_ALLOC) {
continue;
}
- offset = qcow2_alloc_clusters(bs, s->cluster_size);
- if (offset < 0) {
- ret = offset;
- goto fail;
- }
+ if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
+ if (!bs->backing) {
+ /* not backed; therefore we can simply deallocate the
+ * cluster */
+ l2_slice[j] = 0;
+ l2_dirty = true;
+ continue;
+ }
+
+ offset = qcow2_alloc_clusters(bs, s->cluster_size);
+ if (offset < 0) {
+ ret = offset;
+ goto fail;
+ }
- if (l2_refcount > 1) {
- /* For shared L2 tables, set the refcount accordingly (it is
- * already 1 and needs to be l2_refcount) */
- ret = qcow2_update_cluster_refcount(bs,
- offset >> s->cluster_bits,
+ if (l2_refcount > 1) {
+ /* For shared L2 tables, set the refcount accordingly
+ * (it is already 1 and needs to be l2_refcount) */
+ ret = qcow2_update_cluster_refcount(
+ bs, offset >> s->cluster_bits,
refcount_diff(1, l2_refcount), false,
QCOW2_DISCARD_OTHER);
- if (ret < 0) {
- qcow2_free_clusters(bs, offset, s->cluster_size,
- QCOW2_DISCARD_OTHER);
- goto fail;
+ if (ret < 0) {
+ qcow2_free_clusters(bs, offset, s->cluster_size,
+ QCOW2_DISCARD_OTHER);
+ goto fail;
+ }
}
}
- }
- if (offset_into_cluster(s, offset)) {
- qcow2_signal_corruption(bs, true, -1, -1,
- "Cluster allocation offset "
- "%#" PRIx64 " unaligned (L2 offset: %#"
- PRIx64 ", L2 index: %#x)", offset,
- l2_offset, j);
- if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
- qcow2_free_clusters(bs, offset, s->cluster_size,
- QCOW2_DISCARD_ALWAYS);
+ if (offset_into_cluster(s, offset)) {
+ int l2_index = slice * s->l2_slice_size + j;
+ qcow2_signal_corruption(
+ bs, true, -1, -1,
+ "Cluster allocation offset "
+ "%#" PRIx64 " unaligned (L2 offset: %#"
+ PRIx64 ", L2 index: %#x)", offset,
+ l2_offset, l2_index);
+ if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
+ qcow2_free_clusters(bs, offset, s->cluster_size,
+ QCOW2_DISCARD_ALWAYS);
+ }
+ ret = -EIO;
+ goto fail;
}
- ret = -EIO;
- goto fail;
- }
- ret = qcow2_pre_write_overlap_check(bs, 0, offset, s->cluster_size);
- if (ret < 0) {
- if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
- qcow2_free_clusters(bs, offset, s->cluster_size,
- QCOW2_DISCARD_ALWAYS);
+ ret = qcow2_pre_write_overlap_check(bs, 0, offset,
+ s->cluster_size);
+ if (ret < 0) {
+ if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
+ qcow2_free_clusters(bs, offset, s->cluster_size,
+ QCOW2_DISCARD_ALWAYS);
+ }
+ goto fail;
}
- goto fail;
- }
- ret = bdrv_pwrite_zeroes(bs->file, offset, s->cluster_size, 0);
- if (ret < 0) {
- if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
- qcow2_free_clusters(bs, offset, s->cluster_size,
- QCOW2_DISCARD_ALWAYS);
+ ret = bdrv_pwrite_zeroes(bs->file, offset, s->cluster_size, 0);
+ if (ret < 0) {
+ if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) {
+ qcow2_free_clusters(bs, offset, s->cluster_size,
+ QCOW2_DISCARD_ALWAYS);
+ }
+ goto fail;
}
- goto fail;
- }
- if (l2_refcount == 1) {
- l2_table[j] = cpu_to_be64(offset | QCOW_OFLAG_COPIED);
- } else {
- l2_table[j] = cpu_to_be64(offset);
+ if (l2_refcount == 1) {
+ l2_slice[j] = cpu_to_be64(offset | QCOW_OFLAG_COPIED);
+ } else {
+ l2_slice[j] = cpu_to_be64(offset);
+ }
+ l2_dirty = true;
}
- l2_dirty = true;
- }
- if (is_active_l1) {
- if (l2_dirty) {
- qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
- qcow2_cache_depends_on_flush(s->l2_table_cache);
- }
- qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
- } else {
- if (l2_dirty) {
- 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;
+ if (is_active_l1) {
+ if (l2_dirty) {
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
+ qcow2_cache_depends_on_flush(s->l2_table_cache);
}
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
+ } else {
+ if (l2_dirty) {
+ ret = qcow2_pre_write_overlap_check(
+ bs, QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2,
+ slice_offset, slice_size2);
+ if (ret < 0) {
+ goto fail;
+ }
- ret = bdrv_write(bs->file, l2_offset / BDRV_SECTOR_SIZE,
- (void *)l2_table, s->cluster_sectors);
- if (ret < 0) {
- goto fail;
+ ret = bdrv_pwrite(bs->file, slice_offset,
+ l2_slice, slice_size2);
+ if (ret < 0) {
+ goto fail;
+ }
}
}
}
@@ -2014,11 +2039,11 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
ret = 0;
fail:
- if (l2_table) {
+ if (l2_slice) {
if (!is_active_l1) {
- qemu_vfree(l2_table);
+ qemu_vfree(l2_slice);
} else {
- qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
}
}
return ret;
@@ -2070,7 +2095,15 @@ int qcow2_expand_zero_clusters(BlockDriverState *bs,
int l1_sectors = DIV_ROUND_UP(s->snapshots[i].l1_size *
sizeof(uint64_t), BDRV_SECTOR_SIZE);
- l1_table = g_realloc(l1_table, l1_sectors * BDRV_SECTOR_SIZE);
+ uint64_t *new_l1_table =
+ g_try_realloc(l1_table, l1_sectors * BDRV_SECTOR_SIZE);
+
+ if (!new_l1_table) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ l1_table = new_l1_table;
ret = bdrv_read(bs->file,
s->snapshots[i].l1_table_offset / BDRV_SECTOR_SIZE,
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 92701ab7af..d46b69d7f3 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -277,7 +277,7 @@ int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index,
block_index = cluster_index & (s->refcount_block_size - 1);
*refcount = s->get_refcount(refcount_block, block_index);
- qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
+ qcow2_cache_put(s->refcount_block_cache, &refcount_block);
return 0;
}
@@ -421,7 +421,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
/* Now the new refcount block needs to be written to disk */
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE);
- qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache, *refcount_block);
+ qcow2_cache_entry_mark_dirty(s->refcount_block_cache, *refcount_block);
ret = qcow2_cache_flush(bs, s->refcount_block_cache);
if (ret < 0) {
goto fail;
@@ -449,7 +449,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
return -EAGAIN;
}
- qcow2_cache_put(bs, s->refcount_block_cache, refcount_block);
+ qcow2_cache_put(s->refcount_block_cache, refcount_block);
/*
* If we come here, we need to grow the refcount table. Again, a new
@@ -501,7 +501,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
fail:
if (*refcount_block != NULL) {
- qcow2_cache_put(bs, s->refcount_block_cache, refcount_block);
+ qcow2_cache_put(s->refcount_block_cache, refcount_block);
}
return ret;
}
@@ -623,7 +623,7 @@ int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t start_offset,
goto fail;
}
memset(refblock_data, 0, s->cluster_size);
- qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache,
+ qcow2_cache_entry_mark_dirty(s->refcount_block_cache,
refblock_data);
new_table[i] = block_offset;
@@ -656,11 +656,11 @@ int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t start_offset,
s->set_refcount(refblock_data, j, 1);
}
- qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache,
+ qcow2_cache_entry_mark_dirty(s->refcount_block_cache,
refblock_data);
}
- qcow2_cache_put(bs, s->refcount_block_cache, &refblock_data);
+ qcow2_cache_put(s->refcount_block_cache, &refblock_data);
}
assert(block_offset == table_offset);
@@ -836,7 +836,7 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
/* Load the refcount block and allocate it if needed */
if (table_index != old_table_index) {
if (refcount_block) {
- qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
+ qcow2_cache_put(s->refcount_block_cache, &refcount_block);
}
ret = alloc_refcount_block(bs, cluster_index, &refcount_block);
if (ret < 0) {
@@ -845,8 +845,7 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
}
old_table_index = table_index;
- qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache,
- refcount_block);
+ qcow2_cache_entry_mark_dirty(s->refcount_block_cache, refcount_block);
/* we can update the count and save it */
block_index = cluster_index & (s->refcount_block_size - 1);
@@ -872,16 +871,16 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
if (refcount == 0) {
void *table;
- table = qcow2_cache_is_table_offset(bs, s->refcount_block_cache,
+ table = qcow2_cache_is_table_offset(s->refcount_block_cache,
offset);
if (table != NULL) {
- qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
- qcow2_cache_discard(bs, s->refcount_block_cache, table);
+ qcow2_cache_put(s->refcount_block_cache, &refcount_block);
+ qcow2_cache_discard(s->refcount_block_cache, table);
}
- table = qcow2_cache_is_table_offset(bs, s->l2_table_cache, offset);
+ table = qcow2_cache_is_table_offset(s->l2_table_cache, offset);
if (table != NULL) {
- qcow2_cache_discard(bs, s->l2_table_cache, table);
+ qcow2_cache_discard(s->l2_table_cache, table);
}
if (s->discard_passthrough[type]) {
@@ -898,7 +897,7 @@ fail:
/* Write last changed block to disk */
if (refcount_block) {
- qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
+ qcow2_cache_put(s->refcount_block_cache, &refcount_block);
}
/*
@@ -1184,17 +1183,20 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
int64_t l1_table_offset, int l1_size, int addend)
{
BDRVQcow2State *s = bs->opaque;
- uint64_t *l1_table, *l2_table, l2_offset, entry, l1_size2, refcount;
+ uint64_t *l1_table, *l2_slice, l2_offset, entry, l1_size2, refcount;
bool l1_allocated = false;
int64_t old_entry, old_l2_offset;
+ unsigned slice, slice_size2, n_slices;
int i, j, l1_modified = 0, nb_csectors;
int ret;
assert(addend >= -1 && addend <= 1);
- l2_table = NULL;
+ l2_slice = NULL;
l1_table = NULL;
l1_size2 = l1_size * sizeof(uint64_t);
+ slice_size2 = s->l2_slice_size * sizeof(uint64_t);
+ n_slices = s->cluster_size / slice_size2;
s->cache_discards = true;
@@ -1237,91 +1239,97 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
goto fail;
}
- ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
- (void**) &l2_table);
- if (ret < 0) {
- goto fail;
- }
+ for (slice = 0; slice < n_slices; slice++) {
+ ret = qcow2_cache_get(bs, s->l2_table_cache,
+ l2_offset + slice * slice_size2,
+ (void **) &l2_slice);
+ if (ret < 0) {
+ goto fail;
+ }
- for (j = 0; j < s->l2_size; j++) {
- uint64_t cluster_index;
- uint64_t offset;
-
- entry = be64_to_cpu(l2_table[j]);
- old_entry = entry;
- entry &= ~QCOW_OFLAG_COPIED;
- offset = entry & L2E_OFFSET_MASK;
-
- switch (qcow2_get_cluster_type(entry)) {
- case QCOW2_CLUSTER_COMPRESSED:
- nb_csectors = ((entry >> s->csize_shift) &
- s->csize_mask) + 1;
- if (addend != 0) {
- ret = update_refcount(bs,
- (entry & s->cluster_offset_mask) & ~511,
+ for (j = 0; j < s->l2_slice_size; j++) {
+ uint64_t cluster_index;
+ uint64_t offset;
+
+ entry = be64_to_cpu(l2_slice[j]);
+ old_entry = entry;
+ entry &= ~QCOW_OFLAG_COPIED;
+ offset = entry & L2E_OFFSET_MASK;
+
+ switch (qcow2_get_cluster_type(entry)) {
+ case QCOW2_CLUSTER_COMPRESSED:
+ nb_csectors = ((entry >> s->csize_shift) &
+ s->csize_mask) + 1;
+ if (addend != 0) {
+ ret = update_refcount(
+ bs, (entry & s->cluster_offset_mask) & ~511,
nb_csectors * 512, abs(addend), addend < 0,
QCOW2_DISCARD_SNAPSHOT);
- if (ret < 0) {
+ if (ret < 0) {
+ goto fail;
+ }
+ }
+ /* compressed clusters are never modified */
+ refcount = 2;
+ break;
+
+ case QCOW2_CLUSTER_NORMAL:
+ case QCOW2_CLUSTER_ZERO_ALLOC:
+ if (offset_into_cluster(s, offset)) {
+ /* Here l2_index means table (not slice) index */
+ int l2_index = slice * s->l2_slice_size + j;
+ qcow2_signal_corruption(
+ bs, true, -1, -1, "Cluster "
+ "allocation offset %#" PRIx64
+ " unaligned (L2 offset: %#"
+ PRIx64 ", L2 index: %#x)",
+ offset, l2_offset, l2_index);
+ ret = -EIO;
goto fail;
}
- }
- /* compressed clusters are never modified */
- refcount = 2;
- break;
-
- case QCOW2_CLUSTER_NORMAL:
- case QCOW2_CLUSTER_ZERO_ALLOC:
- if (offset_into_cluster(s, offset)) {
- qcow2_signal_corruption(bs, true, -1, -1, "Cluster "
- "allocation offset %#" PRIx64
- " unaligned (L2 offset: %#"
- PRIx64 ", L2 index: %#x)",
- offset, l2_offset, j);
- ret = -EIO;
- goto fail;
- }
- cluster_index = offset >> s->cluster_bits;
- assert(cluster_index);
- if (addend != 0) {
- ret = qcow2_update_cluster_refcount(bs,
- cluster_index, abs(addend), addend < 0,
- QCOW2_DISCARD_SNAPSHOT);
+ cluster_index = offset >> s->cluster_bits;
+ assert(cluster_index);
+ if (addend != 0) {
+ ret = qcow2_update_cluster_refcount(
+ bs, cluster_index, abs(addend), addend < 0,
+ QCOW2_DISCARD_SNAPSHOT);
+ if (ret < 0) {
+ goto fail;
+ }
+ }
+
+ ret = qcow2_get_refcount(bs, cluster_index, &refcount);
if (ret < 0) {
goto fail;
}
- }
+ break;
- ret = qcow2_get_refcount(bs, cluster_index, &refcount);
- if (ret < 0) {
- goto fail;
- }
- break;
-
- case QCOW2_CLUSTER_ZERO_PLAIN:
- case QCOW2_CLUSTER_UNALLOCATED:
- refcount = 0;
- break;
+ case QCOW2_CLUSTER_ZERO_PLAIN:
+ case QCOW2_CLUSTER_UNALLOCATED:
+ refcount = 0;
+ break;
- default:
- abort();
- }
+ default:
+ abort();
+ }
- if (refcount == 1) {
- entry |= QCOW_OFLAG_COPIED;
- }
- if (entry != old_entry) {
- if (addend > 0) {
- qcow2_cache_set_dependency(bs, s->l2_table_cache,
- s->refcount_block_cache);
+ if (refcount == 1) {
+ entry |= QCOW_OFLAG_COPIED;
+ }
+ if (entry != old_entry) {
+ if (addend > 0) {
+ qcow2_cache_set_dependency(bs, s->l2_table_cache,
+ s->refcount_block_cache);
+ }
+ l2_slice[j] = cpu_to_be64(entry);
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache,
+ l2_slice);
}
- l2_table[j] = cpu_to_be64(entry);
- qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache,
- l2_table);
}
- }
- qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
+ }
if (addend != 0) {
ret = qcow2_update_cluster_refcount(bs, l2_offset >>
@@ -1348,8 +1356,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
ret = bdrv_flush(bs);
fail:
- if (l2_table) {
- qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+ if (l2_slice) {
+ qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
}
s->cache_discards = false;
@@ -2849,7 +2857,7 @@ static int walk_over_reftable(BlockDriverState *bs, uint64_t **new_reftable,
new_reftable_size, new_refblock,
new_refblock_empty, allocated, errp);
if (ret < 0) {
- qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
+ qcow2_cache_put(s->refcount_block_cache, &refblock);
return ret;
}
@@ -2862,7 +2870,7 @@ static int walk_over_reftable(BlockDriverState *bs, uint64_t **new_reftable,
if (new_refcount_bits < 64 && refcount >> new_refcount_bits) {
uint64_t offset;
- qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
+ qcow2_cache_put(s->refcount_block_cache, &refblock);
offset = ((reftable_index << s->refcount_block_bits)
+ refblock_index) << s->cluster_bits;
@@ -2883,7 +2891,7 @@ static int walk_over_reftable(BlockDriverState *bs, uint64_t **new_reftable,
new_refblock_empty = new_refblock_empty && refcount == 0;
}
- qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
+ qcow2_cache_put(s->refcount_block_cache, &refblock);
} else {
/* No refblock means every refcount is 0 */
for (refblock_index = 0; refblock_index < s->refcount_block_size;
@@ -3175,24 +3183,24 @@ static int qcow2_discard_refcount_block(BlockDriverState *bs,
offset_to_reftable_index(s, discard_block_offs),
discard_block_offs,
s->get_refcount(refblock, block_index));
- qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
+ qcow2_cache_put(s->refcount_block_cache, &refblock);
return -EINVAL;
}
s->set_refcount(refblock, block_index, 0);
- qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache, refblock);
+ qcow2_cache_entry_mark_dirty(s->refcount_block_cache, refblock);
- qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
+ qcow2_cache_put(s->refcount_block_cache, &refblock);
if (cluster_index < s->free_cluster_index) {
s->free_cluster_index = cluster_index;
}
- refblock = qcow2_cache_is_table_offset(bs, s->refcount_block_cache,
+ refblock = qcow2_cache_is_table_offset(s->refcount_block_cache,
discard_block_offs);
if (refblock) {
/* discard refblock from the cache if refblock is cached */
- qcow2_cache_discard(bs, s->refcount_block_cache, refblock);
+ qcow2_cache_discard(s->refcount_block_cache, refblock);
}
update_refcount_discard(bs, discard_block_offs, s->cluster_size);
@@ -3235,7 +3243,7 @@ int qcow2_shrink_reftable(BlockDriverState *bs)
} else {
unused_block = buffer_is_zero(refblock, s->cluster_size);
}
- qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
+ qcow2_cache_put(s->refcount_block_cache, &refblock);
reftable_tmp[i] = unused_block ? 0 : cpu_to_be64(s->refcount_table[i]);
}
diff --git a/block/qcow2.c b/block/qcow2.c
index 801e29fc56..57a517e2bd 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -676,6 +676,11 @@ static QemuOptsList qcow2_runtime_opts = {
.help = "Maximum L2 table cache size",
},
{
+ .name = QCOW2_OPT_L2_CACHE_ENTRY_SIZE,
+ .type = QEMU_OPT_SIZE,
+ .help = "Size of each entry in the L2 cache",
+ },
+ {
.name = QCOW2_OPT_REFCOUNT_CACHE_SIZE,
.type = QEMU_OPT_SIZE,
.help = "Maximum refcount block cache size",
@@ -706,8 +711,8 @@ static void cache_clean_timer_cb(void *opaque)
{
BlockDriverState *bs = opaque;
BDRVQcow2State *s = bs->opaque;
- qcow2_cache_clean_unused(bs, s->l2_table_cache);
- qcow2_cache_clean_unused(bs, s->refcount_block_cache);
+ qcow2_cache_clean_unused(s->l2_table_cache);
+ qcow2_cache_clean_unused(s->refcount_block_cache);
timer_mod(s->cache_clean_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
(int64_t) s->cache_clean_interval * 1000);
}
@@ -747,6 +752,7 @@ static void qcow2_attach_aio_context(BlockDriverState *bs,
static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
uint64_t *l2_cache_size,
+ uint64_t *l2_cache_entry_size,
uint64_t *refcount_cache_size, Error **errp)
{
BDRVQcow2State *s = bs->opaque;
@@ -762,6 +768,9 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
*refcount_cache_size = qemu_opt_get_size(opts,
QCOW2_OPT_REFCOUNT_CACHE_SIZE, 0);
+ *l2_cache_entry_size = qemu_opt_get_size(
+ opts, QCOW2_OPT_L2_CACHE_ENTRY_SIZE, s->cluster_size);
+
if (combined_cache_size_set) {
if (l2_cache_size_set && refcount_cache_size_set) {
error_setg(errp, QCOW2_OPT_CACHE_SIZE ", " QCOW2_OPT_L2_CACHE_SIZE
@@ -802,11 +811,21 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
/ DEFAULT_L2_REFCOUNT_SIZE_RATIO;
}
}
+
+ if (*l2_cache_entry_size < (1 << MIN_CLUSTER_BITS) ||
+ *l2_cache_entry_size > s->cluster_size ||
+ !is_power_of_2(*l2_cache_entry_size)) {
+ error_setg(errp, "L2 cache entry size must be a power of two "
+ "between %d and the cluster size (%d)",
+ 1 << MIN_CLUSTER_BITS, s->cluster_size);
+ return;
+ }
}
typedef struct Qcow2ReopenState {
Qcow2Cache *l2_table_cache;
Qcow2Cache *refcount_block_cache;
+ int l2_slice_size; /* Number of entries in a slice of the L2 table */
bool use_lazy_refcounts;
int overlap_check;
bool discard_passthrough[QCOW2_DISCARD_MAX];
@@ -823,7 +842,7 @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
QemuOpts *opts = NULL;
const char *opt_overlap_check, *opt_overlap_check_template;
int overlap_check_template = 0;
- uint64_t l2_cache_size, refcount_cache_size;
+ uint64_t l2_cache_size, l2_cache_entry_size, refcount_cache_size;
int i;
const char *encryptfmt;
QDict *encryptopts = NULL;
@@ -842,15 +861,15 @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
}
/* get L2 table/refcount block cache size from command line options */
- read_cache_sizes(bs, opts, &l2_cache_size, &refcount_cache_size,
- &local_err);
+ read_cache_sizes(bs, opts, &l2_cache_size, &l2_cache_entry_size,
+ &refcount_cache_size, &local_err);
if (local_err) {
error_propagate(errp, local_err);
ret = -EINVAL;
goto fail;
}
- l2_cache_size /= s->cluster_size;
+ l2_cache_size /= l2_cache_entry_size;
if (l2_cache_size < MIN_L2_CACHE_SIZE) {
l2_cache_size = MIN_L2_CACHE_SIZE;
}
@@ -888,8 +907,11 @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
}
}
- r->l2_table_cache = qcow2_cache_create(bs, l2_cache_size);
- r->refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size);
+ r->l2_slice_size = l2_cache_entry_size / sizeof(uint64_t);
+ r->l2_table_cache = qcow2_cache_create(bs, l2_cache_size,
+ l2_cache_entry_size);
+ r->refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size,
+ s->cluster_size);
if (r->l2_table_cache == NULL || r->refcount_block_cache == NULL) {
error_setg(errp, "Could not allocate metadata caches");
ret = -ENOMEM;
@@ -1044,13 +1066,14 @@ static void qcow2_update_options_commit(BlockDriverState *bs,
int i;
if (s->l2_table_cache) {
- qcow2_cache_destroy(bs, s->l2_table_cache);
+ qcow2_cache_destroy(s->l2_table_cache);
}
if (s->refcount_block_cache) {
- qcow2_cache_destroy(bs, s->refcount_block_cache);
+ qcow2_cache_destroy(s->refcount_block_cache);
}
s->l2_table_cache = r->l2_table_cache;
s->refcount_block_cache = r->refcount_block_cache;
+ s->l2_slice_size = r->l2_slice_size;
s->overlap_check = r->overlap_check;
s->use_lazy_refcounts = r->use_lazy_refcounts;
@@ -1073,10 +1096,10 @@ static void qcow2_update_options_abort(BlockDriverState *bs,
Qcow2ReopenState *r)
{
if (r->l2_table_cache) {
- qcow2_cache_destroy(bs, r->l2_table_cache);
+ qcow2_cache_destroy(r->l2_table_cache);
}
if (r->refcount_block_cache) {
- qcow2_cache_destroy(bs, r->refcount_block_cache);
+ qcow2_cache_destroy(r->refcount_block_cache);
}
qapi_free_QCryptoBlockOpenOptions(r->crypto_opts);
}
@@ -1460,7 +1483,7 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
s->autoclear_features &= QCOW2_AUTOCLEAR_MASK;
}
- if (qcow2_load_autoloading_dirty_bitmaps(bs, &local_err)) {
+ if (qcow2_load_dirty_bitmaps(bs, &local_err)) {
update_header = false;
}
if (local_err != NULL) {
@@ -1514,10 +1537,10 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
s->l1_table = NULL;
cache_clean_timer_del(bs);
if (s->l2_table_cache) {
- qcow2_cache_destroy(bs, s->l2_table_cache);
+ qcow2_cache_destroy(s->l2_table_cache);
}
if (s->refcount_block_cache) {
- qcow2_cache_destroy(bs, s->refcount_block_cache);
+ qcow2_cache_destroy(s->refcount_block_cache);
}
qcrypto_block_free(s->crypto);
qapi_free_QCryptoBlockOpenOptions(s->crypto_opts);
@@ -2065,8 +2088,8 @@ static void qcow2_close(BlockDriverState *bs)
}
cache_clean_timer_del(bs);
- qcow2_cache_destroy(bs, s->l2_table_cache);
- qcow2_cache_destroy(bs, s->refcount_block_cache);
+ qcow2_cache_destroy(s->l2_table_cache);
+ qcow2_cache_destroy(s->refcount_block_cache);
qcrypto_block_free(s->crypto);
s->crypto = NULL;
@@ -3259,9 +3282,9 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
host_offset = allocation_start;
guest_offset = old_length;
while (nb_new_data_clusters) {
- int64_t guest_cluster = guest_offset >> s->cluster_bits;
- int64_t nb_clusters = MIN(nb_new_data_clusters,
- s->l2_size - guest_cluster % s->l2_size);
+ int64_t nb_clusters = MIN(
+ nb_new_data_clusters,
+ s->l2_slice_size - offset_to_l2_slice_index(s, guest_offset));
QCowL2Meta allocation = {
.offset = guest_offset,
.alloc_offset = host_offset,
diff --git a/block/qcow2.h b/block/qcow2.h
index 46c8cf44ec..883802241f 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -68,7 +68,7 @@
#define MAX_CLUSTER_BITS 21
/* Must be at least 2 to cover COW */
-#define MIN_L2_CACHE_SIZE 2 /* clusters */
+#define MIN_L2_CACHE_SIZE 2 /* cache entries */
/* Must be at least 4 to cover all cases of refcount table growth */
#define MIN_REFCOUNT_CACHE_SIZE 4 /* clusters */
@@ -100,6 +100,7 @@
#define QCOW2_OPT_OVERLAP_INACTIVE_L2 "overlap-check.inactive-l2"
#define QCOW2_OPT_CACHE_SIZE "cache-size"
#define QCOW2_OPT_L2_CACHE_SIZE "l2-cache-size"
+#define QCOW2_OPT_L2_CACHE_ENTRY_SIZE "l2-cache-entry-size"
#define QCOW2_OPT_REFCOUNT_CACHE_SIZE "refcount-cache-size"
#define QCOW2_OPT_CACHE_CLEAN_INTERVAL "cache-clean-interval"
@@ -251,6 +252,7 @@ typedef struct BDRVQcow2State {
int cluster_bits;
int cluster_size;
int cluster_sectors;
+ int l2_slice_size;
int l2_bits;
int l2_size;
int l1_size;
@@ -463,11 +465,21 @@ static inline int64_t size_to_l1(BDRVQcow2State *s, int64_t size)
return (size + (1ULL << shift) - 1) >> shift;
}
+static inline int offset_to_l1_index(BDRVQcow2State *s, uint64_t offset)
+{
+ return offset >> (s->l2_bits + s->cluster_bits);
+}
+
static inline int offset_to_l2_index(BDRVQcow2State *s, int64_t offset)
{
return (offset >> s->cluster_bits) & (s->l2_size - 1);
}
+static inline int offset_to_l2_slice_index(BDRVQcow2State *s, int64_t offset)
+{
+ return (offset >> s->cluster_bits) & (s->l2_slice_size - 1);
+}
+
static inline int64_t align_offset(int64_t offset, int n)
{
offset = (offset + n - 1) & ~(n - 1);
@@ -636,34 +648,33 @@ void qcow2_free_snapshots(BlockDriverState *bs);
int qcow2_read_snapshots(BlockDriverState *bs);
/* qcow2-cache.c functions */
-Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables);
-int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c);
+Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
+ unsigned table_size);
+int qcow2_cache_destroy(Qcow2Cache *c);
-void qcow2_cache_entry_mark_dirty(BlockDriverState *bs, Qcow2Cache *c,
- void *table);
+void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c);
int qcow2_cache_write(BlockDriverState *bs, Qcow2Cache *c);
int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
Qcow2Cache *dependency);
void qcow2_cache_depends_on_flush(Qcow2Cache *c);
-void qcow2_cache_clean_unused(BlockDriverState *bs, Qcow2Cache *c);
+void qcow2_cache_clean_unused(Qcow2Cache *c);
int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c);
int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
void **table);
int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
void **table);
-void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table);
-void *qcow2_cache_is_table_offset(BlockDriverState *bs, Qcow2Cache *c,
- uint64_t offset);
-void qcow2_cache_discard(BlockDriverState *bs, Qcow2Cache *c, void *table);
+void qcow2_cache_put(Qcow2Cache *c, void **table);
+void *qcow2_cache_is_table_offset(Qcow2Cache *c, uint64_t offset);
+void qcow2_cache_discard(Qcow2Cache *c, void *table);
/* qcow2-bitmap.c functions */
int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
void **refcount_table,
int64_t *refcount_table_size);
-bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp);
+bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, Error **errp);
int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp);
void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp);
int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp);
diff --git a/block/sheepdog.c b/block/sheepdog.c
index af125a2c8d..ac02b10fe0 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -1826,40 +1826,34 @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot,
return 0;
}
-static int sd_prealloc(const char *filename, Error **errp)
+static int sd_prealloc(BlockDriverState *bs, int64_t old_size, int64_t new_size,
+ Error **errp)
{
BlockBackend *blk = NULL;
- BDRVSheepdogState *base = NULL;
+ BDRVSheepdogState *base = bs->opaque;
unsigned long buf_size;
uint32_t idx, max_idx;
uint32_t object_size;
- int64_t vdi_size;
void *buf = NULL;
int ret;
- blk = blk_new_open(filename, NULL, NULL,
- BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
- if (blk == NULL) {
- ret = -EIO;
+ blk = blk_new(BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE,
+ BLK_PERM_ALL);
+
+ ret = blk_insert_bs(blk, bs, errp);
+ if (ret < 0) {
goto out_with_err_set;
}
blk_set_allow_write_beyond_eof(blk, true);
- vdi_size = blk_getlength(blk);
- if (vdi_size < 0) {
- ret = vdi_size;
- goto out;
- }
-
- base = blk_bs(blk)->opaque;
object_size = (UINT32_C(1) << base->inode.block_size_shift);
buf_size = MIN(object_size, SD_DATA_OBJ_SIZE);
buf = g_malloc0(buf_size);
- max_idx = DIV_ROUND_UP(vdi_size, buf_size);
+ max_idx = DIV_ROUND_UP(new_size, buf_size);
- for (idx = 0; idx < max_idx; idx++) {
+ for (idx = old_size / buf_size; idx < max_idx; idx++) {
/*
* The created image can be a cloned image, so we need to read
* a data from the source image.
@@ -2108,7 +2102,20 @@ static int sd_create(const char *filename, QemuOpts *opts,
}
if (prealloc) {
- ret = sd_prealloc(filename, errp);
+ BlockDriverState *bs;
+ QDict *opts;
+
+ opts = qdict_new();
+ qdict_put_str(opts, "driver", "sheepdog");
+ bs = bdrv_open(filename, NULL, opts, BDRV_O_PROTOCOL | BDRV_O_RDWR,
+ errp);
+ if (!bs) {
+ goto out;
+ }
+
+ ret = sd_prealloc(bs, 0, s->inode.vdi_size, errp);
+
+ bdrv_unref(bs);
}
out:
g_free(backing_file);
@@ -2173,15 +2180,16 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset,
int ret, fd;
unsigned int datalen;
uint64_t max_vdi_size;
+ int64_t old_size = s->inode.vdi_size;
- if (prealloc != PREALLOC_MODE_OFF) {
+ if (prealloc != PREALLOC_MODE_OFF && prealloc != PREALLOC_MODE_FULL) {
error_setg(errp, "Unsupported preallocation mode '%s'",
PreallocMode_str(prealloc));
return -ENOTSUP;
}
max_vdi_size = (UINT64_C(1) << s->inode.block_size_shift) * MAX_DATA_OBJS;
- if (offset < s->inode.vdi_size) {
+ if (offset < old_size) {
error_setg(errp, "shrinking is not supported");
return -EINVAL;
} else if (offset > max_vdi_size) {
@@ -2204,9 +2212,17 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset,
if (ret < 0) {
error_setg_errno(errp, -ret, "failed to update an inode");
+ return ret;
}
- return ret;
+ if (prealloc == PREALLOC_MODE_FULL) {
+ ret = sd_prealloc(bs, old_size, offset, errp);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ return 0;
}
/*
diff --git a/blockdev.c b/blockdev.c
index bdbdeae7e4..3fb1ca803c 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2825,14 +2825,9 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
if (!has_persistent) {
persistent = false;
}
- if (!has_autoload) {
- autoload = false;
- }
- if (has_autoload && !persistent) {
- error_setg(errp, "Autoload flag must be used only for persistent "
- "bitmaps");
- return;
+ if (has_autoload) {
+ warn_report("Autoload option is deprecated and its value is ignored");
}
if (persistent &&
@@ -2847,7 +2842,6 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
}
bdrv_dirty_bitmap_set_persistance(bitmap, persistent);
- bdrv_dirty_bitmap_set_autoload(bitmap, autoload);
}
void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
@@ -3569,6 +3563,11 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
return;
}
+ /* Early check to avoid creating target */
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR_SOURCE, errp)) {
+ return;
+ }
+
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
diff --git a/docs/qemu-block-drivers.texi b/docs/qemu-block-drivers.texi
index cd74767ed3..f1793692bb 100644
--- a/docs/qemu-block-drivers.texi
+++ b/docs/qemu-block-drivers.texi
@@ -845,6 +845,16 @@ QEMU transparently handles lock handover during shared storage migration. For
shared virtual disk images between multiple VMs, the "share-rw" device option
should be used.
+By default, the guest has exclusive write access to its disk image. If the
+guest can safely share the disk image with other writers the @code{-device
+...,share-rw=on} parameter can be used. This is only safe if the guest is
+running software, such as a cluster file system, that coordinates disk accesses
+to avoid corruption.
+
+Note that share-rw=on only declares the guest's ability to share the disk.
+Some QEMU features, such as image file formats, require exclusive write access
+to the disk image and this is unaffected by the share-rw=on option.
+
Alternatively, locking can be fully disabled by "locking=off" block device
option. In the command line, the option is usually in the form of
"file.locking=off" as the protocol driver is normally placed as a "file" child
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
index 3da8486ab1..e3f4bbf51d 100644
--- a/include/block/dirty-bitmap.h
+++ b/include/block/dirty-bitmap.h
@@ -66,7 +66,6 @@ void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap,
void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_bitmap_set_readonly(BdrvDirtyBitmap *bitmap, bool value);
-void bdrv_dirty_bitmap_set_autoload(BdrvDirtyBitmap *bitmap, bool autoload);
void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap,
bool persistent);
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 8046c2da23..5c5921bfb7 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1593,9 +1593,9 @@
# Qcow2 disks support persistent bitmaps. Default is false for
# block-dirty-bitmap-add. (Since: 2.10)
#
-# @autoload: the bitmap will be automatically loaded when the image it is stored
-# in is opened. This flag may only be specified for persistent
-# bitmaps. Default is false for block-dirty-bitmap-add. (Since: 2.10)
+# @autoload: ignored and deprecated since 2.12.
+# Currently, all dirty tracking bitmaps are loaded from Qcow2 on
+# open.
#
# Since: 2.4
##
@@ -2521,6 +2521,11 @@
# @l2-cache-size: the maximum size of the L2 table cache in
# bytes (since 2.2)
#
+# @l2-cache-entry-size: the size of each entry in the L2 cache in
+# bytes. It must be a power of two between 512
+# and the cluster size. The default value is
+# the cluster size (since 2.12)
+#
# @refcount-cache-size: the maximum size of the refcount block cache
# in bytes (since 2.2)
#
@@ -2542,6 +2547,7 @@
'*overlap-check': 'Qcow2OverlapChecks',
'*cache-size': 'int',
'*l2-cache-size': 'int',
+ '*l2-cache-entry-size': 'int',
'*refcount-cache-size': 'int',
'*cache-clean-interval': 'int',
'*encrypt': 'BlockdevQcow2Encryption' } }
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 769968aba4..137f5814a8 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -2757,6 +2757,13 @@ used and it will be removed with no replacement.
The ``convert -s snapshot_id_or_name'' argument is obsoleted
by the ``convert -l snapshot_param'' argument instead.
+@section QEMU Machine Protocol (QMP) commands
+
+@subsection block-dirty-bitmap-add "autoload" parameter (since 2.12.0)
+
+"autoload" parameter is now ignored. All bitmaps are automatically loaded
+from qcow2 images.
+
@section System emulator human monitor commands
@subsection host_net_add (since 2.10.0)
diff --git a/qemu-img.texi b/qemu-img.texi
index fdcf120f36..8a26400adb 100644
--- a/qemu-img.texi
+++ b/qemu-img.texi
@@ -33,38 +33,14 @@ The following commands are supported:
Command parameters:
@table @var
-@item filename
- is a disk image filename
-
-@item --object @var{objectdef}
-
-is a QEMU user creatable object definition. See the @code{qemu(1)} manual
-page for a description of the object properties. The most common object
-type is a @code{secret}, which is used to supply passwords and/or encryption
-keys.
-
-@item --image-opts
-
-Indicates that the source @var{filename} parameter is to be interpreted as a
-full option string, not a plain filename. This parameter is mutually
-exclusive with the @var{-f} parameter.
-
-@item --target-image-opts
-Indicates that the @var{output_filename} parameter(s) are to be interpreted as
-a full option string, not a plain filename. This parameter is mutually
-exclusive with the @var{-O} parameters. It is currently required to also use
-the @var{-n} parameter to skip image creation. This restriction may be relaxed
-in a future release.
+@item filename
+is a disk image filename
@item fmt
is the disk image format. It is guessed automatically in most cases. See below
for a description of the supported disk formats.
-@item --backing-chain
-will enumerate information about backing files in a disk image chain. Refer
-below for further description.
-
@item size
is the disk image size in bytes. Optional suffixes @code{k} or @code{K}
(kilobyte, 1024) @code{M} (megabyte, 1024k) and @code{G} (gigabyte, 1024M)
@@ -74,42 +50,86 @@ and T (terabyte, 1024G) are supported. @code{b} is ignored.
is the destination disk image filename
@item output_fmt
- is the destination format
+is the destination format
+
@item options
is a comma separated list of format specific options in a
name=value format. Use @code{-o ?} for an overview of the options supported
by the used format or see the format descriptions below for details.
+
@item snapshot_param
is param used for internal snapshot, format is
'snapshot.id=[ID],snapshot.name=[NAME]' or '[ID_OR_NAME]'
+
@item snapshot_id_or_name
is deprecated, use snapshot_param instead
+@end table
+
+@table @option
+
+@item --object @var{objectdef}
+is a QEMU user creatable object definition. See the @code{qemu(1)} manual
+page for a description of the object properties. The most common object
+type is a @code{secret}, which is used to supply passwords and/or encryption
+keys.
+
+@item --image-opts
+Indicates that the source @var{filename} parameter is to be interpreted as a
+full option string, not a plain filename. This parameter is mutually
+exclusive with the @var{-f} parameter.
+
+@item --target-image-opts
+Indicates that the @var{output_filename} parameter(s) are to be interpreted as
+a full option string, not a plain filename. This parameter is mutually
+exclusive with the @var{-O} parameters. It is currently required to also use
+the @var{-n} parameter to skip image creation. This restriction may be relaxed
+in a future release.
+
+@item --force-share (-U)
+If specified, @code{qemu-img} will open the image in shared mode, allowing
+other QEMU processes to open it in write mode. For example, this can be used to
+get the image information (with 'info' subcommand) when the image is used by a
+running guest. Note that this could produce inconsistent results because of
+concurrent metadata changes, etc. This option is only allowed when opening
+images in read-only mode.
+
+@item --backing-chain
+will enumerate information about backing files in a disk image chain. Refer
+below for further description.
+
@item -c
indicates that target image must be compressed (qcow format only)
+
@item -h
with or without a command shows help and lists the supported formats
+
@item -p
display progress bar (compare, convert and rebase commands only).
If the @var{-p} option is not used for a command that supports it, the
progress is reported when the process receives a @code{SIGUSR1} or
@code{SIGINFO} signal.
+
@item -q
Quiet mode - do not print any output (except errors). There's no progress bar
in case both @var{-q} and @var{-p} options are used.
+
@item -S @var{size}
indicates the consecutive number of bytes that must contain only zeros
for qemu-img to create a sparse image during conversion. This value is rounded
down to the nearest 512 bytes. You may use the common size suffixes like
@code{k} for kilobytes.
+
@item -t @var{cache}
specifies the cache mode that should be used with the (destination) file. See
the documentation of the emulator's @code{-drive cache=...} option for allowed
values.
+
@item -T @var{src_cache}
specifies the cache mode that should be used with the source file(s). See
the documentation of the emulator's @code{-drive cache=...} option for allowed
values.
+
@end table
Parameters to snapshot subcommand:
diff --git a/qemu-io.c b/qemu-io.c
index f554ab614b..2c00ea068e 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -11,6 +11,9 @@
#include "qemu/osdep.h"
#include <getopt.h>
#include <libgen.h>
+#ifndef _WIN32
+#include <termios.h>
+#endif
#include "qapi/error.h"
#include "qemu-io.h"
@@ -42,6 +45,26 @@ static bool imageOpts;
static ReadLineState *readline_state;
+static int ttyEOF;
+
+static int get_eof_char(void)
+{
+#ifdef _WIN32
+ return 0x4; /* Ctrl-D */
+#else
+ struct termios tty;
+ if (tcgetattr(STDIN_FILENO, &tty) != 0) {
+ if (errno == ENOTTY) {
+ return 0x0; /* just expect read() == 0 */
+ } else {
+ return 0x4; /* Ctrl-D */
+ }
+ }
+
+ return tty.c_cc[VEOF];
+#endif
+}
+
static int close_f(BlockBackend *blk, int argc, char **argv)
{
blk_unref(qemuio_blk);
@@ -323,7 +346,8 @@ static char *fetchline_readline(void)
readline_start(readline_state, get_prompt(), 0, readline_func, &line);
while (!line) {
int ch = getchar();
- if (ch == EOF) {
+ if (ttyEOF != 0x0 && ch == ttyEOF) {
+ printf("\n");
break;
}
readline_handle_byte(readline_state, ch);
@@ -593,6 +617,7 @@ int main(int argc, char **argv)
qemuio_add_command(&close_cmd);
if (isatty(STDIN_FILENO)) {
+ ttyEOF = get_eof_char();
readline_state = readline_init(readline_printf_func,
readline_flush_func,
NULL,
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
index 6a80be009b..3026714471 100644
--- a/target/m68k/cpu.c
+++ b/target/m68k/cpu.c
@@ -113,6 +113,7 @@ static void m68000_cpu_initfn(Object *obj)
m68k_set_feature(env, M68K_FEATURE_M68000);
m68k_set_feature(env, M68K_FEATURE_USP);
m68k_set_feature(env, M68K_FEATURE_WORD_INDEX);
+ m68k_set_feature(env, M68K_FEATURE_MOVEP);
}
static void m68020_cpu_initfn(Object *obj)
@@ -135,6 +136,7 @@ static void m68020_cpu_initfn(Object *obj)
m68k_set_feature(env, M68K_FEATURE_BKPT);
m68k_set_feature(env, M68K_FEATURE_RTD);
m68k_set_feature(env, M68K_FEATURE_CHK2);
+ m68k_set_feature(env, M68K_FEATURE_MOVEP);
}
#define m68030_cpu_initfn m68020_cpu_initfn
diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index 627fb787b6..1d79885222 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -492,6 +492,7 @@ enum m68k_features {
M68K_FEATURE_RTD,
M68K_FEATURE_CHK2,
M68K_FEATURE_M68040, /* instructions specific to MC68040 */
+ M68K_FEATURE_MOVEP,
};
static inline int m68k_feature(CPUM68KState *env, int feature)
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 34db97b8a0..70c7583621 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -2078,6 +2078,51 @@ DISAS_INSN(movem)
tcg_temp_free(addr);
}
+DISAS_INSN(movep)
+{
+ uint8_t i;
+ int16_t displ;
+ TCGv reg;
+ TCGv addr;
+ TCGv abuf;
+ TCGv dbuf;
+
+ displ = read_im16(env, s);
+
+ addr = AREG(insn, 0);
+ reg = DREG(insn, 9);
+
+ abuf = tcg_temp_new();
+ tcg_gen_addi_i32(abuf, addr, displ);
+ dbuf = tcg_temp_new();
+
+ if (insn & 0x40) {
+ i = 4;
+ } else {
+ i = 2;
+ }
+
+ if (insn & 0x80) {
+ for ( ; i > 0 ; i--) {
+ tcg_gen_shri_i32(dbuf, reg, (i - 1) * 8);
+ tcg_gen_qemu_st8(dbuf, abuf, IS_USER(s));
+ if (i > 1) {
+ tcg_gen_addi_i32(abuf, abuf, 2);
+ }
+ }
+ } else {
+ for ( ; i > 0 ; i--) {
+ tcg_gen_qemu_ld8u(dbuf, abuf, IS_USER(s));
+ tcg_gen_deposit_i32(reg, reg, dbuf, (i - 1) * 8, 8);
+ if (i > 1) {
+ tcg_gen_addi_i32(abuf, abuf, 2);
+ }
+ }
+ }
+ tcg_temp_free(abuf);
+ tcg_temp_free(dbuf);
+}
+
DISAS_INSN(bitop_im)
{
int opsize;
@@ -5678,6 +5723,7 @@ void register_m68k_insns (CPUM68KState *env)
BASE(bitop_reg, 0140, f1c0);
BASE(bitop_reg, 0180, f1c0);
BASE(bitop_reg, 01c0, f1c0);
+ INSN(movep, 0108, f138, MOVEP);
INSN(arith_im, 0280, fff8, CF_ISA_A);
INSN(arith_im, 0200, ff00, M68000);
INSN(undef, 02c0, ffc0, M68000);
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 278c13aa93..a1bcbffe12 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -319,16 +319,15 @@ check-qtest-ppc-y += tests/boot-order-test$(EXESUF)
check-qtest-ppc-y += tests/prom-env-test$(EXESUF)
check-qtest-ppc-y += tests/drive_del-test$(EXESUF)
check-qtest-ppc-y += tests/boot-serial-test$(EXESUF)
+check-qtest-ppc-y += tests/m48t59-test$(EXESUF)
+gcov-files-ppc-y += hw/timer/m48t59.c
-check-qtest-ppc64-y = tests/spapr-phb-test$(EXESUF)
-gcov-files-ppc64-y = ppc64-softmmu/hw/ppc/spapr_pci.c
-check-qtest-ppc64-y += tests/endianness-test$(EXESUF)
-check-qtest-ppc64-y += tests/boot-order-test$(EXESUF)
-check-qtest-ppc64-y += tests/prom-env-test$(EXESUF)
+check-qtest-ppc64-y = $(check-qtest-ppc-y)
+gcov-files-ppc64-y = $(subst ppc-softmmu/,ppc64-softmmu/,$(gcov-files-ppc-y))
+check-qtest-ppc64-y += tests/spapr-phb-test$(EXESUF)
+gcov-files-ppc64-y += ppc64-softmmu/hw/ppc/spapr_pci.c
check-qtest-ppc64-y += tests/pnv-xscom-test$(EXESUF)
-check-qtest-ppc64-y += tests/drive_del-test$(EXESUF)
check-qtest-ppc64-y += tests/migration-test$(EXESUF)
-check-qtest-ppc64-y += tests/boot-serial-test$(EXESUF)
check-qtest-ppc64-y += tests/rtas-test$(EXESUF)
check-qtest-ppc64-$(CONFIG_SLIRP) += tests/pxe-test$(EXESUF)
check-qtest-ppc64-y += tests/usb-hcd-ohci-test$(EXESUF)
@@ -351,13 +350,13 @@ check-qtest-sh4-y = tests/endianness-test$(EXESUF)
check-qtest-sh4eb-y = tests/endianness-test$(EXESUF)
check-qtest-sparc-y = tests/prom-env-test$(EXESUF)
-#check-qtest-sparc-y += tests/m48t59-test$(EXESUF)
-#gcov-files-sparc-y = hw/timer/m48t59.c
+check-qtest-sparc-y += tests/m48t59-test$(EXESUF)
+gcov-files-sparc-y = hw/timer/m48t59.c
+check-qtest-sparc-y += tests/boot-serial-test$(EXESUF)
check-qtest-sparc64-y = tests/endianness-test$(EXESUF)
-#check-qtest-sparc64-y += tests/m48t59-test$(EXESUF)
-#gcov-files-sparc64-y += hw/timer/m48t59.c
check-qtest-sparc64-y += tests/prom-env-test$(EXESUF)
+check-qtest-sparc64-y += tests/boot-serial-test$(EXESUF)
check-qtest-arm-y = tests/tmp105-test$(EXESUF)
check-qtest-arm-y += tests/ds1338-test$(EXESUF)
@@ -372,6 +371,7 @@ check-qtest-arm-y += tests/sdhci-test$(EXESUF)
check-qtest-aarch64-y = tests/numa-test$(EXESUF)
check-qtest-aarch64-y += tests/sdhci-test$(EXESUF)
+check-qtest-aarch64-y += tests/boot-serial-test$(EXESUF)
check-qtest-microblazeel-y = $(check-qtest-microblaze-y)
diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 7aa5af428c..2342fe3099 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -158,10 +158,11 @@ static AHCIQState *ahci_vboot(const char *cli, va_list ap)
s = g_new0(AHCIQState, 1);
s->parent = qtest_pc_vboot(cli, ap);
+ global_qtest = s->parent->qts;
alloc_set_flags(s->parent->alloc, ALLOC_LEAK_ASSERT);
/* Verify that we have an AHCI device present. */
- s->dev = get_ahci_device(&s->fingerprint);
+ s->dev = get_ahci_device(s->parent->qts, &s->fingerprint);
return s;
}
diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c
index 2b332ed3c1..65b271a173 100644
--- a/tests/bios-tables-test.c
+++ b/tests/bios-tables-test.c
@@ -668,7 +668,7 @@ static void test_acpi_one(const char *params, test_data *data)
qtest_start(args);
- boot_sector_test();
+ boot_sector_test(global_qtest);
data->tables = g_array_new(false, true, sizeof(AcpiSdtTable));
test_acpi_rsdp_address(data);
diff --git a/tests/boot-order-test.c b/tests/boot-order-test.c
index 60c5545e45..e70f5dedba 100644
--- a/tests/boot-order-test.c
+++ b/tests/boot-order-test.c
@@ -41,7 +41,7 @@ static void test_a_boot_order(const char *machine,
* system_reset only requests reset. We get a RESET event after
* the actual reset completes. Need to wait for that.
*/
- qmp_discard_response(""); /* HACK: wait for event */
+ qmp_eventwait("RESET");
actual = read_boot_order();
g_assert_cmphex(actual, ==, expected_reboot);
qtest_quit(global_qtest);
@@ -132,7 +132,7 @@ static void test_prep_boot_order(void)
static uint64_t read_boot_order_pmac(void)
{
- QFWCFG *fw_cfg = mm_fw_cfg_init(0xf0000510);
+ QFWCFG *fw_cfg = mm_fw_cfg_init(global_qtest, 0xf0000510);
return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE);
}
@@ -157,7 +157,7 @@ static void test_pmac_newworld_boot_order(void)
static uint64_t read_boot_order_sun4m(void)
{
- QFWCFG *fw_cfg = mm_fw_cfg_init(0xd00000510ULL);
+ QFWCFG *fw_cfg = mm_fw_cfg_init(global_qtest, 0xd00000510ULL);
return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE);
}
@@ -169,7 +169,7 @@ static void test_sun4m_boot_order(void)
static uint64_t read_boot_order_sun4u(void)
{
- QFWCFG *fw_cfg = io_fw_cfg_init(0x510);
+ QFWCFG *fw_cfg = io_fw_cfg_init(global_qtest, 0x510);
return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE);
}
diff --git a/tests/boot-sector.c b/tests/boot-sector.c
index be29d5bb9b..c373f0e715 100644
--- a/tests/boot-sector.c
+++ b/tests/boot-sector.c
@@ -5,7 +5,7 @@
*
* Authors:
* Michael S. Tsirkin <mst@redhat.com>
- * Victor Kaplansky <victork@redhat.com>
+ * Victor Kaplansky <victork@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
@@ -130,7 +130,7 @@ int boot_sector_init(char *fname)
}
/* Loop until signature in memory is OK. */
-void boot_sector_test(void)
+void boot_sector_test(QTestState *qts)
{
uint8_t signature_low;
uint8_t signature_high;
@@ -146,8 +146,8 @@ void boot_sector_test(void)
* instruction.
*/
for (i = 0; i < TEST_CYCLES; ++i) {
- signature_low = readb(SIGNATURE_ADDR);
- signature_high = readb(SIGNATURE_ADDR + 1);
+ signature_low = qtest_readb(qts, SIGNATURE_ADDR);
+ signature_high = qtest_readb(qts, SIGNATURE_ADDR + 1);
signature = (signature_high << 8) | signature_low;
if (signature == SIGNATURE) {
break;
diff --git a/tests/boot-sector.h b/tests/boot-sector.h
index 35d61c7e2b..6ee6bb4d97 100644
--- a/tests/boot-sector.h
+++ b/tests/boot-sector.h
@@ -5,7 +5,7 @@
*
* Authors:
* Michael S. Tsirkin <mst@redhat.com>
- * Victor Kaplansky <victork@redhat.com>
+ * Victor Kaplansky <victork@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
@@ -14,11 +14,13 @@
#ifndef TEST_BOOT_SECTOR_H
#define TEST_BOOT_SECTOR_H
+#include "libqtest.h"
+
/* Create boot disk file. fname must be a suitable string for mkstemp() */
int boot_sector_init(char *fname);
/* Loop until signature in memory is OK. */
-void boot_sector_test(void);
+void boot_sector_test(QTestState *qts);
/* unlink boot disk file. */
void boot_sector_cleanup(const char *fname);
diff --git a/tests/boot-serial-test.c b/tests/boot-serial-test.c
index ea87a80be7..511bf314a3 100644
--- a/tests/boot-serial-test.c
+++ b/tests/boot-serial-test.c
@@ -55,6 +55,13 @@ static const uint8_t bios_raspi2[] = {
0x00, 0x10, 0x20, 0x3f, /* 0x3f201000 = UART0 base addr */
};
+static const uint8_t kernel_aarch64[] = {
+ 0x81, 0x0a, 0x80, 0x52, /* mov w1, #0x54 */
+ 0x02, 0x20, 0xa1, 0xd2, /* mov x2, #0x9000000 */
+ 0x41, 0x00, 0x00, 0x39, /* strb w1, [x2] */
+ 0xfd, 0xff, 0xff, 0x17, /* b -12 (loop) */
+};
+
typedef struct testdef {
const char *arch; /* Target architecture */
const char *machine; /* Name of the machine */
@@ -69,8 +76,11 @@ static testdef_t tests[] = {
{ "alpha", "clipper", "", "PCI:" },
{ "ppc", "ppce500", "", "U-Boot" },
{ "ppc", "prep", "", "Open Hack'Ware BIOS" },
+ { "ppc", "g3beige", "", "PowerPC,750" },
+ { "ppc", "mac99", "", "PowerPC,G4" },
{ "ppc64", "ppce500", "", "U-Boot" },
{ "ppc64", "prep", "", "Open Hack'Ware BIOS" },
+ { "ppc64", "mac99", "", "PowerPC,970FX" },
{ "ppc64", "pseries", "", "Open Firmware" },
{ "ppc64", "powernv", "-cpu POWER8", "OPAL" },
{ "i386", "isapc", "-cpu qemu32 -device sga", "SGABIOS" },
@@ -78,6 +88,10 @@ static testdef_t tests[] = {
{ "i386", "q35", "-device sga", "SGABIOS" },
{ "x86_64", "isapc", "-cpu qemu32 -device sga", "SGABIOS" },
{ "x86_64", "q35", "-device sga", "SGABIOS" },
+ { "sparc", "LX", "", "TMS390S10" },
+ { "sparc", "SS-4", "", "MB86904" },
+ { "sparc", "SS-600MP", "", "TMS390Z55" },
+ { "sparc64", "sun4u", "", "UltraSPARC" },
{ "s390x", "s390-ccw-virtio",
"-nodefaults -device sclpconsole,chardev=serial0", "virtio device" },
{ "m68k", "mcf5208evb", "", "TT", sizeof(kernel_mcf5208), kernel_mcf5208 },
@@ -88,6 +102,8 @@ static testdef_t tests[] = {
{ "moxie", "moxiesim", "", "TT", sizeof(bios_moxiesim), 0, bios_moxiesim },
{ "arm", "raspi2", "", "TT", sizeof(bios_raspi2), 0, bios_raspi2 },
{ "hppa", "hppa", "", "SeaBIOS wants SYSTEM HALT" },
+ { "aarch64", "virt", "-cpu cortex-a57", "TT", sizeof(kernel_aarch64),
+ kernel_aarch64 },
{ NULL }
};
diff --git a/tests/ds1338-test.c b/tests/ds1338-test.c
index 26968bc82a..742dad9113 100644
--- a/tests/ds1338-test.c
+++ b/tests/ds1338-test.c
@@ -61,16 +61,14 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
s = qtest_start("-display none -machine imx25-pdk");
- i2c = imx_i2c_create(IMX25_I2C_0_BASE);
+ i2c = imx_i2c_create(s, IMX25_I2C_0_BASE);
addr = DS1338_ADDR;
qtest_add_func("/ds1338/tx-rx", send_and_receive);
ret = g_test_run();
- if (s) {
- qtest_quit(s);
- }
+ qtest_quit(s);
g_free(i2c);
return ret;
diff --git a/tests/e1000e-test.c b/tests/e1000e-test.c
index c612dc64ec..32aa738b72 100644
--- a/tests/e1000e-test.c
+++ b/tests/e1000e-test.c
@@ -392,12 +392,12 @@ static void data_test_init(e1000e_device *d)
qtest_start(cmdline);
g_free(cmdline);
- test_bus = qpci_init_pc(NULL);
- g_assert_nonnull(test_bus);
-
- test_alloc = pc_alloc_init();
+ test_alloc = pc_alloc_init(global_qtest);
g_assert_nonnull(test_alloc);
+ test_bus = qpci_init_pc(global_qtest, test_alloc);
+ g_assert_nonnull(test_bus);
+
e1000e_device_init(test_bus, d);
}
diff --git a/tests/fw_cfg-test.c b/tests/fw_cfg-test.c
index 81f45bdfc8..1548bf14b2 100644
--- a/tests/fw_cfg-test.c
+++ b/tests/fw_cfg-test.c
@@ -102,12 +102,13 @@ static void test_fw_cfg_boot_menu(void)
int main(int argc, char **argv)
{
QTestState *s;
- char *cmdline;
int ret;
g_test_init(&argc, &argv, NULL);
- fw_cfg = pc_fw_cfg_init();
+ s = qtest_init("-uuid 4600cb32-38ec-4b2f-8acb-81c6ea54f2d8");
+
+ fw_cfg = pc_fw_cfg_init(s);
qtest_add_func("fw_cfg/signature", test_fw_cfg_signature);
qtest_add_func("fw_cfg/id", test_fw_cfg_id);
@@ -125,15 +126,9 @@ int main(int argc, char **argv)
qtest_add_func("fw_cfg/numa", test_fw_cfg_numa);
qtest_add_func("fw_cfg/boot_menu", test_fw_cfg_boot_menu);
- cmdline = g_strdup_printf("-uuid 4600cb32-38ec-4b2f-8acb-81c6ea54f2d8 ");
- s = qtest_start(cmdline);
- g_free(cmdline);
-
ret = g_test_run();
- if (s) {
- qtest_quit(s);
- }
+ qtest_quit(s);
return ret;
}
diff --git a/tests/i440fx-test.c b/tests/i440fx-test.c
index e9d05c87d1..4390e5591e 100644
--- a/tests/i440fx-test.c
+++ b/tests/i440fx-test.c
@@ -38,7 +38,7 @@ static QPCIBus *test_start_get_bus(const TestData *s)
cmdline = g_strdup_printf("-smp %d", s->num_cpus);
qtest_start(cmdline);
g_free(cmdline);
- return qpci_init_pc(NULL);
+ return qpci_init_pc(global_qtest, NULL);
}
static void test_i440fx_defaults(gconstpointer opaque)
diff --git a/tests/ide-test.c b/tests/ide-test.c
index be427e41d6..2384c2c3e2 100644
--- a/tests/ide-test.c
+++ b/tests/ide-test.c
@@ -132,7 +132,7 @@ static void ide_test_start(const char *cmdline_fmt, ...)
va_end(ap);
qtest_start(cmdline);
- guest_malloc = pc_alloc_init();
+ guest_malloc = pc_alloc_init(global_qtest);
g_free(cmdline);
}
@@ -150,7 +150,7 @@ static QPCIDevice *get_pci_device(QPCIBar *bmdma_bar, QPCIBar *ide_bar)
uint16_t vendor_id, device_id;
if (!pcibus) {
- pcibus = qpci_init_pc(NULL);
+ pcibus = qpci_init_pc(global_qtest, NULL);
}
/* Find PCI device and verify it's the right one */
diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c
index 37763425ee..8af16ee79a 100644
--- a/tests/ivshmem-test.c
+++ b/tests/ivshmem-test.c
@@ -131,6 +131,7 @@ static void setup_vm_cmd(IVState *s, const char *cmd, bool msix)
g_printerr("ivshmem-test tests are only available on x86 or ppc64\n");
exit(EXIT_FAILURE);
}
+ global_qtest = s->qs->qts;
s->dev = get_device(s->qs->pcibus);
s->reg_bar = qpci_iomap(s->dev, 0, &barsize);
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index 13c0749582..bc201d762b 100644
--- a/tests/libqos/ahci.c
+++ b/tests/libqos/ahci.c
@@ -123,13 +123,13 @@ bool is_atapi(AHCIQState *ahci, uint8_t port)
/**
* Locate, verify, and return a handle to the AHCI device.
*/
-QPCIDevice *get_ahci_device(uint32_t *fingerprint)
+QPCIDevice *get_ahci_device(QTestState *qts, uint32_t *fingerprint)
{
QPCIDevice *ahci;
uint32_t ahci_fingerprint;
QPCIBus *pcibus;
- pcibus = qpci_init_pc(NULL);
+ pcibus = qpci_init_pc(qts, NULL);
/* Find the AHCI PCI device and verify it's the right one. */
ahci = qpci_device_find(pcibus, QPCI_DEVFN(0x1F, 0x02));
@@ -283,7 +283,8 @@ void ahci_hba_enable(AHCIQState *ahci)
/* Allocate Memory for the Command List Buffer & FIS Buffer */
/* PxCLB space ... 0x20 per command, as in 4.2.2 p 36 */
ahci->port[i].clb = ahci_alloc(ahci, num_cmd_slots * 0x20);
- qmemset(ahci->port[i].clb, 0x00, num_cmd_slots * 0x20);
+ qtest_memset(ahci->parent->qts, ahci->port[i].clb, 0x00,
+ num_cmd_slots * 0x20);
g_test_message("CLB: 0x%08" PRIx64, ahci->port[i].clb);
ahci_px_wreg(ahci, i, AHCI_PX_CLB, ahci->port[i].clb);
g_assert_cmphex(ahci->port[i].clb, ==,
@@ -291,7 +292,7 @@ void ahci_hba_enable(AHCIQState *ahci)
/* PxFB space ... 0x100, as in 4.2.1 p 35 */
ahci->port[i].fb = ahci_alloc(ahci, 0x100);
- qmemset(ahci->port[i].fb, 0x00, 0x100);
+ qtest_memset(ahci->parent->qts, ahci->port[i].fb, 0x00, 0x100);
g_test_message("FB: 0x%08" PRIx64, ahci->port[i].fb);
ahci_px_wreg(ahci, i, AHCI_PX_FB, ahci->port[i].fb);
g_assert_cmphex(ahci->port[i].fb, ==,
@@ -397,7 +398,7 @@ void ahci_port_clear(AHCIQState *ahci, uint8_t port)
g_assert_cmphex(ahci_px_rreg(ahci, port, AHCI_PX_IS), ==, 0);
/* Wipe the FIS-Receive Buffer */
- qmemset(ahci->port[port].fb, 0x00, 0x100);
+ qtest_memset(ahci->parent->qts, ahci->port[port].fb, 0x00, 0x100);
}
/**
@@ -466,7 +467,7 @@ void ahci_port_check_d2h_sanity(AHCIQState *ahci, uint8_t port, uint8_t slot)
RegD2HFIS *d2h = g_malloc0(0x20);
uint32_t reg;
- memread(ahci->port[port].fb + 0x40, d2h, 0x20);
+ qtest_memread(ahci->parent->qts, ahci->port[port].fb + 0x40, d2h, 0x20);
g_assert_cmphex(d2h->fis_type, ==, 0x34);
reg = ahci_px_rreg(ahci, port, AHCI_PX_TFD);
@@ -484,7 +485,7 @@ void ahci_port_check_pio_sanity(AHCIQState *ahci, uint8_t port,
/* We cannot check the Status or E_Status registers, because
* the status may have again changed between the PIO Setup FIS
* and the conclusion of the command with the D2H Register FIS. */
- memread(ahci->port[port].fb + 0x20, pio, 0x20);
+ qtest_memread(ahci->parent->qts, ahci->port[port].fb + 0x20, pio, 0x20);
g_assert_cmphex(pio->fis_type, ==, 0x5f);
/* BUG: PIO Setup FIS as utilized by QEMU tries to fit the entire
@@ -516,7 +517,7 @@ void ahci_get_command_header(AHCIQState *ahci, uint8_t port,
{
uint64_t ba = ahci->port[port].clb;
ba += slot * sizeof(AHCICommandHeader);
- memread(ba, cmd, sizeof(AHCICommandHeader));
+ qtest_memread(ahci->parent->qts, ba, cmd, sizeof(AHCICommandHeader));
cmd->flags = le16_to_cpu(cmd->flags);
cmd->prdtl = le16_to_cpu(cmd->prdtl);
@@ -537,7 +538,7 @@ void ahci_set_command_header(AHCIQState *ahci, uint8_t port,
tmp.prdbc = cpu_to_le32(cmd->prdbc);
tmp.ctba = cpu_to_le64(cmd->ctba);
- memwrite(ba, &tmp, sizeof(AHCICommandHeader));
+ qtest_memwrite(ahci->parent->qts, ba, &tmp, sizeof(AHCICommandHeader));
}
void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot)
@@ -575,7 +576,7 @@ void ahci_write_fis(AHCIQState *ahci, AHCICommand *cmd)
tmp.count = cpu_to_le16(tmp.count);
}
- memwrite(addr, &tmp, sizeof(tmp));
+ qtest_memwrite(ahci->parent->qts, addr, &tmp, sizeof(tmp));
}
unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port)
@@ -636,7 +637,7 @@ void ahci_exec(AHCIQState *ahci, uint8_t port,
if (opts->size && !opts->buffer) {
opts->buffer = ahci_alloc(ahci, opts->size);
g_assert(opts->buffer);
- qmemset(opts->buffer, 0x00, opts->size);
+ qtest_memset(ahci->parent->qts, opts->buffer, 0x00, opts->size);
}
/* Command creation */
@@ -661,15 +662,15 @@ void ahci_exec(AHCIQState *ahci, uint8_t port,
ahci_command_commit(ahci, cmd, port);
ahci_command_issue_async(ahci, cmd);
if (opts->error) {
- qmp_eventwait("STOP");
+ qtest_qmp_eventwait(ahci->parent->qts, "STOP");
}
if (opts->mid_cb) {
rc = opts->mid_cb(ahci, cmd, opts);
g_assert_cmpint(rc, ==, 0);
}
if (opts->error) {
- qmp_async("{'execute':'cont' }");
- qmp_eventwait("RESUME");
+ qtest_async_qmp(ahci->parent->qts, "{'execute':'cont' }");
+ qtest_qmp_eventwait(ahci->parent->qts, "RESUME");
}
/* Wait for command to complete and verify sanity */
@@ -697,7 +698,7 @@ AHCICommand *ahci_guest_io_halt(AHCIQState *ahci, uint8_t port,
ahci_command_adjust(cmd, sector, buffer, bufsize, 0);
ahci_command_commit(ahci, cmd, port);
ahci_command_issue_async(ahci, cmd);
- qmp_eventwait("STOP");
+ qtest_qmp_eventwait(ahci->parent->qts, "STOP");
return cmd;
}
@@ -706,8 +707,8 @@ AHCICommand *ahci_guest_io_halt(AHCIQState *ahci, uint8_t port,
void ahci_guest_io_resume(AHCIQState *ahci, AHCICommand *cmd)
{
/* Complete the command */
- qmp_async("{'execute':'cont' }");
- qmp_eventwait("RESUME");
+ qtest_async_qmp(ahci->parent->qts, "{'execute':'cont' }");
+ qtest_qmp_eventwait(ahci->parent->qts, "RESUME");
ahci_command_wait(ahci, cmd);
ahci_command_verify(ahci, cmd);
ahci_command_free(cmd);
@@ -754,16 +755,16 @@ void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd,
g_assert(props);
ptr = ahci_alloc(ahci, bufsize);
g_assert(!bufsize || ptr);
- qmemset(ptr, 0x00, bufsize);
+ qtest_memset(ahci->parent->qts, ptr, 0x00, bufsize);
if (bufsize && props->write) {
- bufwrite(ptr, buffer, bufsize);
+ qtest_bufwrite(ahci->parent->qts, ptr, buffer, bufsize);
}
ahci_guest_io(ahci, port, ide_cmd, ptr, bufsize, sector);
if (bufsize && props->read) {
- bufread(ptr, buffer, bufsize);
+ qtest_bufread(ahci->parent->qts, ptr, buffer, bufsize);
}
ahci_free(ahci, ptr);
@@ -901,7 +902,7 @@ static int copy_buffer(AHCIQState *ahci, AHCICommand *cmd,
const AHCIOpts *opts)
{
unsigned char *rx = opts->opaque;
- bufread(opts->buffer, rx, opts->size);
+ qtest_bufread(ahci->parent->qts, opts->buffer, rx, opts->size);
return 0;
}
@@ -1141,7 +1142,7 @@ void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port)
ahci_write_fis(ahci, cmd);
/* Then ATAPI CMD, if needed */
if (cmd->props->atapi) {
- memwrite(table_ptr + 0x40, cmd->atapi_cmd, 16);
+ qtest_memwrite(ahci->parent->qts, table_ptr + 0x40, cmd->atapi_cmd, 16);
}
/* Construct and write the PRDs to the command table */
@@ -1162,8 +1163,8 @@ void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port)
prd.dbc |= cpu_to_le32(0x80000000); /* Request DPS Interrupt */
/* Commit the PRD entry to the Command Table */
- memwrite(table_ptr + 0x80 + (i * sizeof(PRD)),
- &prd, sizeof(PRD));
+ qtest_memwrite(ahci->parent->qts, table_ptr + 0x80 + (i * sizeof(PRD)),
+ &prd, sizeof(PRD));
}
/* Bookmark the PRDTL and CTBA values */
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index 5f9627bb0f..715ca1e226 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -571,7 +571,7 @@ void ahci_free(AHCIQState *ahci, uint64_t addr);
void ahci_clean_mem(AHCIQState *ahci);
/* Device management */
-QPCIDevice *get_ahci_device(uint32_t *fingerprint);
+QPCIDevice *get_ahci_device(QTestState *qts, uint32_t *fingerprint);
void free_ahci_device(QPCIDevice *dev);
void ahci_pci_enable(AHCIQState *ahci);
void start_ahci_device(AHCIQState *ahci);
diff --git a/tests/libqos/fw_cfg.c b/tests/libqos/fw_cfg.c
index 4d9dc3fd0b..d0889d1e22 100644
--- a/tests/libqos/fw_cfg.c
+++ b/tests/libqos/fw_cfg.c
@@ -56,7 +56,7 @@ uint64_t qfw_cfg_get_u64(QFWCFG *fw_cfg, uint16_t key)
static void mm_fw_cfg_select(QFWCFG *fw_cfg, uint16_t key)
{
- writew(fw_cfg->base, key);
+ qtest_writew(fw_cfg->qts, fw_cfg->base, key);
}
static void mm_fw_cfg_read(QFWCFG *fw_cfg, void *data, size_t len)
@@ -65,15 +65,16 @@ static void mm_fw_cfg_read(QFWCFG *fw_cfg, void *data, size_t len)
int i;
for (i = 0; i < len; i++) {
- ptr[i] = readb(fw_cfg->base + 2);
+ ptr[i] = qtest_readb(fw_cfg->qts, fw_cfg->base + 2);
}
}
-QFWCFG *mm_fw_cfg_init(uint64_t base)
+QFWCFG *mm_fw_cfg_init(QTestState *qts, uint64_t base)
{
QFWCFG *fw_cfg = g_malloc0(sizeof(*fw_cfg));
fw_cfg->base = base;
+ fw_cfg->qts = qts;
fw_cfg->select = mm_fw_cfg_select;
fw_cfg->read = mm_fw_cfg_read;
@@ -82,7 +83,7 @@ QFWCFG *mm_fw_cfg_init(uint64_t base)
static void io_fw_cfg_select(QFWCFG *fw_cfg, uint16_t key)
{
- outw(fw_cfg->base, key);
+ qtest_outw(fw_cfg->qts, fw_cfg->base, key);
}
static void io_fw_cfg_read(QFWCFG *fw_cfg, void *data, size_t len)
@@ -91,15 +92,16 @@ static void io_fw_cfg_read(QFWCFG *fw_cfg, void *data, size_t len)
int i;
for (i = 0; i < len; i++) {
- ptr[i] = inb(fw_cfg->base + 1);
+ ptr[i] = qtest_inb(fw_cfg->qts, fw_cfg->base + 1);
}
}
-QFWCFG *io_fw_cfg_init(uint16_t base)
+QFWCFG *io_fw_cfg_init(QTestState *qts, uint16_t base)
{
QFWCFG *fw_cfg = g_malloc0(sizeof(*fw_cfg));
fw_cfg->base = base;
+ fw_cfg->qts = qts;
fw_cfg->select = io_fw_cfg_select;
fw_cfg->read = io_fw_cfg_read;
diff --git a/tests/libqos/fw_cfg.h b/tests/libqos/fw_cfg.h
index e8371b2317..0353416af0 100644
--- a/tests/libqos/fw_cfg.h
+++ b/tests/libqos/fw_cfg.h
@@ -13,12 +13,14 @@
#ifndef LIBQOS_FW_CFG_H
#define LIBQOS_FW_CFG_H
+#include "libqtest.h"
typedef struct QFWCFG QFWCFG;
struct QFWCFG
{
uint64_t base;
+ QTestState *qts;
void (*select)(QFWCFG *fw_cfg, uint16_t key);
void (*read)(QFWCFG *fw_cfg, void *data, size_t len);
};
@@ -30,12 +32,12 @@ uint16_t qfw_cfg_get_u16(QFWCFG *fw_cfg, uint16_t key);
uint32_t qfw_cfg_get_u32(QFWCFG *fw_cfg, uint16_t key);
uint64_t qfw_cfg_get_u64(QFWCFG *fw_cfg, uint16_t key);
-QFWCFG *mm_fw_cfg_init(uint64_t base);
-QFWCFG *io_fw_cfg_init(uint16_t base);
+QFWCFG *mm_fw_cfg_init(QTestState *qts, uint64_t base);
+QFWCFG *io_fw_cfg_init(QTestState *qts, uint16_t base);
-static inline QFWCFG *pc_fw_cfg_init(void)
+static inline QFWCFG *pc_fw_cfg_init(QTestState *qts)
{
- return io_fw_cfg_init(0x510);
+ return io_fw_cfg_init(qts, 0x510);
}
#endif
diff --git a/tests/libqos/i2c-imx.c b/tests/libqos/i2c-imx.c
index 1c4b4314ba..0945f2ecdc 100644
--- a/tests/libqos/i2c-imx.c
+++ b/tests/libqos/i2c-imx.c
@@ -40,8 +40,8 @@ typedef struct IMXI2C {
static void imx_i2c_set_slave_addr(IMXI2C *s, uint8_t addr,
enum IMXI2CDirection direction)
{
- writeb(s->addr + I2DR_ADDR, (addr << 1) |
- (direction == IMX_I2C_READ ? 1 : 0));
+ qtest_writeb(s->parent.qts, s->addr + I2DR_ADDR,
+ (addr << 1) | (direction == IMX_I2C_READ ? 1 : 0));
}
static void imx_i2c_send(I2CAdapter *i2c, uint8_t addr,
@@ -63,35 +63,35 @@ static void imx_i2c_send(I2CAdapter *i2c, uint8_t addr,
I2CR_MTX |
I2CR_TXAK;
- writeb(s->addr + I2CR_ADDR, data);
- status = readb(s->addr + I2SR_ADDR);
+ qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data);
+ status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
g_assert((status & I2SR_IBB) != 0);
/* set the slave address */
imx_i2c_set_slave_addr(s, addr, IMX_I2C_WRITE);
- status = readb(s->addr + I2SR_ADDR);
+ status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
g_assert((status & I2SR_IIF) != 0);
g_assert((status & I2SR_RXAK) == 0);
/* ack the interrupt */
- writeb(s->addr + I2SR_ADDR, 0);
- status = readb(s->addr + I2SR_ADDR);
+ qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0);
+ status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
g_assert((status & I2SR_IIF) == 0);
while (size < len) {
/* check we are still busy */
- status = readb(s->addr + I2SR_ADDR);
+ status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
g_assert((status & I2SR_IBB) != 0);
/* write the data */
- writeb(s->addr + I2DR_ADDR, buf[size]);
- status = readb(s->addr + I2SR_ADDR);
+ qtest_writeb(i2c->qts, s->addr + I2DR_ADDR, buf[size]);
+ status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
g_assert((status & I2SR_IIF) != 0);
g_assert((status & I2SR_RXAK) == 0);
/* ack the interrupt */
- writeb(s->addr + I2SR_ADDR, 0);
- status = readb(s->addr + I2SR_ADDR);
+ qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0);
+ status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
g_assert((status & I2SR_IIF) == 0);
size++;
@@ -99,8 +99,8 @@ static void imx_i2c_send(I2CAdapter *i2c, uint8_t addr,
/* release the bus */
data &= ~(I2CR_MSTA | I2CR_MTX);
- writeb(s->addr + I2CR_ADDR, data);
- status = readb(s->addr + I2SR_ADDR);
+ qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data);
+ status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
g_assert((status & I2SR_IBB) == 0);
}
@@ -123,19 +123,19 @@ static void imx_i2c_recv(I2CAdapter *i2c, uint8_t addr,
I2CR_MTX |
I2CR_TXAK;
- writeb(s->addr + I2CR_ADDR, data);
- status = readb(s->addr + I2SR_ADDR);
+ qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data);
+ status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
g_assert((status & I2SR_IBB) != 0);
/* set the slave address */
imx_i2c_set_slave_addr(s, addr, IMX_I2C_READ);
- status = readb(s->addr + I2SR_ADDR);
+ status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
g_assert((status & I2SR_IIF) != 0);
g_assert((status & I2SR_RXAK) == 0);
/* ack the interrupt */
- writeb(s->addr + I2SR_ADDR, 0);
- status = readb(s->addr + I2SR_ADDR);
+ qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0);
+ status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
g_assert((status & I2SR_IIF) == 0);
/* set the bus for read */
@@ -144,23 +144,23 @@ static void imx_i2c_recv(I2CAdapter *i2c, uint8_t addr,
if (len != 1) {
data &= ~I2CR_TXAK;
}
- writeb(s->addr + I2CR_ADDR, data);
- status = readb(s->addr + I2SR_ADDR);
+ qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data);
+ status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
g_assert((status & I2SR_IBB) != 0);
/* dummy read */
- readb(s->addr + I2DR_ADDR);
- status = readb(s->addr + I2SR_ADDR);
+ qtest_readb(i2c->qts, s->addr + I2DR_ADDR);
+ status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
g_assert((status & I2SR_IIF) != 0);
/* ack the interrupt */
- writeb(s->addr + I2SR_ADDR, 0);
- status = readb(s->addr + I2SR_ADDR);
+ qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0);
+ status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
g_assert((status & I2SR_IIF) == 0);
while (size < len) {
/* check we are still busy */
- status = readb(s->addr + I2SR_ADDR);
+ status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
g_assert((status & I2SR_IBB) != 0);
if (size == (len - 1)) {
@@ -170,30 +170,30 @@ static void imx_i2c_recv(I2CAdapter *i2c, uint8_t addr,
/* ack the data read */
data |= I2CR_TXAK;
}
- writeb(s->addr + I2CR_ADDR, data);
+ qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data);
/* read the data */
- buf[size] = readb(s->addr + I2DR_ADDR);
+ buf[size] = qtest_readb(i2c->qts, s->addr + I2DR_ADDR);
if (size != (len - 1)) {
- status = readb(s->addr + I2SR_ADDR);
+ status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
g_assert((status & I2SR_IIF) != 0);
/* ack the interrupt */
- writeb(s->addr + I2SR_ADDR, 0);
+ qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0);
}
- status = readb(s->addr + I2SR_ADDR);
+ status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
g_assert((status & I2SR_IIF) == 0);
size++;
}
- status = readb(s->addr + I2SR_ADDR);
+ status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
g_assert((status & I2SR_IBB) == 0);
}
-I2CAdapter *imx_i2c_create(uint64_t addr)
+I2CAdapter *imx_i2c_create(QTestState *qts, uint64_t addr)
{
IMXI2C *s = g_malloc0(sizeof(*s));
I2CAdapter *i2c = (I2CAdapter *)s;
@@ -202,6 +202,7 @@ I2CAdapter *imx_i2c_create(uint64_t addr)
i2c->send = imx_i2c_send;
i2c->recv = imx_i2c_recv;
+ i2c->qts = qts;
return i2c;
}
diff --git a/tests/libqos/i2c-omap.c b/tests/libqos/i2c-omap.c
index f603fdf43c..1ef6e7b200 100644
--- a/tests/libqos/i2c-omap.c
+++ b/tests/libqos/i2c-omap.c
@@ -51,8 +51,8 @@ static void omap_i2c_set_slave_addr(OMAPI2C *s, uint8_t addr)
{
uint16_t data = addr;
- writew(s->addr + OMAP_I2C_SA, data);
- data = readw(s->addr + OMAP_I2C_SA);
+ qtest_writew(s->parent.qts, s->addr + OMAP_I2C_SA, data);
+ data = qtest_readw(s->parent.qts, s->addr + OMAP_I2C_SA);
g_assert_cmphex(data, ==, addr);
}
@@ -65,38 +65,38 @@ static void omap_i2c_send(I2CAdapter *i2c, uint8_t addr,
omap_i2c_set_slave_addr(s, addr);
data = len;
- writew(s->addr + OMAP_I2C_CNT, data);
+ qtest_writew(i2c->qts, s->addr + OMAP_I2C_CNT, data);
data = OMAP_I2C_CON_I2C_EN |
OMAP_I2C_CON_TRX |
OMAP_I2C_CON_MST |
OMAP_I2C_CON_STT |
OMAP_I2C_CON_STP;
- writew(s->addr + OMAP_I2C_CON, data);
- data = readw(s->addr + OMAP_I2C_CON);
+ qtest_writew(i2c->qts, s->addr + OMAP_I2C_CON, data);
+ data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_CON);
g_assert((data & OMAP_I2C_CON_STP) != 0);
- data = readw(s->addr + OMAP_I2C_STAT);
+ data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_STAT);
g_assert((data & OMAP_I2C_STAT_NACK) == 0);
while (len > 1) {
- data = readw(s->addr + OMAP_I2C_STAT);
+ data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_STAT);
g_assert((data & OMAP_I2C_STAT_XRDY) != 0);
data = buf[0] | ((uint16_t)buf[1] << 8);
- writew(s->addr + OMAP_I2C_DATA, data);
+ qtest_writew(i2c->qts, s->addr + OMAP_I2C_DATA, data);
buf = (uint8_t *)buf + 2;
len -= 2;
}
if (len == 1) {
- data = readw(s->addr + OMAP_I2C_STAT);
+ data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_STAT);
g_assert((data & OMAP_I2C_STAT_XRDY) != 0);
data = buf[0];
- writew(s->addr + OMAP_I2C_DATA, data);
+ qtest_writew(i2c->qts, s->addr + OMAP_I2C_DATA, data);
}
- data = readw(s->addr + OMAP_I2C_CON);
+ data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_CON);
g_assert((data & OMAP_I2C_CON_STP) == 0);
}
@@ -109,30 +109,30 @@ static void omap_i2c_recv(I2CAdapter *i2c, uint8_t addr,
omap_i2c_set_slave_addr(s, addr);
data = len;
- writew(s->addr + OMAP_I2C_CNT, data);
+ qtest_writew(i2c->qts, s->addr + OMAP_I2C_CNT, data);
data = OMAP_I2C_CON_I2C_EN |
OMAP_I2C_CON_MST |
OMAP_I2C_CON_STT |
OMAP_I2C_CON_STP;
- writew(s->addr + OMAP_I2C_CON, data);
- data = readw(s->addr + OMAP_I2C_CON);
+ qtest_writew(i2c->qts, s->addr + OMAP_I2C_CON, data);
+ data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_CON);
g_assert((data & OMAP_I2C_CON_STP) == 0);
- data = readw(s->addr + OMAP_I2C_STAT);
+ data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_STAT);
g_assert((data & OMAP_I2C_STAT_NACK) == 0);
- data = readw(s->addr + OMAP_I2C_CNT);
+ data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_CNT);
g_assert_cmpuint(data, ==, len);
while (len > 0) {
- data = readw(s->addr + OMAP_I2C_STAT);
+ data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_STAT);
g_assert((data & OMAP_I2C_STAT_RRDY) != 0);
g_assert((data & OMAP_I2C_STAT_ROVR) == 0);
- data = readw(s->addr + OMAP_I2C_DATA);
+ data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_DATA);
- stat = readw(s->addr + OMAP_I2C_STAT);
+ stat = qtest_readw(i2c->qts, s->addr + OMAP_I2C_STAT);
if (unlikely(len == 1)) {
g_assert((stat & OMAP_I2C_STAT_SBD) != 0);
@@ -148,11 +148,11 @@ static void omap_i2c_recv(I2CAdapter *i2c, uint8_t addr,
}
}
- data = readw(s->addr + OMAP_I2C_CON);
+ data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_CON);
g_assert((data & OMAP_I2C_CON_STP) == 0);
}
-I2CAdapter *omap_i2c_create(uint64_t addr)
+I2CAdapter *omap_i2c_create(QTestState *qts, uint64_t addr)
{
OMAPI2C *s = g_malloc0(sizeof(*s));
I2CAdapter *i2c = (I2CAdapter *)s;
@@ -162,9 +162,10 @@ I2CAdapter *omap_i2c_create(uint64_t addr)
i2c->send = omap_i2c_send;
i2c->recv = omap_i2c_recv;
+ i2c->qts = qts;
/* verify the mmio address by looking for a known signature */
- data = readw(addr + OMAP_I2C_REV);
+ data = qtest_readw(qts, addr + OMAP_I2C_REV);
g_assert_cmphex(data, ==, 0x34);
return i2c;
diff --git a/tests/libqos/i2c.h b/tests/libqos/i2c.h
index 6e648f922a..eb40b808bd 100644
--- a/tests/libqos/i2c.h
+++ b/tests/libqos/i2c.h
@@ -9,6 +9,7 @@
#ifndef LIBQOS_I2C_H
#define LIBQOS_I2C_H
+#include "libqtest.h"
typedef struct I2CAdapter I2CAdapter;
struct I2CAdapter {
@@ -16,6 +17,8 @@ struct I2CAdapter {
const uint8_t *buf, uint16_t len);
void (*recv)(I2CAdapter *adapter, uint8_t addr,
uint8_t *buf, uint16_t len);
+
+ QTestState *qts;
};
void i2c_send(I2CAdapter *i2c, uint8_t addr,
@@ -24,9 +27,9 @@ void i2c_recv(I2CAdapter *i2c, uint8_t addr,
uint8_t *buf, uint16_t len);
/* libi2c-omap.c */
-I2CAdapter *omap_i2c_create(uint64_t addr);
+I2CAdapter *omap_i2c_create(QTestState *qts, uint64_t addr);
/* libi2c-imx.c */
-I2CAdapter *imx_i2c_create(uint64_t addr);
+I2CAdapter *imx_i2c_create(QTestState *qts, uint64_t addr);
#endif
diff --git a/tests/libqos/libqos-pc.c b/tests/libqos/libqos-pc.c
index b554758802..a9c1aceaa7 100644
--- a/tests/libqos/libqos-pc.c
+++ b/tests/libqos/libqos-pc.c
@@ -25,7 +25,7 @@ QOSState *qtest_pc_boot(const char *cmdline_fmt, ...)
qs = qtest_vboot(&qos_ops, cmdline_fmt, ap);
va_end(ap);
- qtest_irq_intercept_in(global_qtest, "ioapic");
+ qtest_irq_intercept_in(qs->qts, "ioapic");
return qs;
}
diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c
index 306d4c06de..5124e982c1 100644
--- a/tests/libqos/libqos.c
+++ b/tests/libqos/libqos.c
@@ -18,18 +18,14 @@ QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap)
{
char *cmdline;
- struct QOSState *qs = g_new(QOSState, 1);
+ QOSState *qs = g_new0(QOSState, 1);
cmdline = g_strdup_vprintf(cmdline_fmt, ap);
- qs->qts = qtest_start(cmdline);
+ qs->qts = qtest_init(cmdline);
qs->ops = ops;
if (ops) {
- if (ops->init_allocator) {
- qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS);
- }
- if (ops->qpci_init && qs->alloc) {
- qs->pcibus = ops->qpci_init(qs->alloc);
- }
+ qs->alloc = ops->init_allocator(qs->qts, ALLOC_NO_FLAGS);
+ qs->pcibus = ops->qpci_init(qs->qts, qs->alloc);
}
g_free(cmdline);
@@ -85,29 +81,21 @@ void set_context(QOSState *s)
global_qtest = s->qts;
}
-static QDict *qmp_execute(const char *command)
+static QDict *qmp_execute(QTestState *qts, const char *command)
{
- char *fmt;
- QDict *rsp;
-
- fmt = g_strdup_printf("{ 'execute': '%s' }", command);
- rsp = qmp(fmt);
- g_free(fmt);
-
- return rsp;
+ return qtest_qmp(qts, "{ 'execute': %s }", command);
}
void migrate(QOSState *from, QOSState *to, const char *uri)
{
const char *st;
- char *s;
QDict *rsp, *sub;
bool running;
set_context(from);
/* Is the machine currently running? */
- rsp = qmp_execute("query-status");
+ rsp = qmp_execute(from->qts, "query-status");
g_assert(qdict_haskey(rsp, "return"));
sub = qdict_get_qdict(rsp, "return");
g_assert(qdict_haskey(sub, "running"));
@@ -115,30 +103,28 @@ void migrate(QOSState *from, QOSState *to, const char *uri)
QDECREF(rsp);
/* Issue the migrate command. */
- s = g_strdup_printf("{ 'execute': 'migrate',"
- "'arguments': { 'uri': '%s' } }",
- uri);
- rsp = qmp(s);
- g_free(s);
+ rsp = qtest_qmp(from->qts,
+ "{ 'execute': 'migrate', 'arguments': { 'uri': %s }}",
+ uri);
g_assert(qdict_haskey(rsp, "return"));
QDECREF(rsp);
/* Wait for STOP event, but only if we were running: */
if (running) {
- qmp_eventwait("STOP");
+ qtest_qmp_eventwait(from->qts, "STOP");
}
/* If we were running, we can wait for an event. */
if (running) {
migrate_allocator(from->alloc, to->alloc);
set_context(to);
- qmp_eventwait("RESUME");
+ qtest_qmp_eventwait(to->qts, "RESUME");
return;
}
/* Otherwise, we need to wait: poll until migration is completed. */
while (1) {
- rsp = qmp_execute("query-migrate");
+ rsp = qmp_execute(from->qts, "query-migrate");
g_assert(qdict_haskey(rsp, "return"));
sub = qdict_get_qdict(rsp, "return");
g_assert(qdict_haskey(sub, "status"));
diff --git a/tests/libqos/libqos.h b/tests/libqos/libqos.h
index 231969766f..07d4b93d1d 100644
--- a/tests/libqos/libqos.h
+++ b/tests/libqos/libqos.h
@@ -8,9 +8,9 @@
typedef struct QOSState QOSState;
typedef struct QOSOps {
- QGuestAllocator *(*init_allocator)(QAllocOpts);
+ QGuestAllocator *(*init_allocator)(QTestState *qts, QAllocOpts);
void (*uninit_allocator)(QGuestAllocator *);
- QPCIBus *(*qpci_init)(QGuestAllocator *alloc);
+ QPCIBus *(*qpci_init)(QTestState *qts, QGuestAllocator *alloc);
void (*qpci_free)(QPCIBus *bus);
void (*shutdown)(QOSState *);
} QOSOps;
diff --git a/tests/libqos/malloc-pc.c b/tests/libqos/malloc-pc.c
index dd2b900c5f..634b9c288a 100644
--- a/tests/libqos/malloc-pc.c
+++ b/tests/libqos/malloc-pc.c
@@ -29,11 +29,11 @@ void pc_alloc_uninit(QGuestAllocator *allocator)
alloc_uninit(allocator);
}
-QGuestAllocator *pc_alloc_init_flags(QAllocOpts flags)
+QGuestAllocator *pc_alloc_init_flags(QTestState *qts, QAllocOpts flags)
{
QGuestAllocator *s;
uint64_t ram_size;
- QFWCFG *fw_cfg = pc_fw_cfg_init();
+ QFWCFG *fw_cfg = pc_fw_cfg_init(qts);
ram_size = qfw_cfg_get_u64(fw_cfg, FW_CFG_RAM_SIZE);
s = alloc_init_flags(flags, 1 << 20, MIN(ram_size, 0xE0000000));
@@ -45,7 +45,7 @@ QGuestAllocator *pc_alloc_init_flags(QAllocOpts flags)
return s;
}
-inline QGuestAllocator *pc_alloc_init(void)
+inline QGuestAllocator *pc_alloc_init(QTestState *qts)
{
- return pc_alloc_init_flags(ALLOC_NO_FLAGS);
+ return pc_alloc_init_flags(qts, ALLOC_NO_FLAGS);
}
diff --git a/tests/libqos/malloc-pc.h b/tests/libqos/malloc-pc.h
index 86ab9f0429..10f3da6cf2 100644
--- a/tests/libqos/malloc-pc.h
+++ b/tests/libqos/malloc-pc.h
@@ -15,8 +15,8 @@
#include "libqos/malloc.h"
-QGuestAllocator *pc_alloc_init(void);
-QGuestAllocator *pc_alloc_init_flags(QAllocOpts flags);
+QGuestAllocator *pc_alloc_init(QTestState *qts);
+QGuestAllocator *pc_alloc_init_flags(QTestState *qts, QAllocOpts flags);
void pc_alloc_uninit(QGuestAllocator *allocator);
#endif
diff --git a/tests/libqos/malloc-spapr.c b/tests/libqos/malloc-spapr.c
index 006404af33..1c359cea6c 100644
--- a/tests/libqos/malloc-spapr.c
+++ b/tests/libqos/malloc-spapr.c
@@ -22,7 +22,7 @@ void spapr_alloc_uninit(QGuestAllocator *allocator)
alloc_uninit(allocator);
}
-QGuestAllocator *spapr_alloc_init_flags(QAllocOpts flags)
+QGuestAllocator *spapr_alloc_init_flags(QTestState *qts, QAllocOpts flags)
{
QGuestAllocator *s;
@@ -34,5 +34,5 @@ QGuestAllocator *spapr_alloc_init_flags(QAllocOpts flags)
QGuestAllocator *spapr_alloc_init(void)
{
- return spapr_alloc_init_flags(ALLOC_NO_FLAGS);
+ return spapr_alloc_init_flags(NULL, ALLOC_NO_FLAGS);
}
diff --git a/tests/libqos/malloc-spapr.h b/tests/libqos/malloc-spapr.h
index 64d0e770d1..52a9346a26 100644
--- a/tests/libqos/malloc-spapr.h
+++ b/tests/libqos/malloc-spapr.h
@@ -11,7 +11,7 @@
#include "libqos/malloc.h"
QGuestAllocator *spapr_alloc_init(void);
-QGuestAllocator *spapr_alloc_init_flags(QAllocOpts flags);
+QGuestAllocator *spapr_alloc_init_flags(QTestState *qts, QAllocOpts flags);
void spapr_alloc_uninit(QGuestAllocator *allocator);
#endif
diff --git a/tests/libqos/malloc.h b/tests/libqos/malloc.h
index ae9dac8f61..828fddabdb 100644
--- a/tests/libqos/malloc.h
+++ b/tests/libqos/malloc.h
@@ -14,6 +14,7 @@
#define LIBQOS_MALLOC_H
#include "qemu/queue.h"
+#include "libqtest.h"
typedef enum {
ALLOC_NO_FLAGS = 0x00,
diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
index cd4e20e1ea..a2daf6103d 100644
--- a/tests/libqos/pci-pc.c
+++ b/tests/libqos/pci-pc.c
@@ -115,11 +115,11 @@ static void qpci_pc_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint3
outl(0xcfc, value);
}
-QPCIBus *qpci_init_pc(QGuestAllocator *alloc)
+QPCIBus *qpci_init_pc(QTestState *qts, QGuestAllocator *alloc)
{
- QPCIBusPC *ret;
+ QPCIBusPC *ret = g_new0(QPCIBusPC, 1);
- ret = g_malloc(sizeof(*ret));
+ assert(qts);
ret->bus.pio_readb = qpci_pc_pio_readb;
ret->bus.pio_readw = qpci_pc_pio_readw;
@@ -142,6 +142,7 @@ QPCIBus *qpci_init_pc(QGuestAllocator *alloc)
ret->bus.config_writew = qpci_pc_config_writew;
ret->bus.config_writel = qpci_pc_config_writel;
+ ret->bus.qts = qts;
ret->bus.pio_alloc_ptr = 0xc000;
ret->bus.mmio_alloc_ptr = 0xE0000000;
ret->bus.mmio_limit = 0x100000000ULL;
@@ -173,9 +174,5 @@ void qpci_unplug_acpi_device_test(const char *id, uint8_t slot)
outb(ACPI_PCIHP_ADDR + PCI_EJ_BASE, 1 << slot);
- response = qmp("");
- g_assert(response);
- g_assert(qdict_haskey(response, "event"));
- g_assert(!strcmp(qdict_get_str(response, "event"), "DEVICE_DELETED"));
- QDECREF(response);
+ qmp_eventwait("DEVICE_DELETED");
}
diff --git a/tests/libqos/pci-pc.h b/tests/libqos/pci-pc.h
index 9479b51642..491eeac756 100644
--- a/tests/libqos/pci-pc.h
+++ b/tests/libqos/pci-pc.h
@@ -16,7 +16,7 @@
#include "libqos/pci.h"
#include "libqos/malloc.h"
-QPCIBus *qpci_init_pc(QGuestAllocator *alloc);
+QPCIBus *qpci_init_pc(QTestState *qts, QGuestAllocator *alloc);
void qpci_free_pc(QPCIBus *bus);
#endif
diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c
index 2043f1e123..c0f7e6db9b 100644
--- a/tests/libqos/pci-spapr.c
+++ b/tests/libqos/pci-spapr.c
@@ -108,21 +108,24 @@ static uint8_t qpci_spapr_config_readb(QPCIBus *bus, int devfn, uint8_t offset)
{
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
uint32_t config_addr = (devfn << 8) | offset;
- return qrtas_ibm_read_pci_config(s->alloc, s->buid, config_addr, 1);
+ return qrtas_ibm_read_pci_config(bus->qts, s->alloc, s->buid,
+ config_addr, 1);
}
static uint16_t qpci_spapr_config_readw(QPCIBus *bus, int devfn, uint8_t offset)
{
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
uint32_t config_addr = (devfn << 8) | offset;
- return qrtas_ibm_read_pci_config(s->alloc, s->buid, config_addr, 2);
+ return qrtas_ibm_read_pci_config(bus->qts, s->alloc, s->buid,
+ config_addr, 2);
}
static uint32_t qpci_spapr_config_readl(QPCIBus *bus, int devfn, uint8_t offset)
{
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
uint32_t config_addr = (devfn << 8) | offset;
- return qrtas_ibm_read_pci_config(s->alloc, s->buid, config_addr, 4);
+ return qrtas_ibm_read_pci_config(bus->qts, s->alloc, s->buid,
+ config_addr, 4);
}
static void qpci_spapr_config_writeb(QPCIBus *bus, int devfn, uint8_t offset,
@@ -130,7 +133,8 @@ static void qpci_spapr_config_writeb(QPCIBus *bus, int devfn, uint8_t offset,
{
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
uint32_t config_addr = (devfn << 8) | offset;
- qrtas_ibm_write_pci_config(s->alloc, s->buid, config_addr, 1, value);
+ qrtas_ibm_write_pci_config(bus->qts, s->alloc, s->buid,
+ config_addr, 1, value);
}
static void qpci_spapr_config_writew(QPCIBus *bus, int devfn, uint8_t offset,
@@ -138,7 +142,8 @@ static void qpci_spapr_config_writew(QPCIBus *bus, int devfn, uint8_t offset,
{
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
uint32_t config_addr = (devfn << 8) | offset;
- qrtas_ibm_write_pci_config(s->alloc, s->buid, config_addr, 2, value);
+ qrtas_ibm_write_pci_config(bus->qts, s->alloc, s->buid,
+ config_addr, 2, value);
}
static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset,
@@ -146,7 +151,8 @@ static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset,
{
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
uint32_t config_addr = (devfn << 8) | offset;
- qrtas_ibm_write_pci_config(s->alloc, s->buid, config_addr, 4, value);
+ qrtas_ibm_write_pci_config(bus->qts, s->alloc, s->buid,
+ config_addr, 4, value);
}
#define SPAPR_PCI_BASE (1ULL << 45)
@@ -154,11 +160,11 @@ static void qpci_spapr_config_writel(QPCIBus *bus, int devfn, uint8_t offset,
#define SPAPR_PCI_MMIO32_WIN_SIZE 0x80000000 /* 2 GiB */
#define SPAPR_PCI_IO_WIN_SIZE 0x10000
-QPCIBus *qpci_init_spapr(QGuestAllocator *alloc)
+QPCIBus *qpci_init_spapr(QTestState *qts, QGuestAllocator *alloc)
{
- QPCIBusSPAPR *ret;
+ QPCIBusSPAPR *ret = g_new0(QPCIBusSPAPR, 1);
- ret = g_malloc(sizeof(*ret));
+ assert(qts);
ret->alloc = alloc;
@@ -197,6 +203,7 @@ QPCIBus *qpci_init_spapr(QGuestAllocator *alloc)
ret->mmio32.pci_base = SPAPR_PCI_MMIO32_WIN_SIZE;
ret->mmio32.size = SPAPR_PCI_MMIO32_WIN_SIZE;
+ ret->bus.qts = qts;
ret->bus.pio_alloc_ptr = 0xc000;
ret->bus.mmio_alloc_ptr = ret->mmio32.pci_base;
ret->bus.mmio_limit = ret->mmio32.pci_base + ret->mmio32.size;
diff --git a/tests/libqos/pci-spapr.h b/tests/libqos/pci-spapr.h
index 4192126d86..387686dfc8 100644
--- a/tests/libqos/pci-spapr.h
+++ b/tests/libqos/pci-spapr.h
@@ -11,7 +11,7 @@
#include "libqos/malloc.h"
#include "libqos/pci.h"
-QPCIBus *qpci_init_spapr(QGuestAllocator *alloc);
+QPCIBus *qpci_init_spapr(QTestState *qts, QGuestAllocator *alloc);
void qpci_free_spapr(QPCIBus *bus);
#endif
diff --git a/tests/libqos/pci.h b/tests/libqos/pci.h
index ed480614ff..429c382282 100644
--- a/tests/libqos/pci.h
+++ b/tests/libqos/pci.h
@@ -48,6 +48,7 @@ struct QPCIBus {
void (*config_writel)(QPCIBus *bus, int devfn,
uint8_t offset, uint32_t value);
+ QTestState *qts;
uint16_t pio_alloc_ptr;
uint64_t mmio_alloc_ptr, mmio_limit;
};
diff --git a/tests/libqos/rtas.c b/tests/libqos/rtas.c
index 0269803ce0..d81ff4274d 100644
--- a/tests/libqos/rtas.c
+++ b/tests/libqos/rtas.c
@@ -7,26 +7,28 @@
#include "libqtest.h"
#include "libqos/rtas.h"
-static void qrtas_copy_args(uint64_t target_args, uint32_t nargs,
- uint32_t *args)
+static void qrtas_copy_args(QTestState *qts, uint64_t target_args,
+ uint32_t nargs, uint32_t *args)
{
int i;
for (i = 0; i < nargs; i++) {
- writel(target_args + i * sizeof(uint32_t), args[i]);
+ qtest_writel(qts, target_args + i * sizeof(uint32_t), args[i]);
}
}
-static void qrtas_copy_ret(uint64_t target_ret, uint32_t nret, uint32_t *ret)
+static void qrtas_copy_ret(QTestState *qts, uint64_t target_ret,
+ uint32_t nret, uint32_t *ret)
{
int i;
for (i = 0; i < nret; i++) {
- ret[i] = readl(target_ret + i * sizeof(uint32_t));
+ ret[i] = qtest_readl(qts, target_ret + i * sizeof(uint32_t));
}
}
-static uint64_t qrtas_call(QGuestAllocator *alloc, const char *name,
+static uint64_t qrtas_call(QTestState *qts, QGuestAllocator *alloc,
+ const char *name,
uint32_t nargs, uint32_t *args,
uint32_t nret, uint32_t *ret)
{
@@ -36,10 +38,9 @@ static uint64_t qrtas_call(QGuestAllocator *alloc, const char *name,
target_args = guest_alloc(alloc, nargs * sizeof(uint32_t));
target_ret = guest_alloc(alloc, nret * sizeof(uint32_t));
- qrtas_copy_args(target_args, nargs, args);
- res = qtest_rtas_call(global_qtest, name,
- nargs, target_args, nret, target_ret);
- qrtas_copy_ret(target_ret, nret, ret);
+ qrtas_copy_args(qts, target_args, nargs, args);
+ res = qtest_rtas_call(qts, name, nargs, target_args, nret, target_ret);
+ qrtas_copy_ret(qts, target_ret, nret, ret);
guest_free(alloc, target_ret);
guest_free(alloc, target_args);
@@ -47,12 +48,13 @@ static uint64_t qrtas_call(QGuestAllocator *alloc, const char *name,
return res;
}
-int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns)
+int qrtas_get_time_of_day(QTestState *qts, QGuestAllocator *alloc,
+ struct tm *tm, uint32_t *ns)
{
int res;
uint32_t ret[8];
- res = qrtas_call(alloc, "get-time-of-day", 0, NULL, 8, ret);
+ res = qrtas_call(qts, alloc, "get-time-of-day", 0, NULL, 8, ret);
if (res != 0) {
return res;
}
@@ -70,7 +72,8 @@ int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns)
return res;
}
-uint32_t qrtas_ibm_read_pci_config(QGuestAllocator *alloc, uint64_t buid,
+uint32_t qrtas_ibm_read_pci_config(QTestState *qts, QGuestAllocator *alloc,
+ uint64_t buid,
uint32_t addr, uint32_t size)
{
int res;
@@ -80,7 +83,7 @@ uint32_t qrtas_ibm_read_pci_config(QGuestAllocator *alloc, uint64_t buid,
args[1] = buid >> 32;
args[2] = buid & 0xffffffff;
args[3] = size;
- res = qrtas_call(alloc, "ibm,read-pci-config", 4, args, 2, ret);
+ res = qrtas_call(qts, alloc, "ibm,read-pci-config", 4, args, 2, ret);
if (res != 0) {
return -1;
}
@@ -92,7 +95,8 @@ uint32_t qrtas_ibm_read_pci_config(QGuestAllocator *alloc, uint64_t buid,
return ret[1];
}
-int qrtas_ibm_write_pci_config(QGuestAllocator *alloc, uint64_t buid,
+int qrtas_ibm_write_pci_config(QTestState *qts, QGuestAllocator *alloc,
+ uint64_t buid,
uint32_t addr, uint32_t size, uint32_t val)
{
int res;
@@ -103,7 +107,7 @@ int qrtas_ibm_write_pci_config(QGuestAllocator *alloc, uint64_t buid,
args[2] = buid & 0xffffffff;
args[3] = size;
args[4] = val;
- res = qrtas_call(alloc, "ibm,write-pci-config", 5, args, 1, ret);
+ res = qrtas_call(qts, alloc, "ibm,write-pci-config", 5, args, 1, ret);
if (res != 0) {
return -1;
}
diff --git a/tests/libqos/rtas.h b/tests/libqos/rtas.h
index 498eb19230..459e23aaf4 100644
--- a/tests/libqos/rtas.h
+++ b/tests/libqos/rtas.h
@@ -7,9 +7,11 @@
#define LIBQOS_RTAS_H
#include "libqos/malloc.h"
-int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns);
-uint32_t qrtas_ibm_read_pci_config(QGuestAllocator *alloc, uint64_t buid,
- uint32_t addr, uint32_t size);
-int qrtas_ibm_write_pci_config(QGuestAllocator *alloc, uint64_t buid,
- uint32_t addr, uint32_t size, uint32_t val);
+int qrtas_get_time_of_day(QTestState *qts, QGuestAllocator *alloc,
+ struct tm *tm, uint32_t *ns);
+uint32_t qrtas_ibm_read_pci_config(QTestState *qts, QGuestAllocator *alloc,
+ uint64_t buid, uint32_t addr, uint32_t size);
+int qrtas_ibm_write_pci_config(QTestState *qts, QGuestAllocator *alloc,
+ uint64_t buid, uint32_t addr, uint32_t size,
+ uint32_t val);
#endif /* LIBQOS_RTAS_H */
diff --git a/tests/libqtest.c b/tests/libqtest.c
index f2c285374b..13c910069b 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -15,12 +15,13 @@
*/
#include "qemu/osdep.h"
-#include "libqtest.h"
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/un.h>
+#include "libqtest.h"
+#include "qemu/cutils.h"
#include "qapi/error.h"
#include "qapi/qmp/json-parser.h"
#include "qapi/qmp/json-streamer.h"
@@ -363,12 +364,14 @@ redo:
g_string_free(line, TRUE);
if (strcmp(words[0], "IRQ") == 0) {
- int irq;
+ long irq;
+ int ret;
g_assert(words[1] != NULL);
g_assert(words[2] != NULL);
- irq = strtoul(words[2], NULL, 0);
+ ret = qemu_strtol(words[2], NULL, 0, &irq);
+ g_assert(!ret);
g_assert_cmpint(irq, >=, 0);
g_assert_cmpint(irq, <, MAX_IRQ);
@@ -730,11 +733,13 @@ void qtest_outl(QTestState *s, uint16_t addr, uint32_t value)
static uint32_t qtest_in(QTestState *s, const char *cmd, uint16_t addr)
{
gchar **args;
- uint32_t value;
+ int ret;
+ unsigned long value;
qtest_sendf(s, "%s 0x%x\n", cmd, addr);
args = qtest_rsp(s, 2);
- value = strtoul(args[1], NULL, 0);
+ ret = qemu_strtoul(args[1], NULL, 0, &value);
+ g_assert(!ret && value <= UINT32_MAX);
g_strfreev(args);
return value;
@@ -785,11 +790,13 @@ void qtest_writeq(QTestState *s, uint64_t addr, uint64_t value)
static uint64_t qtest_read(QTestState *s, const char *cmd, uint64_t addr)
{
gchar **args;
+ int ret;
uint64_t value;
qtest_sendf(s, "%s 0x%" PRIx64 "\n", cmd, addr);
args = qtest_rsp(s, 2);
- value = strtoull(args[1], NULL, 0);
+ ret = qemu_strtou64(args[1], NULL, 0, &value);
+ g_assert(!ret);
g_strfreev(args);
return value;
diff --git a/tests/m48t59-test.c b/tests/m48t59-test.c
index 0f921ef38a..26af7d6e8e 100644
--- a/tests/m48t59-test.c
+++ b/tests/m48t59-test.c
@@ -28,47 +28,48 @@
static uint32_t base;
static uint16_t reg_base = 0x1ff0; /* 0x7f0 for m48t02 */
static int base_year;
+static const char *base_machine;
static bool use_mmio;
-static uint8_t cmos_read_mmio(uint8_t reg)
+static uint8_t cmos_read_mmio(QTestState *s, uint8_t reg)
{
- return readb(base + (uint32_t)reg_base + (uint32_t)reg);
+ return qtest_readb(s, base + (uint32_t)reg_base + (uint32_t)reg);
}
-static void cmos_write_mmio(uint8_t reg, uint8_t val)
+static void cmos_write_mmio(QTestState *s, uint8_t reg, uint8_t val)
{
uint8_t data = val;
- writeb(base + (uint32_t)reg_base + (uint32_t)reg, data);
+ qtest_writeb(s, base + (uint32_t)reg_base + (uint32_t)reg, data);
}
-static uint8_t cmos_read_ioio(uint8_t reg)
+static uint8_t cmos_read_ioio(QTestState *s, uint8_t reg)
{
- outw(base + 0, reg_base + (uint16_t)reg);
- return inb(base + 3);
+ qtest_outw(s, base + 0, reg_base + (uint16_t)reg);
+ return qtest_inb(s, base + 3);
}
-static void cmos_write_ioio(uint8_t reg, uint8_t val)
+static void cmos_write_ioio(QTestState *s, uint8_t reg, uint8_t val)
{
- outw(base + 0, reg_base + (uint16_t)reg);
- outb(base + 3, val);
+ qtest_outw(s, base + 0, reg_base + (uint16_t)reg);
+ qtest_outb(s, base + 3, val);
}
-static uint8_t cmos_read(uint8_t reg)
+static uint8_t cmos_read(QTestState *s, uint8_t reg)
{
if (use_mmio) {
- return cmos_read_mmio(reg);
+ return cmos_read_mmio(s, reg);
} else {
- return cmos_read_ioio(reg);
+ return cmos_read_ioio(s, reg);
}
}
-static void cmos_write(uint8_t reg, uint8_t val)
+static void cmos_write(QTestState *s, uint8_t reg, uint8_t val)
{
if (use_mmio) {
- cmos_write_mmio(reg, val);
+ cmos_write_mmio(s, reg, val);
} else {
- cmos_write_ioio(reg, val);
+ cmos_write_ioio(s, reg, val);
}
}
@@ -106,18 +107,18 @@ static void print_tm(struct tm *tm)
}
#endif
-static void cmos_get_date_time(struct tm *date)
+static void cmos_get_date_time(QTestState *s, struct tm *date)
{
int sec, min, hour, mday, mon, year;
time_t ts;
struct tm dummy;
- sec = cmos_read(RTC_SECONDS);
- min = cmos_read(RTC_MINUTES);
- hour = cmos_read(RTC_HOURS);
- mday = cmos_read(RTC_DAY_OF_MONTH);
- mon = cmos_read(RTC_MONTH);
- year = cmos_read(RTC_YEAR);
+ sec = cmos_read(s, RTC_SECONDS);
+ min = cmos_read(s, RTC_MINUTES);
+ hour = cmos_read(s, RTC_HOURS);
+ mday = cmos_read(s, RTC_DAY_OF_MONTH);
+ mon = cmos_read(s, RTC_MONTH);
+ year = cmos_read(s, RTC_YEAR);
sec = bcd2dec(sec);
min = bcd2dec(min);
@@ -143,11 +144,18 @@ static void cmos_get_date_time(struct tm *date)
ts = mktime(date);
}
-static void check_time(int wiggle)
+static QTestState *m48t59_qtest_start(void)
+{
+ return qtest_startf("-M %s -rtc clock=vm", base_machine);
+}
+
+static void bcd_check_time(void)
{
struct tm start, date[4], end;
struct tm *datep;
time_t ts;
+ const int wiggle = 2;
+ QTestState *s = m48t59_qtest_start();
/*
* This check assumes a few things. First, we cannot guarantee that we get
@@ -165,10 +173,10 @@ static void check_time(int wiggle)
ts = time(NULL);
gmtime_r(&ts, &start);
- cmos_get_date_time(&date[0]);
- cmos_get_date_time(&date[1]);
- cmos_get_date_time(&date[2]);
- cmos_get_date_time(&date[3]);
+ cmos_get_date_time(s, &date[0]);
+ cmos_get_date_time(s, &date[1]);
+ cmos_get_date_time(s, &date[2]);
+ cmos_get_date_time(s, &date[3]);
ts = time(NULL);
gmtime_r(&ts, &end);
@@ -198,30 +206,15 @@ static void check_time(int wiggle)
g_assert_cmpint(ABS(t - s), <=, wiggle);
}
-}
-
-static int wiggle = 2;
-static void bcd_check_time(void)
-{
- if (strcmp(qtest_get_arch(), "sparc64") == 0) {
- base = 0x74;
- base_year = 1900;
- use_mmio = false;
- } else if (strcmp(qtest_get_arch(), "sparc") == 0) {
- base = 0x71200000;
- base_year = 1968;
- use_mmio = true;
- } else { /* PPC: need to map macio in PCI */
- g_assert_not_reached();
- }
- check_time(wiggle);
+ qtest_quit(s);
}
/* success if no crash or abort */
static void fuzz_registers(void)
{
unsigned int i;
+ QTestState *s = m48t59_qtest_start();
for (i = 0; i < 1000; i++) {
uint8_t reg, val;
@@ -234,27 +227,47 @@ static void fuzz_registers(void)
continue;
}
- cmos_write(reg, val);
- cmos_read(reg);
+ cmos_write(s, reg, val);
+ cmos_read(s, reg);
+ }
+
+ qtest_quit(s);
+}
+
+static void base_setup(void)
+{
+ const char *arch = qtest_get_arch();
+
+ if (g_str_equal(arch, "sparc")) {
+ /* Note: For sparc64, we'd need to map-in the PCI bridge memory first */
+ base = 0x71200000;
+ base_year = 1968;
+ base_machine = "SS-5";
+ use_mmio = true;
+ } else if (g_str_equal(arch, "ppc") || g_str_equal(arch, "ppc64")) {
+ base = 0xF0000000;
+ base_year = 1968;
+ base_machine = "ref405ep";
+ use_mmio = true;
+ } else {
+ g_assert_not_reached();
}
}
int main(int argc, char **argv)
{
- QTestState *s = NULL;
int ret;
- g_test_init(&argc, &argv, NULL);
+ base_setup();
- s = qtest_start("-rtc clock=vm");
+ g_test_init(&argc, &argv, NULL);
- qtest_add_func("/rtc/bcd/check-time", bcd_check_time);
+ if (g_test_slow()) {
+ /* Do not run this in timing-sensitive environments */
+ qtest_add_func("/rtc/bcd-check-time", bcd_check_time);
+ }
qtest_add_func("/rtc/fuzz-registers", fuzz_registers);
ret = g_test_run();
- if (s) {
- qtest_quit(s);
- }
-
return ret;
}
diff --git a/tests/megasas-test.c b/tests/megasas-test.c
index ce960e7f81..81837e14af 100644
--- a/tests/megasas-test.c
+++ b/tests/megasas-test.c
@@ -15,13 +15,16 @@
static QOSState *qmegasas_start(const char *extra_opts)
{
+ QOSState *qs;
const char *arch = qtest_get_arch();
const char *cmd = "-drive id=hd0,if=none,file=null-co://,format=raw "
"-device megasas,id=scsi0,addr=04.0 "
"-device scsi-hd,bus=scsi0.0,drive=hd0 %s";
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
- return qtest_pc_boot(cmd, extra_opts ? : "");
+ qs = qtest_pc_boot(cmd, extra_opts ? : "");
+ global_qtest = qs->qts;
+ return qs;
}
g_printerr("virtio-scsi tests are only available on x86 or ppc64\n");
diff --git a/tests/pxe-test.c b/tests/pxe-test.c
index 5ca84805eb..6e3679672c 100644
--- a/tests/pxe-test.c
+++ b/tests/pxe-test.c
@@ -71,7 +71,7 @@ static void test_pxe_one(const testdef_t *test, bool ipv6)
test->model);
qtest_start(args);
- boot_sector_test();
+ boot_sector_test(global_qtest);
qtest_quit(global_qtest);
g_free(args);
}
diff --git a/tests/q35-test.c b/tests/q35-test.c
index 187d68fb7e..3eaedf4b24 100644
--- a/tests/q35-test.c
+++ b/tests/q35-test.c
@@ -87,7 +87,7 @@ static void test_smram_lock(void)
qtest_start("-M q35");
- pcibus = qpci_init_pc(NULL);
+ pcibus = qpci_init_pc(global_qtest, NULL);
g_assert(pcibus != NULL);
pcidev = qpci_device_find(pcibus, 0);
@@ -146,7 +146,7 @@ static void test_tseg_size(const void *data)
g_free(cmdline);
/* locate the DRAM controller */
- pcibus = qpci_init_pc(NULL);
+ pcibus = qpci_init_pc(global_qtest, NULL);
g_assert(pcibus != NULL);
pcidev = qpci_device_find(pcibus, 0);
g_assert(pcidev != NULL);
diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
index 1ac5d56233..f6dce7947c 100644
--- a/tests/qemu-iotests/059.out
+++ b/tests/qemu-iotests/059.out
@@ -2358,5 +2358,5 @@ Offset Length Mapped to File
0x140000000 0x10000 0x50000 TEST_DIR/t-s003.vmdk
=== Testing afl image with a very large capacity ===
-qemu-img: Could not open 'TEST_DIR/afl9.IMGFMT': Could not open 'TEST_DIR/afl9.IMGFMT': Invalid argument
+qemu-img: Can't get image size 'TEST_DIR/afl9.IMGFMT': File too large
*** done
diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
index f5678b10c9..911b6f2894 100755
--- a/tests/qemu-iotests/061
+++ b/tests/qemu-iotests/061
@@ -54,6 +54,22 @@ $QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
_check_test_img
echo
+echo "=== Testing version downgrade with zero expansion and 4K cache entries ==="
+echo
+IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
+$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c "write -z 32M 128k" "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c map "$TEST_IMG" | _filter_qemu_io
+$PYTHON qcow2.py "$TEST_IMG" dump-header
+$QEMU_IMG amend -o "compat=0.10" --image-opts \
+ driver=qcow2,file.filename=$TEST_IMG,l2-cache-entry-size=4096
+$PYTHON qcow2.py "$TEST_IMG" dump-header
+$QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c "read -P 0 32M 128k" "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c map "$TEST_IMG" | _filter_qemu_io
+_check_test_img
+
+echo
echo "=== Testing dirty version downgrade ==="
echo
IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
index 942485de99..e857ef9a7d 100644
--- a/tests/qemu-iotests/061.out
+++ b/tests/qemu-iotests/061.out
@@ -52,6 +52,67 @@ read 131072/131072 bytes at offset 0
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
No errors were found on the image.
+=== Testing version downgrade with zero expansion and 4K cache entries ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+wrote 131072/131072 bytes at offset 0
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 131072/131072 bytes at offset 33554432
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+128 KiB (0x20000) bytes allocated at offset 0 bytes (0x0)
+31.875 MiB (0x1fe0000) bytes not allocated at offset 128 KiB (0x20000)
+128 KiB (0x20000) bytes allocated at offset 32 MiB (0x2000000)
+31.875 MiB (0x1fe0000) bytes not allocated at offset 32.125 MiB (0x2020000)
+magic 0x514649fb
+version 3
+backing_file_offset 0x0
+backing_file_size 0x0
+cluster_bits 16
+size 67108864
+crypt_method 0
+l1_size 1
+l1_table_offset 0x30000
+refcount_table_offset 0x10000
+refcount_table_clusters 1
+nb_snapshots 0
+snapshot_offset 0x0
+incompatible_features 0x0
+compatible_features 0x1
+autoclear_features 0x0
+refcount_order 4
+header_length 104
+
+Header extension:
+magic 0x6803f857
+length 144
+data <binary>
+
+magic 0x514649fb
+version 2
+backing_file_offset 0x0
+backing_file_size 0x0
+cluster_bits 16
+size 67108864
+crypt_method 0
+l1_size 1
+l1_table_offset 0x30000
+refcount_table_offset 0x10000
+refcount_table_clusters 1
+nb_snapshots 0
+snapshot_offset 0x0
+incompatible_features 0x0
+compatible_features 0x0
+autoclear_features 0x0
+refcount_order 4
+header_length 72
+
+read 131072/131072 bytes at offset 0
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 131072/131072 bytes at offset 33554432
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+64 MiB (0x4000000) bytes not allocated at offset 0 bytes (0x0)
+No errors were found on the image.
+
=== Testing dirty version downgrade ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
diff --git a/tests/qemu-iotests/103 b/tests/qemu-iotests/103
index d0cfab8844..2841318492 100755
--- a/tests/qemu-iotests/103
+++ b/tests/qemu-iotests/103
@@ -66,6 +66,14 @@ $QEMU_IO -c "open -o cache-size=1M,refcount-cache-size=2M $TEST_IMG" 2>&1 \
$QEMU_IO -c "open -o cache-size=0,l2-cache-size=0,refcount-cache-size=0 $TEST_IMG" \
2>&1 | _filter_testdir | _filter_imgfmt
+# Invalid cache entry sizes
+$QEMU_IO -c "open -o l2-cache-entry-size=256 $TEST_IMG" \
+ 2>&1 | _filter_testdir | _filter_imgfmt
+$QEMU_IO -c "open -o l2-cache-entry-size=4242 $TEST_IMG" \
+ 2>&1 | _filter_testdir | _filter_imgfmt
+$QEMU_IO -c "open -o l2-cache-entry-size=128k $TEST_IMG" \
+ 2>&1 | _filter_testdir | _filter_imgfmt
+
echo
echo '=== Testing valid option combinations ==='
echo
@@ -94,6 +102,15 @@ $QEMU_IO -c "open -o l2-cache-size=1M,refcount-cache-size=0.25M $TEST_IMG" \
-c 'read -P 42 0 64k' \
| _filter_qemu_io
+# Valid cache entry sizes
+$QEMU_IO -c "open -o l2-cache-entry-size=512 $TEST_IMG" \
+ 2>&1 | _filter_testdir | _filter_imgfmt
+$QEMU_IO -c "open -o l2-cache-entry-size=16k $TEST_IMG" \
+ 2>&1 | _filter_testdir | _filter_imgfmt
+$QEMU_IO -c "open -o l2-cache-entry-size=64k $TEST_IMG" \
+ 2>&1 | _filter_testdir | _filter_imgfmt
+
+
echo
echo '=== Testing minimal L2 cache and COW ==='
echo
diff --git a/tests/qemu-iotests/103.out b/tests/qemu-iotests/103.out
index b7aaadf89a..bd45d3875a 100644
--- a/tests/qemu-iotests/103.out
+++ b/tests/qemu-iotests/103.out
@@ -9,6 +9,9 @@ can't open device TEST_DIR/t.IMGFMT: cache-size, l2-cache-size and refcount-cach
can't open device TEST_DIR/t.IMGFMT: l2-cache-size may not exceed cache-size
can't open device TEST_DIR/t.IMGFMT: refcount-cache-size may not exceed cache-size
can't open device TEST_DIR/t.IMGFMT: cache-size, l2-cache-size and refcount-cache-size may not be set the same time
+can't open device TEST_DIR/t.IMGFMT: L2 cache entry size must be a power of two between 512 and the cluster size (65536)
+can't open device TEST_DIR/t.IMGFMT: L2 cache entry size must be a power of two between 512 and the cluster size (65536)
+can't open device TEST_DIR/t.IMGFMT: L2 cache entry size must be a power of two between 512 and the cluster size (65536)
=== Testing valid option combinations ===
diff --git a/tests/qemu-iotests/137 b/tests/qemu-iotests/137
index 5a01250005..87965625d8 100755
--- a/tests/qemu-iotests/137
+++ b/tests/qemu-iotests/137
@@ -83,6 +83,9 @@ $QEMU_IO \
-c "reopen -o overlap-check.inactive-l2=off" \
-c "reopen -o cache-size=1M" \
-c "reopen -o l2-cache-size=512k" \
+ -c "reopen -o l2-cache-entry-size=512" \
+ -c "reopen -o l2-cache-entry-size=4k" \
+ -c "reopen -o l2-cache-entry-size=64k" \
-c "reopen -o refcount-cache-size=128k" \
-c "reopen -o cache-clean-interval=5" \
-c "reopen -o cache-clean-interval=0" \
@@ -107,6 +110,8 @@ $QEMU_IO \
-c "reopen -o cache-size=1M,l2-cache-size=2M" \
-c "reopen -o cache-size=1M,refcount-cache-size=2M" \
-c "reopen -o l2-cache-size=256T" \
+ -c "reopen -o l2-cache-entry-size=33k" \
+ -c "reopen -o l2-cache-entry-size=128k" \
-c "reopen -o refcount-cache-size=256T" \
-c "reopen -o overlap-check=constant,overlap-check.template=all" \
-c "reopen -o overlap-check=blubb" \
diff --git a/tests/qemu-iotests/137.out b/tests/qemu-iotests/137.out
index 05efd74d17..e28e1eadba 100644
--- a/tests/qemu-iotests/137.out
+++ b/tests/qemu-iotests/137.out
@@ -20,6 +20,8 @@ cache-size, l2-cache-size and refcount-cache-size may not be set the same time
l2-cache-size may not exceed cache-size
refcount-cache-size may not exceed cache-size
L2 cache size too big
+L2 cache entry size must be a power of two between 512 and the cluster size (65536)
+L2 cache entry size must be a power of two between 512 and the cluster size (65536)
L2 cache size too big
Conflicting values for qcow2 options 'overlap-check' ('constant') and 'overlap-check.template' ('all')
Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are any of the following: none, constant, cached, all
diff --git a/tests/qemu-iotests/155 b/tests/qemu-iotests/155
index fc9fa975be..42dae04c83 100755
--- a/tests/qemu-iotests/155
+++ b/tests/qemu-iotests/155
@@ -64,7 +64,7 @@ class BaseClass(iotests.QMPTestCase):
'file': {'driver': 'file',
'filename': source_img}}
self.vm.add_blockdev(self.qmp_to_opts(blockdev))
- self.vm.add_device('floppy,id=qdev0,drive=source')
+ self.vm.add_device('virtio-blk,id=qdev0,drive=source')
self.vm.launch()
self.assertIntactSourceBackingChain()
@@ -173,21 +173,24 @@ class MirrorBaseClass(BaseClass):
def testFull(self):
self.runMirror('full')
- node = self.findBlockNode('target', 'qdev0')
+ node = self.findBlockNode('target',
+ '/machine/peripheral/qdev0/virtio-backend')
self.assertCorrectBackingImage(node, None)
self.assertIntactSourceBackingChain()
def testTop(self):
self.runMirror('top')
- node = self.findBlockNode('target', 'qdev0')
+ node = self.findBlockNode('target',
+ '/machine/peripheral/qdev0/virtio-backend')
self.assertCorrectBackingImage(node, back2_img)
self.assertIntactSourceBackingChain()
def testNone(self):
self.runMirror('none')
- node = self.findBlockNode('target', 'qdev0')
+ node = self.findBlockNode('target',
+ '/machine/peripheral/qdev0/virtio-backend')
self.assertCorrectBackingImage(node, source_img)
self.assertIntactSourceBackingChain()
@@ -239,7 +242,8 @@ class TestCommit(BaseClass):
self.vm.event_wait('BLOCK_JOB_COMPLETED')
- node = self.findBlockNode(None, 'qdev0')
+ node = self.findBlockNode(None,
+ '/machine/peripheral/qdev0/virtio-backend')
self.assert_qmp(node, 'image' + '/backing-image' * 0 + '/filename',
back1_img)
self.assert_qmp(node, 'image' + '/backing-image' * 1 + '/filename',
diff --git a/tests/qemu-iotests/165 b/tests/qemu-iotests/165
index a3932db3de..2936929627 100755
--- a/tests/qemu-iotests/165
+++ b/tests/qemu-iotests/165
@@ -64,7 +64,7 @@ class TestPersistentDirtyBitmap(iotests.QMPTestCase):
def qmpAddBitmap(self):
self.vm.qmp('block-dirty-bitmap-add', node='drive0',
- name='bitmap0', persistent=True, autoload=True)
+ name='bitmap0', persistent=True)
def test_persistent(self):
self.vm = self.mkVm()
diff --git a/tests/qemu-iotests/176 b/tests/qemu-iotests/176
index d38b3aeb91..32baa116dd 100755
--- a/tests/qemu-iotests/176
+++ b/tests/qemu-iotests/176
@@ -95,7 +95,7 @@ case $reason in
"file": { "driver": "file", "filename": "$TEST_IMG" } } }
{ "execute": "block-dirty-bitmap-add",
"arguments": { "node": "drive0", "name": "bitmap0",
- "persistent": true, "autoload": true } }
+ "persistent": true } }
{ "execute": "quit" }
EOF
;;
diff --git a/tests/qemu-iotests/sample_images/afl9.vmdk.bz2 b/tests/qemu-iotests/sample_images/afl9.vmdk.bz2
index 03615d36a1..9fcd0af45a 100644
--- a/tests/qemu-iotests/sample_images/afl9.vmdk.bz2
+++ b/tests/qemu-iotests/sample_images/afl9.vmdk.bz2
Binary files differ
diff --git a/tests/qmp-test.c b/tests/qmp-test.c
index 908f9b981f..580848307a 100644
--- a/tests/qmp-test.c
+++ b/tests/qmp-test.c
@@ -43,32 +43,32 @@ static void test_version(QObject *version)
visit_free(v);
}
-static void test_malformed(void)
+static void test_malformed(QTestState *qts)
{
QDict *resp;
/* Not even a dictionary */
- resp = qmp("null");
+ resp = qtest_qmp(qts, "null");
g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
QDECREF(resp);
/* No "execute" key */
- resp = qmp("{}");
+ resp = qtest_qmp(qts, "{}");
g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
QDECREF(resp);
/* "execute" isn't a string */
- resp = qmp("{ 'execute': true }");
+ resp = qtest_qmp(qts, "{ 'execute': true }");
g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
QDECREF(resp);
/* "arguments" isn't a dictionary */
- resp = qmp("{ 'execute': 'no-such-cmd', 'arguments': [] }");
+ resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'arguments': [] }");
g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
QDECREF(resp);
/* extra key */
- resp = qmp("{ 'execute': 'no-such-cmd', 'extra': true }");
+ resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'extra': true }");
g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
QDECREF(resp);
}
@@ -77,11 +77,12 @@ static void test_qmp_protocol(void)
{
QDict *resp, *q, *ret;
QList *capabilities;
+ QTestState *qts;
- global_qtest = qtest_init_without_qmp_handshake(common_args);
+ qts = qtest_init_without_qmp_handshake(common_args);
/* Test greeting */
- resp = qmp_receive();
+ resp = qtest_qmp_receive(qts);
q = qdict_get_qdict(resp, "QMP");
g_assert(q);
test_version(qdict_get(q, "version"));
@@ -90,46 +91,46 @@ static void test_qmp_protocol(void)
QDECREF(resp);
/* Test valid command before handshake */
- resp = qmp("{ 'execute': 'query-version' }");
+ resp = qtest_qmp(qts, "{ 'execute': 'query-version' }");
g_assert_cmpstr(get_error_class(resp), ==, "CommandNotFound");
QDECREF(resp);
/* Test malformed commands before handshake */
- test_malformed();
+ test_malformed(qts);
/* Test handshake */
- resp = qmp("{ 'execute': 'qmp_capabilities' }");
+ resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }");
ret = qdict_get_qdict(resp, "return");
g_assert(ret && !qdict_size(ret));
QDECREF(resp);
/* Test repeated handshake */
- resp = qmp("{ 'execute': 'qmp_capabilities' }");
+ resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }");
g_assert_cmpstr(get_error_class(resp), ==, "CommandNotFound");
QDECREF(resp);
/* Test valid command */
- resp = qmp("{ 'execute': 'query-version' }");
+ resp = qtest_qmp(qts, "{ 'execute': 'query-version' }");
test_version(qdict_get(resp, "return"));
QDECREF(resp);
/* Test malformed commands */
- test_malformed();
+ test_malformed(qts);
/* Test 'id' */
- resp = qmp("{ 'execute': 'query-name', 'id': 'cookie#1' }");
+ resp = qtest_qmp(qts, "{ 'execute': 'query-name', 'id': 'cookie#1' }");
ret = qdict_get_qdict(resp, "return");
g_assert(ret);
g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, "cookie#1");
QDECREF(resp);
/* Test command failure with 'id' */
- resp = qmp("{ 'execute': 'human-monitor-command', 'id': 2 }");
+ resp = qtest_qmp(qts, "{ 'execute': 'human-monitor-command', 'id': 2 }");
g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
g_assert_cmpint(qdict_get_int(resp, "id"), ==, 2);
QDECREF(resp);
- qtest_end();
+ qtest_quit(qts);
}
static int query_error_class(const char *cmd)
diff --git a/tests/rtas-test.c b/tests/rtas-test.c
index 276c87ef84..009bda6d23 100644
--- a/tests/rtas-test.c
+++ b/tests/rtas-test.c
@@ -14,9 +14,10 @@ static void test_rtas_get_time_of_day(void)
time_t t1, t2;
qs = qtest_spapr_boot("-machine pseries");
+ global_qtest = qs->qts;
t1 = time(NULL);
- ret = qrtas_get_time_of_day(qs->alloc, &tm, &ns);
+ ret = qrtas_get_time_of_day(qs->qts, qs->alloc, &tm, &ns);
g_assert_cmpint(ret, ==, 0);
t2 = mktimegm(&tm);
g_assert(t2 - t1 < 5); /* 5 sec max to run the test */
diff --git a/tests/rtl8139-test.c b/tests/rtl8139-test.c
index 7de7dc45ae..68bfc42178 100644
--- a/tests/rtl8139-test.c
+++ b/tests/rtl8139-test.c
@@ -35,7 +35,7 @@ static QPCIDevice *get_device(void)
{
QPCIDevice *dev;
- pcibus = qpci_init_pc(NULL);
+ pcibus = qpci_init_pc(global_qtest, NULL);
qpci_device_foreach(pcibus, 0x10ec, 0x8139, save_fn, &dev);
g_assert(dev != NULL);
@@ -197,11 +197,12 @@ int main(int argc, char **argv)
{
int ret;
+ qtest_start("-device rtl8139");
+
g_test_init(&argc, &argv, NULL);
qtest_add_func("/rtl8139/nop", nop);
qtest_add_func("/rtl8139/timer", test_init);
- qtest_start("-device rtl8139");
ret = g_test_run();
qtest_end();
diff --git a/tests/sdhci-test.c b/tests/sdhci-test.c
index 493023fd0c..6b3a5328e0 100644
--- a/tests/sdhci-test.c
+++ b/tests/sdhci-test.c
@@ -187,7 +187,7 @@ static QSDHCI *machine_start(const struct sdhci_t *test)
global_qtest = qtest_startf("-machine %s -device sdhci-pci",
test->machine);
- s->pci.bus = qpci_init_pc(NULL);
+ s->pci.bus = qpci_init_pc(global_qtest, NULL);
/* Find PCI device and verify it's the right one */
s->pci.dev = qpci_device_find(s->pci.bus, QPCI_DEVFN(4, 0));
diff --git a/tests/tco-test.c b/tests/tco-test.c
index 8ab43d742a..aee17af3c1 100644
--- a/tests/tco-test.c
+++ b/tests/tco-test.c
@@ -64,7 +64,7 @@ static void test_init(TestData *d)
global_qtest = qs;
qtest_irq_intercept_in(qs, "ioapic");
- d->bus = qpci_init_pc(NULL);
+ d->bus = qpci_init_pc(qs, NULL);
d->dev = qpci_device_find(d->bus, QPCI_DEVFN(0x1f, 0x00));
g_assert(d->dev != NULL);
@@ -237,9 +237,8 @@ static void test_tco_max_timeout(void)
static QDict *get_watchdog_action(void)
{
- QDict *ev = qmp("");
+ QDict *ev = qmp_eventwait_ref("WATCHDOG");
QDict *data;
- g_assert(!strcmp(qdict_get_str(ev, "event"), "WATCHDOG"));
data = qdict_get_qdict(ev, "data");
QINCREF(data);
diff --git a/tests/tmp105-test.c b/tests/tmp105-test.c
index e9a3cb7ac3..66c7a0147f 100644
--- a/tests/tmp105-test.c
+++ b/tests/tmp105-test.c
@@ -155,15 +155,13 @@ int main(int argc, char **argv)
s = qtest_start("-machine n800 "
"-device tmp105,bus=i2c-bus.0,id=" TMP105_TEST_ID
",address=0x49");
- i2c = omap_i2c_create(OMAP2_I2C_1_BASE);
+ i2c = omap_i2c_create(s, OMAP2_I2C_1_BASE);
qtest_add_func("/tmp105/tx-rx", send_and_receive);
ret = g_test_run();
- if (s) {
- qtest_quit(s);
- }
+ qtest_quit(s);
g_free(i2c);
return ret;
diff --git a/tests/usb-hcd-ehci-test.c b/tests/usb-hcd-ehci-test.c
index 944eb1c088..55d4743a2a 100644
--- a/tests/usb-hcd-ehci-test.c
+++ b/tests/usb-hcd-ehci-test.c
@@ -52,7 +52,7 @@ static void ehci_port_test(struct qhc *hc, int port, uint32_t expect)
static void test_init(void)
{
- pcibus = qpci_init_pc(NULL);
+ pcibus = qpci_init_pc(global_qtest, NULL);
g_assert(pcibus != NULL);
qusb_pci_init_one(pcibus, &uhci1, QPCI_DEVFN(0x1d, 0), 4);
diff --git a/tests/usb-hcd-uhci-test.c b/tests/usb-hcd-uhci-test.c
index 62e0c7829d..6a7e5a2fed 100644
--- a/tests/usb-hcd-uhci-test.c
+++ b/tests/usb-hcd-uhci-test.c
@@ -77,6 +77,7 @@ int main(int argc, char **argv)
"available on x86 or ppc64\n");
exit(EXIT_FAILURE);
}
+ global_qtest = qs->qts;
ret = g_test_run();
qtest_shutdown(qs);
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index a217353e2c..22e9202b8d 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -180,7 +180,7 @@ static void init_virtio_dev(TestServer *s, uint32_t features_mask)
uint32_t features;
int i;
- s->bus = qpci_init_pc(NULL);
+ s->bus = qpci_init_pc(global_qtest, NULL);
g_assert_nonnull(s->bus);
s->dev = qvirtio_pci_device_find(s->bus, VIRTIO_ID_NET);
@@ -191,7 +191,7 @@ static void init_virtio_dev(TestServer *s, uint32_t features_mask)
qvirtio_set_acknowledge(&s->dev->vdev);
qvirtio_set_driver(&s->dev->vdev);
- s->alloc = pc_alloc_init();
+ s->alloc = pc_alloc_init(global_qtest);
for (i = 0; i < s->queues * 2; i++) {
s->vq[i] = qvirtqueue_setup(&s->dev->vdev, s->alloc, i);
diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c
index 54edcb9955..a2b31085f6 100644
--- a/tests/virtio-9p-test.c
+++ b/tests/virtio-9p-test.c
@@ -44,6 +44,7 @@ static QVirtIO9P *qvirtio_9p_start(const char *driver)
g_printerr("virtio-9p tests are only available on x86 or ppc64\n");
exit(EXIT_FAILURE);
}
+ global_qtest = v9p->qs->qts;
return v9p;
}
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
index 2ac64e5e25..9be9ffb378 100644
--- a/tests/virtio-blk-test.c
+++ b/tests/virtio-blk-test.c
@@ -77,6 +77,7 @@ static QOSState *pci_test_start(void)
g_printerr("virtio-blk tests are only available on x86 or ppc64\n");
exit(EXIT_FAILURE);
}
+ global_qtest = qs->qts;
unlink(tmp_path);
g_free(tmp_path);
return qs;
diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c
index 4114839457..0a3c5dd257 100644
--- a/tests/virtio-net-test.c
+++ b/tests/virtio-net-test.c
@@ -54,18 +54,21 @@ static QVirtioPCIDevice *virtio_net_pci_init(QPCIBus *bus, int slot)
static QOSState *pci_test_start(int socket)
{
+ QOSState *qs;
const char *arch = qtest_get_arch();
const char *cmd = "-netdev socket,fd=%d,id=hs0 -device "
"virtio-net-pci,netdev=hs0";
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
- return qtest_pc_boot(cmd, socket);
- }
- if (strcmp(arch, "ppc64") == 0) {
- return qtest_spapr_boot(cmd, socket);
+ qs = qtest_pc_boot(cmd, socket);
+ } else if (strcmp(arch, "ppc64") == 0) {
+ qs = qtest_spapr_boot(cmd, socket);
+ } else {
+ g_printerr("virtio-net tests are only available on x86 or ppc64\n");
+ exit(EXIT_FAILURE);
}
- g_printerr("virtio-net tests are only available on x86 or ppc64\n");
- exit(EXIT_FAILURE);
+ global_qtest = qs->qts;
+ return qs;
}
static void driver_init(QVirtioDevice *dev)
diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c
index bcf408fbb6..7393d69bb2 100644
--- a/tests/virtio-scsi-test.c
+++ b/tests/virtio-scsi-test.c
@@ -34,20 +34,22 @@ typedef struct {
static QOSState *qvirtio_scsi_start(const char *extra_opts)
{
+ QOSState *qs;
const char *arch = qtest_get_arch();
const char *cmd = "-drive id=drv0,if=none,file=null-co://,format=raw "
"-device virtio-scsi-pci,id=vs0 "
"-device scsi-hd,bus=vs0.0,drive=drv0 %s";
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
- return qtest_pc_boot(cmd, extra_opts ? : "");
- }
- if (strcmp(arch, "ppc64") == 0) {
- return qtest_spapr_boot(cmd, extra_opts ? : "");
+ qs = qtest_pc_boot(cmd, extra_opts ? : "");
+ } else if (strcmp(arch, "ppc64") == 0) {
+ qs = qtest_spapr_boot(cmd, extra_opts ? : "");
+ } else {
+ g_printerr("virtio-scsi tests are only available on x86 or ppc64\n");
+ exit(EXIT_FAILURE);
}
-
- g_printerr("virtio-scsi tests are only available on x86 or ppc64\n");
- exit(EXIT_FAILURE);
+ global_qtest = qs->qts;
+ return qs;
}
static void qvirtio_scsi_stop(QOSState *qs)
diff --git a/tests/vmgenid-test.c b/tests/vmgenid-test.c
index 7190e680dc..2ec274e37c 100644
--- a/tests/vmgenid-test.c
+++ b/tests/vmgenid-test.c
@@ -45,7 +45,7 @@ static uint32_t acpi_find_vgia(void)
int i;
/* Wait for guest firmware to finish and start the payload. */
- boot_sector_test();
+ boot_sector_test(global_qtest);
/* Tables should be initialized now. */
rsdp_offset = acpi_find_rsdp_address();
diff --git a/tests/wdt_ib700-test.c b/tests/wdt_ib700-test.c
index 6062d4e942..3b5bbcf007 100644
--- a/tests/wdt_ib700-test.c
+++ b/tests/wdt_ib700-test.c
@@ -12,108 +12,98 @@
#include "qapi/qmp/qdict.h"
#include "qemu/timer.h"
-static void qmp_check_no_event(void)
+static void qmp_check_no_event(QTestState *s)
{
- QDict *resp = qmp("{'execute':'query-status'}");
+ QDict *resp = qtest_qmp(s, "{'execute':'query-status'}");
g_assert(qdict_haskey(resp, "return"));
QDECREF(resp);
}
-static QDict *qmp_get_event(const char *name)
-{
- QDict *event = qmp("");
- QDict *data;
- g_assert(qdict_haskey(event, "event"));
- g_assert(!strcmp(qdict_get_str(event, "event"), name));
-
- if (qdict_haskey(event, "data")) {
- data = qdict_get_qdict(event, "data");
- QINCREF(data);
- } else {
- data = NULL;
- }
-
- QDECREF(event);
- return data;
-}
-
static QDict *ib700_program_and_wait(QTestState *s)
{
- clock_step(NANOSECONDS_PER_SECOND * 40);
- qmp_check_no_event();
+ QDict *event, *data;
+
+ qtest_clock_step(s, NANOSECONDS_PER_SECOND * 40);
+ qmp_check_no_event(s);
/* 2 second limit */
- outb(0x443, 14);
+ qtest_outb(s, 0x443, 14);
/* Ping */
- clock_step(NANOSECONDS_PER_SECOND);
- qmp_check_no_event();
- outb(0x443, 14);
+ qtest_clock_step(s, NANOSECONDS_PER_SECOND);
+ qmp_check_no_event(s);
+ qtest_outb(s, 0x443, 14);
/* Disable */
- clock_step(NANOSECONDS_PER_SECOND);
- qmp_check_no_event();
- outb(0x441, 1);
- clock_step(3 * NANOSECONDS_PER_SECOND);
- qmp_check_no_event();
+ qtest_clock_step(s, NANOSECONDS_PER_SECOND);
+ qmp_check_no_event(s);
+ qtest_outb(s, 0x441, 1);
+ qtest_clock_step(s, 3 * NANOSECONDS_PER_SECOND);
+ qmp_check_no_event(s);
/* Enable and let it fire */
- outb(0x443, 13);
- clock_step(3 * NANOSECONDS_PER_SECOND);
- qmp_check_no_event();
- clock_step(2 * NANOSECONDS_PER_SECOND);
- return qmp_get_event("WATCHDOG");
+ qtest_outb(s, 0x443, 13);
+ qtest_clock_step(s, 3 * NANOSECONDS_PER_SECOND);
+ qmp_check_no_event(s);
+ qtest_clock_step(s, 2 * NANOSECONDS_PER_SECOND);
+ event = qtest_qmp_eventwait_ref(s, "WATCHDOG");
+ data = qdict_get_qdict(event, "data");
+ QINCREF(data);
+ QDECREF(event);
+ return data;
}
static void ib700_pause(void)
{
QDict *d;
- QTestState *s = qtest_start("-watchdog-action pause -device ib700");
+ QTestState *s = qtest_init("-watchdog-action pause -device ib700");
+
qtest_irq_intercept_in(s, "ioapic");
d = ib700_program_and_wait(s);
g_assert(!strcmp(qdict_get_str(d, "action"), "pause"));
QDECREF(d);
- d = qmp_get_event("STOP");
- QDECREF(d);
- qtest_end();
+ qtest_qmp_eventwait(s, "STOP");
+ qtest_quit(s);
}
static void ib700_reset(void)
{
QDict *d;
- QTestState *s = qtest_start("-watchdog-action reset -device ib700");
+ QTestState *s = qtest_init("-watchdog-action reset -device ib700");
+
qtest_irq_intercept_in(s, "ioapic");
d = ib700_program_and_wait(s);
g_assert(!strcmp(qdict_get_str(d, "action"), "reset"));
QDECREF(d);
- d = qmp_get_event("RESET");
- QDECREF(d);
- qtest_end();
+ qtest_qmp_eventwait(s, "RESET");
+ qtest_quit(s);
}
static void ib700_shutdown(void)
{
QDict *d;
- QTestState *s = qtest_start("-watchdog-action reset -no-reboot -device ib700");
+ QTestState *s;
+
+ s = qtest_init("-watchdog-action reset -no-reboot -device ib700");
qtest_irq_intercept_in(s, "ioapic");
d = ib700_program_and_wait(s);
g_assert(!strcmp(qdict_get_str(d, "action"), "reset"));
QDECREF(d);
- d = qmp_get_event("SHUTDOWN");
- QDECREF(d);
- qtest_end();
+ qtest_qmp_eventwait(s, "SHUTDOWN");
+ qtest_quit(s);
}
static void ib700_none(void)
{
QDict *d;
- QTestState *s = qtest_start("-watchdog-action none -device ib700");
+ QTestState *s = qtest_init("-watchdog-action none -device ib700");
+
qtest_irq_intercept_in(s, "ioapic");
d = ib700_program_and_wait(s);
g_assert(!strcmp(qdict_get_str(d, "action"), "none"));
QDECREF(d);
- qtest_end();
+ qtest_quit(s);
}
int main(int argc, char **argv)