Block layer patches:

- Relax restrictions for blockdev-snapshot (allows libvirt to do live
   storage migration with blockdev-mirror)
 - luks: Delete created files when block_crypto_co_create_opts_luks fails
 - Fix memleaks in qmp_object_add
 -----BEGIN PGP SIGNATURE-----
 
 iQIcBAABAgAGBQJeaQYTAAoJEH8JsnLIjy/WQwYP/3pzAjqVecL3dGmnPWAkBqCV
 CFpxT2nIMe+xCBvWQBoeekHsFJ7GQf4E1WVNRZgoAh9VQkvkajZsVNn8Auo2Veq2
 c7w/R4xf/Wet2hKGVRS0JXwbg69U5BbpcF7E2DRNfp+CvaDCafHSDNeGTb3hFUjT
 x1jwhK6VqfY7+LHU0B0QmX2KA66nDx1p8l8HJQYd1MlCKAbj8kv/swEbqBJn32hA
 32CIYfC4VCqkW5va1eOjd3Kyi/ugkFCHTI8+mOa45/BFBzIiKfCsDaFHh/DI59QB
 qcDKkUcO3+W788vCKgJQGnG070TwKPx2OnjhxFKiEGaoX3Sz+AY4wUvf3mfFl8GM
 zYqTdOy4Xh0ckvA6JCS0jtAKmANkeEGqnECAgub22Z+kyOzqC05B1FkYwqYDcFXY
 atWKm5Vr47jgD6Oq6O0OpZaZrAUWOfoBmq4ErnrBEHuW5329NEInmjYwxednK+43
 CwU/lSdX7ujRSsjS8Xi1dHS4pxHK/mg51dInL44zGFUayegiLPgA8cuESE0mHOfZ
 67X14rxu6D4Y5r0L+w7rsSGjByR29VynE1McL9fZ1Wp29JHaQ5fjdG6GMXEwYxmV
 R0YNXe85FAlNgqj0Bme+fR2YPxZ48NqHIMOvFFStNHyfD0qQN0TtT1iarfEcBR0u
 jm8MnSoIDLkRXEgBW9bW
 =ociU
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging

Block layer patches:

- Relax restrictions for blockdev-snapshot (allows libvirt to do live
  storage migration with blockdev-mirror)
- luks: Delete created files when block_crypto_co_create_opts_luks fails
- Fix memleaks in qmp_object_add

# gpg: Signature made Wed 11 Mar 2020 15:38:59 GMT
# gpg:                using RSA key 7F09B272C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full]
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74  56FE 7F09 B272 C88F 2FD6

* remotes/kevin/tags/for-upstream:
  qemu-iotests: adding LUKS cleanup for non-UTF8 secret error
  crypto.c: cleanup created file when block_crypto_co_create_opts_luks fails
  block.c: adding bdrv_co_delete_file
  block: introducing 'bdrv_co_delete_file' interface
  tests/qemu-iotests: Fix socket_scm_helper build path
  qapi: Add '@allow-write-only-overlay' feature for 'blockdev-snapshot'
  iotests: Add iothread cases to 155
  block: Fix cross-AioContext blockdev-snapshot
  iotests: Test mirror with temporarily disabled target backing file
  iotests: Fix run_job() with use_log=False
  block: Relax restrictions for blockdev-snapshot
  block: Make bdrv_get_cumulative_perm() public
  qom-qmp-cmds: fix two memleaks in qmp_object_add

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-03-12 16:51:26 +00:00
commit 49780a582d
17 changed files with 262 additions and 57 deletions

31
block.c
View File

