mirror of https://github.com/xemu-project/xemu.git
Block layer patches:
- block: Fix update of BDRV_O_AUTO_RDONLY in update_flags_from_options() - block: Fix option inheritance after stream/commit job graph changes - qemu-img: Fix memory leak and typo in error message - nvme: Fixes for lockups and crashes - scsi-disk: Fix crash if underlying host file or disk returns error - Several qemu-iotests fixes and improvements -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJb9vemAAoJEH8JsnLIjy/WWJQQAKiW7/Ku1i4DgZz6n97+HumE CryEgO/Hx9YnQPJPcEWNQVNtdO311rJSprLkmt83tOwQ1ew9lvqdcq9ptEUb4dW9 9bV31nP2nRkR3/cyLgWuYALH3Y6eSMwLQiYb0DaWKL2sxiMdghvK3gALXb3r+AtI F2uuQC6N6xNKj5srrTcxMman22QYIqkeuONWY9La9mQWG44WI5Gc+mF1LKMNk7x9 bBsvP5+ukm3O4+vvGylZjOXYpCgwQngSLvGG/rsHwBTBrDQiy3m1JoxxXzqr+Z4K p2b5wU2vFgfJ6cDGZJQWHQ/XAH3njmuPJEg+DOe7SUuGio2gQZCHlHU0xtp0GrQh BkYMfRUfb+rJ/t/mamX1y45XSBdvR0hJkgdgZYeHbFfV80Do63GqfqzOCDkKBocg /cbcDAvLiztoQpSa3aLMCHobs2X4Jn41ODUEidRbWsn3W099R2vIAUnxht/RI8Dm A5a7zfzXgMyEeXywxdCGM2k2oQsDnZoZLqNYJjkVmn3eqSIt3aLaSWtX0U7EVbEC PwNXAhz0Gl1YFhkgzEd8qkNH60lUb7Lone+3471iKACY0gjEeN5Ljsv/+HhaTQi/ a5HTAf+eUUO9OJt3DNE4pbUORDH0XMZBb3vTqfqf9a0iKWxXnuX25xm5YfVyagDi 54ZVHTqL+4zskS7uHD1O =dCUx -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging Block layer patches: - block: Fix update of BDRV_O_AUTO_RDONLY in update_flags_from_options() - block: Fix option inheritance after stream/commit job graph changes - qemu-img: Fix memory leak and typo in error message - nvme: Fixes for lockups and crashes - scsi-disk: Fix crash if underlying host file or disk returns error - Several qemu-iotests fixes and improvements # gpg: Signature made Thu 22 Nov 2018 18:38:30 GMT # gpg: using RSA key 7F09B272C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" # Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6 * remotes/kevin/tags/for-upstream: block: Update BlockDriverState.inherits_from on bdrv_drop_intermediate() block: Update BlockDriverState.inherits_from on bdrv_set_backing_hd() iotests: Enhance 223 to cover multiple bitmap granularities nvme: fix bug with PCI IRQ pins on teardown nvme: fix CMB endianness confusion Revert "nvme: fix oob access issue(CVE-2018-16847)" nvme: fix out-of-bounds access to the CMB nvme: call blk_drain in NVMe reset code to avoid lockups iotests: fix nbd test 233 to work correctly with raw images block: Fix update of BDRV_O_AUTO_RDONLY in update_flags_from_options() scsi-disk: Fix crash if underlying host file or disk returns error qemu-img: Fix leak qemu-img: Fix typo iotests: Skip 233 if certtool not installed iotests: Replace assertEquals() with assertEqual() iotests: Replace time.clock() with Timeout Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
5298f4d67a
41
block.c
41
block.c
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
static void nvmetest_cmb_test(void)
|
||||
{
|
||||
const int cmb_bar_size = 2 * MiB;
|
||||
QOSState *qs;
|
||||
QPCIDevice *pdev;
|
||||
QPCIBar bar;
|
||||
|
||||
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);
|
||||
|
||||
qnvme_stop(qs);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
qtest_add_func("/nvme/nop", nop);
|
||||
qtest_add_func("/nvme/cmb_test", nvmetest_cmb_test);
|
||||
|
||||
qtest_start("-drive id=drv0,if=none,file=null-co://,format=raw "
|
||||
"-device nvme,drive=drv0,serial=foo");
|
||||
ret = g_test_run();
|
||||
|
||||
qtest_end();
|
||||
|
||||
return ret;
|
||||
return g_test_run();
|
||||
}
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'])
|
||||
|
||||
|
|
Loading…
Reference in New Issue