aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--block/block-backend.c19
-rw-r--r--docs/devel/testing.rst50
-rw-r--r--hw/block/dataplane/xen-block.c2
-rw-r--r--hw/block/fdc.c9
-rw-r--r--hw/block/m25p80.c6
-rw-r--r--hw/block/nand.c2
-rw-r--r--hw/block/nvme-ns.c7
-rw-r--r--hw/block/onenand.c2
-rw-r--r--hw/block/pflash_cfi01.c2
-rw-r--r--hw/block/pflash_cfi02.c2
-rw-r--r--hw/block/swim.c6
-rw-r--r--hw/block/virtio-blk.c6
-rw-r--r--hw/block/xen-block.c2
-rw-r--r--hw/ide/core.c2
-rw-r--r--hw/misc/sifive_u_otp.c2
-rw-r--r--hw/ppc/pnv_pnor.c2
-rw-r--r--hw/scsi/scsi-disk.c10
-rw-r--r--hw/scsi/scsi-generic.c4
-rw-r--r--hw/sd/sd.c6
-rw-r--r--hw/usb/dev-storage.c4
-rw-r--r--include/sysemu/block-backend.h3
-rwxr-xr-xtests/check-block.sh3
-rw-r--r--tests/qemu-iotests/146.out780
-rwxr-xr-xtests/qemu-iotests/check1095
-rw-r--r--tests/qemu-iotests/common.env.in3
-rw-r--r--tests/qemu-iotests/findtests.py159
-rw-r--r--tests/qemu-iotests/group323
-rw-r--r--tests/qemu-iotests/iotests.py8
-rw-r--r--tests/qemu-iotests/meson.build3
-rw-r--r--tests/qemu-iotests/testenv.py281
-rw-r--r--tests/qemu-iotests/testrunner.py367
-rwxr-xr-xtests/qemu-iotests/tests/migrate-bitmaps-postcopy-test (renamed from tests/qemu-iotests/199)0
-rw-r--r--tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test.out (renamed from tests/qemu-iotests/199.out)0
-rwxr-xr-xtests/qemu-iotests/tests/migrate-bitmaps-test (renamed from tests/qemu-iotests/169)0
-rw-r--r--tests/qemu-iotests/tests/migrate-bitmaps-test.out (renamed from tests/qemu-iotests/169.out)0
-rw-r--r--tests/qtest/virtio-scsi-test.c39
37 files changed, 1481 insertions, 1729 deletions
diff --git a/Makefile b/Makefile
index a380bbf..291ea19 100644
--- a/Makefile
+++ b/Makefile
@@ -236,7 +236,6 @@ distclean: clean
rm -f config-host.mak config-host.h*
rm -f tests/tcg/config-*.mak
rm -f config-all-disas.mak config.status
- rm -f tests/qemu-iotests/common.env
rm -f roms/seabios/config.mak roms/vgabios/config.mak
rm -f qemu-plugins-ld.symbols qemu-plugins-ld64.symbols
rm -f *-config-target.h *-config-devices.mak *-config-devices.h
diff --git a/block/block-backend.c b/block/block-backend.c
index ce78d30..e493f17 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -1826,17 +1826,30 @@ void blk_error_action(BlockBackend *blk, BlockErrorAction action,
}
}
-bool blk_is_read_only(BlockBackend *blk)
+/*
+ * Returns true if the BlockBackend can support taking write permissions
+ * (because its root node is not read-only).
+ */
+bool blk_supports_write_perm(BlockBackend *blk)
{
BlockDriverState *bs = blk_bs(blk);
if (bs) {
- return bdrv_is_read_only(bs);
+ return !bdrv_is_read_only(bs);
} else {
- return blk->root_state.read_only;
+ return !blk->root_state.read_only;
}
}
+/*
+ * Returns true if the BlockBackend can be written to in its current
+ * configuration (i.e. if write permission have been requested)
+ */
+bool blk_is_writable(BlockBackend *blk)
+{
+ return blk->perm & BLK_PERM_WRITE;
+}
+
bool blk_is_sg(BlockBackend *blk)
{
BlockDriverState *bs = blk_bs(blk);
diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst
index 9f8b77c..809af69 100644
--- a/docs/devel/testing.rst
+++ b/docs/devel/testing.rst
@@ -111,7 +111,7 @@ check-block
-----------
``make check-block`` runs a subset of the block layer iotests (the tests that
-are in the "auto" group in ``tests/qemu-iotests/group``).
+are in the "auto" group).
See the "QEMU iotests" section below for more information.
GCC gcov support
@@ -224,6 +224,54 @@ another application on the host may have locked the file, possibly leading to a
test failure. If using such devices are explicitly desired, consider adding
``locking=off`` option to disable image locking.
+Test case groups
+----------------
+
+"Tests may belong to one or more test groups, which are defined in the form
+of a comment in the test source file. By convention, test groups are listed
+in the second line of the test file, after the "#!/..." line, like this:
+
+.. code::
+
+ #!/usr/bin/env python3
+ # group: auto quick
+ #
+ ...
+
+Another way of defining groups is creating the tests/qemu-iotests/group.local
+file. This should be used only for downstream (this file should never appear
+in upstream). This file may be used for defining some downstream test groups
+or for temporarily disabling tests, like this:
+
+.. code::
+
+ # groups for some company downstream process
+ #
+ # ci - tests to run on build
+ # down - our downstream tests, not for upstream
+ #
+ # Format of each line is:
+ # TEST_NAME TEST_GROUP [TEST_GROUP ]...
+
+ 013 ci
+ 210 disabled
+ 215 disabled
+ our-ugly-workaround-test down ci
+
+Note that the following group names have a special meaning:
+
+- quick: Tests in this group should finish within a few seconds.
+
+- auto: Tests in this group are used during "make check" and should be
+ runnable in any case. That means they should run with every QEMU binary
+ (also non-x86), with every QEMU configuration (i.e. must not fail if
+ an optional feature is not compiled in - but reporting a "skip" is ok),
+ work at least with the qcow2 file format, work with all kind of host
+ filesystems and users (e.g. "nobody" or "root") and must not take too
+ much memory and disk space (since CI pipelines tend to fail otherwise).
+
+- disabled: Tests in this group are disabled and ignored by check.
+
.. _docker-ref:
Docker based tests
diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c
index 3675f8d..8607875 100644
--- a/hw/block/dataplane/xen-block.c
+++ b/hw/block/dataplane/xen-block.c
@@ -168,7 +168,7 @@ static int xen_block_parse_request(XenBlockRequest *request)
};
if (request->req.operation != BLKIF_OP_READ &&
- blk_is_read_only(dataplane->blk)) {
+ !blk_is_writable(dataplane->blk)) {
error_report("error: write req for ro device");
goto err;
}
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
index 3636874..292ea87 100644
--- a/hw/block/fdc.c
+++ b/hw/block/fdc.c
@@ -444,7 +444,7 @@ static void fd_revalidate(FDrive *drv)
FLOPPY_DPRINTF("revalidate\n");
if (drv->blk != NULL) {
- drv->ro = blk_is_read_only(drv->blk);
+ drv->ro = !blk_is_writable(drv->blk);
if (!blk_is_inserted(drv->blk)) {
FLOPPY_DPRINTF("No disk in drive\n");
drv->disk = FLOPPY_DRIVE_TYPE_NONE;
@@ -479,8 +479,8 @@ static void fd_change_cb(void *opaque, bool load, Error **errp)
blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort);
} else {
if (!blkconf_apply_backend_options(drive->conf,
- blk_is_read_only(drive->blk), false,
- errp)) {
+ !blk_supports_write_perm(drive->blk),
+ false, errp)) {
return;
}
}
@@ -553,7 +553,8 @@ static void floppy_drive_realize(DeviceState *qdev, Error **errp)
* read-only node later */
read_only = true;
} else {
- read_only = !blk_bs(dev->conf.blk) || blk_is_read_only(dev->conf.blk);
+ read_only = !blk_bs(dev->conf.blk) ||
+ !blk_supports_write_perm(dev->conf.blk);
}
if (!blkconf_blocksizes(&dev->conf, errp)) {
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index b744a58..0412d3e 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -508,7 +508,7 @@ static void flash_sync_page(Flash *s, int page)
{
QEMUIOVector *iov;
- if (!s->blk || blk_is_read_only(s->blk)) {
+ if (!s->blk || !blk_is_writable(s->blk)) {
return;
}
@@ -524,7 +524,7 @@ static inline void flash_sync_area(Flash *s, int64_t off, int64_t len)
{
QEMUIOVector *iov;
- if (!s->blk || blk_is_read_only(s->blk)) {
+ if (!s->blk || !blk_is_writable(s->blk)) {
return;
}
@@ -1434,7 +1434,7 @@ static void m25p80_realize(SSIPeripheral *ss, Error **errp)
if (s->blk) {
uint64_t perm = BLK_PERM_CONSISTENT_READ |
- (blk_is_read_only(s->blk) ? 0 : BLK_PERM_WRITE);
+ (blk_supports_write_perm(s->blk) ? BLK_PERM_WRITE : 0);
ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp);
if (ret < 0) {
return;
diff --git a/hw/block/nand.c b/hw/block/nand.c
index 913292a..8bc80e3 100644
--- a/hw/block/nand.c
+++ b/hw/block/nand.c
@@ -400,7 +400,7 @@ static void nand_realize(DeviceState *dev, Error **errp)
pagesize = 1 << s->oob_shift;
s->mem_oob = 1;
if (s->blk) {
- if (blk_is_read_only(s->blk)) {
+ if (!blk_supports_write_perm(s->blk)) {
error_setg(errp, "Can't use a read-only drive");
return;
}
diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c
index 31c80cd..2670787 100644
--- a/hw/block/nvme-ns.c
+++ b/hw/block/nvme-ns.c
@@ -48,13 +48,14 @@ static void nvme_ns_init(NvmeNamespace *ns)
static int nvme_ns_init_blk(NvmeCtrl *n, NvmeNamespace *ns, Error **errp)
{
+ bool read_only;
+
if (!blkconf_blocksizes(&ns->blkconf, errp)) {
return -1;
}
- if (!blkconf_apply_backend_options(&ns->blkconf,
- blk_is_read_only(ns->blkconf.blk),
- false, errp)) {
+ read_only = !blk_supports_write_perm(ns->blkconf.blk);
+ if (!blkconf_apply_backend_options(&ns->blkconf, read_only, false, errp)) {
return -1;
}
diff --git a/hw/block/onenand.c b/hw/block/onenand.c
index 579a73d..afc0cd3 100644
--- a/hw/block/onenand.c
+++ b/hw/block/onenand.c
@@ -797,7 +797,7 @@ static void onenand_realize(DeviceState *dev, Error **errp)
s->image = memset(g_malloc(size + (size >> 5)),
0xff, size + (size >> 5));
} else {
- if (blk_is_read_only(s->blk)) {
+ if (!blk_supports_write_perm(s->blk)) {
error_setg(errp, "Can't use a read-only drive");
return;
}
diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
index ccf3267..22287a1 100644
--- a/hw/block/pflash_cfi01.c
+++ b/hw/block/pflash_cfi01.c
@@ -745,7 +745,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
if (pfl->blk) {
uint64_t perm;
- pfl->ro = blk_is_read_only(pfl->blk);
+ pfl->ro = !blk_supports_write_perm(pfl->blk);
perm = BLK_PERM_CONSISTENT_READ | (pfl->ro ? 0 : BLK_PERM_WRITE);
ret = blk_set_perm(pfl->blk, perm, BLK_PERM_ALL, errp);
if (ret < 0) {
diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 2ad2f6b..7962cff 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -802,7 +802,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
if (pfl->blk) {
uint64_t perm;
- pfl->ro = blk_is_read_only(pfl->blk);
+ pfl->ro = !blk_supports_write_perm(pfl->blk);
perm = BLK_PERM_CONSISTENT_READ | (pfl->ro ? 0 : BLK_PERM_WRITE);
ret = blk_set_perm(pfl->blk, perm, BLK_PERM_ALL, errp);
if (ret < 0) {
diff --git a/hw/block/swim.c b/hw/block/swim.c
index 20133a8..509c2f4 100644
--- a/hw/block/swim.c
+++ b/hw/block/swim.c
@@ -137,8 +137,8 @@ static void swim_change_cb(void *opaque, bool load, Error **errp)
blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort);
} else {
if (!blkconf_apply_backend_options(drive->conf,
- blk_is_read_only(drive->blk), false,
- errp)) {
+ !blk_supports_write_perm(drive->blk),
+ false, errp)) {
return;
}
}
@@ -210,7 +210,7 @@ static void swim_drive_realize(DeviceState *qdev, Error **errp)
dev->conf.werror = BLOCKDEV_ON_ERROR_AUTO;
if (!blkconf_apply_backend_options(&dev->conf,
- blk_is_read_only(dev->conf.blk),
+ !blk_supports_write_perm(dev->conf.blk),
false, errp)) {
return;
}
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index bac2d6f..e8600b0 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -1021,7 +1021,7 @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features,
virtio_has_feature(features, VIRTIO_BLK_F_CONFIG_WCE))) {
virtio_add_feature(&features, VIRTIO_BLK_F_WCE);
}
- if (blk_is_read_only(s->blk)) {
+ if (!blk_is_writable(s->blk)) {
virtio_add_feature(&features, VIRTIO_BLK_F_RO);
}
if (s->conf.num_queues > 1) {
@@ -1175,8 +1175,8 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
}
if (!blkconf_apply_backend_options(&conf->conf,
- blk_is_read_only(conf->conf.blk), true,
- errp)) {
+ !blk_supports_write_perm(conf->conf.blk),
+ true, errp)) {
return;
}
s->original_wce = blk_enable_write_cache(conf->conf.blk);
diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c
index 718d886..0e7d66c 100644
--- a/hw/block/xen-block.c
+++ b/hw/block/xen-block.c
@@ -567,7 +567,7 @@ static void xen_disk_realize(XenBlockDevice *blockdev, Error **errp)
return;
}
- blockdev->info = blk_is_read_only(conf->blk) ? VDISK_READONLY : 0;
+ blockdev->info = blk_supports_write_perm(conf->blk) ? 0 : VDISK_READONLY;
}
static void xen_disk_class_init(ObjectClass *class, void *data)
diff --git a/hw/ide/core.c b/hw/ide/core.c
index b49e4cf..81db2c9 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -2537,7 +2537,7 @@ int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind,
error_setg(errp, "Device needs media, but drive is empty");
return -1;
}
- if (blk_is_read_only(blk)) {
+ if (!blk_is_writable(blk)) {
error_setg(errp, "Can't use a read-only drive");
return -1;
}
diff --git a/hw/misc/sifive_u_otp.c b/hw/misc/sifive_u_otp.c
index f921c67..b8e8b9e 100644
--- a/hw/misc/sifive_u_otp.c
+++ b/hw/misc/sifive_u_otp.c
@@ -228,7 +228,7 @@ static void sifive_u_otp_realize(DeviceState *dev, Error **errp)
if (s->blk) {
perm = BLK_PERM_CONSISTENT_READ |
- (blk_is_read_only(s->blk) ? 0 : BLK_PERM_WRITE);
+ (blk_supports_write_perm(s->blk) ? BLK_PERM_WRITE : 0);
ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp);
if (ret < 0) {
return;
diff --git a/hw/ppc/pnv_pnor.c b/hw/ppc/pnv_pnor.c
index ef8dff0..4b455de 100644
--- a/hw/ppc/pnv_pnor.c
+++ b/hw/ppc/pnv_pnor.c
@@ -86,7 +86,7 @@ static void pnv_pnor_realize(DeviceState *dev, Error **errp)
if (s->blk) {
uint64_t perm = BLK_PERM_CONSISTENT_READ |
- (blk_is_read_only(s->blk) ? 0 : BLK_PERM_WRITE);
+ (blk_supports_write_perm(s->blk) ? BLK_PERM_WRITE : 0);
ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp);
if (ret < 0) {
return;
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 29504ea..ed52fcd 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -1270,7 +1270,7 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
if (s->qdev.type == TYPE_DISK) {
dev_specific_param = s->features & (1 << SCSI_DISK_F_DPOFUA) ? 0x10 : 0;
- if (blk_is_read_only(s->qdev.conf.blk)) {
+ if (!blk_is_writable(s->qdev.conf.blk)) {
dev_specific_param |= 0x80; /* Readonly. */
}
} else {
@@ -1704,7 +1704,7 @@ static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf)
goto invalid_param_len;
}
- if (blk_is_read_only(s->qdev.conf.blk)) {
+ if (!blk_is_writable(s->qdev.conf.blk)) {
block_acct_invalid(blk_get_stats(s->qdev.conf.blk), BLOCK_ACCT_UNMAP);
scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
return;
@@ -1795,7 +1795,7 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf)
return;
}
- if (blk_is_read_only(s->qdev.conf.blk)) {
+ if (!blk_is_writable(s->qdev.conf.blk)) {
scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
return;
}
@@ -2207,7 +2207,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
case WRITE_VERIFY_10:
case WRITE_VERIFY_12:
case WRITE_VERIFY_16:
- if (blk_is_read_only(s->qdev.conf.blk)) {
+ if (!blk_is_writable(s->qdev.conf.blk)) {
scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
return 0;
}
@@ -2380,7 +2380,7 @@ static void scsi_realize(SCSIDevice *dev, Error **errp)
}
}
- read_only = blk_is_read_only(s->qdev.conf.blk);
+ read_only = !blk_supports_write_perm(s->qdev.conf.blk);
if (dev->type == TYPE_ROM) {
read_only = true;
}
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index 9740f7e..ab22014 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -306,7 +306,7 @@ static void scsi_read_complete(void * opaque, int ret)
* readonly.
*/
if ((s->type == TYPE_DISK || s->type == TYPE_TAPE || s->type == TYPE_ZBC) &&
- blk_is_read_only(s->conf.blk) &&
+ !blk_is_writable(s->conf.blk) &&
(r->req.cmd.buf[0] == MODE_SENSE ||
r->req.cmd.buf[0] == MODE_SENSE_10) &&
(r->req.cmd.buf[1] & 0x8) == 0) {
@@ -694,7 +694,7 @@ static void scsi_generic_realize(SCSIDevice *s, Error **errp)
return;
}
if (!blkconf_apply_backend_options(&s->conf,
- blk_is_read_only(s->conf.blk),
+ !blk_supports_write_perm(s->conf.blk),
true, errp)) {
return;
}
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index b395251..8517dbc 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -567,7 +567,7 @@ static void sd_reset(DeviceState *dev)
sd_set_sdstatus(sd);
g_free(sd->wp_groups);
- sd->wp_switch = sd->blk ? blk_is_read_only(sd->blk) : false;
+ sd->wp_switch = sd->blk ? !blk_is_writable(sd->blk) : false;
sd->wpgrps_size = sect;
sd->wp_groups = bitmap_new(sd->wpgrps_size);
memset(sd->function_group, 0, sizeof(sd->function_group));
@@ -735,7 +735,7 @@ void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert)
{
sd->readonly_cb = readonly;
sd->inserted_cb = insert;
- qemu_set_irq(readonly, sd->blk ? blk_is_read_only(sd->blk) : 0);
+ qemu_set_irq(readonly, sd->blk ? !blk_is_writable(sd->blk) : 0);
qemu_set_irq(insert, sd->blk ? blk_is_inserted(sd->blk) : 0);
}
@@ -2131,7 +2131,7 @@ static void sd_realize(DeviceState *dev, Error **errp)
if (sd->blk) {
int64_t blk_size;
- if (blk_is_read_only(sd->blk)) {
+ if (!blk_supports_write_perm(sd->blk)) {
error_setg(errp, "Cannot use read-only drive as SD card");
return;
}
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index f0f0058..c49e8b8 100644
--- a/hw/usb/dev-storage.c
+++ b/hw/usb/dev-storage.c
@@ -613,8 +613,8 @@ static void usb_msd_storage_realize(USBDevice *dev, Error **errp)
return;
}
- if (!blkconf_apply_backend_options(&s->conf, blk_is_read_only(blk), true,
- errp)) {
+ if (!blkconf_apply_backend_options(&s->conf, !blk_supports_write_perm(blk),
+ true, errp)) {
return;
}
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 8203d7f..880e903 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -191,7 +191,8 @@ BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read,
int error);
void blk_error_action(BlockBackend *blk, BlockErrorAction action,
bool is_read, int error);
-bool blk_is_read_only(BlockBackend *blk);
+bool blk_supports_write_perm(BlockBackend *blk);
+bool blk_is_writable(BlockBackend *blk);
bool blk_is_sg(BlockBackend *blk);
bool blk_enable_write_cache(BlockBackend *blk);
void blk_set_enable_write_cache(BlockBackend *blk, bool wce);
diff --git a/tests/check-block.sh b/tests/check-block.sh
index e4f3790..f86cb86 100755
--- a/tests/check-block.sh
+++ b/tests/check-block.sh
@@ -73,10 +73,11 @@ cd tests/qemu-iotests
# QEMU_CHECK_BLOCK_AUTO is used to disable some unstable sub-tests
export QEMU_CHECK_BLOCK_AUTO=1
+export PYTHONUTF8=1
ret=0
for fmt in $format_list ; do
- ./check -makecheck -$fmt $group || ret=1
+ ${PYTHON} ./check -makecheck -$fmt $group || ret=1
done
exit $ret
diff --git a/tests/qemu-iotests/146.out b/tests/qemu-iotests/146.out
index 80513cd..c67ba4b 100644
--- a/tests/qemu-iotests/146.out
+++ b/tests/qemu-iotests/146.out
@@ -2,414 +2,414 @@ QA output created by 146
=== Testing VPC Autodetect ===
-[{ "start": 0, "length": 136363130880, "depth": 0, "zero": true, "data": false }]
+[{ "start": 0, "length": 136363130880, "depth": 0, "zero": true, "data": false}]
=== Testing VPC with current_size force ===
-[{ "start": 0, "length": 136365211648, "depth": 0, "zero": true, "data": false }]
+[{ "start": 0, "length": 136365211648, "depth": 0, "zero": true, "data": false}]
=== Testing VPC with chs force ===
-[{ "start": 0, "length": 136363130880, "depth": 0, "zero": true, "data": false }]
+[{ "start": 0, "length": 136363130880, "depth": 0, "zero": true, "data": false}]
=== Testing Hyper-V Autodetect ===
-[{ "start": 0, "length": 136365211648, "depth": 0, "zero": true, "data": false }]
+[{ "start": 0, "length": 136365211648, "depth": 0, "zero": true, "data": false}]
=== Testing Hyper-V with current_size force ===
-[{ "start": 0, "length": 136365211648, "depth": 0, "zero": true, "data": false }]
+[{ "start": 0, "length": 136365211648, "depth": 0, "zero": true, "data": false}]
=== Testing Hyper-V with chs force ===
-[{ "start": 0, "length": 136363130880, "depth": 0, "zero": true, "data": false }]
+[{ "start": 0, "length": 136363130880, "depth": 0, "zero": true, "data": false}]
=== Testing d2v Autodetect ===
-[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 4194304, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 6291456, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 8388608, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 10485760, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 12582912, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 14680064, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 16777216, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 18874368, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 20971520, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 23068672, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 25165824, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 27262976, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 29360128, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 31457280, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 33554432, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 35651584, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 37748736, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 39845888, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 41943040, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 44040192, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 46137344, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 48234496, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 50331648, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 52428800, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 54525952, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 56623104, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 58720256, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 60817408, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 62914560, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 65011712, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 67108864, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 69206016, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 71303168, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 73400320, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 75497472, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 77594624, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 79691776, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 81788928, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 83886080, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 85983232, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 88080384, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 90177536, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 92274688, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 94371840, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 96468992, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 98566144, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 100663296, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 102760448, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 104857600, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 106954752, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 109051904, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 111149056, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 113246208, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 115343360, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 117440512, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 119537664, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 121634816, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 123731968, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 125829120, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 127926272, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 130023424, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 132120576, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 134217728, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 136314880, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 138412032, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 140509184, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 142606336, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 144703488, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 146800640, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 148897792, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 150994944, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 153092096, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 155189248, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 157286400, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 159383552, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 161480704, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 163577856, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 165675008, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 167772160, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 169869312, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 171966464, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 174063616, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 176160768, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 178257920, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 180355072, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 182452224, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 184549376, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 186646528, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 188743680, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 190840832, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 192937984, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 195035136, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 197132288, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 199229440, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 201326592, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 203423744, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 205520896, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 207618048, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 209715200, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 211812352, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 213909504, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 216006656, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 218103808, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 220200960, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 222298112, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 224395264, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 226492416, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 228589568, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 230686720, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 232783872, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 234881024, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 236978176, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 239075328, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 241172480, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 243269632, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 245366784, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 247463936, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 249561088, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 251658240, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 253755392, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 255852544, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 257949696, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 260046848, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 262144000, "length": 1310720, "depth": 0, "zero": false, "data": true, "offset": OFFSET }]
+[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 4194304, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 6291456, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 8388608, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 10485760, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 12582912, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 14680064, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 16777216, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 18874368, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 20971520, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 23068672, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 25165824, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 27262976, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 29360128, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 31457280, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 33554432, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 35651584, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 37748736, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 39845888, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 41943040, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 44040192, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 46137344, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 48234496, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 50331648, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 52428800, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 54525952, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 56623104, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 58720256, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 60817408, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 62914560, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 65011712, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 67108864, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 69206016, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 71303168, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 73400320, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 75497472, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 77594624, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 79691776, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 81788928, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 83886080, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 85983232, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 88080384, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 90177536, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 92274688, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 94371840, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 96468992, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 98566144, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 100663296, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 102760448, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 104857600, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 106954752, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 109051904, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 111149056, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 113246208, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 115343360, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 117440512, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 119537664, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 121634816, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 123731968, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 125829120, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 127926272, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 130023424, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 132120576, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 134217728, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 136314880, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 138412032, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 140509184, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 142606336, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 144703488, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 146800640, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 148897792, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 150994944, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 153092096, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 155189248, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 157286400, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 159383552, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 161480704, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 163577856, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 165675008, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 167772160, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 169869312, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 171966464, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 174063616, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 176160768, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 178257920, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 180355072, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 182452224, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 184549376, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 186646528, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 188743680, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 190840832, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 192937984, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 195035136, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 197132288, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 199229440, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 201326592, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 203423744, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 205520896, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 207618048, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 209715200, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 211812352, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 213909504, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 216006656, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 218103808, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 220200960, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 222298112, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 224395264, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 226492416, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 228589568, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 230686720, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 232783872, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 234881024, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 236978176, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 239075328, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 241172480, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 243269632, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 245366784, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 247463936, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 249561088, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 251658240, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 253755392, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 255852544, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 257949696, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 260046848, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 262144000, "length": 1310720, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
=== Testing d2v with current_size force ===
-[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 4194304, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 6291456, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 8388608, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 10485760, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 12582912, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 14680064, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 16777216, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 18874368, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 20971520, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 23068672, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 25165824, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 27262976, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 29360128, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 31457280, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 33554432, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 35651584, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 37748736, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 39845888, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 41943040, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 44040192, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 46137344, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 48234496, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 50331648, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 52428800, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 54525952, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 56623104, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 58720256, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 60817408, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 62914560, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 65011712, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 67108864, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 69206016, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 71303168, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 73400320, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 75497472, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 77594624, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 79691776, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 81788928, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 83886080, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 85983232, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 88080384, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 90177536, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 92274688, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 94371840, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 96468992, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 98566144, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 100663296, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 102760448, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 104857600, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 106954752, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 109051904, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 111149056, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 113246208, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 115343360, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 117440512, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 119537664, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 121634816, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 123731968, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 125829120, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 127926272, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 130023424, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 132120576, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 134217728, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 136314880, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 138412032, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 140509184, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 142606336, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 144703488, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 146800640, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 148897792, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 150994944, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 153092096, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 155189248, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 157286400, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 159383552, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 161480704, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 163577856, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 165675008, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 167772160, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 169869312, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 171966464, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 174063616, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 176160768, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 178257920, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 180355072, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 182452224, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 184549376, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 186646528, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 188743680, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 190840832, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 192937984, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 195035136, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 197132288, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 199229440, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 201326592, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 203423744, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 205520896, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 207618048, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 209715200, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 211812352, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 213909504, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 216006656, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 218103808, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 220200960, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 222298112, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 224395264, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 226492416, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 228589568, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 230686720, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 232783872, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 234881024, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 236978176, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 239075328, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 241172480, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 243269632, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 245366784, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 247463936, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 249561088, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 251658240, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 253755392, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 255852544, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 257949696, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 260046848, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 262144000, "length": 1310720, "depth": 0, "zero": false, "data": true, "offset": OFFSET }]
+[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 4194304, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 6291456, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 8388608, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 10485760, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 12582912, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 14680064, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 16777216, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 18874368, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 20971520, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 23068672, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 25165824, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 27262976, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 29360128, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 31457280, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 33554432, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 35651584, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 37748736, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 39845888, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 41943040, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 44040192, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 46137344, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 48234496, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 50331648, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 52428800, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 54525952, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 56623104, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 58720256, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 60817408, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 62914560, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 65011712, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 67108864, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 69206016, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 71303168, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 73400320, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 75497472, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 77594624, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 79691776, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 81788928, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 83886080, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 85983232, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 88080384, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 90177536, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 92274688, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 94371840, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 96468992, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 98566144, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 100663296, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 102760448, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 104857600, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 106954752, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 109051904, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 111149056, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 113246208, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 115343360, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 117440512, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 119537664, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 121634816, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 123731968, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 125829120, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 127926272, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 130023424, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 132120576, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 134217728, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 136314880, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 138412032, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 140509184, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 142606336, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 144703488, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 146800640, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 148897792, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 150994944, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 153092096, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 155189248, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 157286400, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 159383552, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 161480704, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 163577856, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 165675008, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 167772160, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 169869312, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 171966464, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 174063616, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 176160768, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 178257920, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 180355072, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 182452224, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 184549376, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 186646528, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 188743680, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 190840832, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 192937984, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 195035136, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 197132288, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 199229440, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 201326592, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 203423744, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 205520896, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 207618048, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 209715200, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 211812352, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 213909504, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 216006656, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 218103808, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 220200960, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 222298112, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 224395264, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 226492416, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 228589568, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 230686720, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 232783872, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 234881024, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 236978176, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 239075328, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 241172480, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 243269632, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 245366784, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 247463936, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 249561088, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 251658240, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 253755392, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 255852544, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 257949696, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 260046848, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 262144000, "length": 1310720, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
=== Testing d2v with chs force ===
-[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 4194304, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 6291456, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 8388608, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 10485760, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 12582912, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 14680064, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 16777216, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 18874368, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 20971520, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 23068672, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 25165824, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 27262976, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 29360128, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 31457280, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 33554432, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 35651584, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 37748736, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 39845888, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 41943040, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 44040192, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 46137344, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 48234496, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 50331648, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 52428800, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 54525952, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 56623104, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 58720256, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 60817408, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 62914560, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 65011712, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 67108864, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 69206016, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 71303168, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 73400320, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 75497472, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 77594624, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 79691776, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 81788928, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 83886080, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 85983232, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 88080384, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 90177536, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 92274688, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 94371840, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 96468992, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 98566144, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 100663296, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 102760448, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 104857600, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 106954752, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 109051904, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 111149056, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 113246208, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 115343360, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 117440512, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 119537664, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 121634816, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 123731968, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 125829120, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 127926272, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 130023424, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 132120576, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 134217728, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 136314880, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 138412032, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 140509184, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 142606336, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 144703488, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 146800640, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 148897792, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 150994944, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 153092096, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 155189248, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 157286400, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 159383552, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 161480704, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 163577856, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 165675008, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 167772160, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 169869312, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 171966464, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 174063616, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 176160768, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 178257920, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 180355072, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 182452224, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 184549376, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 186646528, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 188743680, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 190840832, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 192937984, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 195035136, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 197132288, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 199229440, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 201326592, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 203423744, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 205520896, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 207618048, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 209715200, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 211812352, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 213909504, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 216006656, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 218103808, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 220200960, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 222298112, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 224395264, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 226492416, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 228589568, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 230686720, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 232783872, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 234881024, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 236978176, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 239075328, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 241172480, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 243269632, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 245366784, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 247463936, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 249561088, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 251658240, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 253755392, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 255852544, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 257949696, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 260046848, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET },
-{ "start": 262144000, "length": 1310720, "depth": 0, "zero": false, "data": true, "offset": OFFSET }]
+[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 4194304, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 6291456, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 8388608, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 10485760, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 12582912, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 14680064, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 16777216, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 18874368, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 20971520, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 23068672, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 25165824, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 27262976, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 29360128, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 31457280, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 33554432, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 35651584, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 37748736, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 39845888, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 41943040, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 44040192, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 46137344, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 48234496, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 50331648, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 52428800, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 54525952, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 56623104, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 58720256, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 60817408, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 62914560, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 65011712, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 67108864, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 69206016, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 71303168, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 73400320, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 75497472, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 77594624, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 79691776, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 81788928, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 83886080, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 85983232, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 88080384, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 90177536, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 92274688, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 94371840, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 96468992, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 98566144, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 100663296, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 102760448, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 104857600, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 106954752, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 109051904, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 111149056, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 113246208, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 115343360, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 117440512, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 119537664, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 121634816, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 123731968, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 125829120, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 127926272, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 130023424, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 132120576, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 134217728, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 136314880, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 138412032, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 140509184, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 142606336, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 144703488, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 146800640, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 148897792, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 150994944, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 153092096, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 155189248, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 157286400, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 159383552, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 161480704, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 163577856, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 165675008, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 167772160, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 169869312, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 171966464, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 174063616, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 176160768, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 178257920, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 180355072, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 182452224, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 184549376, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 186646528, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 188743680, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 190840832, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 192937984, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 195035136, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 197132288, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 199229440, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 201326592, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 203423744, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 205520896, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 207618048, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 209715200, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 211812352, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 213909504, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 216006656, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 218103808, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 220200960, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 222298112, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 224395264, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 226492416, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 228589568, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 230686720, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 232783872, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 234881024, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 236978176, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 239075328, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 241172480, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 243269632, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 245366784, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 247463936, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 249561088, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 251658240, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 253755392, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 255852544, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 257949696, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 260046848, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
+{ "start": 262144000, "length": 1310720, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
=== Testing Image create, default ===
@@ -417,15 +417,15 @@ Formatting 'TEST_DIR/IMGFMT-create-test.IMGFMT', fmt=IMGFMT size=4294967296
=== Read created image, default opts ====
-[{ "start": 0, "length": 4295467008, "depth": 0, "zero": true, "data": false }]
+[{ "start": 0, "length": 4295467008, "depth": 0, "zero": true, "data": false}]
=== Read created image, force_size_calc=chs ====
-[{ "start": 0, "length": 4295467008, "depth": 0, "zero": true, "data": false }]
+[{ "start": 0, "length": 4295467008, "depth": 0, "zero": true, "data": false}]
=== Read created image, force_size_calc=current_size ====
-[{ "start": 0, "length": 4295467008, "depth": 0, "zero": true, "data": false }]
+[{ "start": 0, "length": 4295467008, "depth": 0, "zero": true, "data": false}]
=== Testing Image create, force_size ===
@@ -433,13 +433,13 @@ Formatting 'TEST_DIR/IMGFMT-create-test.IMGFMT', fmt=IMGFMT size=4294967296
=== Read created image, default opts ====
-[{ "start": 0, "length": 4294967296, "depth": 0, "zero": true, "data": false }]
+[{ "start": 0, "length": 4294967296, "depth": 0, "zero": true, "data": false}]
=== Read created image, force_size_calc=chs ====
-[{ "start": 0, "length": 4294967296, "depth": 0, "zero": true, "data": false }]
+[{ "start": 0, "length": 4294967296, "depth": 0, "zero": true, "data": false}]
=== Read created image, force_size_calc=current_size ====
-[{ "start": 0, "length": 4294967296, "depth": 0, "zero": true, "data": false }]
+[{ "start": 0, "length": 4294967296, "depth": 0, "zero": true, "data": false}]
*** done
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
index 952762d..5190dee 100755
--- a/tests/qemu-iotests/check
+++ b/tests/qemu-iotests/check
@@ -1,7 +1,8 @@
-#!/usr/bin/env bash
+#!/usr/bin/env python3
#
-# Copyright (C) 2009 Red Hat, Inc.
-# Copyright (c) 2000-2002,2006 Silicon Graphics, Inc. All Rights Reserved.
+# Configure environment and run group of tests in it.
+#
+# Copyright (c) 2020-2021 Virtuozzo International GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
@@ -14,967 +15,129 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-#
-# Control script for QA
-#
-
-status=0
-needwrap=true
-try=0
-n_bad=0
-bad=""
-notrun=""
-casenotrun=""
-interrupt=true
-makecheck=false
-
-_init_error()
-{
- echo "check: $1" >&2
- exit 1
-}
-
-if [ -L "$0" ]
-then
- # called from the build tree
- source_iotests=$(dirname "$(readlink "$0")")
- if [ -z "$source_iotests" ]
- then
- _init_error "failed to obtain source tree name from check symlink"
- fi
- source_iotests=$(cd "$source_iotests"; pwd) || _init_error "failed to enter source tree"
- build_iotests=$(cd "$(dirname "$0")"; pwd)
-else
- # called from the source tree
- source_iotests=$PWD
- # this may be an in-tree build (note that in the following code we may not
- # assume that it truly is and have to test whether the build results
- # actually exist)
- build_iotests=$PWD
-fi
-
-build_root="$build_iotests/../.."
-
-# we need common.env
-if ! . "$build_iotests/common.env"
-then
- _init_error "failed to source common.env (make sure the qemu-iotests are run from tests/qemu-iotests in the build tree)"
-fi
-
-# we need common.config
-if ! . "$source_iotests/common.config"
-then
- _init_error "failed to source common.config"
-fi
-
-_full_imgfmt_details()
-{
- if [ -n "$IMGOPTS" ]; then
- echo "$IMGFMT ($IMGOPTS)"
- else
- echo "$IMGFMT"
- fi
-}
-
-_full_platform_details()
-{
- os=$(uname -s)
- host=$(hostname -s)
- kernel=$(uname -r)
- platform=$(uname -m)
- echo "$os/$platform $host $kernel"
-}
-
-_full_env_details()
-{
- cat <<EOF
-QEMU -- "$QEMU_PROG" $QEMU_OPTIONS
-QEMU_IMG -- "$QEMU_IMG_PROG" $QEMU_IMG_OPTIONS
-QEMU_IO -- "$QEMU_IO_PROG" $QEMU_IO_OPTIONS
-QEMU_NBD -- "$QEMU_NBD_PROG" $QEMU_NBD_OPTIONS
-IMGFMT -- $FULL_IMGFMT_DETAILS
-IMGPROTO -- $IMGPROTO
-PLATFORM -- $FULL_HOST_DETAILS
-TEST_DIR -- $TEST_DIR
-SOCK_DIR -- $SOCK_DIR
-SOCKET_SCM_HELPER -- $SOCKET_SCM_HELPER
-
-EOF
-}
-
-# $1 = prog to look for
-set_prog_path()
-{
- p=$(command -v $1 2> /dev/null)
- if [ -n "$p" -a -x "$p" ]; then
- type -p "$p"
- else
- return 1
- fi
-}
-
-if [ -z "$TEST_DIR" ]; then
- TEST_DIR=$PWD/scratch
-fi
-mkdir -p "$TEST_DIR" || _init_error 'Failed to create TEST_DIR'
-
-tmp_sock_dir=false
-if [ -z "$SOCK_DIR" ]; then
- SOCK_DIR=$(mktemp -d)
- tmp_sock_dir=true
-fi
-mkdir -p "$SOCK_DIR" || _init_error 'Failed to create SOCK_DIR'
-
-diff="diff -u"
-verbose=false
-debug=false
-group=false
-xgroup=false
-imgopts=false
-showme=false
-sortme=false
-expunge=true
-have_test_arg=false
-cachemode=false
-aiomode=false
-
-tmp="${TEST_DIR}"/$$
-rm -f $tmp.list $tmp.tmp $tmp.sed
-
-export IMGFMT=raw
-export IMGFMT_GENERIC=true
-export IMGPROTO=file
-export IMGOPTS=""
-export CACHEMODE="writeback"
-export AIOMODE="threads"
-export QEMU_IO_OPTIONS=""
-export QEMU_IO_OPTIONS_NO_FMT=""
-export CACHEMODE_IS_DEFAULT=true
-export VALGRIND_QEMU=
-export IMGKEYSECRET=
-export IMGOPTSSYNTAX=false
-
-# Save current tty settings, since an aborting qemu call may leave things
-# screwed up
-STTY_RESTORE=
-if test -t 0; then
- STTY_RESTORE=$(stty -g)
-fi
-
-for r
-do
-
- if $group
- then
- # arg after -g
- group_list=$(sed -n <"$source_iotests/group" -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{
-s/ .*//p
-}')
- if [ -z "$group_list" ]
- then
- echo "Group \"$r\" is empty or not defined?"
- exit 1
- fi
- [ ! -s $tmp.list ] && touch $tmp.list
- for t in $group_list
- do
- if grep -s "^$t\$" $tmp.list >/dev/null
- then
- :
- else
- echo "$t" >>$tmp.list
- fi
- done
- group=false
- continue
-
- elif $xgroup
- then
- # arg after -x
- # Populate $tmp.list with all tests
- awk '/^[0-9]{3,}/ {print $1}' "${source_iotests}/group" > $tmp.list 2>/dev/null
- group_list=$(sed -n <"$source_iotests/group" -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{
-s/ .*//p
-}')
- if [ -z "$group_list" ]
- then
- echo "Group \"$r\" is empty or not defined?"
- exit 1
- fi
- numsed=0
- rm -f $tmp.sed
- for t in $group_list
- do
- if [ $numsed -gt 100 ]
- then
- sed -f $tmp.sed <$tmp.list >$tmp.tmp
- mv $tmp.tmp $tmp.list
- numsed=0
- rm -f $tmp.sed
- fi
- echo "/^$t\$/d" >>$tmp.sed
- numsed=$(expr $numsed + 1)
- done
- sed -f $tmp.sed <$tmp.list >$tmp.tmp
- mv $tmp.tmp $tmp.list
- xgroup=false
- continue
-
- elif $imgopts
- then
- IMGOPTS="$r"
- imgopts=false
- continue
- elif $cachemode
- then
- CACHEMODE="$r"
- CACHEMODE_IS_DEFAULT=false
- cachemode=false
- continue
- elif $aiomode
- then
- AIOMODE="$r"
- aiomode=false
- continue
- fi
-
- xpand=true
- case "$r"
- in
-
- -\? | -h | --help) # usage
- echo "Usage: $0 [options] [testlist]"'
-
-common options
- -v verbose
- -d debug
-
-image format options
- -raw test raw (default)
- -bochs test bochs
- -cloop test cloop
- -parallels test parallels
- -qcow test qcow
- -qcow2 test qcow2
- -qed test qed
- -vdi test vdi
- -vpc test vpc
- -vhdx test vhdx
- -vmdk test vmdk
- -luks test luks
- -dmg test dmg
-
-image protocol options
- -file test file (default)
- -rbd test rbd
- -sheepdog test sheepdog
- -nbd test nbd
- -fuse test fuse
- -ssh test ssh
- -nfs test nfs
-
-other options
- -xdiff graphical mode diff
- -nocache use O_DIRECT on backing file
- -misalign misalign memory allocations
- -n show me, do not run tests
- -o options -o options to pass to qemu-img create/convert
- -c mode cache mode
- -i mode AIO mode
- -makecheck pretty print output for make check
-
-testlist options
- -g group[,group...] include tests from these groups
- -x group[,group...] exclude tests from these groups
- NNN include test NNN
- NNN-NNN include test range (eg. 012-021)
-'
- exit 0
- ;;
-
- -raw)
- IMGFMT=raw
- xpand=false
- ;;
-
- -bochs)
- IMGFMT=bochs
- IMGFMT_GENERIC=false
- xpand=false
- ;;
-
- -cloop)
- IMGFMT=cloop
- IMGFMT_GENERIC=false
- xpand=false
- ;;
-
- -parallels)
- IMGFMT=parallels
- xpand=false
- ;;
-
- -qcow)
- IMGFMT=qcow
- xpand=false
- ;;
-
- -qcow2)
- IMGFMT=qcow2
- xpand=false
- ;;
-
- -luks)
- IMGOPTSSYNTAX=true
- IMGFMT=luks
- IMGKEYSECRET=123456
- xpand=false
- ;;
-
- -dmg)
- IMGFMT=dmg
- IMGFMT_GENERIC=false
- xpand=false
- ;;
-
- -qed)
- IMGFMT=qed
- xpand=false
- ;;
-
- -vdi)
- IMGFMT=vdi
- xpand=false
- ;;
-
- -vmdk)
- IMGFMT=vmdk
- xpand=false
- ;;
-
- -vpc)
- IMGFMT=vpc
- xpand=false
- ;;
-
- -vhdx)
- IMGFMT=vhdx
- xpand=false
- ;;
-
- -file)
- IMGPROTO=file
- xpand=false
- ;;
-
- -rbd)
- IMGPROTO=rbd
- xpand=false
- ;;
-
- -sheepdog)
- IMGPROTO=sheepdog
- xpand=false
- ;;
-
- -nbd)
- IMGPROTO=nbd
- xpand=false
- ;;
-
- -fuse)
- IMGPROTO=fuse
- xpand=false
- ;;
-
- -ssh)
- IMGPROTO=ssh
- xpand=false
- ;;
-
- -nfs)
- IMGPROTO=nfs
- xpand=false
- ;;
-
- -nocache)
- CACHEMODE="none"
- CACHEMODE_IS_DEFAULT=false
- xpand=false
- ;;
-
- -misalign)
- QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --misalign"
- xpand=false
- ;;
-
- -valgrind)
- VALGRIND_QEMU='y'
- xpand=false
- ;;
-
- -g) # -g group ... pick from group file
- group=true
- xpand=false
- ;;
-
- -xdiff) # graphical diff mode
- xpand=false
-
- if [ ! -z "$DISPLAY" ]
- then
- command -v xdiff >/dev/null 2>&1 && diff=xdiff
- command -v gdiff >/dev/null 2>&1 && diff=gdiff
- command -v tkdiff >/dev/null 2>&1 && diff=tkdiff
- command -v xxdiff >/dev/null 2>&1 && diff=xxdiff
- fi
- ;;
- -makecheck) # makecheck friendly output
- makecheck=true
- xpand=false
- ;;
- -n) # show me, don't do it
- showme=true
- xpand=false
- ;;
- -o)
- imgopts=true
- xpand=false
- ;;
- -c)
- cachemode=true
- xpand=false
- ;;
- -i)
- aiomode=true
- xpand=false
- ;;
- -T) # deprecated timestamp option
- xpand=false
- ;;
- -v)
- verbose=true
- xpand=false
- ;;
- -d)
- debug=true
- xpand=false
- ;;
- -x) # -x group ... exclude from group file
- xgroup=true
- xpand=false
- ;;
- '[0-9][0-9][0-9] [0-9][0-9][0-9][0-9]')
- echo "No tests?"
- status=1
- exit $status
- ;;
-
- [0-9]*-[0-9]*)
- eval $(echo $r | sed -e 's/^/start=/' -e 's/-/ end=/')
- ;;
-
- [0-9]*-)
- eval $(echo $r | sed -e 's/^/start=/' -e 's/-//')
- end=$(echo [0-9][0-9][0-9] [0-9][0-9][0-9][0-9] | sed -e 's/\[0-9]//g' -e 's/ *$//' -e 's/.* //')
- if [ -z "$end" ]
- then
- echo "No tests in range \"$r\"?"
- status=1
- exit $status
- fi
- ;;
-
- *)
- start=$r
- end=$r
- ;;
-
- esac
-
- # get rid of leading 0s as can be interpreted as octal
- start=$(echo $start | sed 's/^0*//')
- end=$(echo $end | sed 's/^0*//')
-
- if $xpand
- then
- have_test_arg=true
- awk </dev/null '
-BEGIN { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \
- | while read id
- do
- if grep -s "^$id\( \|\$\)" "$source_iotests/group" >/dev/null
- then
- # in group file ... OK
- echo $id >>$tmp.list
- else
- if [ -f expunged ] && $expunge && egrep "^$id([ ]|\$)" expunged >/dev/null
- then
- # expunged ... will be reported, but not run, later
- echo $id >>$tmp.list
- else
- # oops
- if [ "$start" == "$end" -a "$id" == "$end" ]
- then
- echo "$id - unknown test"
- exit 1
- else
- echo "$id - unknown test, ignored"
- fi
- fi
- fi
- done || exit 1
- fi
-
-done
-
-# Set qemu-io cache mode with $CACHEMODE we have
-QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --cache $CACHEMODE"
-# Set qemu-io aio mode with $AIOMODE we have
-QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --aio $AIOMODE"
-
-QEMU_IO_OPTIONS_NO_FMT="$QEMU_IO_OPTIONS"
-if [ "$IMGOPTSSYNTAX" != "true" ]; then
- QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS -f $IMGFMT"
-fi
-
-# Set default options for qemu-img create -o if they were not specified
-if [ "$IMGFMT" == "qcow2" ] && ! (echo "$IMGOPTS" | grep "compat=" > /dev/null); then
- IMGOPTS=$(_optstr_add "$IMGOPTS" "compat=1.1")
-fi
-if [ "$IMGFMT" == "luks" ] && ! (echo "$IMGOPTS" | grep "iter-time=" > /dev/null); then
- IMGOPTS=$(_optstr_add "$IMGOPTS" "iter-time=10")
-fi
-if [ "$IMGFMT" == "vmdk" ] && ! (echo "$IMGOPTS" | grep "zeroed_grain=" > /dev/null); then
- IMGOPTS=$(_optstr_add "$IMGOPTS" "zeroed_grain=on")
-fi
-
-if [ -z "$SAMPLE_IMG_DIR" ]; then
- SAMPLE_IMG_DIR="$source_iotests/sample_images"
-fi
-
-export TEST_DIR
-export SOCK_DIR
-export SAMPLE_IMG_DIR
-
-if [ -s $tmp.list ]
-then
- # found some valid test numbers ... this is good
- :
-else
- if $have_test_arg
- then
- # had test numbers, but none in group file ... do nothing
- touch $tmp.list
- else
- # no test numbers, do everything from group file
- sed -n -e '/^[0-9][0-9][0-9]*/s/^\([0-9]*\).*/\1/p' <"$source_iotests/group" >$tmp.list
- fi
-fi
-
-# should be sort -n, but this did not work for Linux when this
-# was ported from IRIX
-#
-list=$(sort $tmp.list)
-rm -f $tmp.list $tmp.tmp $tmp.sed
-
-if [ -z "$QEMU_PROG" ]
-then
- if [ -x "$build_iotests/qemu" ]; then
- export QEMU_PROG="$build_iotests/qemu"
- elif [ -x "$build_root/qemu-system-${qemu_arch}" ]; then
- export QEMU_PROG="$build_root/qemu-system-${qemu_arch}"
- else
- pushd "$build_root" > /dev/null
- for binary in qemu-system-*
- do
- if [ -x "$binary" ]
- then
- export QEMU_PROG="$build_root/$binary"
- break
- fi
- done
- popd > /dev/null
- [ "$QEMU_PROG" = "" ] && _init_error "qemu not found"
- fi
-fi
-export QEMU_PROG="$(type -p "$QEMU_PROG")"
-
-export QEMU_OPTIONS="-nodefaults -display none -accel qtest"
-case "$QEMU_PROG" in
- *qemu-system-arm|*qemu-system-aarch64)
- export QEMU_OPTIONS="$QEMU_OPTIONS -machine virt"
- ;;
- *qemu-system-avr)
- export QEMU_OPTIONS="$QEMU_OPTIONS -machine mega2560"
- ;;
- *qemu-system-rx)
- export QEMU_OPTIONS="$QEMU_OPTIONS -machine gdbsim-r5f562n8"
- ;;
- *qemu-system-tricore)
- export QEMU_OPTIONS="-$QEMU_OPTIONS -machine tricore_testboard"
- ;;
-esac
-
-if [ -z "$QEMU_IMG_PROG" ]; then
- if [ -x "$build_iotests/qemu-img" ]; then
- export QEMU_IMG_PROG="$build_iotests/qemu-img"
- elif [ -x "$build_root/qemu-img" ]; then
- export QEMU_IMG_PROG="$build_root/qemu-img"
- else
- _init_error "qemu-img not found"
- fi
-fi
-export QEMU_IMG_PROG="$(type -p "$QEMU_IMG_PROG")"
-
-if [ -z "$QEMU_IO_PROG" ]; then
- if [ -x "$build_iotests/qemu-io" ]; then
- export QEMU_IO_PROG="$build_iotests/qemu-io"
- elif [ -x "$build_root/qemu-io" ]; then
- export QEMU_IO_PROG="$build_root/qemu-io"
- else
- _init_error "qemu-io not found"
- fi
-fi
-export QEMU_IO_PROG="$(type -p "$QEMU_IO_PROG")"
-
-if [ -z $QEMU_NBD_PROG ]; then
- if [ -x "$build_iotests/qemu-nbd" ]; then
- export QEMU_NBD_PROG="$build_iotests/qemu-nbd"
- elif [ -x "$build_root/qemu-nbd" ]; then
- export QEMU_NBD_PROG="$build_root/qemu-nbd"
- else
- _init_error "qemu-nbd not found"
- fi
-fi
-export QEMU_NBD_PROG="$(type -p "$QEMU_NBD_PROG")"
-
-if [ -z "$QSD_PROG" ]; then
- if [ -x "$build_iotests/qemu-storage-daemon" ]; then
- export QSD_PROG="$build_iotests/qemu-storage-daemon"
- elif [ -x "$build_root/storage-daemon/qemu-storage-daemon" ]; then
- export QSD_PROG="$build_root/storage-daemon/qemu-storage-daemon"
- else
- _init_error "qemu-storage-daemon not found"
- fi
-fi
-export QSD_PROG="$(type -p "$QSD_PROG")"
-
-if [ -x "$build_iotests/socket_scm_helper" ]
-then
- export SOCKET_SCM_HELPER="$build_iotests/socket_scm_helper"
-fi
-
-python_usable=false
-if $PYTHON -c 'import sys; sys.exit(0 if sys.version_info >= (3,6) else 1)'
-then
- # Our python framework also requires virtio-blk
- if "$QEMU_PROG" -M none -device help | grep -q virtio-blk >/dev/null 2>&1
- then
- python_usable=true
- else
- python_unusable_because="Missing virtio-blk in QEMU binary"
- fi
-else
- python_unusable_because="Unsupported Python version"
-fi
-
-default_machine=$($QEMU_PROG -machine help | sed -n '/(default)/ s/ .*//p')
-default_alias_machine=$($QEMU_PROG -machine help | \
- sed -n "/(alias of $default_machine)/ { s/ .*//p; q; }")
-if [[ "$default_alias_machine" ]]; then
- default_machine="$default_alias_machine"
-fi
-
-export QEMU_DEFAULT_MACHINE="$default_machine"
-
-TIMESTAMP_FILE=check.time-$IMGPROTO-$IMGFMT
-
-_wallclock()
-{
- date "+%H %M %S" | awk '{ print $1*3600 + $2*60 + $3 }'
-}
-
-_wrapup()
-{
- if $showme
- then
- :
- elif $needwrap
- then
- if [ -f $TIMESTAMP_FILE -a -f $tmp.time ]
- then
- cat $TIMESTAMP_FILE $tmp.time \
- | awk '
- { t[$1] = $2 }
-END { if (NR > 0) {
- for (i in t) print i " " t[i]
- }
- }' \
- | sort -n >$tmp.out
- mv $tmp.out $TIMESTAMP_FILE
- fi
-
- if [ -f $tmp.expunged ]
- then
- notrun=$(wc -l <$tmp.expunged | sed -e 's/ *//g')
- try=$(expr $try - $notrun)
- list=$(echo "$list" | sed -f $tmp.expunged)
- fi
-
- echo "" >>check.log
- date >>check.log
- echo $list | fmt | sed -e 's/^/ /' >>check.log
- $interrupt && echo "Interrupted!" >>check.log
-
- if [ ! -z "$notrun" ]
- then
- echo "Not run:$notrun"
- echo "Not run:$notrun" >>check.log
- fi
- if [ ! -z "$casenotrun" ]
- then
- echo "Some cases not run in:$casenotrun"
- echo "Some cases not run in:$casenotrun" >>check.log
- fi
- if [ ! -z "$n_bad" -a $n_bad != 0 ]
- then
- echo "Failures:$bad"
- echo "Failed $n_bad of $try iotests"
- echo "Failures:$bad" | fmt >>check.log
- echo "Failed $n_bad of $try iotests" >>check.log
- else
- echo "Passed all $try iotests"
- echo "Passed all $try iotests" >>check.log
- fi
- needwrap=false
- fi
-
- if test -n "$STTY_RESTORE"; then
- stty $STTY_RESTORE
- fi
- rm -f "${TEST_DIR}"/*.out "${TEST_DIR}"/*.err "${TEST_DIR}"/*.time
- rm -f "${TEST_DIR}"/check.pid "${TEST_DIR}"/check.sts
- rm -f $tmp.*
-
- if $tmp_sock_dir
- then
- rm -rf "$SOCK_DIR"
- fi
-}
-
-trap "_wrapup; exit \$status" 0 1 2 3 15
-
-# Report the test start and results. For makecheck we want to pretty
-# print the whole report at the end of the execution.
-# args: $seq, $starttime, $lasttime
-_report_test_start()
-{
- if ! $makecheck; then
- if [ -n "$3" ]; then
- local lasttime=" (last: $3s)"
- fi
- printf "%-8s %-10s [%s] %4s%-14s\r" "$1" "..." "$2" "..." "$lasttime"
- fi
-}
-# args:$seq $status $starttime $lasttime $thistime $details
-_report_test_result()
-{
- local status lasttime thistime
- if $makecheck; then
- if [ -n "$2" ] && [ "$2" != "pass" ]; then
- status=" [$2]"
- fi
- printf " TEST iotest-$IMGFMT: %s%s\n" "$1" "$status"
- return
- fi
-
- if [ -n "$4" ]; then
- lasttime=" (last: $4s)"
- fi
- if [ -n "$5" ]; then
- thistime=" $5s"
- fi
- case "$2" in
- "pass") status=$(printf "\e[32m%-10s\e[0m" "$2") ;;
- "fail") status=$(printf "\e[1m\e[31m%-10s\e[0m" "$2") ;;
- "not run") status=$(printf "\e[33m%-10s\e[0m" "$2") ;;
- *) status=$(printf "%-10s" "$2") ;;
- esac
-
- printf "%-8s %s [%s] [%s] %4s%-14s %s\n" "$1" "$status" "$3" "$(date '+%T')" "$thistime" "$lasttime" "$6"
-}
-
-[ -f $TIMESTAMP_FILE ] || touch $TIMESTAMP_FILE
-
-FULL_IMGFMT_DETAILS=$(_full_imgfmt_details)
-FULL_HOST_DETAILS=$(_full_platform_details)
-
-if ! $makecheck; then
- _full_env_details
-fi
-
-seq="check"
-
-[ -n "$TESTS_REMAINING_LOG" ] && echo $list > $TESTS_REMAINING_LOG
-
-for seq in $list
-do
- err=false # error flag
- printdiff=false # show diff to reference output?
- status="" # test result summary
- results="" # test result details
- thistime="" # time the test took
-
- if [ -n "$TESTS_REMAINING_LOG" ] ; then
- sed -e "s/$seq//" -e 's/ / /' -e 's/^ *//' $TESTS_REMAINING_LOG > $TESTS_REMAINING_LOG.tmp
- mv $TESTS_REMAINING_LOG.tmp $TESTS_REMAINING_LOG
- sync
- fi
-
- lasttime=$(sed -n -e "/^$seq /s/.* //p" <$TIMESTAMP_FILE)
- starttime=$(date "+%T")
- _report_test_start $seq $starttime $lasttime
-
- if $showme
- then
- status="not run"
- elif [ -f expunged ] && $expunge && egrep "^$seq([ ]|\$)" expunged >/dev/null
- then
- status="not run"
- results="expunged"
- rm -f $seq.out.bad
- echo "/^$seq\$/d" >>$tmp.expunged
- elif [ ! -f "$source_iotests/$seq" ]
- then
- status="not run"
- results="no such test?"
- echo "/^$seq\$/d" >>$tmp.expunged
- else
- # really going to try and run this one
- #
- rm -f $seq.out.bad
- rm -f core $seq.notrun
- rm -f $seq.casenotrun
-
- start=$(_wallclock)
-
- if [ "$(head -n 1 "$source_iotests/$seq")" == "#!/usr/bin/env python3" ]; then
- if $python_usable; then
- run_command="$PYTHON $seq"
- else
- run_command="false"
- echo "$python_unusable_because" > $seq.notrun
- fi
- else
- run_command="./$seq"
- fi
- export OUTPUT_DIR=$PWD
- if $debug; then
- (cd "$source_iotests";
- MALLOC_PERTURB_=${MALLOC_PERTURB_:-$(($RANDOM % 255 + 1))} \
- $run_command -d 2>&1 | tee $tmp.out)
- else
- (cd "$source_iotests";
- MALLOC_PERTURB_=${MALLOC_PERTURB_:-$(($RANDOM % 255 + 1))} \
- $run_command >$tmp.out 2>&1)
- fi
- sts=$?
- stop=$(_wallclock)
-
- if [ -f core ]
- then
- mv core $seq.core
- status="fail"
- results="[dumped core] $seq.core"
- err=true
- fi
-
- if [ -f $seq.notrun ]
- then
- # overwrites timestamp output
- status="not run"
- results="$(cat $seq.notrun)"
- else
- if [ $sts -ne 0 ]
- then
- status="fail"
- results=$(printf %s "[failed, exit status $sts]")
- err=true
- fi
-
- reference="$source_iotests/$seq.out"
- reference_machine="$source_iotests/$seq.$QEMU_DEFAULT_MACHINE.out"
- if [ -f "$reference_machine" ]; then
- reference="$reference_machine"
- fi
-
- reference_format="$source_iotests/$seq.out.$IMGFMT"
- if [ -f "$reference_format" ]; then
- reference="$reference_format"
- fi
-
- if [ "$CACHEMODE" = "none" ]; then
- [ -f "$source_iotests/$seq.out.nocache" ] && reference="$source_iotests/$seq.out.nocache"
- fi
-
- if [ ! -f "$reference" ]
- then
- status="fail"
- results="no qualified output"
- err=true
- else
- if diff -w "$reference" $tmp.out >/dev/null 2>&1
- then
- if ! $err; then
- status="pass"
- thistime=$(expr $stop - $start)
- echo "$seq $thistime" >>$tmp.time
- fi
- else
- mv $tmp.out $seq.out.bad
- status="fail"
- results="output mismatch (see $seq.out.bad)"
- printdiff=true
- err=true
- fi
- fi
- fi
- if [ -f $seq.casenotrun ]
- then
- cat $seq.casenotrun
- casenotrun="$casenotrun $seq"
- fi
- fi
-
- # come here for each test, except when $showme is true
- #
- _report_test_result $seq "$status" "$starttime" "$lasttime" "$thistime" "$results"
- case "$status" in
- "pass")
- try=$(expr $try + 1)
- ;;
- "fail")
- try=$(expr $try + 1)
- if $makecheck; then
- _full_env_details
- fi
- if $printdiff; then
- $diff -w "$reference" "$PWD"/$seq.out.bad
- fi
- bad="$bad $seq"
- n_bad=$(expr $n_bad + 1)
- quick=false
- ;;
- "not run")
- notrun="$notrun $seq"
- ;;
- esac
-
- seq="after_$seq"
-done
-interrupt=false
-status=$(expr $n_bad)
-exit
+import os
+import sys
+import argparse
+from findtests import TestFinder
+from testenv import TestEnv
+from testrunner import TestRunner
+
+
+def make_argparser() -> argparse.ArgumentParser:
+ p = argparse.ArgumentParser(description="Test run options")
+
+ p.add_argument('-n', '--dry-run', action='store_true',
+ help='show me, do not run tests')
+ p.add_argument('-makecheck', action='store_true',
+ help='pretty print output for make check')
+
+ p.add_argument('-d', dest='debug', action='store_true', help='debug')
+ p.add_argument('-misalign', action='store_true',
+ help='misalign memory allocations')
+ p.add_argument('--color', choices=['on', 'off', 'auto'],
+ default='auto', help="use terminal colors. The default "
+ "'auto' value means use colors if terminal stdout detected")
+
+ g_env = p.add_argument_group('test environment options')
+ mg = g_env.add_mutually_exclusive_group()
+ # We don't set default for cachemode, as we need to distinguish default
+ # from user input later.
+ mg.add_argument('-nocache', dest='cachemode', action='store_const',
+ const='none', help='set cache mode "none" (O_DIRECT), '
+ 'sets CACHEMODE environment variable')
+ mg.add_argument('-c', dest='cachemode',
+ help='sets CACHEMODE environment variable')
+
+ g_env.add_argument('-i', dest='aiomode', default='threads',
+ help='sets AIOMODE environment variable')
+
+ p.set_defaults(imgfmt='raw', imgproto='file')
+
+ format_list = ['raw', 'bochs', 'cloop', 'parallels', 'qcow', 'qcow2',
+ 'qed', 'vdi', 'vpc', 'vhdx', 'vmdk', 'luks', 'dmg']
+ g_fmt = p.add_argument_group(
+ ' image format options',
+ 'The following options set the IMGFMT environment variable. '
+ 'At most one choice is allowed, default is "raw"')
+ mg = g_fmt.add_mutually_exclusive_group()
+ for fmt in format_list:
+ mg.add_argument('-' + fmt, dest='imgfmt', action='store_const',
+ const=fmt, help=f'test {fmt}')
+
+ protocol_list = ['file', 'rbd', 'sheepdog', 'nbd', 'ssh', 'nfs',
+ 'fuse']
+ g_prt = p.add_argument_group(
+ ' image protocol options',
+ 'The following options set the IMGPROTO environment variable. '
+ 'At most one choice is allowed, default is "file"')
+ mg = g_prt.add_mutually_exclusive_group()
+ for prt in protocol_list:
+ mg.add_argument('-' + prt, dest='imgproto', action='store_const',
+ const=prt, help=f'test {prt}')
+
+ g_bash = p.add_argument_group('bash tests options',
+ 'The following options are ignored by '
+ 'python tests.')
+ # TODO: make support for the following options in iotests.py
+ g_bash.add_argument('-o', dest='imgopts',
+ help='options to pass to qemu-img create/convert, '
+ 'sets IMGOPTS environment variable')
+ g_bash.add_argument('-valgrind', action='store_true',
+ help='use valgrind, sets VALGRIND_QEMU environment '
+ 'variable')
+
+ g_sel = p.add_argument_group('test selecting options',
+ 'The following options specify test set '
+ 'to run.')
+ g_sel.add_argument('-g', '--groups', metavar='group1,...',
+ help='include tests from these groups')
+ g_sel.add_argument('-x', '--exclude-groups', metavar='group1,...',
+ help='exclude tests from these groups')
+ g_sel.add_argument('--start-from', metavar='TEST',
+ help='Start from specified test: make sorted sequence '
+ 'of tests as usual and then drop tests from the first '
+ 'one to TEST (not inclusive). This may be used to '
+ 'rerun failed ./check command, starting from the '
+ 'middle of the process.')
+ g_sel.add_argument('tests', metavar='TEST_FILES', nargs='*',
+ help='tests to run')
+
+ return p
+
+
+if __name__ == '__main__':
+ args = make_argparser().parse_args()
+
+ env = TestEnv(imgfmt=args.imgfmt, imgproto=args.imgproto,
+ aiomode=args.aiomode, cachemode=args.cachemode,
+ imgopts=args.imgopts, misalign=args.misalign,
+ debug=args.debug, valgrind=args.valgrind)
+
+ testfinder = TestFinder(test_dir=env.source_iotests)
+
+ groups = args.groups.split(',') if args.groups else None
+ x_groups = args.exclude_groups.split(',') if args.exclude_groups else None
+
+ group_local = os.path.join(env.source_iotests, 'group.local')
+ if os.path.isfile(group_local):
+ try:
+ testfinder.add_group_file(group_local)
+ except ValueError as e:
+ sys.exit(f"Failed to parse group file '{group_local}': {e}")
+
+ try:
+ tests = testfinder.find_tests(groups=groups, exclude_groups=x_groups,
+ tests=args.tests,
+ start_from=args.start_from)
+ if not tests:
+ raise ValueError('No tests selected')
+ except ValueError as e:
+ sys.exit(e)
+
+ if args.dry_run:
+ print('\n'.join(tests))
+ else:
+ with TestRunner(env, makecheck=args.makecheck,
+ color=args.color) as tr:
+ tr.run_tests([os.path.join(env.source_iotests, t) for t in tests])
diff --git a/tests/qemu-iotests/common.env.in b/tests/qemu-iotests/common.env.in
deleted file mode 100644
index e565cdf..0000000
--- a/tests/qemu-iotests/common.env.in
+++ /dev/null
@@ -1,3 +0,0 @@
-# Automatically generated by configure - do not modify
-
-export PYTHON='@PYTHON@'
diff --git a/tests/qemu-iotests/findtests.py b/tests/qemu-iotests/findtests.py
new file mode 100644
index 0000000..dd77b45
--- /dev/null
+++ b/tests/qemu-iotests/findtests.py
@@ -0,0 +1,159 @@
+# TestFinder class, define set of tests to run.
+#
+# Copyright (c) 2020-2021 Virtuozzo International GmbH
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import os
+import glob
+import re
+from collections import defaultdict
+from contextlib import contextmanager
+from typing import Optional, List, Iterator, Set
+
+
+@contextmanager
+def chdir(path: Optional[str] = None) -> Iterator[None]:
+ if path is None:
+ yield
+ return
+
+ saved_dir = os.getcwd()
+ os.chdir(path)
+ try:
+ yield
+ finally:
+ os.chdir(saved_dir)
+
+
+class TestFinder:
+ def __init__(self, test_dir: Optional[str] = None) -> None:
+ self.groups = defaultdict(set)
+
+ with chdir(test_dir):
+ self.all_tests = glob.glob('[0-9][0-9][0-9]')
+ self.all_tests += [f for f in glob.iglob('tests/*')
+ if not f.endswith('.out') and
+ os.path.isfile(f + '.out')]
+
+ for t in self.all_tests:
+ with open(t, encoding="utf-8") as f:
+ for line in f:
+ if line.startswith('# group: '):
+ for g in line.split()[2:]:
+ self.groups[g].add(t)
+ break
+
+ def add_group_file(self, fname: str) -> None:
+ with open(fname, encoding="utf-8") as f:
+ for line in f:
+ line = line.strip()
+
+ if (not line) or line[0] == '#':
+ continue
+
+ words = line.split()
+ test_file = self.parse_test_name(words[0])
+ groups = words[1:]
+
+ for g in groups:
+ self.groups[g].add(test_file)
+
+ def parse_test_name(self, name: str) -> str:
+ if '/' in name:
+ raise ValueError('Paths are unsupported for test selection, '
+ f'requiring "{name}" is wrong')
+
+ if re.fullmatch(r'\d+', name):
+ # Numbered tests are old naming convention. We should convert them
+ # to three-digit-length, like 1 --> 001.
+ name = f'{int(name):03}'
+ else:
+ # Named tests all should be in tests/ subdirectory
+ name = os.path.join('tests', name)
+
+ if name not in self.all_tests:
+ raise ValueError(f'Test "{name}" is not found')
+
+ return name
+
+ def find_tests(self, groups: Optional[List[str]] = None,
+ exclude_groups: Optional[List[str]] = None,
+ tests: Optional[List[str]] = None,
+ start_from: Optional[str] = None) -> List[str]:
+ """Find tests
+
+ Algorithm:
+
+ 1. a. if some @groups specified
+ a.1 Take all tests from @groups
+ a.2 Drop tests, which are in at least one of @exclude_groups or in
+ 'disabled' group (if 'disabled' is not listed in @groups)
+ a.3 Add tests from @tests (don't exclude anything from them)
+
+ b. else, if some @tests specified:
+ b.1 exclude_groups must be not specified, so just take @tests
+
+ c. else (only @exclude_groups list is non-empty):
+ c.1 Take all tests
+ c.2 Drop tests, which are in at least one of @exclude_groups or in
+ 'disabled' group
+
+ 2. sort
+
+ 3. If start_from specified, drop tests from first one to @start_from
+ (not inclusive)
+ """
+ if groups is None:
+ groups = []
+ if exclude_groups is None:
+ exclude_groups = []
+ if tests is None:
+ tests = []
+
+ res: Set[str] = set()
+ if groups:
+ # Some groups specified. exclude_groups supported, additionally
+ # selecting some individual tests supported as well.
+ res.update(*(self.groups[g] for g in groups))
+ elif tests:
+ # Some individual tests specified, but no groups. In this case
+ # we don't support exclude_groups.
+ if exclude_groups:
+ raise ValueError("Can't exclude from individually specified "
+ "tests.")
+ else:
+ # No tests no groups: start from all tests, exclude_groups
+ # supported.
+ res.update(self.all_tests)
+
+ if 'disabled' not in groups and 'disabled' not in exclude_groups:
+ # Don't want to modify function argument, so create new list.
+ exclude_groups = exclude_groups + ['disabled']
+
+ res = res.difference(*(self.groups[g] for g in exclude_groups))
+
+ # We want to add @tests. But for compatibility with old test names,
+ # we should convert any number < 100 to number padded by
+ # leading zeroes, like 1 -> 001 and 23 -> 023.
+ for t in tests:
+ res.add(self.parse_test_name(t))
+
+ sequence = sorted(res)
+
+ if start_from is not None:
+ del sequence[:sequence.index(self.parse_test_name(start_from))]
+
+ return sequence
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
deleted file mode 100644
index a0d0bf1..0000000
--- a/tests/qemu-iotests/group
+++ /dev/null
@@ -1,323 +0,0 @@
-#
-# QA groups control file
-# Defines test groups
-#
-# Some notes about the groups:
-#
-# - do not start group names with a digit
-#
-# - quick : Tests in this group should finish within some few seconds.
-#
-# - img : Tests in this group can be used to excercise the qemu-img tool.
-#
-# - auto : Tests in this group are used during "make check" and should be
-# runnable in any case. That means they should run with every QEMU binary
-# (also non-x86), with every QEMU configuration (i.e. must not fail if
-# an optional feature is not compiled in - but reporting a "skip" is ok),
-# work at least with the qcow2 file format, work with all kind of host
-# filesystems and users (e.g. "nobody" or "root") and must not take too
-# much memory and disk space (since CI pipelines tend to fail otherwise).
-#
-
-#
-# test-group association ... one line per test
-#
-001 rw auto quick
-002 rw auto quick
-003 rw auto
-004 rw auto quick
-005 img auto quick
-# 006 was removed, do not reuse
-007 snapshot auto
-008 rw auto quick
-009 rw auto quick
-010 rw auto quick
-011 rw auto quick
-012 auto quick
-013 rw auto
-014 rw
-015 rw snapshot
-# 016 was removed, do not reuse
-017 rw backing auto quick
-018 rw backing auto quick
-019 rw backing auto quick
-020 rw backing auto quick
-021 io auto quick
-022 rw snapshot auto
-023 rw
-024 rw backing auto quick
-025 rw auto quick
-026 rw blkdbg
-027 rw auto quick
-028 rw backing quick
-029 rw auto quick
-030 rw auto backing
-031 rw auto quick
-032 rw auto quick
-033 rw auto quick
-034 rw auto backing quick
-035 rw auto quick
-036 rw auto quick
-037 rw auto backing quick
-038 rw auto backing quick
-039 rw auto quick
-040 rw auto
-041 rw auto backing
-042 rw auto quick
-043 rw auto backing
-044 rw
-045 rw quick
-046 rw auto aio quick
-047 rw auto quick
-048 img auto quick
-049 rw auto
-050 rw auto backing quick
-051 rw
-052 rw auto backing quick
-053 rw auto quick
-054 rw auto quick
-055 rw
-056 rw backing
-057 rw
-058 rw quick
-059 rw quick
-060 rw auto quick
-061 rw auto
-062 rw auto quick
-063 rw auto quick
-064 rw quick
-065 rw quick
-066 rw auto quick
-# 067 was removed, do not reuse
-068 rw quick
-069 rw auto quick
-070 rw quick
-071 rw auto quick
-072 rw auto quick
-073 rw auto quick
-074 rw auto quick
-075 rw quick
-076 io
-077 rw quick
-078 rw quick
-079 rw auto
-080 rw auto
-081 rw quick
-082 rw quick
-083 rw
-084 img quick
-085 rw
-086 rw auto quick
-087 rw quick
-088 rw quick
-089 rw auto quick
-090 rw auto quick
-091 rw migration quick
-092 rw quick
-093 throttle
-094 rw quick
-095 rw quick
-096 rw quick
-097 rw auto backing
-098 rw auto backing quick
-099 rw auto quick
-# 100 was removed, do not reuse
-101 rw quick
-102 rw quick
-103 rw auto quick
-104 rw auto
-105 rw auto quick
-106 rw quick
-107 rw auto quick
-108 rw auto quick
-109 rw
-110 rw auto backing quick
-111 rw auto quick
-112 rw
-113 rw quick
-114 rw auto quick
-115 rw
-116 rw quick
-117 rw auto
-118 rw
-119 rw quick
-120 rw auto quick
-121 rw
-122 rw
-123 rw quick
-124 rw backing
-125 rw
-126 rw auto backing
-127 rw auto backing quick
-128 rw quick
-129 rw quick
-130 rw quick
-131 rw quick
-132 rw quick
-133 auto quick
-134 rw auto quick
-135 rw
-136 rw
-137 rw auto
-138 rw auto quick
-139 rw quick
-140 rw auto quick
-141 rw auto quick
-142
-143 auto quick
-144 rw quick
-145 quick
-146 quick
-147 img
-148 rw quick
-149 rw sudo
-150 rw auto quick
-151 rw
-152 rw quick
-153 rw quick
-154 rw auto backing quick
-155 rw
-156 rw auto quick
-157 quick
-158 rw auto quick
-159 rw auto quick
-160 rw quick
-161 rw auto quick
-162 quick
-163 rw
-165 rw quick
-169 rw migration
-170 rw auto quick
-171 rw quick
-172 auto
-173 rw
-174 auto
-175 quick
-176 rw auto backing
-177 rw auto quick
-178 img
-179 rw auto quick
-181 rw auto migration quick
-182 rw quick
-183 rw migration quick
-184 rw auto quick
-185 rw
-186 rw auto
-187 rw auto
-188 rw quick
-189 rw
-190 rw auto quick
-191 rw auto
-192 rw auto quick
-194 rw migration quick
-195 rw auto quick
-196 rw quick migration
-197 rw quick
-198 rw
-199 rw migration
-200 rw
-201 rw migration quick
-202 rw quick
-203 rw auto migration quick
-204 rw quick
-205 rw quick
-206 rw
-207 rw
-208 rw quick
-209 rw quick
-210 rw
-211 rw quick
-212 rw quick
-213 rw quick
-214 rw auto
-215 rw quick
-216 rw quick
-217 rw auto quick
-218 rw quick
-219 rw
-220 rw auto
-221 rw quick
-222 rw quick
-223 rw quick
-224 rw quick
-225 rw quick
-226 auto quick
-227 quick
-228 rw quick
-229 auto quick
-231 quick
-232 quick
-233 quick
-234 quick migration
-235 quick
-236 quick
-237 rw quick
-238 quick
-239 rw quick
-240 quick
-241 rw quick
-242 rw quick
-243 rw quick
-244 rw auto quick
-245 rw
-246 rw quick
-247 rw quick
-248 rw quick
-249 rw auto quick
-250 rw quick
-251 rw auto quick
-252 rw auto backing quick
-253 rw quick
-254 rw backing quick
-255 rw quick
-256 rw auto quick
-257 rw
-258 rw quick
-259 rw auto quick
-260 rw quick
-261 rw
-262 rw quick migration
-263 rw quick
-264 rw
-265 rw auto quick
-266 rw quick
-267 rw auto quick snapshot
-268 rw auto quick
-270 rw backing quick
-271 rw auto
-272 rw
-273 backing quick
-274 rw backing
-277 rw quick
-279 rw backing quick
-280 rw migration quick
-281 rw quick
-282 rw img quick
-283 auto quick
-284 rw
-286 rw quick
-287 auto quick
-288 quick
-289 rw quick
-290 rw auto quick
-291 rw quick
-292 rw auto quick
-293 rw
-294 rw quick
-295 rw
-296 rw
-297 meta
-298
-299 auto quick
-300 migration
-301 backing quick
-302 quick
-303 rw quick
-304 rw quick
-305 rw quick
-307 rw quick export
-308 rw
-309 rw auto quick
-310 rw quick
-312 rw quick
-313 rw auto quick
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 335e6fe..00be68e 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -1131,6 +1131,13 @@ def _verify_formats(required_formats: Sequence[str] = ()) -> None:
if usf_list:
notrun(f'formats {usf_list} are not whitelisted')
+
+def _verify_virtio_blk() -> None:
+ out = qemu_pipe('-M', 'none', '-device', 'help')
+ if 'virtio-blk' not in out:
+ notrun('Missing virtio-blk in QEMU binary')
+
+
def supports_quorum():
return 'quorum' in qemu_img_pipe('--help')
@@ -1308,6 +1315,7 @@ def execute_setup_common(supported_fmts: Sequence[str] = (),
_verify_cache_mode(supported_cache_modes)
_verify_aio_mode(supported_aio_modes)
_verify_formats(required_fmts)
+ _verify_virtio_blk()
return debug
diff --git a/tests/qemu-iotests/meson.build b/tests/qemu-iotests/meson.build
index 26658ce..67aed1e 100644
--- a/tests/qemu-iotests/meson.build
+++ b/tests/qemu-iotests/meson.build
@@ -3,6 +3,3 @@ if 'CONFIG_LINUX' in config_host
else
socket_scm_helper = []
endif
-configure_file(output: 'common.env',
- input: files('common.env.in'),
- configuration: {'PYTHON': python.full_path()})
diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py
new file mode 100644
index 0000000..b31275f
--- /dev/null
+++ b/tests/qemu-iotests/testenv.py
@@ -0,0 +1,281 @@
+# TestEnv class to manage test environment variables.
+#
+# Copyright (c) 2020-2021 Virtuozzo International GmbH
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import os
+import sys
+import tempfile
+from pathlib import Path
+import shutil
+import collections
+import random
+import subprocess
+import glob
+from typing import Dict, Any, Optional, ContextManager
+
+
+def isxfile(path: str) -> bool:
+ return os.path.isfile(path) and os.access(path, os.X_OK)
+
+
+def get_default_machine(qemu_prog: str) -> str:
+ outp = subprocess.run([qemu_prog, '-machine', 'help'], check=True,
+ universal_newlines=True,
+ stdout=subprocess.PIPE).stdout
+
+ machines = outp.split('\n')
+ try:
+ default_machine = next(m for m in machines if m.endswith(' (default)'))
+ except StopIteration:
+ return ''
+ default_machine = default_machine.split(' ', 1)[0]
+
+ alias_suf = ' (alias of {})'.format(default_machine)
+ alias = next((m for m in machines if m.endswith(alias_suf)), None)
+ if alias is not None:
+ default_machine = alias.split(' ', 1)[0]
+
+ return default_machine
+
+
+class TestEnv(ContextManager['TestEnv']):
+ """
+ Manage system environment for running tests
+
+ The following variables are supported/provided. They are represented by
+ lower-cased TestEnv attributes.
+ """
+
+ # We store environment variables as instance attributes, and there are a
+ # lot of them. Silence pylint:
+ # pylint: disable=too-many-instance-attributes
+
+ env_variables = ['PYTHONPATH', 'TEST_DIR', 'SOCK_DIR', 'SAMPLE_IMG_DIR',
+ 'OUTPUT_DIR', 'PYTHON', 'QEMU_PROG', 'QEMU_IMG_PROG',
+ 'QEMU_IO_PROG', 'QEMU_NBD_PROG', 'QSD_PROG',
+ 'SOCKET_SCM_HELPER', 'QEMU_OPTIONS', 'QEMU_IMG_OPTIONS',
+ 'QEMU_IO_OPTIONS', 'QEMU_IO_OPTIONS_NO_FMT',
+ 'QEMU_NBD_OPTIONS', 'IMGOPTS', 'IMGFMT', 'IMGPROTO',
+ 'AIOMODE', 'CACHEMODE', 'VALGRIND_QEMU',
+ 'CACHEMODE_IS_DEFAULT', 'IMGFMT_GENERIC', 'IMGOPTSSYNTAX',
+ 'IMGKEYSECRET', 'QEMU_DEFAULT_MACHINE', 'MALLOC_PERTURB_']
+
+ def get_env(self) -> Dict[str, str]:
+ env = {}
+ for v in self.env_variables:
+ val = getattr(self, v.lower(), None)
+ if val is not None:
+ env[v] = val
+
+ return env
+
+ def init_directories(self) -> None:
+ """Init directory variables:
+ PYTHONPATH
+ TEST_DIR
+ SOCK_DIR
+ SAMPLE_IMG_DIR
+ OUTPUT_DIR
+ """
+ self.pythonpath = os.getenv('PYTHONPATH')
+ if self.pythonpath:
+ self.pythonpath = self.source_iotests + os.pathsep + \
+ self.pythonpath
+ else:
+ self.pythonpath = self.source_iotests
+
+ self.test_dir = os.getenv('TEST_DIR',
+ os.path.join(os.getcwd(), 'scratch'))
+ Path(self.test_dir).mkdir(parents=True, exist_ok=True)
+
+ try:
+ self.sock_dir = os.environ['SOCK_DIR']
+ self.tmp_sock_dir = False
+ Path(self.test_dir).mkdir(parents=True, exist_ok=True)
+ except KeyError:
+ self.sock_dir = tempfile.mkdtemp()
+ self.tmp_sock_dir = True
+
+ self.sample_img_dir = os.getenv('SAMPLE_IMG_DIR',
+ os.path.join(self.source_iotests,
+ 'sample_images'))
+
+ self.output_dir = os.getcwd() # OUTPUT_DIR
+
+ def init_binaries(self) -> None:
+ """Init binary path variables:
+ PYTHON (for bash tests)
+ QEMU_PROG, QEMU_IMG_PROG, QEMU_IO_PROG, QEMU_NBD_PROG, QSD_PROG
+ SOCKET_SCM_HELPER
+ """
+ self.python = sys.executable
+
+ def root(*names: str) -> str:
+ return os.path.join(self.build_root, *names)
+
+ arch = os.uname().machine
+ if 'ppc64' in arch:
+ arch = 'ppc64'
+
+ self.qemu_prog = os.getenv('QEMU_PROG', root(f'qemu-system-{arch}'))
+ if not os.path.exists(self.qemu_prog):
+ pattern = root('qemu-system-*')
+ try:
+ progs = glob.iglob(pattern)
+ self.qemu_prog = next(p for p in progs if isxfile(p))
+ except StopIteration:
+ sys.exit("Not found any Qemu executable binary by pattern "
+ f"'{pattern}'")
+
+ self.qemu_img_prog = os.getenv('QEMU_IMG_PROG', root('qemu-img'))
+ self.qemu_io_prog = os.getenv('QEMU_IO_PROG', root('qemu-io'))
+ self.qemu_nbd_prog = os.getenv('QEMU_NBD_PROG', root('qemu-nbd'))
+ self.qsd_prog = os.getenv('QSD_PROG', root('storage-daemon',
+ 'qemu-storage-daemon'))
+
+ for b in [self.qemu_img_prog, self.qemu_io_prog, self.qemu_nbd_prog,
+ self.qemu_prog, self.qsd_prog]:
+ if not os.path.exists(b):
+ sys.exit('No such file: ' + b)
+ if not isxfile(b):
+ sys.exit('Not executable: ' + b)
+
+ helper_path = os.path.join(self.build_iotests, 'socket_scm_helper')
+ if isxfile(helper_path):
+ self.socket_scm_helper = helper_path # SOCKET_SCM_HELPER
+
+ def __init__(self, imgfmt: str, imgproto: str, aiomode: str,
+ cachemode: Optional[str] = None,
+ imgopts: Optional[str] = None,
+ misalign: bool = False,
+ debug: bool = False,
+ valgrind: bool = False) -> None:
+ self.imgfmt = imgfmt
+ self.imgproto = imgproto
+ self.aiomode = aiomode
+ self.imgopts = imgopts
+ self.misalign = misalign
+ self.debug = debug
+
+ if valgrind:
+ self.valgrind_qemu = 'y'
+
+ if cachemode is None:
+ self.cachemode_is_default = 'true'
+ self.cachemode = 'writeback'
+ else:
+ self.cachemode_is_default = 'false'
+ self.cachemode = cachemode
+
+ # Initialize generic paths: build_root, build_iotests, source_iotests,
+ # which are needed to initialize some environment variables. They are
+ # used by init_*() functions as well.
+
+ if os.path.islink(sys.argv[0]):
+ # called from the build tree
+ self.source_iotests = os.path.dirname(os.readlink(sys.argv[0]))
+ self.build_iotests = os.path.dirname(os.path.abspath(sys.argv[0]))
+ else:
+ # called from the source tree
+ self.source_iotests = os.getcwd()
+ self.build_iotests = self.source_iotests
+
+ self.build_root = os.path.join(self.build_iotests, '..', '..')
+
+ self.init_directories()
+ self.init_binaries()
+
+ self.malloc_perturb_ = os.getenv('MALLOC_PERTURB_',
+ str(random.randrange(1, 255)))
+
+ # QEMU_OPTIONS
+ self.qemu_options = '-nodefaults -display none -accel qtest'
+ machine_map = (
+ ('arm', 'virt'),
+ ('aarch64', 'virt'),
+ ('avr', 'mega2560'),
+ ('rx', 'gdbsim-r5f562n8'),
+ ('tricore', 'tricore_testboard')
+ )
+ for suffix, machine in machine_map:
+ if self.qemu_prog.endswith(f'qemu-system-{suffix}'):
+ self.qemu_options += f' -machine {machine}'
+
+ # QEMU_DEFAULT_MACHINE
+ self.qemu_default_machine = get_default_machine(self.qemu_prog)
+
+ self.qemu_img_options = os.getenv('QEMU_IMG_OPTIONS')
+ self.qemu_nbd_options = os.getenv('QEMU_NBD_OPTIONS')
+
+ is_generic = self.imgfmt not in ['bochs', 'cloop', 'dmg']
+ self.imgfmt_generic = 'true' if is_generic else 'false'
+
+ self.qemu_io_options = f'--cache {self.cachemode} --aio {self.aiomode}'
+ if self.misalign:
+ self.qemu_io_options += ' --misalign'
+
+ self.qemu_io_options_no_fmt = self.qemu_io_options
+
+ if self.imgfmt == 'luks':
+ self.imgoptssyntax = 'true'
+ self.imgkeysecret = '123456'
+ if not self.imgopts:
+ self.imgopts = 'iter-time=10'
+ elif 'iter-time=' not in self.imgopts:
+ self.imgopts += ',iter-time=10'
+ else:
+ self.imgoptssyntax = 'false'
+ self.qemu_io_options += ' -f ' + self.imgfmt
+
+ if self.imgfmt == 'vmdk':
+ if not self.imgopts:
+ self.imgopts = 'zeroed_grain=on'
+ elif 'zeroed_grain=' not in self.imgopts:
+ self.imgopts += ',zeroed_grain=on'
+
+ def close(self) -> None:
+ if self.tmp_sock_dir:
+ shutil.rmtree(self.sock_dir)
+
+ def __enter__(self) -> 'TestEnv':
+ return self
+
+ def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
+ self.close()
+
+ def print_env(self) -> None:
+ template = """\
+QEMU -- "{QEMU_PROG}" {QEMU_OPTIONS}
+QEMU_IMG -- "{QEMU_IMG_PROG}" {QEMU_IMG_OPTIONS}
+QEMU_IO -- "{QEMU_IO_PROG}" {QEMU_IO_OPTIONS}
+QEMU_NBD -- "{QEMU_NBD_PROG}" {QEMU_NBD_OPTIONS}
+IMGFMT -- {IMGFMT}{imgopts}
+IMGPROTO -- {IMGPROTO}
+PLATFORM -- {platform}
+TEST_DIR -- {TEST_DIR}
+SOCK_DIR -- {SOCK_DIR}
+SOCKET_SCM_HELPER -- {SOCKET_SCM_HELPER}"""
+
+ args = collections.defaultdict(str, self.get_env())
+
+ if 'IMGOPTS' in args:
+ args['imgopts'] = f" ({args['IMGOPTS']})"
+
+ u = os.uname()
+ args['platform'] = f'{u.sysname}/{u.machine} {u.nodename} {u.release}'
+
+ print(template.format_map(args))
diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py
new file mode 100644
index 0000000..a581be6
--- /dev/null
+++ b/tests/qemu-iotests/testrunner.py
@@ -0,0 +1,367 @@
+# Class for actually running tests.
+#
+# Copyright (c) 2020-2021 Virtuozzo International GmbH
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import os
+from pathlib import Path
+import datetime
+import time
+import difflib
+import subprocess
+import contextlib
+import json
+import termios
+import sys
+from contextlib import contextmanager
+from typing import List, Optional, Iterator, Any, Sequence, Dict, \
+ ContextManager
+
+from testenv import TestEnv
+
+
+def silent_unlink(path: Path) -> None:
+ try:
+ path.unlink()
+ except OSError:
+ pass
+
+
+def file_diff(file1: str, file2: str) -> List[str]:
+ with open(file1, encoding="utf-8") as f1, \
+ open(file2, encoding="utf-8") as f2:
+ # We want to ignore spaces at line ends. There are a lot of mess about
+ # it in iotests.
+ # TODO: fix all tests to not produce extra spaces, fix all .out files
+ # and use strict diff here!
+ seq1 = [line.rstrip() for line in f1]
+ seq2 = [line.rstrip() for line in f2]
+ res = [line.rstrip()
+ for line in difflib.unified_diff(seq1, seq2, file1, file2)]
+ return res
+
+
+# We want to save current tty settings during test run,
+# since an aborting qemu call may leave things screwed up.
+@contextmanager
+def savetty() -> Iterator[None]:
+ isterm = sys.stdin.isatty()
+ if isterm:
+ fd = sys.stdin.fileno()
+ attr = termios.tcgetattr(fd)
+
+ try:
+ yield
+ finally:
+ if isterm:
+ termios.tcsetattr(fd, termios.TCSADRAIN, attr)
+
+
+class LastElapsedTime(ContextManager['LastElapsedTime']):
+ """ Cache for elapsed time for tests, to show it during new test run
+
+ It is safe to use get() at any time. To use update(), you must either
+ use it inside with-block or use save() after update().
+ """
+ def __init__(self, cache_file: str, env: TestEnv) -> None:
+ self.env = env
+ self.cache_file = cache_file
+ self.cache: Dict[str, Dict[str, Dict[str, float]]]
+
+ try:
+ with open(cache_file, encoding="utf-8") as f:
+ self.cache = json.load(f)
+ except (OSError, ValueError):
+ self.cache = {}
+
+ def get(self, test: str,
+ default: Optional[float] = None) -> Optional[float]:
+ if test not in self.cache:
+ return default
+
+ if self.env.imgproto not in self.cache[test]:
+ return default
+
+ return self.cache[test][self.env.imgproto].get(self.env.imgfmt,
+ default)
+
+ def update(self, test: str, elapsed: float) -> None:
+ d = self.cache.setdefault(test, {})
+ d.setdefault(self.env.imgproto, {})[self.env.imgfmt] = elapsed
+
+ def save(self) -> None:
+ with open(self.cache_file, 'w', encoding="utf-8") as f:
+ json.dump(self.cache, f)
+
+ def __enter__(self) -> 'LastElapsedTime':
+ return self
+
+ def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
+ self.save()
+
+
+class TestResult:
+ def __init__(self, status: str, description: str = '',
+ elapsed: Optional[float] = None, diff: Sequence[str] = (),
+ casenotrun: str = '', interrupted: bool = False) -> None:
+ self.status = status
+ self.description = description
+ self.elapsed = elapsed
+ self.diff = diff
+ self.casenotrun = casenotrun
+ self.interrupted = interrupted
+
+
+class TestRunner(ContextManager['TestRunner']):
+ def __init__(self, env: TestEnv, makecheck: bool = False,
+ color: str = 'auto') -> None:
+ self.env = env
+ self.test_run_env = self.env.get_env()
+ self.makecheck = makecheck
+ self.last_elapsed = LastElapsedTime('.last-elapsed-cache', env)
+
+ assert color in ('auto', 'on', 'off')
+ self.color = (color == 'on') or (color == 'auto' and
+ sys.stdout.isatty())
+
+ self._stack: contextlib.ExitStack
+
+ def __enter__(self) -> 'TestRunner':
+ self._stack = contextlib.ExitStack()
+ self._stack.enter_context(self.env)
+ self._stack.enter_context(self.last_elapsed)
+ self._stack.enter_context(savetty())
+ return self
+
+ def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
+ self._stack.close()
+
+ def test_print_one_line(self, test: str, starttime: str,
+ endtime: Optional[str] = None, status: str = '...',
+ lasttime: Optional[float] = None,
+ thistime: Optional[float] = None,
+ description: str = '',
+ test_field_width: Optional[int] = None,
+ end: str = '\n') -> None:
+ """ Print short test info before/after test run """
+ test = os.path.basename(test)
+
+ if test_field_width is None:
+ test_field_width = 8
+
+ if self.makecheck and status != '...':
+ if status and status != 'pass':
+ status = f' [{status}]'
+ else:
+ status = ''
+
+ print(f' TEST iotest-{self.env.imgfmt}: {test}{status}')
+ return
+
+ if lasttime:
+ lasttime_s = f' (last: {lasttime:.1f}s)'
+ else:
+ lasttime_s = ''
+ if thistime:
+ thistime_s = f'{thistime:.1f}s'
+ else:
+ thistime_s = '...'
+
+ if endtime:
+ endtime = f'[{endtime}]'
+ else:
+ endtime = ''
+
+ if self.color:
+ if status == 'pass':
+ col = '\033[32m'
+ elif status == 'fail':
+ col = '\033[1m\033[31m'
+ elif status == 'not run':
+ col = '\033[33m'
+ else:
+ col = ''
+
+ col_end = '\033[0m'
+ else:
+ col = ''
+ col_end = ''
+
+ print(f'{test:{test_field_width}} {col}{status:10}{col_end} '
+ f'[{starttime}] {endtime:13}{thistime_s:5} {lasttime_s:14} '
+ f'{description}', end=end)
+
+ def find_reference(self, test: str) -> str:
+ if self.env.cachemode == 'none':
+ ref = f'{test}.out.nocache'
+ if os.path.isfile(ref):
+ return ref
+
+ ref = f'{test}.out.{self.env.imgfmt}'
+ if os.path.isfile(ref):
+ return ref
+
+ ref = f'{test}.{self.env.qemu_default_machine}.out'
+ if os.path.isfile(ref):
+ return ref
+
+ return f'{test}.out'
+
+ def do_run_test(self, test: str) -> TestResult:
+ f_test = Path(test)
+ f_bad = Path(f_test.name + '.out.bad')
+ f_notrun = Path(f_test.name + '.notrun')
+ f_casenotrun = Path(f_test.name + '.casenotrun')
+ f_reference = Path(self.find_reference(test))
+
+ if not f_test.exists():
+ return TestResult(status='fail',
+ description=f'No such test file: {f_test}')
+
+ if not os.access(str(f_test), os.X_OK):
+ sys.exit(f'Not executable: {f_test}')
+
+ if not f_reference.exists():
+ return TestResult(status='not run',
+ description='No qualified output '
+ f'(expected {f_reference})')
+
+ for p in (f_bad, f_notrun, f_casenotrun):
+ silent_unlink(p)
+
+ args = [str(f_test.resolve())]
+ if self.env.debug:
+ args.append('-d')
+
+ with f_test.open(encoding="utf-8") as f:
+ try:
+ if f.readline() == '#!/usr/bin/env python3':
+ args.insert(0, self.env.python)
+ except UnicodeDecodeError: # binary test? for future.
+ pass
+
+ env = os.environ.copy()
+ env.update(self.test_run_env)
+
+ t0 = time.time()
+ with f_bad.open('w', encoding="utf-8") as f:
+ proc = subprocess.Popen(args, cwd=str(f_test.parent), env=env,
+ stdout=f, stderr=subprocess.STDOUT)
+ try:
+ proc.wait()
+ except KeyboardInterrupt:
+ proc.terminate()
+ proc.wait()
+ return TestResult(status='not run',
+ description='Interrupted by user',
+ interrupted=True)
+ ret = proc.returncode
+
+ elapsed = round(time.time() - t0, 1)
+
+ if ret != 0:
+ return TestResult(status='fail', elapsed=elapsed,
+ description=f'failed, exit status {ret}',
+ diff=file_diff(str(f_reference), str(f_bad)))
+
+ if f_notrun.exists():
+ return TestResult(status='not run',
+ description=f_notrun.read_text().strip())
+
+ casenotrun = ''
+ if f_casenotrun.exists():
+ casenotrun = f_casenotrun.read_text()
+
+ diff = file_diff(str(f_reference), str(f_bad))
+ if diff:
+ return TestResult(status='fail', elapsed=elapsed,
+ description=f'output mismatch (see {f_bad})',
+ diff=diff, casenotrun=casenotrun)
+ else:
+ f_bad.unlink()
+ self.last_elapsed.update(test, elapsed)
+ return TestResult(status='pass', elapsed=elapsed,
+ casenotrun=casenotrun)
+
+ def run_test(self, test: str,
+ test_field_width: Optional[int] = None) -> TestResult:
+ last_el = self.last_elapsed.get(test)
+ start = datetime.datetime.now().strftime('%H:%M:%S')
+
+ self.test_print_one_line(test=test, starttime=start, lasttime=last_el,
+ end='\r', test_field_width=test_field_width)
+
+ res = self.do_run_test(test)
+
+ end = datetime.datetime.now().strftime('%H:%M:%S')
+ self.test_print_one_line(test=test, status=res.status,
+ starttime=start, endtime=end,
+ lasttime=last_el, thistime=res.elapsed,
+ description=res.description,
+ test_field_width=test_field_width)
+
+ if res.casenotrun:
+ print(res.casenotrun)
+
+ return res
+
+ def run_tests(self, tests: List[str]) -> None:
+ n_run = 0
+ failed = []
+ notrun = []
+ casenotrun = []
+
+ if not self.makecheck:
+ self.env.print_env()
+ print()
+
+ test_field_width = max(len(os.path.basename(t)) for t in tests) + 2
+
+ for t in tests:
+ name = os.path.basename(t)
+ res = self.run_test(t, test_field_width=test_field_width)
+
+ assert res.status in ('pass', 'fail', 'not run')
+
+ if res.casenotrun:
+ casenotrun.append(t)
+
+ if res.status != 'not run':
+ n_run += 1
+
+ if res.status == 'fail':
+ failed.append(name)
+ if self.makecheck:
+ self.env.print_env()
+ if res.diff:
+ print('\n'.join(res.diff))
+ elif res.status == 'not run':
+ notrun.append(name)
+
+ if res.interrupted:
+ break
+
+ if notrun:
+ print('Not run:', ' '.join(notrun))
+
+ if casenotrun:
+ print('Some cases not run in:', ' '.join(casenotrun))
+
+ if failed:
+ print('Failures:', ' '.join(failed))
+ print(f'Failed {len(failed)} of {n_run} iotests')
+ else:
+ print(f'Passed all {n_run} iotests')
diff --git a/tests/qemu-iotests/199 b/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test
index dbf10e5..dbf10e5 100755
--- a/tests/qemu-iotests/199
+++ b/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test
diff --git a/tests/qemu-iotests/199.out b/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test.out
index 8d7e9967..8d7e9967 100644
--- a/tests/qemu-iotests/199.out
+++ b/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test.out
diff --git a/tests/qemu-iotests/169 b/tests/qemu-iotests/tests/migrate-bitmaps-test
index a5c7bc8..a5c7bc8 100755
--- a/tests/qemu-iotests/169
+++ b/tests/qemu-iotests/tests/migrate-bitmaps-test
diff --git a/tests/qemu-iotests/169.out b/tests/qemu-iotests/tests/migrate-bitmaps-test.out
index cafb816..cafb816 100644
--- a/tests/qemu-iotests/169.out
+++ b/tests/qemu-iotests/tests/migrate-bitmaps-test.out
diff --git a/tests/qtest/virtio-scsi-test.c b/tests/qtest/virtio-scsi-test.c
index 0415e75..1b7ecc1 100644
--- a/tests/qtest/virtio-scsi-test.c
+++ b/tests/qtest/virtio-scsi-test.c
@@ -200,6 +200,32 @@ static void test_unaligned_write_same(void *obj, void *data,
qvirtio_scsi_pci_free(vs);
}
+static void test_write_to_cdrom(void *obj, void *data,
+ QGuestAllocator *t_alloc)
+{
+ QVirtioSCSI *scsi = obj;
+ QVirtioSCSIQueues *vs;
+ uint8_t buf[2048] = { 0 };
+ const uint8_t write_cdb[VIRTIO_SCSI_CDB_SIZE] = {
+ /* WRITE(10) to LBA 0, transfer length 1 */
+ 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00
+ };
+ struct virtio_scsi_cmd_resp resp;
+
+ alloc = t_alloc;
+ vs = qvirtio_scsi_init(scsi->vdev);
+
+ virtio_scsi_do_command(vs, write_cdb, NULL, 0, buf, 2048, &resp);
+ g_assert_cmphex(resp.response, ==, 0);
+ g_assert_cmphex(resp.status, ==, CHECK_CONDITION);
+ g_assert_cmphex(resp.sense[0], ==, 0x70);
+ g_assert_cmphex(resp.sense[2], ==, DATA_PROTECT);
+ g_assert_cmphex(resp.sense[12], ==, 0x27); /* WRITE PROTECTED */
+ g_assert_cmphex(resp.sense[13], ==, 0x00); /* WRITE PROTECTED */
+
+ qvirtio_scsi_pci_free(vs);
+}
+
static void test_iothread_attach_node(void *obj, void *data,
QGuestAllocator *t_alloc)
{
@@ -267,6 +293,16 @@ static void *virtio_scsi_setup(GString *cmd_line, void *arg)
return arg;
}
+static void *virtio_scsi_setup_cd(GString *cmd_line, void *arg)
+{
+ g_string_append(cmd_line,
+ " -drive file=null-co://,"
+ "file.read-zeroes=on,"
+ "if=none,id=dr1,format=raw "
+ "-device scsi-cd,drive=dr1,lun=0,scsi-id=1");
+ return arg;
+}
+
static void *virtio_scsi_setup_iothread(GString *cmd_line, void *arg)
{
g_string_append(cmd_line,
@@ -287,6 +323,9 @@ static void register_virtio_scsi_test(void)
qos_add_test("unaligned-write-same", "virtio-scsi",
test_unaligned_write_same, &opts);
+ opts.before = virtio_scsi_setup_cd;
+ qos_add_test("write-to-cdrom", "virtio-scsi", test_write_to_cdrom, &opts);
+
opts.before = virtio_scsi_setup_iothread;
opts.edge = (QOSGraphEdgeOptions) {
.extra_device_opts = "iothread=thread0",