@ -668,6 +668,32 @@ int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp)
} }
} }
int coroutine_fn bdrv_co_delete_file(BlockDriverState *bs, Error **errp)
{
Error *local_err = NULL;
int ret;
assert(bs != NULL);
if (!bs->drv) {
error_setg(errp, "Block node '%s' is not opened", bs->filename);
return -ENOMEDIUM;
}
if (!bs->drv->bdrv_co_delete_file) {
error_setg(errp, "Driver '%s' does not support image deletion",
bs->drv->format_name);
return -ENOTSUP;
}
ret = bs->drv->bdrv_co_delete_file(bs, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
}
return ret;
}
/** /**
* Try to get @bs's logical and physical block size. * Try to get @bs's logical and physical block size.
* On success, store them in @bsz struct and return 0. * On success, store them in @bsz struct and return 0.
@ -1872,8 +1898,6 @@ static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q,
bool *tighten_restrictions, Error **errp); bool *tighten_restrictions, Error **errp);
static void bdrv_child_abort_perm_update(BdrvChild *c); static void bdrv_child_abort_perm_update(BdrvChild *c);
static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared); static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared);
static void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
uint64_t *shared_perm);
typedef struct BlockReopenQueueEntry { typedef struct BlockReopenQueueEntry {
bool prepared; bool prepared;
@ -2097,7 +2121,7 @@ static void bdrv_set_perm(BlockDriverState *bs, uint64_t cumulative_perms,
} }
} }
static void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm, void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
uint64_t *shared_perm) uint64_t *shared_perm)
{ {
BdrvChild *c; BdrvChild *c;
@ -4367,6 +4391,7 @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
bdrv_ref(from); bdrv_ref(from);
assert(qemu_get_current_aio_context() == qemu_get_aio_context()); assert(qemu_get_current_aio_context() == qemu_get_aio_context());
assert(bdrv_get_aio_context(from) == bdrv_get_aio_context(to));
bdrv_drained_begin(from); bdrv_drained_begin(from);
/* Put all parents into @list and calculate their cumulative permissions */ /* Put all parents into @list and calculate their cumulative permissions */

View File

