diff options
-rw-r--r-- | block.c | 41 | ||||
-rw-r--r-- | hw/block/nvme.c | 19 | ||||
-rw-r--r-- | hw/scsi/scsi-disk.c | 2 | ||||
-rw-r--r-- | qemu-img.c | 3 | ||||
-rw-r--r-- | tests/Makefile.include | 2 | ||||
-rw-r--r-- | tests/nvme-test.c | 68 | ||||
-rwxr-xr-x | tests/qemu-iotests/041 | 6 | ||||
-rwxr-xr-x | tests/qemu-iotests/118 | 20 | ||||
-rwxr-xr-x | tests/qemu-iotests/161 | 137 | ||||
-rw-r--r-- | tests/qemu-iotests/161.out | 39 | ||||
-rwxr-xr-x | tests/qemu-iotests/223 | 43 | ||||
-rw-r--r-- | tests/qemu-iotests/223.out | 32 | ||||
-rwxr-xr-x | tests/qemu-iotests/233 | 9 | ||||
-rw-r--r-- | tests/qemu-iotests/common.tls | 3 | ||||
-rw-r--r-- | tests/qemu-iotests/group | 1 | ||||
-rw-r--r-- | tests/qemu-iotests/iotests.py | 2 |
16 files changed, 364 insertions, 63 deletions
@@ -1137,7 +1137,7 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags) static void update_flags_from_options(int *flags, QemuOpts *opts) { - *flags &= ~BDRV_O_CACHE_MASK; + *flags &= ~(BDRV_O_CACHE_MASK | BDRV_O_RDWR | BDRV_O_AUTO_RDONLY); assert(qemu_opt_find(opts, BDRV_OPT_CACHE_NO_FLUSH)); if (qemu_opt_get_bool_del(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) { @@ -1149,8 +1149,6 @@ static void update_flags_from_options(int *flags, QemuOpts *opts) *flags |= BDRV_O_NOCACHE; } - *flags &= ~BDRV_O_RDWR; - assert(qemu_opt_find(opts, BDRV_OPT_READ_ONLY)); if (!qemu_opt_get_bool_del(opts, BDRV_OPT_READ_ONLY, false)) { *flags |= BDRV_O_RDWR; @@ -2262,6 +2260,18 @@ static void bdrv_parent_cb_change_media(BlockDriverState *bs, bool load) } } +/* Return true if you can reach parent going through child->inherits_from + * recursively. If parent or child are NULL, return false */ +static bool bdrv_inherits_from_recursive(BlockDriverState *child, + BlockDriverState *parent) +{ + while (child && child != parent) { + child = child->inherits_from; + } + + return child != NULL; +} + /* * Sets the backing file link of a BDS. A new reference is created; callers * which don't need their own reference any more must call bdrv_unref(). @@ -2269,6 +2279,9 @@ static void bdrv_parent_cb_change_media(BlockDriverState *bs, bool load) void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, Error **errp) { + bool update_inherits_from = bdrv_chain_contains(bs, backing_hd) && + bdrv_inherits_from_recursive(backing_hd, bs); + if (backing_hd) { bdrv_ref(backing_hd); } @@ -2284,6 +2297,12 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, bs->backing = bdrv_attach_child(bs, backing_hd, "backing", &child_backing, errp); + /* If backing_hd was already part of bs's backing chain, and + * inherits_from pointed recursively to bs then let's update it to + * point directly to bs (else it will become NULL). */ + if (update_inherits_from) { + backing_hd->inherits_from = bs; + } if (!bs->backing) { bdrv_unref(backing_hd); } @@ -3836,6 +3855,8 @@ BlockDriverState *bdrv_find_base(BlockDriverState *bs) int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, const char *backing_file_str) { + BlockDriverState *explicit_top = top; + bool update_inherits_from; BdrvChild *c, *next; Error *local_err = NULL; int ret = -EIO; @@ -3851,6 +3872,16 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, goto exit; } + /* If 'base' recursively inherits from 'top' then we should set + * base->inherits_from to top->inherits_from after 'top' and all + * other intermediate nodes have been dropped. + * If 'top' is an implicit node (e.g. "commit_top") we should skip + * it because no one inherits from it. We use explicit_top for that. */ + while (explicit_top && explicit_top->implicit) { + explicit_top = backing_bs(explicit_top); + } + update_inherits_from = bdrv_inherits_from_recursive(base, explicit_top); + /* success - we can delete the intermediate states, and link top->base */ /* TODO Check graph modification op blockers (BLK_PERM_GRAPH_MOD) once * we've figured out how they should work. */ @@ -3886,6 +3917,10 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, bdrv_unref(top); } + if (update_inherits_from) { + base->inherits_from = explicit_top->inherits_from; + } + ret = 0; exit: bdrv_unref(top); diff --git a/hw/block/nvme.c b/hw/block/nvme.c index d0226e7fdc..9fbe5673cb 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -554,6 +554,7 @@ static uint16_t nvme_del_cq(NvmeCtrl *n, NvmeCmd *cmd) trace_nvme_err_invalid_del_cq_notempty(qid); return NVME_INVALID_QUEUE_DEL; } + nvme_irq_deassert(n, cq); trace_nvme_del_cq(qid); nvme_free_cq(cq, n); return NVME_SUCCESS; @@ -797,6 +798,8 @@ static void nvme_clear_ctrl(NvmeCtrl *n) { int i; + blk_drain(n->conf.blk); + for (i = 0; i < n->num_queues; i++) { if (n->sq[i] != NULL) { nvme_free_sq(n->sq[i], n); @@ -1175,23 +1178,13 @@ static void nvme_cmb_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { NvmeCtrl *n = (NvmeCtrl *)opaque; - - if (addr + size > NVME_CMBSZ_GETSIZE(n->bar.cmbsz)) { - return; - } - memcpy(&n->cmbuf[addr], &data, size); + stn_le_p(&n->cmbuf[addr], size, data); } static uint64_t nvme_cmb_read(void *opaque, hwaddr addr, unsigned size) { - uint64_t val; NvmeCtrl *n = (NvmeCtrl *)opaque; - - if (addr + size > NVME_CMBSZ_GETSIZE(n->bar.cmbsz)) { - return 0; - } - memcpy(&val, &n->cmbuf[addr], size); - return val; + return ldn_le_p(&n->cmbuf[addr], size); } static const MemoryRegionOps nvme_cmb_ops = { @@ -1199,7 +1192,7 @@ static const MemoryRegionOps nvme_cmb_ops = { .write = nvme_cmb_write, .endianness = DEVICE_LITTLE_ENDIAN, .impl = { - .min_access_size = 2, + .min_access_size = 1, .max_access_size = 8, }, }; diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 6eb258d3f3..0e9027c8f3 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -482,7 +482,7 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed) if (action == BLOCK_ERROR_ACTION_STOP) { scsi_req_retry(&r->req); } - return false; + return true; } static void scsi_write_complete_noio(SCSIDiskReq *r, int ret) diff --git a/qemu-img.c b/qemu-img.c index 13a6ca31b4..ad04f59565 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -261,8 +261,9 @@ static int print_block_option_help(const char *filename, const char *fmt) return 1; } if (!proto_drv->create_opts) { - error_report("Protocal driver '%s' does not support image creation", + error_report("Protocol driver '%s' does not support image creation", proto_drv->format_name); + qemu_opts_free(create_opts); return 1; } create_opts = qemu_opts_append(create_opts, proto_drv->create_opts); diff --git a/tests/Makefile.include b/tests/Makefile.include index 613242bc6e..fb0b449c02 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -730,7 +730,7 @@ tests/test-hmp$(EXESUF): tests/test-hmp.o tests/machine-none-test$(EXESUF): tests/machine-none-test.o tests/drive_del-test$(EXESUF): tests/drive_del-test.o $(libqos-virtio-obj-y) tests/qdev-monitor-test$(EXESUF): tests/qdev-monitor-test.o $(libqos-pc-obj-y) -tests/nvme-test$(EXESUF): tests/nvme-test.o +tests/nvme-test$(EXESUF): tests/nvme-test.o $(libqos-pc-obj-y) tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o tests/ac97-test$(EXESUF): tests/ac97-test.o diff --git a/tests/nvme-test.c b/tests/nvme-test.c index 7674a446e4..2700ba838a 100644 --- a/tests/nvme-test.c +++ b/tests/nvme-test.c @@ -8,25 +8,73 @@ */ #include "qemu/osdep.h" +#include "qemu/units.h" #include "libqtest.h" +#include "libqos/libqos-pc.h" + +static QOSState *qnvme_start(const char *extra_opts) +{ + QOSState *qs; + const char *arch = qtest_get_arch(); + const char *cmd = "-drive id=drv0,if=none,file=null-co://,format=raw " + "-device nvme,addr=0x4.0,serial=foo,drive=drv0 %s"; + + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + qs = qtest_pc_boot(cmd, extra_opts ? : ""); + global_qtest = qs->qts; + return qs; + } + + g_printerr("nvme tests are only available on x86\n"); + exit(EXIT_FAILURE); +} + +static void qnvme_stop(QOSState *qs) +{ + qtest_shutdown(qs); +} -/* Tests only initialization so far. TODO: Replace with functional tests */ static void nop(void) { + QOSState *qs; + + qs = qnvme_start(NULL); + qnvme_stop(qs); } -int main(int argc, char **argv) +static void nvmetest_cmb_test(void) { - int ret; + const int cmb_bar_size = 2 * MiB; + QOSState *qs; + QPCIDevice *pdev; + QPCIBar bar; - g_test_init(&argc, &argv, NULL); - qtest_add_func("/nvme/nop", nop); + qs = qnvme_start("-global nvme.cmb_size_mb=2"); + pdev = qpci_device_find(qs->pcibus, QPCI_DEVFN(4,0)); + g_assert(pdev != NULL); + + qpci_device_enable(pdev); + bar = qpci_iomap(pdev, 2, NULL); + + qpci_io_writel(pdev, bar, 0, 0xccbbaa99); + g_assert_cmpint(qpci_io_readb(pdev, bar, 0), ==, 0x99); + g_assert_cmpint(qpci_io_readw(pdev, bar, 0), ==, 0xaa99); + + /* Test partially out-of-bounds accesses. */ + qpci_io_writel(pdev, bar, cmb_bar_size - 1, 0x44332211); + g_assert_cmpint(qpci_io_readb(pdev, bar, cmb_bar_size - 1), ==, 0x11); + g_assert_cmpint(qpci_io_readw(pdev, bar, cmb_bar_size - 1), !=, 0x2211); + g_assert_cmpint(qpci_io_readl(pdev, bar, cmb_bar_size - 1), !=, 0x44332211); + g_free(pdev); - qtest_start("-drive id=drv0,if=none,file=null-co://,format=raw " - "-device nvme,drive=drv0,serial=foo"); - ret = g_test_run(); + qnvme_stop(qs); +} - qtest_end(); +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + qtest_add_func("/nvme/nop", nop); + qtest_add_func("/nvme/cmb_test", nvmetest_cmb_test); - return ret; + return g_test_run(); } diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index 3615011d98..26bf1701eb 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -469,7 +469,7 @@ new_state = "1" self.assert_qmp(event, 'data/id', 'drive0') event = self.vm.get_qmp_event(wait=True) - self.assertEquals(event['event'], 'BLOCK_JOB_ERROR') + self.assertEqual(event['event'], 'BLOCK_JOB_ERROR') self.assert_qmp(event, 'data/device', 'drive0') self.assert_qmp(event, 'data/operation', 'read') result = self.vm.qmp('query-block-jobs') @@ -494,7 +494,7 @@ new_state = "1" self.assert_qmp(event, 'data/id', 'drive0') event = self.vm.get_qmp_event(wait=True) - self.assertEquals(event['event'], 'BLOCK_JOB_ERROR') + self.assertEqual(event['event'], 'BLOCK_JOB_ERROR') self.assert_qmp(event, 'data/device', 'drive0') self.assert_qmp(event, 'data/operation', 'read') result = self.vm.qmp('query-block-jobs') @@ -625,7 +625,7 @@ new_state = "1" self.assert_qmp(result, 'return', {}) event = self.vm.event_wait(name='BLOCK_JOB_ERROR') - self.assertEquals(event['event'], 'BLOCK_JOB_ERROR') + self.assertEqual(event['event'], 'BLOCK_JOB_ERROR') self.assert_qmp(event, 'data/device', 'drive0') self.assert_qmp(event, 'data/operation', 'write') result = self.vm.qmp('query-block-jobs') diff --git a/tests/qemu-iotests/118 b/tests/qemu-iotests/118 index ff3b2ae3e7..603e10e8a2 100755 --- a/tests/qemu-iotests/118 +++ b/tests/qemu-iotests/118 @@ -53,21 +53,17 @@ class ChangeBaseClass(iotests.QMPTestCase): if not self.has_real_tray: return - timeout = time.clock() + 3 - while not self.has_opened and time.clock() < timeout: - self.process_events() - if not self.has_opened: - self.fail('Timeout while waiting for the tray to open') + with iotests.Timeout(3, 'Timeout while waiting for the tray to open'): + while not self.has_opened: + self.process_events() def wait_for_close(self): if not self.has_real_tray: return - timeout = time.clock() + 3 - while not self.has_closed and time.clock() < timeout: - self.process_events() - if not self.has_opened: - self.fail('Timeout while waiting for the tray to close') + with iotests.Timeout(3, 'Timeout while waiting for the tray to close'): + while not self.has_closed: + self.process_events() class GeneralChangeTestsBaseClass(ChangeBaseClass): @@ -265,7 +261,7 @@ class GeneralChangeTestsBaseClass(ChangeBaseClass): result = self.vm.qmp('blockdev-close-tray', id=self.device_name) # Should be a no-op self.assert_qmp(result, 'return', {}) - self.assertEquals(self.vm.get_qmp_events(wait=False), []) + self.assertEqual(self.vm.get_qmp_events(wait=False), []) def test_remove_on_closed(self): if not self.has_real_tray: @@ -452,7 +448,7 @@ class TestChangeReadOnly(ChangeBaseClass): read_only_mode='retain') self.assert_qmp(result, 'error/class', 'GenericError') - self.assertEquals(self.vm.get_qmp_events(wait=False), []) + self.assertEqual(self.vm.get_qmp_events(wait=False), []) result = self.vm.qmp('query-block') self.assert_qmp(result, 'return[0]/inserted/ro', False) diff --git a/tests/qemu-iotests/161 b/tests/qemu-iotests/161 new file mode 100755 index 0000000000..180df17ad6 --- /dev/null +++ b/tests/qemu-iotests/161 @@ -0,0 +1,137 @@ +#!/bin/bash +# +# Test reopening a backing image after block-stream and block-commit +# +# Copyright (C) 2018 Igalia, S.L. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=berto@igalia.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img + rm -f "$TEST_IMG.base" + rm -f "$TEST_IMG.int" +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.qemu + +# Any format implementing BlockDriver.bdrv_change_backing_file +_supported_fmt qcow2 qed +_supported_proto file +_supported_os Linux + +IMG_SIZE=1M + +# Create the images +TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE | _filter_imgfmt +TEST_IMG="$TEST_IMG.int" _make_test_img -b "$TEST_IMG.base" | _filter_imgfmt +_make_test_img -b "$TEST_IMG.int" | _filter_imgfmt + +# First test: reopen $TEST.IMG changing the detect-zeroes option on +# its backing file ($TEST_IMG.int). +echo +echo "*** Change an option on the backing file" +echo +_launch_qemu -drive if=none,file="${TEST_IMG}" +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'qmp_capabilities' }" \ + 'return' + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'human-monitor-command', + 'arguments': { 'command-line': + 'qemu-io none0 \"reopen -o backing.detect-zeroes=on\"' } }" \ + "return" + +_cleanup_qemu + +# Second test: stream $TEST_IMG.base into $TEST_IMG.int and then +# reopen $TEST.IMG changing the detect-zeroes option on its new +# backing file ($TEST_IMG.base). +echo +echo "*** Stream and then change an option on the backing file" +echo +_launch_qemu -drive if=none,file="${TEST_IMG}" +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'qmp_capabilities' }" \ + 'return' + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'block-stream', \ + 'arguments': { 'device': 'none0', + 'base': '${TEST_IMG}.base' } }" \ + 'return' + +# Wait for block-stream to finish +sleep 0.5 + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'human-monitor-command', + 'arguments': { 'command-line': + 'qemu-io none0 \"reopen -o backing.detect-zeroes=on\"' } }" \ + "return" + +_cleanup_qemu + +# Third test: commit $TEST_IMG.int into $TEST_IMG.base and then reopen +# $TEST.IMG changing the detect-zeroes option on its new backing file +# ($TEST_IMG.base). +echo +echo "*** Commit and then change an option on the backing file" +echo +# Create the images again +TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE | _filter_imgfmt +TEST_IMG="$TEST_IMG.int" _make_test_img -b "$TEST_IMG.base" | _filter_imgfmt +_make_test_img -b "$TEST_IMG.int" | _filter_imgfmt + +_launch_qemu -drive if=none,file="${TEST_IMG}" +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'qmp_capabilities' }" \ + 'return' + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'block-commit', \ + 'arguments': { 'device': 'none0', + 'top': '${TEST_IMG}.int' } }" \ + 'return' + +# Wait for block-commit to finish +sleep 0.5 + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'human-monitor-command', + 'arguments': { 'command-line': + 'qemu-io none0 \"reopen -o backing.detect-zeroes=on\"' } }" \ + "return" + +_cleanup_qemu + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/161.out b/tests/qemu-iotests/161.out new file mode 100644 index 0000000000..39951993ee --- /dev/null +++ b/tests/qemu-iotests/161.out @@ -0,0 +1,39 @@ +QA output created by 161 +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=1048576 +Formatting 'TEST_DIR/t.IMGFMT.int', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.int + +*** Change an option on the backing file + +{"return": {}} +{"return": ""} + +*** Stream and then change an option on the backing file + +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "none0"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "none0"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "none0"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "none0"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "none0", "len": 1048576, "offset": 1048576, "speed": 0, "type": "stream"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "none0"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "none0"}} +{"return": ""} + +*** Commit and then change an option on the backing file + +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=1048576 +Formatting 'TEST_DIR/t.IMGFMT.int', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.base +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.int +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "none0"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "none0"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "none0"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "none0"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "none0", "len": 1048576, "offset": 1048576, "speed": 0, "type": "commit"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "none0"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "none0"}} +{"return": ""} +*** done diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223 index 72419e0338..397b865d34 100755 --- a/tests/qemu-iotests/223 +++ b/tests/qemu-iotests/223 @@ -57,10 +57,11 @@ run_qemu() } echo -echo "=== Create partially sparse image, then add dirty bitmap ===" +echo "=== Create partially sparse image, then add dirty bitmaps ===" echo -_make_test_img 4M +# Two bitmaps, to contrast granularity issues +_make_test_img -o cluster_size=4k 4M $QEMU_IO -c 'w -P 0x11 1M 2M' "$TEST_IMG" | _filter_qemu_io run_qemu <<EOF { "execute": "qmp_capabilities" } @@ -78,7 +79,16 @@ run_qemu <<EOF "arguments": { "node": "n", "name": "b", - "persistent": true + "persistent": true, + "granularity": 65536 + } +} +{ "execute": "block-dirty-bitmap-add", + "arguments": { + "node": "n", + "name": "b2", + "persistent": true, + "granularity": 512 } } { "execute": "quit" } @@ -88,10 +98,11 @@ echo echo "=== Write part of the file under active bitmap ===" echo -$QEMU_IO -c 'w -P 0x22 2M 2M' "$TEST_IMG" | _filter_qemu_io +$QEMU_IO -c 'w -P 0x22 512 512' -c 'w -P 0x33 2M 2M' "$TEST_IMG" \ + | _filter_qemu_io echo -echo "=== End dirty bitmap, and start serving image over NBD ===" +echo "=== End dirty bitmaps, and start serving image over NBD ===" echo _launch_qemu 2> >(_filter_nbd) @@ -103,6 +114,8 @@ _send_qemu_cmd $QEMU_HANDLE '{"execute":"blockdev-add", "file":{"driver":"file", "filename":"'"$TEST_IMG"'"}}}' "return" _send_qemu_cmd $QEMU_HANDLE '{"execute":"x-block-dirty-bitmap-disable", "arguments":{"node":"n", "name":"b"}}' "return" +_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-block-dirty-bitmap-disable", + "arguments":{"node":"n", "name":"b2"}}' "return" _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-start", "arguments":{"addr":{"type":"unix", "data":{"path":"'"$TEST_DIR/nbd"'"}}}}' "return" @@ -110,26 +123,40 @@ _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", "arguments":{"device":"n"}}' "return" _send_qemu_cmd $QEMU_HANDLE '{"execute":"x-nbd-server-add-bitmap", "arguments":{"name":"n", "bitmap":"b"}}' "return" +_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", + "arguments":{"device":"n", "name":"n2"}}' "return" +_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-nbd-server-add-bitmap", + "arguments":{"name":"n2", "bitmap":"b2"}}' "return" echo -echo "=== Contrast normal status with dirty-bitmap status ===" +echo "=== Contrast normal status to large granularity dirty-bitmap ===" echo QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT IMG="driver=nbd,export=n,server.type=unix,server.path=$TEST_DIR/nbd" -$QEMU_IO -r -c 'r -P 0 0 1m' -c 'r -P 0x11 1m 1m' \ - -c 'r -P 0x22 2m 2m' --image-opts "$IMG" | _filter_qemu_io +$QEMU_IO -r -c 'r -P 0x22 512 512' -c 'r -P 0 512k 512k' -c 'r -P 0x11 1m 1m' \ + -c 'r -P 0x33 2m 2m' --image-opts "$IMG" | _filter_qemu_io $QEMU_IMG map --output=json --image-opts \ "$IMG" | _filter_qemu_img_map $QEMU_IMG map --output=json --image-opts \ "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b" | _filter_qemu_img_map echo +echo "=== Contrast to small granularity dirty-bitmap ===" +echo + +IMG="driver=nbd,export=n2,server.type=unix,server.path=$TEST_DIR/nbd" +$QEMU_IMG map --output=json --image-opts \ + "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b2" | _filter_qemu_img_map + +echo echo "=== End NBD server ===" echo _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove", "arguments":{"name":"n"}}' "return" +_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove", + "arguments":{"name":"n2"}}' "return" _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-stop"}' "return" _send_qemu_cmd $QEMU_HANDLE '{"execute":"quit"}' "return" diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out index 33021c8e6a..de417477de 100644 --- a/tests/qemu-iotests/223.out +++ b/tests/qemu-iotests/223.out @@ -1,6 +1,6 @@ QA output created by 223 -=== Create partially sparse image, then add dirty bitmap === +=== Create partially sparse image, then add dirty bitmaps === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4194304 wrote 2097152/2097152 bytes at offset 1048576 @@ -11,15 +11,18 @@ QMP_VERSION {"return": {}} {"return": {}} {"return": {}} +{"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} === Write part of the file under active bitmap === +wrote 512/512 bytes at offset 512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 2097152/2097152 bytes at offset 2097152 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -=== End dirty bitmap, and start serving image over NBD === +=== End dirty bitmaps, and start serving image over NBD === {"return": {}} {"return": {}} @@ -27,18 +30,32 @@ wrote 2097152/2097152 bytes at offset 2097152 {"return": {}} {"return": {}} {"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} -=== Contrast normal status with dirty-bitmap status === +=== Contrast normal status to large granularity dirty-bitmap === -read 1048576/1048576 bytes at offset 0 -1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 524288/524288 bytes at offset 524288 +512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 1048576/1048576 bytes at offset 1048576 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 2097152/2097152 bytes at offset 2097152 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false}, +[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true}, +{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false}, { "start": 1048576, "length": 3145728, "depth": 0, "zero": false, "data": true}] -[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true}, +[{ "start": 0, "length": 65536, "depth": 0, "zero": false, "data": false}, +{ "start": 65536, "length": 2031616, "depth": 0, "zero": false, "data": true}, +{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}] + +=== Contrast to small granularity dirty-bitmap === + +[{ "start": 0, "length": 512, "depth": 0, "zero": false, "data": true}, +{ "start": 512, "length": 512, "depth": 0, "zero": false, "data": false}, +{ "start": 1024, "length": 2096128, "depth": 0, "zero": false, "data": true}, { "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}] === End NBD server === @@ -46,4 +63,5 @@ read 2097152/2097152 bytes at offset 2097152 {"return": {}} {"return": {}} {"return": {}} +{"return": {}} *** done diff --git a/tests/qemu-iotests/233 b/tests/qemu-iotests/233 index a4da60d0ad..1814efe333 100755 --- a/tests/qemu-iotests/233 +++ b/tests/qemu-iotests/233 @@ -66,7 +66,7 @@ $QEMU_IO -c 'w -P 0x11 1m 1m' "$TEST_IMG" | _filter_qemu_io echo echo "== check TLS client to plain server fails ==" -nbd_server_start_tcp_socket "$TEST_IMG" +nbd_server_start_tcp_socket -f $IMGFMT "$TEST_IMG" $QEMU_IMG info --image-opts \ --object tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0 \ @@ -78,7 +78,10 @@ nbd_server_stop echo echo "== check plain client to TLS server fails ==" -nbd_server_start_tcp_socket --object tls-creds-x509,dir=${tls_dir}/server1,endpoint=server,id=tls0,verify-peer=yes --tls-creds tls0 "$TEST_IMG" +nbd_server_start_tcp_socket \ + --object tls-creds-x509,dir=${tls_dir}/server1,endpoint=server,id=tls0,verify-peer=yes \ + --tls-creds tls0 \ + -f $IMGFMT "$TEST_IMG" $QEMU_IMG info nbd://localhost:$nbd_tcp_port 2>&1 | sed "s/$nbd_tcp_port/PORT/g" @@ -104,7 +107,7 @@ $QEMU_IO -c 'r -P 0x11 1m 1m' -c 'w -P 0x22 1m 1m' --image-opts \ driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \ 2>&1 | _filter_qemu_io -$QEMU_IO -f qcow2 -r -U -c 'r -P 0x22 1m 1m' "$TEST_IMG" | _filter_qemu_io +$QEMU_IO -f $IMGFMT -r -U -c 'r -P 0x22 1m 1m' "$TEST_IMG" | _filter_qemu_io # success, all done echo "*** done" diff --git a/tests/qemu-iotests/common.tls b/tests/qemu-iotests/common.tls index 39f17c1b99..eae81789bb 100644 --- a/tests/qemu-iotests/common.tls +++ b/tests/qemu-iotests/common.tls @@ -31,6 +31,9 @@ tls_x509_cleanup() tls_x509_init() { + (certtool --help) >/dev/null 2>&1 || \ + _notrun "certtool utility not found, skipping test" + mkdir -p "${tls_dir}" # use a fixed key so we don't waste system entropy on diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 2722103381..ddf1a5b549 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -167,6 +167,7 @@ 158 rw auto quick 159 rw auto quick 160 rw auto quick +161 rw auto quick 162 auto quick 163 rw auto 165 rw auto quick diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 27bb2b600c..d537538ba0 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -581,7 +581,7 @@ class QMPTestCase(unittest.TestCase): def wait_ready_and_cancel(self, drive='drive0'): self.wait_ready(drive=drive) event = self.cancel_and_wait(drive=drive) - self.assertEquals(event['event'], 'BLOCK_JOB_COMPLETED') + self.assertEqual(event['event'], 'BLOCK_JOB_COMPLETED') self.assert_qmp(event, 'data/type', 'mirror') self.assert_qmp(event, 'data/offset', event['data']['len']) |