@ -30,6 +30,7 @@
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu/module.h" #include "qemu/module.h"
#include "qemu/option.h" #include "qemu/option.h"
#include "qemu/cutils.h"
#include "crypto.h" #include "crypto.h"
typedef struct BlockCrypto BlockCrypto; typedef struct BlockCrypto BlockCrypto;
@ -657,6 +658,23 @@ static int coroutine_fn block_crypto_co_create_opts_luks(const char *filename,
ret = 0; ret = 0;
fail: fail:
/*
* If an error occurred, delete 'filename'. Even if the file existed
* beforehand, it has been truncated and corrupted in the process.
*/
if (ret && bs) {
Error *local_delete_err = NULL;
int r_del = bdrv_co_delete_file(bs, &local_delete_err);
/*
* ENOTSUP will happen if the block driver doesn't support
* the 'bdrv_co_delete_file' interface. This is a predictable
* scenario and shouldn't be reported back to the user.
*/
if ((r_del < 0) && (r_del != -ENOTSUP)) {
error_report_err(local_delete_err);
}
}
bdrv_unref(bs); bdrv_unref(bs);
qapi_free_QCryptoBlockCreateOptions(create_opts); qapi_free_QCryptoBlockCreateOptions(create_opts);
qobject_unref(cryptoopts); qobject_unref(cryptoopts);

View File

@ -2445,6 +2445,28 @@ static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
return raw_co_create(&options, errp); return raw_co_create(&options, errp);
} }
static int coroutine_fn raw_co_delete_file(BlockDriverState *bs,
Error **errp)
{
struct stat st;
int ret;
if (!(stat(bs->filename, &st) == 0) || !S_ISREG(st.st_mode)) {
error_setg_errno(errp, ENOENT, "%s is not a regular file",
bs->filename);
return -ENOENT;
}
ret = unlink(bs->filename);
if (ret < 0) {
ret = -errno;
error_setg_errno(errp, -ret, "Error when deleting file %s",
bs->filename);
}
return ret;
}
/* /*
* Find allocation range in @bs around offset @start. * Find allocation range in @bs around offset @start.
* May change underlying file descriptor's file offset. * May change underlying file descriptor's file offset.
@ -3075,6 +3097,7 @@ BlockDriver bdrv_file = {
.bdrv_co_block_status = raw_co_block_status, .bdrv_co_block_status = raw_co_block_status,
.bdrv_co_invalidate_cache = raw_co_invalidate_cache, .bdrv_co_invalidate_cache = raw_co_invalidate_cache,
.bdrv_co_pwrite_zeroes = raw_co_pwrite_zeroes, .bdrv_co_pwrite_zeroes = raw_co_pwrite_zeroes,
.bdrv_co_delete_file = raw_co_delete_file,
.bdrv_co_preadv = raw_co_preadv, .bdrv_co_preadv = raw_co_preadv,
.bdrv_co_pwritev = raw_co_pwritev, .bdrv_co_pwritev = raw_co_pwritev,

View File

@ -1470,8 +1470,7 @@ static void external_snapshot_prepare(BlkActionState *common,
DO_UPCAST(ExternalSnapshotState, common, common); DO_UPCAST(ExternalSnapshotState, common, common);
TransactionAction *action = common->action; TransactionAction *action = common->action;
AioContext *aio_context; AioContext *aio_context;
AioContext *old_context; uint64_t perm, shared;
int ret;
/* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar /* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar
* purpose but a different set of parameters */ * purpose but a different set of parameters */
@ -1586,16 +1585,17 @@ static void external_snapshot_prepare(BlkActionState *common,
goto out; goto out;
} }
if (bdrv_has_blk(state->new_bs)) { /*
* Allow attaching a backing file to an overlay that's already in use only
* if the parents don't assume that they are already seeing a valid image.
* (Specifically, allow it as a mirror target, which is write-only access.)
*/
bdrv_get_cumulative_perm(state->new_bs, &perm, &shared);
if (perm & BLK_PERM_CONSISTENT_READ) {
error_setg(errp, "The overlay is already in use"); error_setg(errp, "The overlay is already in use");
goto out; goto out;
} }
if (bdrv_op_is_blocked(state->new_bs, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT,
errp)) {
goto out;
}
if (state->new_bs->backing != NULL) { if (state->new_bs->backing != NULL) {
error_setg(errp, "The overlay already has a backing image"); error_setg(errp, "The overlay already has a backing image");
goto out; goto out;
@ -1606,20 +1606,6 @@ static void external_snapshot_prepare(BlkActionState *common,
goto out; goto out;
} }
/* Honor bdrv_try_set_aio_context() context acquisition requirements. */
old_context = bdrv_get_aio_context(state->new_bs);
aio_context_release(aio_context);
aio_context_acquire(old_context);
ret = bdrv_try_set_aio_context(state->new_bs, aio_context, errp);
aio_context_release(old_context);
aio_context_acquire(aio_context);
if (ret < 0) {
goto out;
}
/* This removes our old bs and adds the new bs. This is an operation that /* This removes our old bs and adds the new bs. This is an operation that
* can fail, so we need to do it in .prepare; undoing it for abort is * can fail, so we need to do it in .prepare; undoing it for abort is
* always possible. */ * always possible. */

View File

@ -363,6 +363,7 @@ bool bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *base,
int bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base, int bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base,
Error **errp); Error **errp);
void bdrv_unfreeze_backing_chain(BlockDriverState *bs, BlockDriverState *base); void bdrv_unfreeze_backing_chain(BlockDriverState *bs, BlockDriverState *base);
int coroutine_fn bdrv_co_delete_file(BlockDriverState *bs, Error **errp);
typedef struct BdrvCheckResult { typedef struct BdrvCheckResult {

View File

@ -314,6 +314,10 @@ struct BlockDriver {
*/ */
int coroutine_fn (*bdrv_co_flush)(BlockDriverState *bs); int coroutine_fn (*bdrv_co_flush)(BlockDriverState *bs);
/* Delete a created file. */
int coroutine_fn (*bdrv_co_delete_file)(BlockDriverState *bs,
Error **errp);
/* /*
* Flushes all data that was already written to the OS all the way down to * Flushes all data that was already written to the OS all the way down to
* the disk (for example file-posix.c calls fsync()). * the disk (for example file-posix.c calls fsync()).
@ -1224,6 +1228,9 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
void *opaque, Error **errp); void *opaque, Error **errp);
void bdrv_root_unref_child(BdrvChild *child); void bdrv_root_unref_child(BdrvChild *child);
void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
uint64_t *shared_perm);
/** /**
* Sets a BdrvChild's permissions. Avoid if the parent is a BDS; use * Sets a BdrvChild's permissions. Avoid if the parent is a BDS; use
* bdrv_child_refresh_perms() instead and make the parent's * bdrv_child_refresh_perms() instead and make the parent's

View File

@ -1472,6 +1472,12 @@
# #
# For the arguments, see the documentation of BlockdevSnapshot. # For the arguments, see the documentation of BlockdevSnapshot.
# #
# Features:
# @allow-write-only-overlay: If present, the check whether this operation is safe
# was relaxed so that it can be used to change
# backing file of a destination of a blockdev-mirror.
# (since 5.0)
#
# Since: 2.5 # Since: 2.5
# #
# Example: # Example:
@ -1492,7 +1498,8 @@
# #
## ##
{ 'command': 'blockdev-snapshot', { 'command': 'blockdev-snapshot',
'data': 'BlockdevSnapshot' } 'data': 'BlockdevSnapshot',
'features': [ 'allow-write-only-overlay' ] }
## ##
# @change-backing-file: # @change-backing-file:

View File

@ -247,26 +247,22 @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
QDict *pdict; QDict *pdict;
Visitor *v; Visitor *v;
Object *obj; Object *obj;
const char *type; g_autofree char *type = NULL;
const char *id; g_autofree char *id = NULL;
type = qdict_get_try_str(qdict, "qom-type"); type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
if (!type) { if (!type) {
error_setg(errp, QERR_MISSING_PARAMETER, "qom-type"); error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
return; return;
} else {
type = g_strdup(type);
qdict_del(qdict, "qom-type");
} }
qdict_del(qdict, "qom-type");
id = qdict_get_try_str(qdict, "id"); id = g_strdup(qdict_get_try_str(qdict, "id"));
if (!id) { if (!id) {
error_setg(errp, QERR_MISSING_PARAMETER, "id"); error_setg(errp, QERR_MISSING_PARAMETER, "id");
return; return;
} else {
id = g_strdup(id);
qdict_del(qdict, "id");
} }
qdict_del(qdict, "id");
props = qdict_get(qdict, "props"); props = qdict_get(qdict, "props");
if (props) { if (props) {

View File

@ -589,6 +589,7 @@ include $(SRC_PATH)/tests/qtest/Makefile.include
tests/test-qga$(EXESUF): qemu-ga$(EXESUF) tests/test-qga$(EXESUF): qemu-ga$(EXESUF)
tests/test-qga$(EXESUF): tests/test-qga.o $(qtest-obj-y) tests/test-qga$(EXESUF): tests/test-qga.o $(qtest-obj-y)
tests/vhost-user-bridge$(EXESUF): tests/vhost-user-bridge.o $(test-util-obj-y) libvhost-user.a tests/vhost-user-bridge$(EXESUF): tests/vhost-user-bridge.o $(test-util-obj-y) libvhost-user.a
tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
SPEED = quick SPEED = quick

View File

@ -82,7 +82,7 @@ Formatting 'TEST_DIR/12-snapshot-v0.IMGFMT', fmt=IMGFMT size=134217728 backing_f
=== Invalid command - cannot create a snapshot using a file BDS === === Invalid command - cannot create a snapshot using a file BDS ===
{ 'execute': 'blockdev-snapshot', 'arguments': { 'node':'virtio0', 'overlay':'file_12' } } { 'execute': 'blockdev-snapshot', 'arguments': { 'node':'virtio0', 'overlay':'file_12' } }
{"error": {"class": "GenericError", "desc": "The overlay does not support backing images"}} {"error": {"class": "GenericError", "desc": "The overlay is already in use"}}
=== Invalid command - snapshot node used as active layer === === Invalid command - snapshot node used as active layer ===
@ -96,7 +96,7 @@ Formatting 'TEST_DIR/12-snapshot-v0.IMGFMT', fmt=IMGFMT size=134217728 backing_f
=== Invalid command - snapshot node used as backing hd === === Invalid command - snapshot node used as backing hd ===
{ 'execute': 'blockdev-snapshot', 'arguments': { 'node': 'virtio0', 'overlay':'snap_11' } } { 'execute': 'blockdev-snapshot', 'arguments': { 'node': 'virtio0', 'overlay':'snap_11' } }
{"error": {"class": "GenericError", "desc": "Node 'snap_11' is busy: node is used as backing hd of 'snap_12'"}} {"error": {"class": "GenericError", "desc": "The overlay is already in use"}}
=== Invalid command - snapshot node has a backing image === === Invalid command - snapshot node has a backing image ===

View File

@ -45,10 +45,18 @@ target_img = os.path.join(iotests.test_dir, 'target.' + iotests.imgfmt)
# image during runtime, only makes sense if # image during runtime, only makes sense if
# target_blockdev_backing is not None # target_blockdev_backing is not None
# (None: same as target_backing) # (None: same as target_backing)
# target_open_with_backing: If True, the target image is added with its backing
# chain opened right away. If False, blockdev-add
# opens it without a backing file and job completion
# is supposed to open the backing chain.
# use_iothread: If True, an iothread is configured for the virtio-blk device
# that uses the image being mirrored
class BaseClass(iotests.QMPTestCase): class BaseClass(iotests.QMPTestCase):
target_blockdev_backing = None target_blockdev_backing = None
target_real_backing = None target_real_backing = None
target_open_with_backing = True
use_iothread = False
def setUp(self): def setUp(self):
qemu_img('create', '-f', iotests.imgfmt, back0_img, '1440K') qemu_img('create', '-f', iotests.imgfmt, back0_img, '1440K')
@ -64,7 +72,16 @@ class BaseClass(iotests.QMPTestCase):
'file': {'driver': 'file', 'file': {'driver': 'file',
'filename': source_img}} 'filename': source_img}}
self.vm.add_blockdev(self.vm.qmp_to_opts(blockdev)) self.vm.add_blockdev(self.vm.qmp_to_opts(blockdev))
self.vm.add_device('virtio-blk,id=qdev0,drive=source')
if self.use_iothread:
self.vm.add_object('iothread,id=iothread0')
iothread = ",iothread=iothread0"
else:
iothread = ""
self.vm.add_device('virtio-scsi%s' % iothread)
self.vm.add_device('scsi-hd,id=qdev0,drive=source')
self.vm.launch() self.vm.launch()
self.assertIntactSourceBackingChain() self.assertIntactSourceBackingChain()
@ -80,8 +97,12 @@ class BaseClass(iotests.QMPTestCase):
options = { 'node-name': 'target', options = { 'node-name': 'target',
'driver': iotests.imgfmt, 'driver': iotests.imgfmt,
'file': { 'driver': 'file', 'file': { 'driver': 'file',
'node-name': 'target-file',
'filename': target_img } } 'filename': target_img } }
if self.target_blockdev_backing:
if not self.target_open_with_backing:
options['backing'] = None
elif self.target_blockdev_backing:
options['backing'] = self.target_blockdev_backing options['backing'] = self.target_blockdev_backing
result = self.vm.qmp('blockdev-add', **options) result = self.vm.qmp('blockdev-add', **options)
@ -147,10 +168,14 @@ class BaseClass(iotests.QMPTestCase):
# cmd: Mirroring command to execute, either drive-mirror or blockdev-mirror # cmd: Mirroring command to execute, either drive-mirror or blockdev-mirror
class MirrorBaseClass(BaseClass): class MirrorBaseClass(BaseClass):
def openBacking(self):
pass
def runMirror(self, sync): def runMirror(self, sync):
if self.cmd == 'blockdev-mirror': if self.cmd == 'blockdev-mirror':
result = self.vm.qmp(self.cmd, job_id='mirror-job', device='source', result = self.vm.qmp(self.cmd, job_id='mirror-job', device='source',
sync=sync, target='target') sync=sync, target='target',
auto_finalize=False)
else: else:
if self.existing: if self.existing:
mode = 'existing' mode = 'existing'
@ -159,33 +184,31 @@ class MirrorBaseClass(BaseClass):
result = self.vm.qmp(self.cmd, job_id='mirror-job', device='source', result = self.vm.qmp(self.cmd, job_id='mirror-job', device='source',
sync=sync, target=target_img, sync=sync, target=target_img,
format=iotests.imgfmt, mode=mode, format=iotests.imgfmt, mode=mode,
node_name='target') node_name='target', auto_finalize=False)
self.assert_qmp(result, 'return', {}) self.assert_qmp(result, 'return', {})
self.complete_and_wait('mirror-job') self.vm.run_job('mirror-job', use_log=False, auto_finalize=False,
pre_finalize=self.openBacking, auto_dismiss=True)
def testFull(self): def testFull(self):
self.runMirror('full') self.runMirror('full')
node = self.findBlockNode('target', node = self.findBlockNode('target', 'qdev0')
'/machine/peripheral/qdev0/virtio-backend')
self.assertCorrectBackingImage(node, None) self.assertCorrectBackingImage(node, None)
self.assertIntactSourceBackingChain() self.assertIntactSourceBackingChain()
def testTop(self): def testTop(self):
self.runMirror('top') self.runMirror('top')
node = self.findBlockNode('target', node = self.findBlockNode('target', 'qdev0')
'/machine/peripheral/qdev0/virtio-backend')
self.assertCorrectBackingImage(node, back2_img) self.assertCorrectBackingImage(node, back2_img)
self.assertIntactSourceBackingChain() self.assertIntactSourceBackingChain()
def testNone(self): def testNone(self):
self.runMirror('none') self.runMirror('none')
node = self.findBlockNode('target', node = self.findBlockNode('target', 'qdev0')
'/machine/peripheral/qdev0/virtio-backend')
self.assertCorrectBackingImage(node, source_img) self.assertCorrectBackingImage(node, source_img)
self.assertIntactSourceBackingChain() self.assertIntactSourceBackingChain()
@ -221,6 +244,44 @@ class TestBlockdevMirrorForcedBacking(MirrorBaseClass):
target_blockdev_backing = { 'driver': 'null-co' } target_blockdev_backing = { 'driver': 'null-co' }
target_real_backing = 'null-co://' target_real_backing = 'null-co://'
# Attach the backing chain only during completion, with blockdev-reopen
class TestBlockdevMirrorReopen(MirrorBaseClass):
cmd = 'blockdev-mirror'
existing = True
target_backing = 'null-co://'
target_open_with_backing = False
def openBacking(self):
if not self.target_open_with_backing:
result = self.vm.qmp('blockdev-add', node_name="backing",
driver="null-co")
self.assert_qmp(result, 'return', {})
result = self.vm.qmp('x-blockdev-reopen', node_name="target",
driver=iotests.imgfmt, file="target-file",
backing="backing")
self.assert_qmp(result, 'return', {})
class TestBlockdevMirrorReopenIothread(TestBlockdevMirrorReopen):
use_iothread = True
# Attach the backing chain only during completion, with blockdev-snapshot
class TestBlockdevMirrorSnapshot(MirrorBaseClass):
cmd = 'blockdev-mirror'
existing = True
target_backing = 'null-co://'
target_open_with_backing = False
def openBacking(self):
if not self.target_open_with_backing:
result = self.vm.qmp('blockdev-add', node_name="backing",
driver="null-co")
self.assert_qmp(result, 'return', {})
result = self.vm.qmp('blockdev-snapshot', node="backing",
overlay="target")
self.assert_qmp(result, 'return', {})
class TestBlockdevMirrorSnapshotIothread(TestBlockdevMirrorSnapshot):
use_iothread = True
class TestCommit(BaseClass): class TestCommit(BaseClass):
existing = False existing = False
@ -237,8 +298,7 @@ class TestCommit(BaseClass):
self.vm.event_wait('BLOCK_JOB_COMPLETED') self.vm.event_wait('BLOCK_JOB_COMPLETED')
node = self.findBlockNode(None, node = self.findBlockNode(None, 'qdev0')
'/machine/peripheral/qdev0/virtio-backend')
self.assert_qmp(node, 'image' + '/backing-image' * 0 + '/filename', self.assert_qmp(node, 'image' + '/backing-image' * 0 + '/filename',
back1_img) back1_img)
self.assert_qmp(node, 'image' + '/backing-image' * 1 + '/filename', self.assert_qmp(node, 'image' + '/backing-image' * 1 + '/filename',

View File

@ -1,5 +1,5 @@
................... ...............................
---------------------------------------------------------------------- ----------------------------------------------------------------------
Ran 19 tests Ran 31 tests
OK OK

67
tests/qemu-iotests/282 Executable file
View File

@ -0,0 +1,67 @@
#!/usr/bin/env bash
#
# Test qemu-img file cleanup for LUKS when using a non-UTF8 secret
#
# Copyright (C) 2020, IBM Corporation.
#
# 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/>.
#
seq=`basename $0`
echo "QA output created by $seq"
status=1 # failure is the default!
TEST_IMAGE_FILE='vol.img'
_cleanup()
{
_cleanup_test_img
rm non_utf8_secret
rm -f $TEST_IMAGE_FILE
}
trap "_cleanup; exit \$status" 0 1 2 3 15
# get standard environment, filters and checks
. ./common.rc
. ./common.filter
_supported_fmt luks
_supported_proto generic
_unsupported_proto vxhs
echo "== Create non-UTF8 secret =="
echo -n -e '\x3a\x3c\x3b\xff' > non_utf8_secret
SECRET="secret,id=sec0,file=non_utf8_secret"
echo "== Throws an error because of invalid UTF-8 secret =="
$QEMU_IMG create -f $IMGFMT --object $SECRET -o "key-secret=sec0" $TEST_IMAGE_FILE 4M
echo "== Image file should not exist after the error =="
if test -f "$TEST_IMAGE_FILE"; then
exit 1
fi
echo "== Create a stub image file and run qemu-img again =="
touch $TEST_IMAGE_FILE
$QEMU_IMG create -f $IMGFMT --object $SECRET -o "key-secret=sec0" $TEST_IMAGE_FILE 4M
echo "== Pre-existing image file should also be deleted after the error =="
if test -f "$TEST_IMAGE_FILE"; then
exit 1
fi
# success, all done
echo "*** done"
rm -f $seq.full
status=0

View File

@ -0,0 +1,11 @@
QA output created by 282
== Create non-UTF8 secret ==
== Throws an error because of invalid UTF-8 secret ==
qemu-img: vol.img: Data from secret sec0 is not valid UTF-8
Formatting 'vol.img', fmt=luks size=4194304 key-secret=sec0
== Image file should not exist after the error ==
== Create a stub image file and run qemu-img again ==
qemu-img: vol.img: Data from secret sec0 is not valid UTF-8
Formatting 'vol.img', fmt=luks size=4194304 key-secret=sec0
== Pre-existing image file should also be deleted after the error ==
*** done

View File

@ -290,6 +290,7 @@
279 rw backing quick 279 rw backing quick
280 rw migration quick 280 rw migration quick
281 rw quick 281 rw quick
282 rw img quick
283 auto quick 283 auto quick
284 rw 284 rw
286 rw quick 286 rw quick

View File

@ -624,7 +624,10 @@ class VM(qtest.QEMUQtestMachine):
if use_log: if use_log:
log('Job failed: %s' % (j['error'])) log('Job failed: %s' % (j['error']))
elif status == 'ready': elif status == 'ready':
if use_log:
self.qmp_log('job-complete', id=job) self.qmp_log('job-complete', id=job)
else:
self.qmp('job-complete', id=job)
elif status == 'pending' and not auto_finalize: elif status == 'pending' and not auto_finalize:
if pre_finalize: if pre_finalize:
pre_finalize() pre_finalize()

View File

@ -288,7 +288,6 @@ tests/qtest/usb-hcd-ehci-test$(EXESUF): tests/qtest/usb-hcd-ehci-test.o $(libqos
tests/qtest/usb-hcd-xhci-test$(EXESUF): tests/qtest/usb-hcd-xhci-test.o $(libqos-usb-obj-y) tests/qtest/usb-hcd-xhci-test$(EXESUF): tests/qtest/usb-hcd-xhci-test.o $(libqos-usb-obj-y)
tests/qtest/cpu-plug-test$(EXESUF): tests/qtest/cpu-plug-test.o tests/qtest/cpu-plug-test$(EXESUF): tests/qtest/cpu-plug-test.o
tests/qtest/migration-test$(EXESUF): tests/qtest/migration-test.o tests/qtest/migration-helpers.o tests/qtest/migration-test$(EXESUF): tests/qtest/migration-test.o tests/qtest/migration-helpers.o
tests/qtest/qemu-iotests/qtest/socket_scm_helper$(EXESUF): tests/qtest/qemu-iotests/qtest/socket_scm_helper.o
tests/qtest/test-netfilter$(EXESUF): tests/qtest/test-netfilter.o $(qtest-obj-y) tests/qtest/test-netfilter$(EXESUF): tests/qtest/test-netfilter.o $(qtest-obj-y)
tests/qtest/test-filter-mirror$(EXESUF): tests/qtest/test-filter-mirror.o $(qtest-obj-y) tests/qtest/test-filter-mirror$(EXESUF): tests/qtest/test-filter-mirror.o $(qtest-obj-y)
tests/qtest/test-filter-redirector$(EXESUF): tests/qtest/test-filter-redirector.o $(qtest-obj-y) tests/qtest/test-filter-redirector$(EXESUF): tests/qtest/test-filter-redirector.o $(qtest-obj-y)