Block layer patches:

- Block graph change fixes (avoid loops, cope with non-tree graphs)
 - bdrv_set_aio_context() related fixes
 - HMP snapshot commands: Use only tag, not the ID to identify snapshots
 - qmeu-img, commit: Error path fixes
 - block/nvme: Build fix for gcc 9
 - MAINTAINERS updates
 - Fix various issues with bdrv_refresh_filename()
 - Fix various iotests
 - Include LUKS overhead in qemu-img measure for qcow2
 - A fix for vmdk's image creation interface
 -----BEGIN PGP SIGNATURE-----
 
 iQIcBAABAgAGBQJcc/knAAoJEH8JsnLIjy/WptQP/3F8Lh52H4egXaP7NUUuDjQM
 AhqhuDAp/EZBS+xim9kLTogNJADe/rMWdSX/YB5aLpSPYbjasC66NgaLhd6QewgQ
 VIcsLUdlYAyZ5ZjJytimfMTLwm1X02RmVIe55y52DTY8LlfViZzOlf3qwqPm00ao
 EJB2cl8UJLM+PVEu59cCw3R0/06LY+WIJRB32d3tnCBRTkaJwfR9h4lrp/juVcFZ
 U+2eWU68KMbUHSYiWANowN+KRV3uPY4HVA98v3F0vDmcBxlVHOeBg6S+PcT7tK8p
 huzCMwcdwUyPMJgVs/+WBtUnbG0jN6SHUYmFLz859UMVgBnCw5tzBMf8qw1wOA4A
 Iw+zor27Pxj4IlxcLPp5f97YZ8k9acdMR2VKPH6xLJZ1JF+sKa54RfzESd5EJeIj
 Mfcp773H0lIaWcFJ6RY1F0L1E1ta7QigwNBiWMdYfh0a0EWHnDvGyYeaSPYEQ+rl
 e8bZOcfrYwVI7DTDiZOIkGA9D8DXEPDNp+sl6s1DxeY69D0NNaXTtCPqFNNAbFbd
 20uD7yDRZlWq32cQB/K9D5cSkZRSOzdUpLfLU3nQU2+dz11x6OpM6m7DVboSrztD
 1HtPPDzDEvH5dOP7ibd60s+ntjkSiNfNkUgnuVrBE/d/PocC1eHHpZt5V7f43Ofb
 RxVwH5+smzQ9nsNBfQR0
 =gaah
 -----END PGP SIGNATURE-----

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

Block layer patches:

- Block graph change fixes (avoid loops, cope with non-tree graphs)
- bdrv_set_aio_context() related fixes
- HMP snapshot commands: Use only tag, not the ID to identify snapshots
- qmeu-img, commit: Error path fixes
- block/nvme: Build fix for gcc 9
- MAINTAINERS updates
- Fix various issues with bdrv_refresh_filename()
- Fix various iotests
- Include LUKS overhead in qemu-img measure for qcow2
- A fix for vmdk's image creation interface

# gpg: Signature made Mon 25 Feb 2019 14:18:15 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: (71 commits)
  iotests: Skip 211 on insufficient memory
  vmdk: false positive of compat6 with hwversion not set
  iotests: add LUKS payload overhead to 178 qemu-img measure test
  qcow2: include LUKS payload overhead in qemu-img measure
  iotests.py: s/_/-/g on keys in qmp_log()
  iotests: Let 045 be run concurrently
  iotests: Filter SSH paths
  iotests.py: Filter filename in any string value
  iotests.py: Add is_str()
  iotests: Fix 207 to use QMP filters for qmp_log
  iotests: Fix 232 for LUKS
  iotests: Remove superfluous rm from 232
  iotests: Fix 237 for Python 2.x
  iotests: Re-add filename filters
  iotests: Test json:{} filenames of internal BDSs
  block: BDS options may lack the "driver" option
  block/null: Generate filename even with latency-ns
  block/curl: Implement bdrv_refresh_filename()
  block/curl: Harmonize option defaults
  block/nvme: Fix bdrv_refresh_filename()
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-02-26 19:04:47 +00:00
commit adf2e451f3
83 changed files with 2202 additions and 708 deletions

View File

@ -1698,7 +1698,7 @@ F: include/scsi/*
F: scsi/*
Block Jobs
M: Jeff Cody <jcody@redhat.com>
M: John Snow <jsnow@redhat.com>
L: qemu-block@nongnu.org
S: Supported
F: blockjob.c
@ -1711,7 +1711,7 @@ F: block/commit.c
F: block/stream.c
F: block/mirror.c
F: qapi/job.json
T: git https://github.com/codyprime/qemu-kvm-jtc.git block
T: git https://github.com/jnsnow/qemu.git jobs
Block QAPI, monitor, command line
M: Markus Armbruster <armbru@redhat.com>
@ -2261,26 +2261,22 @@ F: block/vmdk.c
RBD
M: Josh Durgin <jdurgin@redhat.com>
M: Jeff Cody <jcody@redhat.com>
L: qemu-block@nongnu.org
S: Supported
F: block/rbd.c
T: git https://github.com/codyprime/qemu-kvm-jtc.git block
Sheepdog
M: Liu Yuan <namei.unix@gmail.com>
M: Jeff Cody <jcody@redhat.com>
L: qemu-block@nongnu.org
S: Supported
L: sheepdog@lists.wpkg.org
S: Odd Fixes
F: block/sheepdog.c
T: git https://github.com/codyprime/qemu-kvm-jtc.git block
VHDX
M: Jeff Cody <jcody@redhat.com>
M: Jeff Cody <codyprime@gmail.com>
L: qemu-block@nongnu.org
S: Supported
F: block/vhdx*
T: git https://github.com/codyprime/qemu-kvm-jtc.git block
VDI
M: Stefan Weil <sw@weilnetz.de>
@ -2310,34 +2306,26 @@ F: docs/interop/nbd.txt
T: git https://repo.or.cz/qemu/ericb.git nbd
NFS
M: Jeff Cody <jcody@redhat.com>
M: Peter Lieven <pl@kamp.de>
L: qemu-block@nongnu.org
S: Maintained
F: block/nfs.c
T: git https://github.com/codyprime/qemu-kvm-jtc.git block
SSH
M: Richard W.M. Jones <rjones@redhat.com>
M: Jeff Cody <jcody@redhat.com>
L: qemu-block@nongnu.org
S: Supported
F: block/ssh.c
T: git https://github.com/codyprime/qemu-kvm-jtc.git block
CURL
M: Jeff Cody <jcody@redhat.com>
L: qemu-block@nongnu.org
S: Supported
F: block/curl.c
T: git https://github.com/codyprime/qemu-kvm-jtc.git block
GLUSTER
M: Jeff Cody <jcody@redhat.com>
L: qemu-block@nongnu.org
S: Supported
F: block/gluster.c
T: git https://github.com/codyprime/qemu-kvm-jtc.git block
Null Block Driver
M: Fam Zheng <fam@euphon.net>

613
block.c
View File

@ -152,53 +152,53 @@ int path_is_absolute(const char *path)
#endif
}
/* if filename is absolute, just copy it to dest. Otherwise, build a
/* if filename is absolute, just return its duplicate. Otherwise, build a
path to it by considering it is relative to base_path. URL are
supported. */
void path_combine(char *dest, int dest_size,
const char *base_path,
const char *filename)
char *path_combine(const char *base_path, const char *filename)
{
const char *protocol_stripped = NULL;
const char *p, *p1;
char *result;
int len;
if (dest_size <= 0)
return;
if (path_is_absolute(filename)) {
pstrcpy(dest, dest_size, filename);
} else {
const char *protocol_stripped = NULL;
if (path_has_protocol(base_path)) {
protocol_stripped = strchr(base_path, ':');
if (protocol_stripped) {
protocol_stripped++;
}
}
p = protocol_stripped ?: base_path;
p1 = strrchr(base_path, '/');
#ifdef _WIN32
{
const char *p2;
p2 = strrchr(base_path, '\\');
if (!p1 || p2 > p1)
p1 = p2;
}
#endif
if (p1)
p1++;
else
p1 = base_path;
if (p1 > p)
p = p1;
len = p - base_path;
if (len > dest_size - 1)
len = dest_size - 1;
memcpy(dest, base_path, len);
dest[len] = '\0';
pstrcat(dest, dest_size, filename);
return g_strdup(filename);
}
if (path_has_protocol(base_path)) {
protocol_stripped = strchr(base_path, ':');
if (protocol_stripped) {
protocol_stripped++;
}
}
p = protocol_stripped ?: base_path;
p1 = strrchr(base_path, '/');
#ifdef _WIN32
{
const char *p2;
p2 = strrchr(base_path, '\\');
if (!p1 || p2 > p1) {
p1 = p2;
}
}
#endif
if (p1) {
p1++;
} else {
p1 = base_path;
}
if (p1 > p) {
p = p1;
}
len = p - base_path;
result = g_malloc(len + strlen(filename) + 1);
memcpy(result, base_path, len);
strcpy(result + len, filename);
return result;
}
/*
@ -303,30 +303,61 @@ fail:
return -EACCES;
}
void bdrv_get_full_backing_filename_from_filename(const char *backed,
const char *backing,
char *dest, size_t sz,
Error **errp)
/*
* If @backing is empty, this function returns NULL without setting
* @errp. In all other cases, NULL will only be returned with @errp
* set.
*
* Therefore, a return value of NULL without @errp set means that
* there is no backing file; if @errp is set, there is one but its
* absolute filename cannot be generated.
*/
char *bdrv_get_full_backing_filename_from_filename(const char *backed,
const char *backing,
Error **errp)
{
if (backing[0] == '\0' || path_has_protocol(backing) ||
path_is_absolute(backing))
{
pstrcpy(dest, sz, backing);
if (backing[0] == '\0') {
return NULL;
} else if (path_has_protocol(backing) || path_is_absolute(backing)) {
return g_strdup(backing);
} else if (backed[0] == '\0' || strstart(backed, "json:", NULL)) {
error_setg(errp, "Cannot use relative backing file names for '%s'",
backed);
return NULL;
} else {
path_combine(dest, sz, backed, backing);
return path_combine(backed, backing);
}
}
void bdrv_get_full_backing_filename(BlockDriverState *bs, char *dest, size_t sz,
Error **errp)
/*
* If @filename is empty or NULL, this function returns NULL without
* setting @errp. In all other cases, NULL will only be returned with
* @errp set.
*/
static char *bdrv_make_absolute_filename(BlockDriverState *relative_to,
const char *filename, Error **errp)
{
char *backed = bs->exact_filename[0] ? bs->exact_filename : bs->filename;
char *dir, *full_name;
bdrv_get_full_backing_filename_from_filename(backed, bs->backing_file,
dest, sz, errp);
if (!filename || filename[0] == '\0') {
return NULL;
} else if (path_has_protocol(filename) || path_is_absolute(filename)) {
return g_strdup(filename);
}
dir = bdrv_dirname(relative_to, errp);
if (!dir) {
return NULL;
}
full_name = g_strconcat(dir, filename, NULL);
g_free(dir);
return full_name;
}
char *bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp)
{
return bdrv_make_absolute_filename(bs, bs->backing_file, errp);
}
void bdrv_register(BlockDriver *bdrv)
@ -1004,6 +1035,8 @@ static void bdrv_backing_attach(BdrvChild *c)
"node is used as backing hd of '%s'",
bdrv_get_device_or_node_name(parent));
bdrv_refresh_filename(backing_hd);
parent->open_flags &= ~BDRV_O_NO_BACKING;
pstrcpy(parent->backing_file, sizeof(parent->backing_file),
backing_hd->filename);
@ -1413,6 +1446,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
}
if (file != NULL) {
bdrv_refresh_filename(blk_bs(file));
filename = blk_bs(file)->filename;
} else {
/*
@ -1954,13 +1988,32 @@ static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q,
ret = bdrv_check_update_perm(c->bs, q, perm, shared, ignore_children, errp);
g_slist_free(ignore_children);
return ret;
if (ret < 0) {
return ret;
}
if (!c->has_backup_perm) {
c->has_backup_perm = true;
c->backup_perm = c->perm;
c->backup_shared_perm = c->shared_perm;
}
/*
* Note: it's OK if c->has_backup_perm was already set, as we can find the
* same child twice during check_perm procedure
*/
c->perm = perm;
c->shared_perm = shared;
return 0;
}
static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared)
{
uint64_t cumulative_perms, cumulative_shared_perms;
c->has_backup_perm = false;
c->perm = perm;
c->shared_perm = shared;
@ -1971,6 +2024,12 @@ static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared)
static void bdrv_child_abort_perm_update(BdrvChild *c)
{
if (c->has_backup_perm) {
c->perm = c->backup_perm;
c->shared_perm = c->backup_shared_perm;
c->has_backup_perm = false;
}
bdrv_abort_perm_update(c->bs);
}
@ -2309,8 +2368,6 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
bdrv_unref(backing_hd);
}
bdrv_refresh_filename(bs);
out:
bdrv_refresh_limits(bs, NULL);
}
@ -2328,10 +2385,11 @@ out:
int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
const char *bdref_key, Error **errp)
{
char *backing_filename = g_malloc0(PATH_MAX);
char *backing_filename = NULL;
char *bdref_key_dot;
const char *reference = NULL;
int ret = 0;
bool implicit_backing = false;
BlockDriverState *backing_hd;
QDict *options;
QDict *tmp_parent_options = NULL;
@ -2362,13 +2420,22 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
*/
reference = qdict_get_try_str(parent_options, bdref_key);
if (reference || qdict_haskey(options, "file.filename")) {
backing_filename[0] = '\0';
/* keep backing_filename NULL */
} else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) {
qobject_unref(options);
goto free_exit;
} else {
bdrv_get_full_backing_filename(bs, backing_filename, PATH_MAX,
&local_err);
if (qdict_size(options) == 0) {
/* If the user specifies options that do not modify the
* backing file's behavior, we might still consider it the
* implicit backing file. But it's easier this way, and
* just specifying some of the backing BDS's options is
* only possible with -drive anyway (otherwise the QAPI
* schema forces the user to specify everything). */
implicit_backing = !strcmp(bs->auto_backing_file, bs->backing_file);
}
backing_filename = bdrv_get_full_backing_filename(bs, &local_err);
if (local_err) {
ret = -EINVAL;
error_propagate(errp, local_err);
@ -2389,9 +2456,8 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
qdict_put_str(options, "driver", bs->backing_format);
}
backing_hd = bdrv_open_inherit(*backing_filename ? backing_filename : NULL,
reference, options, 0, bs, &child_backing,
errp);
backing_hd = bdrv_open_inherit(backing_filename, reference, options, 0, bs,
&child_backing, errp);
if (!backing_hd) {
bs->open_flags |= BDRV_O_NO_BACKING;
error_prepend(errp, "Could not open backing file: ");
@ -2400,6 +2466,12 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
}
bdrv_set_aio_context(backing_hd, bdrv_get_aio_context(bs));
if (implicit_backing) {
bdrv_refresh_filename(backing_hd);
pstrcpy(bs->auto_backing_file, sizeof(bs->auto_backing_file),
backing_hd->filename);
}
/* Hook up the backing file link; drop our reference, bs owns the
* backing_hd reference now */
bdrv_set_backing_hd(bs, backing_hd, &local_err);
@ -2839,8 +2911,6 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
g_free(child_key_dot);
}
bdrv_refresh_filename(bs);
/* Check if any unknown options were used */
if (qdict_size(options) != 0) {
const QDictEntry *entry = qdict_first(options);
@ -3285,6 +3355,7 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
if (local_err != NULL) {
error_propagate(errp, local_err);
} else {
bdrv_refresh_filename(reopen_state->bs);
error_setg(errp, "failed while preparing to reopen image '%s'",
reopen_state->bs->filename);
}
@ -3542,7 +3613,9 @@ void bdrv_close_all(void)
static bool should_update_child(BdrvChild *c, BlockDriverState *to)
{
BdrvChild *to_c;
GQueue *queue;
GHashTable *found;
bool ret;
if (c->role->stay_at_node) {
return false;
@ -3578,14 +3651,43 @@ static bool should_update_child(BdrvChild *c, BlockDriverState *to)
* if A is a child of B, that means we cannot replace A by B there
* because that would create a loop. Silently detaching A from B
* is also not really an option. So overall just leaving A in
* place there is the most sensible choice. */
QLIST_FOREACH(to_c, &to->children, next) {
if (to_c == c) {
return false;
* place there is the most sensible choice.
*
* We would also create a loop in any cases where @c is only
* indirectly referenced by @to. Prevent this by returning false
* if @c is found (by breadth-first search) anywhere in the whole
* subtree of @to.
*/
ret = true;
found = g_hash_table_new(NULL, NULL);
g_hash_table_add(found, to);
queue = g_queue_new();
g_queue_push_tail(queue, to);
while (!g_queue_is_empty(queue)) {
BlockDriverState *v = g_queue_pop_head(queue);
BdrvChild *c2;
QLIST_FOREACH(c2, &v->children, next) {
if (c2 == c) {
ret = false;
break;
}
if (g_hash_table_contains(found, c2->bs)) {
continue;
}
g_queue_push_tail(queue, c2->bs);
g_hash_table_add(found, c2->bs);
}
}
return true;
g_queue_free(queue);
g_hash_table_destroy(found);
return ret;
}
void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
@ -3789,6 +3891,8 @@ int bdrv_change_backing_file(BlockDriverState *bs,
if (ret == 0) {
pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_file ?: "");
pstrcpy(bs->backing_format, sizeof(bs->backing_format), backing_fmt ?: "");
pstrcpy(bs->auto_backing_file, sizeof(bs->auto_backing_file),
backing_file ?: "");
}
return ret;
}
@ -3881,7 +3985,10 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
/* 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. */
backing_file_str = backing_file_str ? backing_file_str : base->filename;
if (!backing_file_str) {
bdrv_refresh_filename(base);
backing_file_str = base->filename;
}
QLIST_FOREACH_SAFE(c, &top->parents, next_parent, next) {
/* Check whether we are allowed to switch c from top to base */
@ -4429,16 +4536,6 @@ bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs)
return bs->supported_zero_flags & BDRV_REQ_MAY_UNMAP;
}
const char *bdrv_get_encrypted_filename(BlockDriverState *bs)
{
if (bs->backing && bs->backing->bs->encrypted)
return bs->backing_file;
else if (bs->encrypted)
return bs->filename;
else
return NULL;
}
void bdrv_get_backing_filename(BlockDriverState *bs,
char *filename, int filename_size)
{
@ -4547,7 +4644,6 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
int is_protocol = 0;
BlockDriverState *curr_bs = NULL;
BlockDriverState *retval = NULL;
Error *local_error = NULL;
if (!bs || !bs->drv || !backing_file) {
return NULL;
@ -4555,7 +4651,6 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
filename_full = g_malloc(PATH_MAX);
backing_file_full = g_malloc(PATH_MAX);
filename_tmp = g_malloc(PATH_MAX);
is_protocol = path_has_protocol(backing_file);
@ -4564,41 +4659,43 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
/* If either of the filename paths is actually a protocol, then
* compare unmodified paths; otherwise make paths relative */
if (is_protocol || path_has_protocol(curr_bs->backing_file)) {
char *backing_file_full_ret;
if (strcmp(backing_file, curr_bs->backing_file) == 0) {
retval = curr_bs->backing->bs;
break;
}
/* Also check against the full backing filename for the image */
bdrv_get_full_backing_filename(curr_bs, backing_file_full, PATH_MAX,
&local_error);
if (local_error == NULL) {
if (strcmp(backing_file, backing_file_full) == 0) {
backing_file_full_ret = bdrv_get_full_backing_filename(curr_bs,
NULL);
if (backing_file_full_ret) {
bool equal = strcmp(backing_file, backing_file_full_ret) == 0;
g_free(backing_file_full_ret);
if (equal) {
retval = curr_bs->backing->bs;
break;
}
} else {
error_free(local_error);
local_error = NULL;
}
} else {
/* If not an absolute filename path, make it relative to the current
* image's filename path */
path_combine(filename_tmp, PATH_MAX, curr_bs->filename,
backing_file);
/* We are going to compare absolute pathnames */
if (!realpath(filename_tmp, filename_full)) {
filename_tmp = bdrv_make_absolute_filename(curr_bs, backing_file,
NULL);
/* We are going to compare canonicalized absolute pathnames */
if (!filename_tmp || !realpath(filename_tmp, filename_full)) {
g_free(filename_tmp);
continue;
}
g_free(filename_tmp);
/* We need to make sure the backing filename we are comparing against
* is relative to the current image filename (or absolute) */
path_combine(filename_tmp, PATH_MAX, curr_bs->filename,
curr_bs->backing_file);
if (!realpath(filename_tmp, backing_file_full)) {
filename_tmp = bdrv_get_full_backing_filename(curr_bs, NULL);
if (!filename_tmp || !realpath(filename_tmp, backing_file_full)) {
g_free(filename_tmp);
continue;
}
g_free(filename_tmp);
if (strcmp(backing_file_full, filename_full) == 0) {
retval = curr_bs->backing->bs;
@ -4609,7 +4706,6 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
g_free(filename_full);
g_free(backing_file_full);
g_free(filename_tmp);
return retval;
}
@ -5096,17 +5192,17 @@ void bdrv_img_create(const char *filename, const char *fmt,
size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, img_size);
if (backing_file && !(flags & BDRV_O_NO_BACKING)) {
BlockDriverState *bs;
char *full_backing = g_new0(char, PATH_MAX);
char *full_backing;
int back_flags;
QDict *backing_options = NULL;
bdrv_get_full_backing_filename_from_filename(filename, backing_file,
full_backing, PATH_MAX,
&local_err);
full_backing =
bdrv_get_full_backing_filename_from_filename(filename, backing_file,
&local_err);
if (local_err) {
g_free(full_backing);
goto out;
}
assert(full_backing);
/* backing files always opened read-only */
back_flags = flags;
@ -5227,6 +5323,9 @@ void bdrv_detach_aio_context(BlockDriverState *bs)
bdrv_detach_aio_context(child->bs);
}
if (bs->quiesce_counter) {
aio_enable_external(bs->aio_context);
}
bs->aio_context = NULL;
}
@ -5240,6 +5339,10 @@ void bdrv_attach_aio_context(BlockDriverState *bs,
return;
}
if (bs->quiesce_counter) {
aio_disable_external(new_context);
}
bs->aio_context = new_context;
QLIST_FOREACH(child, &bs->children, next) {
@ -5261,18 +5364,16 @@ void bdrv_attach_aio_context(BlockDriverState *bs,
bs->walking_aio_notifiers = false;
}
/* The caller must own the AioContext lock for the old AioContext of bs, but it
* must not own the AioContext lock for new_context (unless new_context is
* the same as the current context of bs). */
void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
{
AioContext *ctx = bdrv_get_aio_context(bs);
aio_disable_external(ctx);
bdrv_parent_drained_begin(bs, NULL, false);
bdrv_drain(bs); /* ensure there are no in-flight requests */
while (aio_poll(ctx, false)) {
/* wait for all bottom halves to execute */
if (bdrv_get_aio_context(bs) == new_context) {
return;
}
bdrv_drained_begin(bs);
bdrv_detach_aio_context(bs);
/* This function executes in the old AioContext so acquire the new one in
@ -5280,8 +5381,7 @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
*/
aio_context_acquire(new_context);
bdrv_attach_aio_context(bs, new_context);
bdrv_parent_drained_end(bs, NULL, false);
aio_enable_external(ctx);
bdrv_drained_end(bs);
aio_context_release(new_context);
}
@ -5435,33 +5535,113 @@ out:
return to_replace_bs;
}
static bool append_open_options(QDict *d, BlockDriverState *bs)
/**
* Iterates through the list of runtime option keys that are said to
* be "strong" for a BDS. An option is called "strong" if it changes
* a BDS's data. For example, the null block driver's "size" and
* "read-zeroes" options are strong, but its "latency-ns" option is
* not.
*
* If a key returned by this function ends with a dot, all options
* starting with that prefix are strong.
*/
static const char *const *strong_options(BlockDriverState *bs,
const char *const *curopt)
{
const QDictEntry *entry;
QemuOptDesc *desc;
bool found_any = false;
static const char *const global_options[] = {
"driver", "filename", NULL
};
for (entry = qdict_first(bs->options); entry;
entry = qdict_next(bs->options, entry))
{
/* Exclude all non-driver-specific options */
for (desc = bdrv_runtime_opts.desc; desc->name; desc++) {
if (!strcmp(qdict_entry_key(entry), desc->name)) {
break;
if (!curopt) {
return &global_options[0];
}
curopt++;
if (curopt == &global_options[ARRAY_SIZE(global_options) - 1] && bs->drv) {
curopt = bs->drv->strong_runtime_opts;
}
return (curopt && *curopt) ? curopt : NULL;
}
/**
* Copies all strong runtime options from bs->options to the given
* QDict. The set of strong option keys is determined by invoking
* strong_options().
*
* Returns true iff any strong option was present in bs->options (and
* thus copied to the target QDict) with the exception of "filename"
* and "driver". The caller is expected to use this value to decide
* whether the existence of strong options prevents the generation of
* a plain filename.
*/
static bool append_strong_runtime_options(QDict *d, BlockDriverState *bs)
{
bool found_any = false;
const char *const *option_name = NULL;
if (!bs->drv) {
return false;
}
while ((option_name = strong_options(bs, option_name))) {
bool option_given = false;
assert(strlen(*option_name) > 0);
if ((*option_name)[strlen(*option_name) - 1] != '.') {
QObject *entry = qdict_get(bs->options, *option_name);
if (!entry) {
continue;
}
qdict_put_obj(d, *option_name, qobject_ref(entry));
option_given = true;
} else {
const QDictEntry *entry;
for (entry = qdict_first(bs->options); entry;
entry = qdict_next(bs->options, entry))
{
if (strstart(qdict_entry_key(entry), *option_name, NULL)) {
qdict_put_obj(d, qdict_entry_key(entry),
qobject_ref(qdict_entry_value(entry)));
option_given = true;
}
}
}
if (desc->name) {
continue;
}
qdict_put_obj(d, qdict_entry_key(entry),
qobject_ref(qdict_entry_value(entry)));
found_any = true;
/* While "driver" and "filename" need to be included in a JSON filename,
* their existence does not prohibit generation of a plain filename. */
if (!found_any && option_given &&
strcmp(*option_name, "driver") && strcmp(*option_name, "filename"))
{
found_any = true;
}
}
if (!qdict_haskey(d, "driver")) {
/* Drivers created with bdrv_new_open_driver() may not have a
* @driver option. Add it here. */
qdict_put_str(d, "driver", bs->drv->format_name);
}
return found_any;
}
/* Note: This function may return false positives; it may return true
* even if opening the backing file specified by bs's image header
* would result in exactly bs->backing. */
static bool bdrv_backing_overridden(BlockDriverState *bs)
{
if (bs->backing) {
return strcmp(bs->auto_backing_file,
bs->backing->bs->filename);
} else {
/* No backing BDS, so if the image header reports any backing
* file, it must have been suppressed */
return bs->auto_backing_file[0] != '\0';
}
}
/* Updates the following BDS fields:
* - exact_filename: A filename which may be used for opening a block device
* which (mostly) equals the given BDS (even without any
@ -5477,92 +5657,108 @@ static bool append_open_options(QDict *d, BlockDriverState *bs)
void bdrv_refresh_filename(BlockDriverState *bs)
{
BlockDriver *drv = bs->drv;
BdrvChild *child;
QDict *opts;
bool backing_overridden;
bool generate_json_filename; /* Whether our default implementation should
fill exact_filename (false) or not (true) */
if (!drv) {
return;
}
/* This BDS's file name will most probably depend on its file's name, so
* refresh that first */
if (bs->file) {
bdrv_refresh_filename(bs->file->bs);
/* This BDS's file name may depend on any of its children's file names, so
* refresh those first */
QLIST_FOREACH(child, &bs->children, next) {
bdrv_refresh_filename(child->bs);
}
if (bs->implicit) {
/* For implicit nodes, just copy everything from the single child */
child = QLIST_FIRST(&bs->children);
assert(QLIST_NEXT(child, next) == NULL);
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
child->bs->exact_filename);
pstrcpy(bs->filename, sizeof(bs->filename), child->bs->filename);
bs->full_open_options = qobject_ref(child->bs->full_open_options);
return;
}
backing_overridden = bdrv_backing_overridden(bs);
if (bs->open_flags & BDRV_O_NO_IO) {
/* Without I/O, the backing file does not change anything.
* Therefore, in such a case (primarily qemu-img), we can
* pretend the backing file has not been overridden even if
* it technically has been. */
backing_overridden = false;
}
/* Gather the options QDict */
opts = qdict_new();
generate_json_filename = append_strong_runtime_options(opts, bs);
generate_json_filename |= backing_overridden;
if (drv->bdrv_gather_child_options) {
/* Some block drivers may not want to present all of their children's
* options, or name them differently from BdrvChild.name */
drv->bdrv_gather_child_options(bs, opts, backing_overridden);
} else {
QLIST_FOREACH(child, &bs->children, next) {
if (child->role == &child_backing && !backing_overridden) {
/* We can skip the backing BDS if it has not been overridden */
continue;
}
qdict_put(opts, child->name,
qobject_ref(child->bs->full_open_options));
}
if (backing_overridden && !bs->backing) {
/* Force no backing file */
qdict_put_null(opts, "backing");
}
}
qobject_unref(bs->full_open_options);
bs->full_open_options = opts;
if (drv->bdrv_refresh_filename) {
/* Obsolete information is of no use here, so drop the old file name
* information before refreshing it */
bs->exact_filename[0] = '\0';
if (bs->full_open_options) {
qobject_unref(bs->full_open_options);
bs->full_open_options = NULL;
}
opts = qdict_new();
append_open_options(opts, bs);
drv->bdrv_refresh_filename(bs, opts);
qobject_unref(opts);
drv->bdrv_refresh_filename(bs);
} else if (bs->file) {
/* Try to reconstruct valid information from the underlying file */
bool has_open_options;
bs->exact_filename[0] = '\0';
if (bs->full_open_options) {
qobject_unref(bs->full_open_options);
bs->full_open_options = NULL;
}
opts = qdict_new();
has_open_options = append_open_options(opts, bs);
/* If no specific options have been given for this BDS, the filename of
* the underlying file should suffice for this one as well */
if (bs->file->bs->exact_filename[0] && !has_open_options) {
/*
* We can use the underlying file's filename if:
* - it has a filename,
* - the file is a protocol BDS, and
* - opening that file (as this BDS's format) will automatically create
* the BDS tree we have right now, that is:
* - the user did not significantly change this BDS's behavior with
* some explicit (strong) options
* - no non-file child of this BDS has been overridden by the user
* Both of these conditions are represented by generate_json_filename.
*/
if (bs->file->bs->exact_filename[0] &&
bs->file->bs->drv->bdrv_file_open &&
!generate_json_filename)
{
strcpy(bs->exact_filename, bs->file->bs->exact_filename);
}
/* Reconstructing the full options QDict is simple for most format block
* drivers, as long as the full options are known for the underlying
* file BDS. The full options QDict of that file BDS should somehow
* contain a representation of the filename, therefore the following
* suffices without querying the (exact_)filename of this BDS. */
if (bs->file->bs->full_open_options) {
qdict_put_str(opts, "driver", drv->format_name);
qdict_put(opts, "file",
qobject_ref(bs->file->bs->full_open_options));
bs->full_open_options = opts;
} else {
qobject_unref(opts);
}
} else if (!bs->full_open_options && qdict_size(bs->options)) {
/* There is no underlying file BDS (at least referenced by BDS.file),
* so the full options QDict should be equal to the options given
* specifically for this block device when it was opened (plus the
* driver specification).
* Because those options don't change, there is no need to update
* full_open_options when it's already set. */
opts = qdict_new();
append_open_options(opts, bs);
qdict_put_str(opts, "driver", drv->format_name);
if (bs->exact_filename[0]) {
/* This may not work for all block protocol drivers (some may
* require this filename to be parsed), but we have to find some
* default solution here, so just include it. If some block driver
* does not support pure options without any filename at all or
* needs some special format of the options QDict, it needs to
* implement the driver-specific bdrv_refresh_filename() function.
*/
qdict_put_str(opts, "filename", bs->exact_filename);
}
bs->full_open_options = opts;
}
if (bs->exact_filename[0]) {
pstrcpy(bs->filename, sizeof(bs->filename), bs->exact_filename);
} else if (bs->full_open_options) {
} else {
QString *json = qobject_to_json(QOBJECT(bs->full_open_options));
snprintf(bs->filename, sizeof(bs->filename), "json:%s",
qstring_get_str(json));
@ -5570,6 +5766,33 @@ void bdrv_refresh_filename(BlockDriverState *bs)
}
}
char *bdrv_dirname(BlockDriverState *bs, Error **errp)
{
BlockDriver *drv = bs->drv;
if (!drv) {
error_setg(errp, "Node '%s' is ejected", bs->node_name);
return NULL;
}
if (drv->bdrv_dirname) {
return drv->bdrv_dirname(bs, errp);
}
if (bs->file) {
return bdrv_dirname(bs->file->bs, errp);
}
bdrv_refresh_filename(bs);
if (bs->exact_filename[0] != '\0') {
return path_combine(bs->exact_filename, "");
}
error_setg(errp, "Cannot generate a base directory for %s nodes",
drv->format_name);
return NULL;
}
/*
* Hot add/remove a BDS's child. So the user can take a child offline when
* it is broken and take a new child online

View File

@ -811,51 +811,37 @@ static int64_t blkdebug_getlength(BlockDriverState *bs)
return bdrv_getlength(bs->file->bs);
}
static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)
static void blkdebug_refresh_filename(BlockDriverState *bs)
{
BDRVBlkdebugState *s = bs->opaque;
QDict *opts;
const QDictEntry *e;
bool force_json = false;
int ret;
for (e = qdict_first(options); e; e = qdict_next(options, e)) {
if (strcmp(qdict_entry_key(e), "config") &&
strcmp(qdict_entry_key(e), "x-image"))
{
force_json = true;
break;
}
}
if (force_json && !bs->file->bs->full_open_options) {
/* The config file cannot be recreated, so creating a plain filename
* is impossible */
if (!bs->file->bs->exact_filename[0]) {
return;
}
if (!force_json && bs->file->bs->exact_filename[0]) {
int ret = snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"blkdebug:%s:%s", s->config_file ?: "",
bs->file->bs->exact_filename);
if (ret >= sizeof(bs->exact_filename)) {
/* An overflow makes the filename unusable, so do not report any */
bs->exact_filename[0] = 0;
for (e = qdict_first(bs->full_open_options); e;
e = qdict_next(bs->full_open_options, e))
{
/* Real child options are under "image", but "x-image" may
* contain a filename */
if (strcmp(qdict_entry_key(e), "config") &&
strcmp(qdict_entry_key(e), "image") &&
strcmp(qdict_entry_key(e), "x-image") &&
strcmp(qdict_entry_key(e), "driver"))
{
return;
}
}
opts = qdict_new();
qdict_put_str(opts, "driver", "blkdebug");
qdict_put(opts, "image", qobject_ref(bs->file->bs->full_open_options));
for (e = qdict_first(options); e; e = qdict_next(options, e)) {
if (strcmp(qdict_entry_key(e), "x-image")) {
qdict_put_obj(opts, qdict_entry_key(e),
qobject_ref(qdict_entry_value(e)));
}
ret = snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"blkdebug:%s:%s",
s->config_file ?: "", bs->file->bs->exact_filename);
if (ret >= sizeof(bs->exact_filename)) {
/* An overflow makes the filename unusable, so do not report any */
bs->exact_filename[0] = 0;
}
bs->full_open_options = opts;
}
static void blkdebug_refresh_limits(BlockDriverState *bs, Error **errp)
@ -888,6 +874,20 @@ static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state,
return 0;
}
static const char *const blkdebug_strong_runtime_opts[] = {
"config",
"inject-error.",
"set-state.",
"align",
"max-transfer",
"opt-write-zero",
"max-write-zero",
"opt-discard",
"max-discard",
NULL
};
static BlockDriver bdrv_blkdebug = {
.format_name = "blkdebug",
.protocol_name = "blkdebug",
@ -917,6 +917,8 @@ static BlockDriver bdrv_blkdebug = {
= blkdebug_debug_remove_breakpoint,
.bdrv_debug_resume = blkdebug_debug_resume,
.bdrv_debug_is_suspended = blkdebug_debug_is_suspended,
.strong_runtime_opts = blkdebug_strong_runtime_opts,
};
static void bdrv_blkdebug_init(void)

View File

@ -280,30 +280,6 @@ static int64_t blk_log_writes_getlength(BlockDriverState *bs)
return bdrv_getlength(bs->file->bs);
}
static void blk_log_writes_refresh_filename(BlockDriverState *bs,
QDict *options)
{
BDRVBlkLogWritesState *s = bs->opaque;
/* bs->file->bs has already been refreshed */
bdrv_refresh_filename(s->log_file->bs);
if (bs->file->bs->full_open_options
&& s->log_file->bs->full_open_options)
{
QDict *opts = qdict_new();
qdict_put_str(opts, "driver", "blklogwrites");
qobject_ref(bs->file->bs->full_open_options);
qdict_put(opts, "file", bs->file->bs->full_open_options);
qobject_ref(s->log_file->bs->full_open_options);
qdict_put(opts, "log", s->log_file->bs->full_open_options);
qdict_put_int(opts, "log-sector-size", s->sectorsize);
bs->full_open_options = opts;
}
}
static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c,
const BdrvChildRole *role,
BlockReopenQueue *ro_q,
@ -520,6 +496,13 @@ blk_log_writes_co_pdiscard(BlockDriverState *bs, int64_t offset, int count)
LOG_DISCARD_FLAG, false);
}
static const char *const blk_log_writes_strong_runtime_opts[] = {
"log-append",
"log-sector-size",
NULL
};
static BlockDriver bdrv_blk_log_writes = {
.format_name = "blklogwrites",
.instance_size = sizeof(BDRVBlkLogWritesState),
@ -527,7 +510,6 @@ static BlockDriver bdrv_blk_log_writes = {
.bdrv_open = blk_log_writes_open,
.bdrv_close = blk_log_writes_close,
.bdrv_getlength = blk_log_writes_getlength,
.bdrv_refresh_filename = blk_log_writes_refresh_filename,
.bdrv_child_perm = blk_log_writes_child_perm,
.bdrv_refresh_limits = blk_log_writes_refresh_limits,
@ -539,6 +521,7 @@ static BlockDriver bdrv_blk_log_writes = {
.bdrv_co_block_status = bdrv_co_block_status_from_file,
.is_filter = true,
.strong_runtime_opts = blk_log_writes_strong_runtime_opts,
};
static void bdrv_blk_log_writes_init(void)

View File

@ -281,27 +281,10 @@ static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs,
return bdrv_recurse_is_first_non_filter(s->test_file->bs, candidate);
}
static void blkverify_refresh_filename(BlockDriverState *bs, QDict *options)
static void blkverify_refresh_filename(BlockDriverState *bs)
{
BDRVBlkverifyState *s = bs->opaque;
/* bs->file->bs has already been refreshed */
bdrv_refresh_filename(s->test_file->bs);
if (bs->file->bs->full_open_options
&& s->test_file->bs->full_open_options)
{
QDict *opts = qdict_new();
qdict_put_str(opts, "driver", "blkverify");
qdict_put(opts, "raw",
qobject_ref(bs->file->bs->full_open_options));
qdict_put(opts, "test",
qobject_ref(s->test_file->bs->full_open_options));
bs->full_open_options = opts;
}
if (bs->file->bs->exact_filename[0]
&& s->test_file->bs->exact_filename[0])
{
@ -316,6 +299,15 @@ static void blkverify_refresh_filename(BlockDriverState *bs, QDict *options)
}
}
static char *blkverify_dirname(BlockDriverState *bs, Error **errp)
{
/* In general, there are two BDSs with different dirnames below this one;
* so there is no unique dirname we could return (unless both are equal by
* chance). Therefore, to be consistent, just always return NULL. */
error_setg(errp, "Cannot generate a base directory for blkverify nodes");
return NULL;
}
static BlockDriver bdrv_blkverify = {
.format_name = "blkverify",
.protocol_name = "blkverify",
@ -327,6 +319,7 @@ static BlockDriver bdrv_blkverify = {
.bdrv_child_perm = bdrv_filter_default_perms,
.bdrv_getlength = blkverify_getlength,
.bdrv_refresh_filename = blkverify_refresh_filename,
.bdrv_dirname = blkverify_dirname,
.bdrv_co_preadv = blkverify_co_preadv,
.bdrv_co_pwritev = blkverify_co_pwritev,

View File

@ -1253,12 +1253,12 @@ int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags)
return bdrv_make_zero(blk->root, flags);
}
static void blk_inc_in_flight(BlockBackend *blk)
void blk_inc_in_flight(BlockBackend *blk)
{
atomic_inc(&blk->in_flight);
}
static void blk_dec_in_flight(BlockBackend *blk)
void blk_dec_in_flight(BlockBackend *blk)
{
atomic_dec(&blk->in_flight);
aio_wait_kick();

View File

@ -225,9 +225,8 @@ static int coroutine_fn bdrv_commit_top_preadv(BlockDriverState *bs,
return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
}
static void bdrv_commit_top_refresh_filename(BlockDriverState *bs, QDict *opts)
static void bdrv_commit_top_refresh_filename(BlockDriverState *bs)
{
bdrv_refresh_filename(bs->backing->bs);
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
bs->backing->bs->filename);
}
@ -369,10 +368,12 @@ fail:
if (s->top) {
blk_unref(s->top);
}
job_early_fail(&s->common.job);
/* commit_top_bs has to be replaced after deleting the block job,
* otherwise this would fail because of lack of permissions. */
if (commit_top_bs) {
bdrv_replace_node(commit_top_bs, top, &error_abort);
}
job_early_fail(&s->common.job);
}

View File

@ -619,6 +619,12 @@ block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp)
return spec_info;
}
static const char *const block_crypto_strong_runtime_opts[] = {
BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET,
NULL
};
BlockDriver bdrv_crypto_luks = {
.format_name = "luks",
.instance_size = sizeof(BlockCrypto),
@ -640,6 +646,8 @@ BlockDriver bdrv_crypto_luks = {
.bdrv_getlength = block_crypto_getlength,
.bdrv_get_info = block_crypto_get_info_luks,
.bdrv_get_specific_info = block_crypto_get_specific_info_luks,
.strong_runtime_opts = block_crypto_strong_runtime_opts,
};
static void block_crypto_init(void)

View File

@ -61,8 +61,6 @@ static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
#define CURL_NUM_STATES 8
#define CURL_NUM_ACB 8
#define READ_AHEAD_DEFAULT (256 * 1024)
#define CURL_TIMEOUT_DEFAULT 5
#define CURL_TIMEOUT_MAX 10000
#define CURL_BLOCK_OPT_URL "url"
@ -76,6 +74,10 @@ static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
#define CURL_BLOCK_OPT_PROXY_USERNAME "proxy-username"
#define CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET "proxy-password-secret"
#define CURL_BLOCK_OPT_READAHEAD_DEFAULT (256 * 1024)
#define CURL_BLOCK_OPT_SSLVERIFY_DEFAULT true
#define CURL_BLOCK_OPT_TIMEOUT_DEFAULT 5
struct BDRVCURLState;
static bool libcurl_initialized;
@ -696,7 +698,7 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
}
s->readahead_size = qemu_opt_get_size(opts, CURL_BLOCK_OPT_READAHEAD,
READ_AHEAD_DEFAULT);
CURL_BLOCK_OPT_READAHEAD_DEFAULT);
if ((s->readahead_size & 0x1ff) != 0) {
error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512",
s->readahead_size);
@ -704,13 +706,14 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
}
s->timeout = qemu_opt_get_number(opts, CURL_BLOCK_OPT_TIMEOUT,
CURL_TIMEOUT_DEFAULT);
CURL_BLOCK_OPT_TIMEOUT_DEFAULT);
if (s->timeout > CURL_TIMEOUT_MAX) {
error_setg(errp, "timeout parameter is too large or negative");
goto out_noclean;
}
s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY, true);
s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY,
CURL_BLOCK_OPT_SSLVERIFY_DEFAULT);
cookie = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE);
cookie_secret = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE_SECRET);
@ -947,6 +950,36 @@ static int64_t curl_getlength(BlockDriverState *bs)
return s->len;
}
static void curl_refresh_filename(BlockDriverState *bs)
{
BDRVCURLState *s = bs->opaque;
/* "readahead" and "timeout" do not change the guest-visible data,
* so ignore them */
if (s->sslverify != CURL_BLOCK_OPT_SSLVERIFY_DEFAULT ||
s->cookie || s->username || s->password || s->proxyusername ||
s->proxypassword)
{
return;
}
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), s->url);
}
static const char *const curl_strong_runtime_opts[] = {
CURL_BLOCK_OPT_URL,
CURL_BLOCK_OPT_SSLVERIFY,
CURL_BLOCK_OPT_COOKIE,
CURL_BLOCK_OPT_COOKIE_SECRET,
CURL_BLOCK_OPT_USERNAME,
CURL_BLOCK_OPT_PASSWORD_SECRET,
CURL_BLOCK_OPT_PROXY_USERNAME,
CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET,
NULL
};
static BlockDriver bdrv_http = {
.format_name = "http",
.protocol_name = "http",
@ -961,6 +994,9 @@ static BlockDriver bdrv_http = {
.bdrv_detach_aio_context = curl_detach_aio_context,
.bdrv_attach_aio_context = curl_attach_aio_context,
.bdrv_refresh_filename = curl_refresh_filename,
.strong_runtime_opts = curl_strong_runtime_opts,
};
static BlockDriver bdrv_https = {
@ -977,6 +1013,9 @@ static BlockDriver bdrv_https = {
.bdrv_detach_aio_context = curl_detach_aio_context,
.bdrv_attach_aio_context = curl_attach_aio_context,
.bdrv_refresh_filename = curl_refresh_filename,
.strong_runtime_opts = curl_strong_runtime_opts,
};
static BlockDriver bdrv_ftp = {
@ -993,6 +1032,9 @@ static BlockDriver bdrv_ftp = {
.bdrv_detach_aio_context = curl_detach_aio_context,
.bdrv_attach_aio_context = curl_attach_aio_context,
.bdrv_refresh_filename = curl_refresh_filename,
.strong_runtime_opts = curl_strong_runtime_opts,
};
static BlockDriver bdrv_ftps = {
@ -1009,6 +1051,9 @@ static BlockDriver bdrv_ftps = {
.bdrv_detach_aio_context = curl_detach_aio_context,
.bdrv_attach_aio_context = curl_attach_aio_context,
.bdrv_refresh_filename = curl_refresh_filename,
.strong_runtime_opts = curl_strong_runtime_opts,
};
static void curl_block_init(void)

View File

@ -1495,6 +1495,21 @@ static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs,
}
static const char *const gluster_strong_open_opts[] = {
GLUSTER_OPT_VOLUME,
GLUSTER_OPT_PATH,
GLUSTER_OPT_TYPE,
GLUSTER_OPT_SERVER_PATTERN,
GLUSTER_OPT_HOST,
GLUSTER_OPT_PORT,
GLUSTER_OPT_TO,
GLUSTER_OPT_IPV4,
GLUSTER_OPT_IPV6,
GLUSTER_OPT_SOCKET,
NULL
};
static BlockDriver bdrv_gluster = {
.format_name = "gluster",
.protocol_name = "gluster",
@ -1522,6 +1537,7 @@ static BlockDriver bdrv_gluster = {
#endif
.bdrv_co_block_status = qemu_gluster_co_block_status,
.create_opts = &qemu_gluster_create_opts,
.strong_runtime_opts = gluster_strong_open_opts,
};
static BlockDriver bdrv_gluster_tcp = {
@ -1551,6 +1567,7 @@ static BlockDriver bdrv_gluster_tcp = {
#endif
.bdrv_co_block_status = qemu_gluster_co_block_status,
.create_opts = &qemu_gluster_create_opts,
.strong_runtime_opts = gluster_strong_open_opts,
};
static BlockDriver bdrv_gluster_unix = {
@ -1580,6 +1597,7 @@ static BlockDriver bdrv_gluster_unix = {
#endif
.bdrv_co_block_status = qemu_gluster_co_block_status,
.create_opts = &qemu_gluster_create_opts,
.strong_runtime_opts = gluster_strong_open_opts,
};
/* rdma is deprecated (actually never supported for volfile fetch).
@ -1615,6 +1633,7 @@ static BlockDriver bdrv_gluster_rdma = {
#endif
.bdrv_co_block_status = qemu_gluster_co_block_status,
.create_opts = &qemu_gluster_create_opts,
.strong_runtime_opts = gluster_strong_open_opts,
};
static void bdrv_gluster_init(void)

View File

@ -2448,6 +2448,20 @@ static QemuOptsList iscsi_create_opts = {
}
};
static const char *const iscsi_strong_runtime_opts[] = {
"transport",
"portal",
"target",
"user",
"password",
"password-secret",
"lun",
"initiator-name",
"header-digest",
NULL
};
static BlockDriver bdrv_iscsi = {
.format_name = "iscsi",
.protocol_name = "iscsi",
@ -2482,6 +2496,8 @@ static BlockDriver bdrv_iscsi = {
.bdrv_detach_aio_context = iscsi_detach_aio_context,
.bdrv_attach_aio_context = iscsi_attach_aio_context,
.strong_runtime_opts = iscsi_strong_runtime_opts,
};
#if LIBISCSI_API_VERSION >= (20160603)
@ -2519,6 +2535,8 @@ static BlockDriver bdrv_iser = {
.bdrv_detach_aio_context = iscsi_detach_aio_context,
.bdrv_attach_aio_context = iscsi_attach_aio_context,
.strong_runtime_opts = iscsi_strong_runtime_opts,
};
#endif

View File

@ -1431,14 +1431,13 @@ static int coroutine_fn bdrv_mirror_top_pdiscard(BlockDriverState *bs,
NULL, 0);
}
static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs, QDict *opts)
static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs)
{
if (bs->backing == NULL) {
/* we can be here after failed bdrv_attach_child in
* bdrv_set_backing_hd */
return;
}
bdrv_refresh_filename(bs->backing->bs);
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
bs->backing->bs->filename);
}

View File

@ -76,8 +76,18 @@ static coroutine_fn void nbd_connection_entry(void *opaque)
Error *local_err = NULL;
while (!s->quit) {
/*
* The NBD client can only really be considered idle when it has
* yielded from qio_channel_readv_all_eof(), waiting for data. This is
* the point where the additional scheduled coroutine entry happens
* after nbd_client_attach_aio_context().
*
* Therefore we keep an additional in_flight reference all the time and
* only drop it temporarily here.
*/
assert(s->reply.handle == 0);
ret = nbd_receive_reply(s->ioc, &s->reply, &local_err);
ret = nbd_receive_reply(s->bs, s->ioc, &s->reply, &local_err);
if (local_err) {
trace_nbd_read_reply_entry_fail(ret, error_get_pretty(local_err));
error_free(local_err);
@ -116,6 +126,8 @@ static coroutine_fn void nbd_connection_entry(void *opaque)
s->quit = true;
nbd_recv_coroutines_wake_all(s);
bdrv_dec_in_flight(s->bs);
s->connection_co = NULL;
aio_wait_kick();
}
@ -965,12 +977,30 @@ void nbd_client_detach_aio_context(BlockDriverState *bs)
qio_channel_detach_aio_context(QIO_CHANNEL(client->ioc));
}
static void nbd_client_attach_aio_context_bh(void *opaque)
{
BlockDriverState *bs = opaque;
NBDClientSession *client = nbd_get_client_session(bs);
/* The node is still drained, so we know the coroutine has yielded in
* nbd_read_eof(), the only place where bs->in_flight can reach 0, or it is
* entered for the first time. Both places are safe for entering the
* coroutine.*/
qemu_aio_coroutine_enter(bs->aio_context, client->connection_co);
bdrv_dec_in_flight(bs);
}
void nbd_client_attach_aio_context(BlockDriverState *bs,
AioContext *new_context)
{
NBDClientSession *client = nbd_get_client_session(bs);
qio_channel_attach_aio_context(QIO_CHANNEL(client->ioc), new_context);
aio_co_schedule(new_context, client->connection_co);
bdrv_inc_in_flight(bs);
/* Need to wait here for the BH to run because the BH must run while the
* node is still drained. */
aio_wait_bh_oneshot(new_context, nbd_client_attach_aio_context_bh, bs);
}
void nbd_client_close(BlockDriverState *bs)
@ -1076,6 +1106,7 @@ static int nbd_client_connect(BlockDriverState *bs,
* kick the reply mechanism. */
qio_channel_set_blocking(QIO_CHANNEL(sioc), false, NULL);
client->connection_co = qemu_coroutine_create(nbd_connection_entry, client);
bdrv_inc_in_flight(bs);
nbd_client_attach_aio_context(bs, bdrv_get_aio_context(bs));
logout("Established connection with NBD server\n");
@ -1108,6 +1139,7 @@ int nbd_client_init(BlockDriverState *bs,
{
NBDClientSession *client = nbd_get_client_session(bs);
client->bs = bs;
qemu_co_mutex_init(&client->send_mutex);
qemu_co_queue_init(&client->free_sema);

View File

@ -35,6 +35,7 @@ typedef struct NBDClientSession {
NBDClientRequest requests[MAX_NBD_REQUESTS];
NBDReply reply;
BlockDriverState *bs;
bool quit;
} NBDClientSession;

View File

@ -477,12 +477,9 @@ static void nbd_attach_aio_context(BlockDriverState *bs,
nbd_client_attach_aio_context(bs, new_context);
}
static void nbd_refresh_filename(BlockDriverState *bs, QDict *options)
static void nbd_refresh_filename(BlockDriverState *bs)
{
BDRVNBDState *s = bs->opaque;
QDict *opts = qdict_new();
QObject *saddr_qdict;
Visitor *ov;
const char *host = NULL, *port = NULL, *path = NULL;
if (s->saddr->type == SOCKET_ADDRESS_TYPE_INET) {
@ -495,8 +492,6 @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options)
path = s->saddr->u.q_unix.path;
} /* else can't represent as pseudo-filename */
qdict_put_str(opts, "driver", "nbd");
if (path && s->export) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nbd+unix:///%s?socket=%s", s->export, path);
@ -510,24 +505,29 @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options)
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nbd://%s:%s", host, port);
}
ov = qobject_output_visitor_new(&saddr_qdict);
visit_type_SocketAddress(ov, NULL, &s->saddr, &error_abort);
visit_complete(ov, &saddr_qdict);
visit_free(ov);
qdict_put_obj(opts, "server", saddr_qdict);
if (s->export) {
qdict_put_str(opts, "export", s->export);
}
if (s->tlscredsid) {
qdict_put_str(opts, "tls-creds", s->tlscredsid);
}
qdict_flatten(opts);
bs->full_open_options = opts;
}
static char *nbd_dirname(BlockDriverState *bs, Error **errp)
{
/* The generic bdrv_dirname() implementation is able to work out some
* directory name for NBD nodes, but that would be wrong. So far there is no
* specification for how "export paths" would work, so NBD does not have
* directory names. */
error_setg(errp, "Cannot generate a base directory for NBD nodes");
return NULL;
}
static const char *const nbd_strong_runtime_opts[] = {
"path",
"host",
"port",
"export",
"tls-creds",
"server.",
NULL
};
static BlockDriver bdrv_nbd = {
.format_name = "nbd",
.protocol_name = "nbd",
@ -546,6 +546,8 @@ static BlockDriver bdrv_nbd = {
.bdrv_attach_aio_context = nbd_attach_aio_context,
.bdrv_refresh_filename = nbd_refresh_filename,
.bdrv_co_block_status = nbd_client_co_block_status,
.bdrv_dirname = nbd_dirname,
.strong_runtime_opts = nbd_strong_runtime_opts,
};
static BlockDriver bdrv_nbd_tcp = {
@ -566,6 +568,8 @@ static BlockDriver bdrv_nbd_tcp = {
.bdrv_attach_aio_context = nbd_attach_aio_context,
.bdrv_refresh_filename = nbd_refresh_filename,
.bdrv_co_block_status = nbd_client_co_block_status,
.bdrv_dirname = nbd_dirname,
.strong_runtime_opts = nbd_strong_runtime_opts,
};
static BlockDriver bdrv_nbd_unix = {
@ -586,6 +590,8 @@ static BlockDriver bdrv_nbd_unix = {
.bdrv_attach_aio_context = nbd_attach_aio_context,
.bdrv_refresh_filename = nbd_refresh_filename,
.bdrv_co_block_status = nbd_client_co_block_status,
.bdrv_dirname = nbd_dirname,
.strong_runtime_opts = nbd_strong_runtime_opts,
};
static void bdrv_nbd_init(void)

View File

@ -799,14 +799,9 @@ static int nfs_reopen_prepare(BDRVReopenState *state,
return 0;
}
static void nfs_refresh_filename(BlockDriverState *bs, QDict *options)
static void nfs_refresh_filename(BlockDriverState *bs)
{
NFSClient *client = bs->opaque;
QDict *opts = qdict_new();
QObject *server_qdict;
Visitor *ov;
qdict_put_str(opts, "driver", "nfs");
if (client->uid && !client->gid) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
@ -824,35 +819,20 @@ static void nfs_refresh_filename(BlockDriverState *bs, QDict *options)
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nfs://%s%s", client->server->host, client->path);
}
}
ov = qobject_output_visitor_new(&server_qdict);
visit_type_NFSServer(ov, NULL, &client->server, &error_abort);
visit_complete(ov, &server_qdict);
qdict_put_obj(opts, "server", server_qdict);
qdict_put_str(opts, "path", client->path);
static char *nfs_dirname(BlockDriverState *bs, Error **errp)
{
NFSClient *client = bs->opaque;
if (client->uid) {
qdict_put_int(opts, "user", client->uid);
}
if (client->gid) {
qdict_put_int(opts, "group", client->gid);
}
if (client->tcp_syncnt) {
qdict_put_int(opts, "tcp-syn-cnt", client->tcp_syncnt);
}
if (client->readahead) {
qdict_put_int(opts, "readahead-size", client->readahead);
}
if (client->pagecache) {
qdict_put_int(opts, "page-cache-size", client->pagecache);
}
if (client->debug) {
qdict_put_int(opts, "debug", client->debug);
if (client->uid || client->gid) {
bdrv_refresh_filename(bs);
error_setg(errp, "Cannot generate a base directory for NFS node '%s'",
bs->filename);
return NULL;
}
visit_free(ov);
qdict_flatten(opts);
bs->full_open_options = opts;
return g_strdup_printf("nfs://%s%s/", client->server->host, client->path);
}
#ifdef LIBNFS_FEATURE_PAGECACHE
@ -864,6 +844,15 @@ static void coroutine_fn nfs_co_invalidate_cache(BlockDriverState *bs,
}
#endif
static const char *nfs_strong_runtime_opts[] = {
"path",
"user",
"group",
"server.",
NULL
};
static BlockDriver bdrv_nfs = {
.format_name = "nfs",
.protocol_name = "nfs",
@ -889,6 +878,9 @@ static BlockDriver bdrv_nfs = {
.bdrv_detach_aio_context = nfs_detach_aio_context,
.bdrv_attach_aio_context = nfs_attach_aio_context,
.bdrv_refresh_filename = nfs_refresh_filename,
.bdrv_dirname = nfs_dirname,
.strong_runtime_opts = nfs_strong_runtime_opts,
#ifdef LIBNFS_FEATURE_PAGECACHE
.bdrv_co_invalidate_cache = nfs_co_invalidate_cache,

View File

@ -239,19 +239,33 @@ static int coroutine_fn null_co_block_status(BlockDriverState *bs,
return ret;
}
static void null_refresh_filename(BlockDriverState *bs, QDict *opts)
static void null_refresh_filename(BlockDriverState *bs)
{
qdict_del(opts, "filename");
const QDictEntry *e;
if (!qdict_size(opts)) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://",
bs->drv->format_name);
for (e = qdict_first(bs->full_open_options); e;
e = qdict_next(bs->full_open_options, e))
{
/* These options can be ignored */
if (strcmp(qdict_entry_key(e), "filename") &&
strcmp(qdict_entry_key(e), "driver") &&
strcmp(qdict_entry_key(e), NULL_OPT_LATENCY))
{
return;
}
}
qdict_put_str(opts, "driver", bs->drv->format_name);
bs->full_open_options = qobject_ref(opts);
snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://",
bs->drv->format_name);
}
static const char *const null_strong_runtime_opts[] = {
BLOCK_OPT_SIZE,
NULL_OPT_ZEROES,
NULL
};
static BlockDriver bdrv_null_co = {
.format_name = "null-co",
.protocol_name = "null-co",
@ -269,6 +283,7 @@ static BlockDriver bdrv_null_co = {
.bdrv_co_block_status = null_co_block_status,
.bdrv_refresh_filename = null_refresh_filename,
.strong_runtime_opts = null_strong_runtime_opts,
};
static BlockDriver bdrv_null_aio = {
@ -288,6 +303,7 @@ static BlockDriver bdrv_null_aio = {
.bdrv_co_block_status = null_co_block_status,
.bdrv_refresh_filename = null_refresh_filename,
.strong_runtime_opts = null_strong_runtime_opts,
};
static void bdrv_null_init(void)

View File

@ -82,7 +82,7 @@ typedef volatile struct {
uint8_t reserved1[0xec0];
uint8_t cmd_set_specfic[0x100];
uint32_t doorbells[];
} QEMU_PACKED NVMeRegs;
} NVMeRegs;
QEMU_BUILD_BUG_ON(offsetof(NVMeRegs, doorbells) != 0x1000);
@ -111,6 +111,9 @@ typedef struct {
/* Total size of mapped qiov, accessed under dma_map_lock */
int dma_map_count;
/* PCI address (required for nvme_refresh_filename()) */
char *device;
} BDRVNVMeState;
#define NVME_BLOCK_OPT_DEVICE "device"
@ -557,6 +560,7 @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
qemu_co_mutex_init(&s->dma_map_lock);
qemu_co_queue_init(&s->dma_flush_queue);
s->device = g_strdup(device);
s->nsid = namespace;
s->aio_context = bdrv_get_aio_context(bs);
ret = event_notifier_init(&s->irq_notifier, 0);
@ -729,6 +733,8 @@ static void nvme_close(BlockDriverState *bs)
event_notifier_cleanup(&s->irq_notifier);
qemu_vfio_pci_unmap_bar(s->vfio, 0, (void *)s->regs, 0, NVME_BAR_SIZE);
qemu_vfio_close(s->vfio);
g_free(s->device);
}
static int nvme_file_open(BlockDriverState *bs, QDict *options, int flags,
@ -1053,17 +1059,12 @@ static int nvme_reopen_prepare(BDRVReopenState *reopen_state,
return 0;
}
static void nvme_refresh_filename(BlockDriverState *bs, QDict *opts)
static void nvme_refresh_filename(BlockDriverState *bs)
{
qdict_del(opts, "filename");
BDRVNVMeState *s = bs->opaque;
if (!qdict_size(opts)) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://",
bs->drv->format_name);
}
qdict_put_str(opts, "driver", bs->drv->format_name);
bs->full_open_options = qobject_ref(opts);
snprintf(bs->exact_filename, sizeof(bs->exact_filename), "nvme://%s/%i",
s->device, s->nsid);
}
static void nvme_refresh_limits(BlockDriverState *bs, Error **errp)
@ -1136,6 +1137,13 @@ static void nvme_unregister_buf(BlockDriverState *bs, void *host)
qemu_vfio_dma_unmap(s->vfio, host);
}
static const char *const nvme_strong_runtime_opts[] = {
NVME_BLOCK_OPT_DEVICE,
NVME_BLOCK_OPT_NAMESPACE,
NULL
};
static BlockDriver bdrv_nvme = {
.format_name = "nvme",
.protocol_name = "nvme",
@ -1153,6 +1161,7 @@ static BlockDriver bdrv_nvme = {
.bdrv_refresh_filename = nvme_refresh_filename,
.bdrv_refresh_limits = nvme_refresh_limits,
.strong_runtime_opts = nvme_strong_runtime_opts,
.bdrv_detach_aio_context = nvme_detach_aio_context,
.bdrv_attach_aio_context = nvme_attach_aio_context,

View File

@ -51,6 +51,8 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
return NULL;
}
bdrv_refresh_filename(bs);
info = g_malloc0(sizeof(*info));
info->file = g_strdup(bs->filename);
info->ro = bs->read_only;
@ -264,6 +266,8 @@ void bdrv_query_image_info(BlockDriverState *bs,
goto out;
}
bdrv_refresh_filename(bs);
info = g_new0(ImageInfo, 1);
info->filename = g_strdup(bs->filename);
info->format = g_strdup(bdrv_get_format_name(bs));
@ -292,18 +296,10 @@ void bdrv_query_image_info(BlockDriverState *bs,
backing_filename = bs->backing_file;
if (backing_filename[0] != '\0') {
char *backing_filename2 = g_malloc0(PATH_MAX);
char *backing_filename2;
info->backing_filename = g_strdup(backing_filename);
info->has_backing_filename = true;
bdrv_get_full_backing_filename(bs, backing_filename2, PATH_MAX, &err);
if (err) {
/* Can't reconstruct the full backing filename, so we must omit
* this field and apply a Best Effort to this query. */
g_free(backing_filename2);
backing_filename2 = NULL;
error_free(err);
err = NULL;
}
backing_filename2 = bdrv_get_full_backing_filename(bs, NULL);
/* Always report the full_backing_filename if present, even if it's the
* same as backing_filename. That they are same is useful info. */

View File

@ -31,6 +31,7 @@
#include "qemu/module.h"
#include "qemu/option.h"
#include "qemu/bswap.h"
#include "qemu/cutils.h"
#include <zlib.h>
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qstring.h"
@ -295,11 +296,13 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
goto fail;
}
ret = bdrv_pread(bs->file, header.backing_file_offset,
bs->backing_file, len);
bs->auto_backing_file, len);
if (ret < 0) {
goto fail;
}
bs->backing_file[len] = '\0';
bs->auto_backing_file[len] = '\0';
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
bs->auto_backing_file);
}
/* Disable migration when qcow images are used */
@ -1170,6 +1173,12 @@ static QemuOptsList qcow_create_opts = {
}
};
static const char *const qcow_strong_runtime_opts[] = {
"encrypt." BLOCK_CRYPTO_OPT_QCOW_KEY_SECRET,
NULL
};
static BlockDriver bdrv_qcow = {
.format_name = "qcow",
.instance_size = sizeof(BDRVQcowState),
@ -1193,6 +1202,7 @@ static BlockDriver bdrv_qcow = {
.bdrv_get_info = qcow_get_info,
.create_opts = &qcow_create_opts,
.strong_runtime_opts = qcow_strong_runtime_opts,
};
static void bdrv_qcow_init(void)

View File

@ -285,6 +285,9 @@ static int l2_allocate(BlockDriverState *bs, int l1_index)
goto fail;
}
/* The offset must fit in the offset field of the L1 table entry */
assert((l2_offset & L1E_OFFSET_MASK) == l2_offset);
/* If we're allocating the table at offset 0 then something is wrong */
if (l2_offset == 0) {
qcow2_signal_corruption(bs, true, -1, -1, "Preventing invalid "

View File

@ -358,11 +358,6 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
/* Generate an ID */
find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str));
/* Check that the ID is unique */
if (find_snapshot_by_id_and_name(bs, sn_info->id_str, NULL) >= 0) {
return -EEXIST;
}
/* Populate sn with passed data */
sn->id_str = g_strdup(sn_info->id_str);
sn->name = g_strdup(sn_info->name);

View File

@ -1474,13 +1474,15 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
goto fail;
}
ret = bdrv_pread(bs->file, header.backing_file_offset,
bs->backing_file, len);
bs->auto_backing_file, len);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not read backing file name");
goto fail;
}
bs->backing_file[len] = '\0';
s->image_backing_file = g_strdup(bs->backing_file);
bs->auto_backing_file[len] = '\0';
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
bs->auto_backing_file);
s->image_backing_file = g_strdup(bs->auto_backing_file);
}
/* Internal snapshots */
@ -2518,6 +2520,8 @@ static int qcow2_change_backing_file(BlockDriverState *bs,
return -EINVAL;
}
pstrcpy(bs->auto_backing_file, sizeof(bs->auto_backing_file),
backing_file ?: "");
pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_file ?: "");
pstrcpy(bs->backing_format, sizeof(bs->backing_format), backing_fmt ?: "");
@ -4224,6 +4228,60 @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs)
return ret;
}
static ssize_t qcow2_measure_crypto_hdr_init_func(QCryptoBlock *block,
size_t headerlen, void *opaque, Error **errp)
{
size_t *headerlenp = opaque;
/* Stash away the payload size */
*headerlenp = headerlen;
return 0;
}
static ssize_t qcow2_measure_crypto_hdr_write_func(QCryptoBlock *block,
size_t offset, const uint8_t *buf, size_t buflen,
void *opaque, Error **errp)
{
/* Discard the bytes, we're not actually writing to an image */
return buflen;
}
/* Determine the number of bytes for the LUKS payload */
static bool qcow2_measure_luks_headerlen(QemuOpts *opts, size_t *len,
Error **errp)
{
QDict *opts_qdict;
QDict *cryptoopts_qdict;
QCryptoBlockCreateOptions *cryptoopts;
QCryptoBlock *crypto;
/* Extract "encrypt." options into a qdict */
opts_qdict = qemu_opts_to_qdict(opts, NULL);
qdict_extract_subqdict(opts_qdict, &cryptoopts_qdict, "encrypt.");
qobject_unref(opts_qdict);
/* Build QCryptoBlockCreateOptions object from qdict */
qdict_put_str(cryptoopts_qdict, "format", "luks");
cryptoopts = block_crypto_create_opts_init(cryptoopts_qdict, errp);
qobject_unref(cryptoopts_qdict);
if (!cryptoopts) {
return false;
}
/* Fake LUKS creation in order to determine the payload size */
crypto = qcrypto_block_create(cryptoopts, "encrypt.",
qcow2_measure_crypto_hdr_init_func,
qcow2_measure_crypto_hdr_write_func,
len, errp);
qapi_free_QCryptoBlockCreateOptions(cryptoopts);
if (!crypto) {
return false;
}
qcrypto_block_free(crypto);
return true;
}
static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
Error **errp)
{
@ -4233,11 +4291,13 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
uint64_t virtual_size; /* disk size as seen by guest */
uint64_t refcount_bits;
uint64_t l2_tables;
uint64_t luks_payload_size = 0;
size_t cluster_size;
int version;
char *optstr;
PreallocMode prealloc;
bool has_backing_file;
bool has_luks;
/* Parse image creation options */
cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err);
@ -4267,6 +4327,20 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
has_backing_file = !!optstr;
g_free(optstr);
optstr = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT);
has_luks = optstr && strcmp(optstr, "luks") == 0;
g_free(optstr);
if (has_luks) {
size_t headerlen;
if (!qcow2_measure_luks_headerlen(opts, &headerlen, &local_err)) {
goto err;
}
luks_payload_size = ROUND_UP(headerlen, cluster_size);
}
virtual_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
virtual_size = ROUND_UP(virtual_size, cluster_size);
@ -4337,7 +4411,7 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
info = g_new(BlockMeasureInfo, 1);
info->fully_allocated =
qcow2_calc_prealloc_size(virtual_size, cluster_size,
ctz32(refcount_bits));
ctz32(refcount_bits)) + luks_payload_size;
/* Remove data clusters that are not required. This overestimates the
* required size because metadata needed for the fully allocated file is
@ -4924,6 +4998,12 @@ static QemuOptsList qcow2_create_opts = {
}
};
static const char *const qcow2_strong_runtime_opts[] = {
"encrypt." BLOCK_CRYPTO_OPT_QCOW_KEY_SECRET,
NULL
};
BlockDriver bdrv_qcow2 = {
.format_name = "qcow2",
.instance_size = sizeof(BDRVQcow2State),
@ -4972,6 +5052,7 @@ BlockDriver bdrv_qcow2 = {
.bdrv_inactivate = qcow2_inactivate,
.create_opts = &qcow2_create_opts,
.strong_runtime_opts = qcow2_strong_runtime_opts,
.bdrv_co_check = qcow2_co_check,
.bdrv_amend_options = qcow2_amend_options,

View File

@ -449,11 +449,14 @@ static int coroutine_fn bdrv_qed_do_open(BlockDriverState *bs, QDict *options,
}
ret = qed_read_string(bs->file, s->header.backing_filename_offset,
s->header.backing_filename_size, bs->backing_file,
sizeof(bs->backing_file));
s->header.backing_filename_size,
bs->auto_backing_file,
sizeof(bs->auto_backing_file));
if (ret < 0) {
return ret;
}
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
bs->auto_backing_file);
if (s->header.features & QED_F_BACKING_FORMAT_NO_PROBE) {
pstrcpy(bs->backing_format, sizeof(bs->backing_format), "raw");

View File

@ -1065,36 +1065,64 @@ static void quorum_del_child(BlockDriverState *bs, BdrvChild *child,
bdrv_drained_end(bs);
}
static void quorum_refresh_filename(BlockDriverState *bs, QDict *options)
static void quorum_gather_child_options(BlockDriverState *bs, QDict *target,
bool backing_overridden)
{
BDRVQuorumState *s = bs->opaque;
QDict *opts;
QList *children;
QList *children_list;
int i;
for (i = 0; i < s->num_children; i++) {
bdrv_refresh_filename(s->children[i]->bs);
if (!s->children[i]->bs->full_open_options) {
return;
}
}
/*
* The generic implementation for gathering child options in
* bdrv_refresh_filename() would use the names of the children
* as specified for bdrv_open_child() or bdrv_attach_child(),
* which is "children.%u" with %u being a value
* (s->next_child_index) that is incremented each time a new child
* is added (and never decremented). Since children can be
* deleted at runtime, there may be gaps in that enumeration.
* When creating a new quorum BDS and specifying the children for
* it through runtime options, the enumeration used there may not
* have any gaps, though.
*
* Therefore, we have to create a new gap-less enumeration here
* (which we can achieve by simply putting all of the children's
* full_open_options into a QList).
*
* XXX: Note that there are issues with the current child option
* structure quorum uses (such as the fact that children do
* not really have unique permanent names). Therefore, this
* is going to have to change in the future and ideally we
* want quorum to be covered by the generic implementation.
*/
children_list = qlist_new();
qdict_put(target, "children", children_list);
children = qlist_new();
for (i = 0; i < s->num_children; i++) {
qlist_append(children,
qlist_append(children_list,
qobject_ref(s->children[i]->bs->full_open_options));
}
opts = qdict_new();
qdict_put_str(opts, "driver", "quorum");
qdict_put_int(opts, QUORUM_OPT_VOTE_THRESHOLD, s->threshold);
qdict_put_bool(opts, QUORUM_OPT_BLKVERIFY, s->is_blkverify);
qdict_put_bool(opts, QUORUM_OPT_REWRITE, s->rewrite_corrupted);
qdict_put(opts, "children", children);
bs->full_open_options = opts;
}
static char *quorum_dirname(BlockDriverState *bs, Error **errp)
{
/* In general, there are multiple BDSs with different dirnames below this
* one; so there is no unique dirname we could return (unless all are equal
* by chance, or there is only one). Therefore, to be consistent, just
* always return NULL. */
error_setg(errp, "Cannot generate a base directory for quorum nodes");
return NULL;
}
static const char *const quorum_strong_runtime_opts[] = {
QUORUM_OPT_VOTE_THRESHOLD,
QUORUM_OPT_BLKVERIFY,
QUORUM_OPT_REWRITE,
QUORUM_OPT_READ_PATTERN,
NULL
};
static BlockDriver bdrv_quorum = {
.format_name = "quorum",
@ -1102,7 +1130,8 @@ static BlockDriver bdrv_quorum = {
.bdrv_open = quorum_open,
.bdrv_close = quorum_close,
.bdrv_refresh_filename = quorum_refresh_filename,
.bdrv_gather_child_options = quorum_gather_child_options,
.bdrv_dirname = quorum_dirname,
.bdrv_co_flush_to_disk = quorum_co_flush,
@ -1118,6 +1147,8 @@ static BlockDriver bdrv_quorum = {
.is_filter = true,
.bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter,
.strong_runtime_opts = quorum_strong_runtime_opts,
};
static void bdrv_quorum_init(void)

View File

@ -436,6 +436,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
bs->file->bs->supported_zero_flags);
if (bs->probed && !bdrv_is_read_only(bs)) {
bdrv_refresh_filename(bs->file->bs);
fprintf(stderr,
"WARNING: Image format was not specified for '%s' and probing "
"guessed raw.\n"
@ -531,6 +532,13 @@ static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs,
read_flags, write_flags);
}
static const char *const raw_strong_runtime_opts[] = {
"offset",
"size",
NULL
};
BlockDriver bdrv_raw = {
.format_name = "raw",
.instance_size = sizeof(BDRVRawState),
@ -560,7 +568,8 @@ BlockDriver bdrv_raw = {
.bdrv_lock_medium = &raw_lock_medium,
.bdrv_co_ioctl = &raw_co_ioctl,
.create_opts = &raw_create_opts,
.bdrv_has_zero_init = &raw_has_zero_init
.bdrv_has_zero_init = &raw_has_zero_init,
.strong_runtime_opts = raw_strong_runtime_opts,
};
static void bdrv_raw_init(void)

View File

@ -1228,6 +1228,18 @@ static QemuOptsList qemu_rbd_create_opts = {
}
};
static const char *const qemu_rbd_strong_runtime_opts[] = {
"pool",
"image",
"conf",
"snapshot",
"user",
"server.",
"password-secret",
NULL
};
static BlockDriver bdrv_rbd = {
.format_name = "rbd",
.instance_size = sizeof(BDRVRBDState),
@ -1265,6 +1277,8 @@ static BlockDriver bdrv_rbd = {
#ifdef LIBRBD_SUPPORTS_INVALIDATE
.bdrv_co_invalidate_cache = qemu_rbd_co_invalidate_cache,
#endif
.strong_runtime_opts = qemu_rbd_strong_runtime_opts,
};
static void bdrv_rbd_init(void)

View File

@ -616,8 +616,6 @@ static void replication_done(void *opaque, int ret)
if (ret == 0) {
s->stage = BLOCK_REPLICATION_DONE;
/* refresh top bs's filename */
bdrv_refresh_filename(bs);
s->active_disk = NULL;
s->secondary_disk = NULL;
s->hidden_disk = NULL;
@ -678,6 +676,13 @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp)
aio_context_release(aio_context);
}
static const char *const replication_strong_runtime_opts[] = {
REPLICATION_MODE,
REPLICATION_TOP_ID,
NULL
};
BlockDriver bdrv_replication = {
.format_name = "replication",
.instance_size = sizeof(BDRVReplicationState),
@ -694,6 +699,7 @@ BlockDriver bdrv_replication = {
.bdrv_recurse_is_first_non_filter = replication_recurse_is_first_non_filter,
.has_variable_length = true,
.strong_runtime_opts = replication_strong_runtime_opts,
};
static void bdrv_replication_init(void)

View File

@ -3203,6 +3203,15 @@ static QemuOptsList sd_create_opts = {
}
};
static const char *const sd_strong_runtime_opts[] = {
"vdi",
"snap-id",
"tag",
"server.",
NULL
};
static BlockDriver bdrv_sheepdog = {
.format_name = "sheepdog",
.protocol_name = "sheepdog",
@ -3238,6 +3247,7 @@ static BlockDriver bdrv_sheepdog = {
.bdrv_attach_aio_context = sd_attach_aio_context,
.create_opts = &sd_create_opts,
.strong_runtime_opts = sd_strong_runtime_opts,
};
static BlockDriver bdrv_sheepdog_tcp = {
@ -3275,6 +3285,7 @@ static BlockDriver bdrv_sheepdog_tcp = {
.bdrv_attach_aio_context = sd_attach_aio_context,
.create_opts = &sd_create_opts,
.strong_runtime_opts = sd_strong_runtime_opts,
};
static BlockDriver bdrv_sheepdog_unix = {
@ -3312,6 +3323,7 @@ static BlockDriver bdrv_sheepdog_unix = {
.bdrv_attach_aio_context = sd_attach_aio_context,
.create_opts = &sd_create_opts,
.strong_runtime_opts = sd_strong_runtime_opts,
};
static void bdrv_sheepdog_init(void)

View File

@ -63,7 +63,7 @@ int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
}
for (i = 0; i < nb_sns; i++) {
sn = &sn_tab[i];
if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) {
if (!strcmp(sn->name, name)) {
*sn_info = *sn;
ret = 0;
break;
@ -301,26 +301,6 @@ int bdrv_snapshot_delete(BlockDriverState *bs,
return ret;
}
int bdrv_snapshot_delete_by_id_or_name(BlockDriverState *bs,
const char *id_or_name,
Error **errp)
{
int ret;
Error *local_err = NULL;
ret = bdrv_snapshot_delete(bs, id_or_name, NULL, &local_err);
if (ret == -ENOENT || ret == -EINVAL) {
error_free(local_err);
local_err = NULL;
ret = bdrv_snapshot_delete(bs, NULL, id_or_name, &local_err);
}
if (ret < 0) {
error_propagate(errp, local_err);
}
return ret;
}
int bdrv_snapshot_list(BlockDriverState *bs,
QEMUSnapshotInfo **psn_info)
{
@ -448,7 +428,8 @@ int bdrv_all_delete_snapshot(const char *name, BlockDriverState **first_bad_bs,
aio_context_acquire(ctx);
if (bdrv_can_snapshot(bs) &&
bdrv_snapshot_find(bs, snapshot, name) >= 0) {
ret = bdrv_snapshot_delete_by_id_or_name(bs, name, err);
ret = bdrv_snapshot_delete(bs, snapshot->id_str,
snapshot->name, err);
}
aio_context_release(ctx);
if (ret < 0) {

View File

@ -1254,6 +1254,17 @@ static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset,
return ssh_grow_file(s, offset, errp);
}
static const char *const ssh_strong_runtime_opts[] = {
"host",
"port",
"path",
"user",
"host_key_check",
"server.",
NULL
};
static BlockDriver bdrv_ssh = {
.format_name = "ssh",
.protocol_name = "ssh",
@ -1270,6 +1281,7 @@ static BlockDriver bdrv_ssh = {
.bdrv_co_truncate = ssh_co_truncate,
.bdrv_co_flush_to_disk = ssh_co_flush,
.create_opts = &ssh_create_opts,
.strong_runtime_opts = ssh_strong_runtime_opts,
};
static void bdrv_ssh_init(void)

View File

@ -227,6 +227,12 @@ static void coroutine_fn throttle_co_drain_end(BlockDriverState *bs)
atomic_dec(&tgm->io_limits_disabled);
}
static const char *const throttle_strong_runtime_opts[] = {
QEMU_OPT_THROTTLE_GROUP_NAME,
NULL
};
static BlockDriver bdrv_throttle = {
.format_name = "throttle",
.instance_size = sizeof(ThrottleGroupMember),
@ -259,6 +265,7 @@ static BlockDriver bdrv_throttle = {
.bdrv_co_drain_end = throttle_co_drain_end,
.is_filter = true,
.strong_runtime_opts = throttle_strong_runtime_opts,
};
static void bdrv_throttle_init(void)

View File

@ -803,6 +803,7 @@ int vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed,
if (logs.valid) {
if (bs->read_only) {
bdrv_refresh_filename(bs);
ret = -EPERM;
error_setg(errp,
"VHDX image file '%s' opened read-only, but "

View File

@ -27,6 +27,7 @@
#include "qapi/error.h"
#include "block/block_int.h"
#include "sysemu/block-backend.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qerror.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
@ -386,12 +387,14 @@ static int vmdk_parent_open(BlockDriverState *bs)
ret = -EINVAL;
goto out;
}
if ((end_name - p_name) > sizeof(bs->backing_file) - 1) {
if ((end_name - p_name) > sizeof(bs->auto_backing_file) - 1) {
ret = -EINVAL;
goto out;
}
pstrcpy(bs->backing_file, end_name - p_name + 1, p_name);
pstrcpy(bs->auto_backing_file, end_name - p_name + 1, p_name);
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
bs->auto_backing_file);
}
out:
@ -479,6 +482,7 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
extent->l1_table,
l1_size);
if (ret < 0) {
bdrv_refresh_filename(extent->file->bs);
error_setg_errno(errp, -ret,
"Could not read l1 table from extent '%s'",
extent->file->bs->filename);
@ -499,6 +503,7 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
extent->l1_backup_table,
l1_size);
if (ret < 0) {
bdrv_refresh_filename(extent->file->bs);
error_setg_errno(errp, -ret,
"Could not read l1 backup table from extent '%s'",
extent->file->bs->filename);
@ -530,6 +535,7 @@ static int vmdk_open_vmfs_sparse(BlockDriverState *bs,
ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header));
if (ret < 0) {
bdrv_refresh_filename(file->bs);
error_setg_errno(errp, -ret,
"Could not read header from file '%s'",
file->bs->filename);
@ -607,6 +613,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header));
if (ret < 0) {
bdrv_refresh_filename(file->bs);
error_setg_errno(errp, -ret,
"Could not read header from file '%s'",
file->bs->filename);
@ -861,13 +868,13 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
if (!path_is_absolute(fname) && !path_has_protocol(fname) &&
!desc_file_path[0])
{
bdrv_refresh_filename(bs->file->bs);
error_setg(errp, "Cannot use relative extent paths with VMDK "
"descriptor file '%s'", bs->file->bs->filename);
return -EINVAL;
}
extent_path = g_malloc0(PATH_MAX);
path_combine(extent_path, PATH_MAX, desc_file_path, fname);
extent_path = path_combine(desc_file_path, fname);
ret = snprintf(extent_opt_prefix, 32, "extents.%d", s->num_extents);
assert(ret < 32);
@ -2067,16 +2074,16 @@ static int coroutine_fn vmdk_co_do_create(int64_t size,
if (backing_file) {
BlockBackend *backing;
char *full_backing = g_new0(char, PATH_MAX);
bdrv_get_full_backing_filename_from_filename(blk_bs(blk)->filename, backing_file,
full_backing, PATH_MAX,
&local_err);
char *full_backing =
bdrv_get_full_backing_filename_from_filename(blk_bs(blk)->filename,
backing_file,
&local_err);
if (local_err) {
g_free(full_backing);
error_propagate(errp, local_err);
ret = -ENOENT;
goto exit;
}
assert(full_backing);
backing = blk_new_open(full_backing, NULL, NULL,
BDRV_O_NO_BACKING, errp);
@ -2255,7 +2262,7 @@ static int coroutine_fn vmdk_co_create_opts(const char *filename, QemuOpts *opts
compat6 = qemu_opt_get_bool_del(opts, BLOCK_OPT_COMPAT6, false);
if (strcmp(hw_version, "undefined") == 0) {
g_free(hw_version);
hw_version = g_strdup("4");
hw_version = NULL;
}
fmt = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT);
zeroed_grain = qemu_opt_get_bool_del(opts, BLOCK_OPT_ZEROED_GRAIN, false);
@ -2465,6 +2472,7 @@ static ImageInfo *vmdk_get_extent_info(VmdkExtent *extent)
{
ImageInfo *info = g_new0(ImageInfo, 1);
bdrv_refresh_filename(extent->file->bs);
*info = (ImageInfo){
.filename = g_strdup(extent->file->bs->filename),
.format = g_strdup(extent->type),
@ -2596,6 +2604,23 @@ static int vmdk_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
return 0;
}
static void vmdk_gather_child_options(BlockDriverState *bs, QDict *target,
bool backing_overridden)
{
/* No children but file and backing can be explicitly specified (TODO) */
qdict_put(target, "file",
qobject_ref(bs->file->bs->full_open_options));
if (backing_overridden) {
if (bs->backing) {
qdict_put(target, "backing",
qobject_ref(bs->backing->bs->full_open_options));
} else {
qdict_put_null(target, "backing");
}
}
}
static QemuOptsList vmdk_create_opts = {
.name = "vmdk-create-opts",
.head = QTAILQ_HEAD_INITIALIZER(vmdk_create_opts.head),
@ -2667,6 +2692,7 @@ static BlockDriver bdrv_vmdk = {
.bdrv_get_specific_info = vmdk_get_specific_info,
.bdrv_refresh_limits = vmdk_refresh_limits,
.bdrv_get_info = vmdk_get_info,
.bdrv_gather_child_options = vmdk_gather_child_options,
.supports_backing = true,
.create_opts = &vmdk_create_opts,

View File

@ -1218,6 +1218,12 @@ static QemuOptsList vpc_create_opts = {
}
};
static const char *const vpc_strong_runtime_opts[] = {
VPC_OPT_SIZE_CALC,
NULL
};
static BlockDriver bdrv_vpc = {
.format_name = "vpc",
.instance_size = sizeof(BDRVVPCState),
@ -1238,6 +1244,7 @@ static BlockDriver bdrv_vpc = {
.create_opts = &vpc_create_opts,
.bdrv_has_zero_init = vpc_has_zero_init,
.strong_runtime_opts = vpc_strong_runtime_opts,
};
static void bdrv_vpc_init(void)

View File

@ -3253,6 +3253,16 @@ static void vvfat_close(BlockDriverState *bs)
}
}
static const char *const vvfat_strong_runtime_opts[] = {
"dir",
"fat-type",
"floppy",
"label",
"rw",
NULL
};
static BlockDriver bdrv_vvfat = {
.format_name = "vvfat",
.protocol_name = "fat",
@ -3267,6 +3277,8 @@ static BlockDriver bdrv_vvfat = {
.bdrv_co_preadv = vvfat_co_preadv,
.bdrv_co_pwritev = vvfat_co_pwritev,
.bdrv_co_block_status = vvfat_co_block_status,
.strong_runtime_opts = vvfat_strong_runtime_opts,
};
static void bdrv_vvfat_init(void)

View File

@ -556,6 +556,16 @@ static int64_t vxhs_getlength(BlockDriverState *bs)
return vdisk_size;
}
static const char *const vxhs_strong_runtime_opts[] = {
VXHS_OPT_VDISK_ID,
"tls-creds",
VXHS_OPT_HOST,
VXHS_OPT_PORT,
VXHS_OPT_SERVER".",
NULL
};
static BlockDriver bdrv_vxhs = {
.format_name = "vxhs",
.protocol_name = "vxhs",
@ -567,6 +577,7 @@ static BlockDriver bdrv_vxhs = {
.bdrv_getlength = vxhs_getlength,
.bdrv_aio_preadv = vxhs_aio_preadv,
.bdrv_aio_pwritev = vxhs_aio_pwritev,
.strong_runtime_opts = vxhs_strong_runtime_opts,
};
static void bdrv_vxhs_init(void)

View File

@ -1627,6 +1627,7 @@ static void external_snapshot_prepare(BlkActionState *common,
error_setg_errno(errp, -size, "bdrv_getlength failed");
goto out;
}
bdrv_refresh_filename(state->old_bs);
bdrv_img_create(new_image_file, format,
state->old_bs->filename,
state->old_bs->drv->format_name,
@ -3230,6 +3231,7 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device,
goto out;
}
assert(bdrv_get_aio_context(base_bs) == aio_context);
bdrv_refresh_filename(base_bs);
base_name = base_bs->filename;
}
@ -3349,6 +3351,10 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device,
goto out;
}
} else if (has_top && top) {
/* This strcmp() is just a shortcut, there is no need to
* refresh @bs's filename. If it mismatches,
* bdrv_find_backing_image() will do the refresh and may still
* return @bs. */
if (strcmp(bs->filename, top) != 0) {
top_bs = bdrv_find_backing_image(bs, top);
}
@ -3509,6 +3515,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
if (backup->mode != NEW_IMAGE_MODE_EXISTING) {
assert(backup->format);
if (source) {
bdrv_refresh_filename(source);
bdrv_img_create(backup->target, backup->format, source->filename,
source->drv->format_name, NULL,
size, flags, false, &local_err);
@ -3889,6 +3896,7 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
break;
case NEW_IMAGE_MODE_ABSOLUTE_PATHS:
/* create new image with backing file */
bdrv_refresh_filename(source);
bdrv_img_create(arg->target, format,
source->filename,
source->drv->format_name,

View File

@ -350,49 +350,57 @@ ETEXI
{
.name = "savevm",
.args_type = "name:s?",
.params = "[tag|id]",
.help = "save a VM snapshot. If no tag or id are provided, a new snapshot is created",
.params = "tag",
.help = "save a VM snapshot. If no tag is provided, a new snapshot is created",
.cmd = hmp_savevm,
},
STEXI
@item savevm [@var{tag}|@var{id}]
@item savevm @var{tag}
@findex savevm
Create a snapshot of the whole virtual machine. If @var{tag} is
provided, it is used as human readable identifier. If there is already
a snapshot with the same tag or ID, it is replaced. More info at
a snapshot with the same tag, it is replaced. More info at
@ref{vm_snapshots}.
Since 4.0, savevm stopped allowing the snapshot id to be set, accepting
only @var{tag} as parameter.
ETEXI
{
.name = "loadvm",
.args_type = "name:s",
.params = "tag|id",
.help = "restore a VM snapshot from its tag or id",
.params = "tag",
.help = "restore a VM snapshot from its tag",
.cmd = hmp_loadvm,
.command_completion = loadvm_completion,
},
STEXI
@item loadvm @var{tag}|@var{id}
@item loadvm @var{tag}
@findex loadvm
Set the whole virtual machine to the snapshot identified by the tag
@var{tag} or the unique snapshot ID @var{id}.
@var{tag}.
Since 4.0, loadvm stopped accepting snapshot id as parameter.
ETEXI
{
.name = "delvm",
.args_type = "name:s",
.params = "tag|id",
.help = "delete a VM snapshot from its tag or id",
.params = "tag",
.help = "delete a VM snapshot from its tag",
.cmd = hmp_delvm,
.command_completion = delvm_completion,
},
STEXI
@item delvm @var{tag}|@var{id}
@item delvm @var{tag}
@findex delvm
Delete the snapshot identified by @var{tag} or @var{id}.
Delete the snapshot identified by @var{tag}.
Since 4.0, delvm stopped deleting snapshots by snapshot id, accepting
only @var{tag} as parameter.
ETEXI
{

View File

@ -839,6 +839,7 @@ static void virtio_blk_dma_restart_bh(void *opaque)
if (mrb.num_reqs) {
virtio_blk_submit_multireq(s->blk, &mrb);
}
blk_dec_in_flight(s->conf.conf.blk);
aio_context_release(blk_get_aio_context(s->conf.conf.blk));
}
@ -852,8 +853,11 @@ static void virtio_blk_dma_restart_cb(void *opaque, int running,
}
if (!s->bh) {
/* FIXME The data plane is not started yet, so these requests are
* processed in the main thread. */
s->bh = aio_bh_new(blk_get_aio_context(s->conf.conf.blk),
virtio_blk_dma_restart_bh, s);
blk_inc_in_flight(s->conf.conf.blk);
qemu_bh_schedule(s->bh);
}
}

View File

@ -485,21 +485,17 @@ void bdrv_round_to_clusters(BlockDriverState *bs,
int64_t *cluster_offset,
int64_t *cluster_bytes);
const char *bdrv_get_encrypted_filename(BlockDriverState *bs);
void bdrv_get_backing_filename(BlockDriverState *bs,
char *filename, int filename_size);
void bdrv_get_full_backing_filename(BlockDriverState *bs,
char *dest, size_t sz, Error **errp);
void bdrv_get_full_backing_filename_from_filename(const char *backed,
const char *backing,
char *dest, size_t sz,
Error **errp);
char *bdrv_get_full_backing_filename(BlockDriverState *bs, Error **errp);
char *bdrv_get_full_backing_filename_from_filename(const char *backed,
const char *backing,
Error **errp);
char *bdrv_dirname(BlockDriverState *bs, Error **errp);
int path_has_protocol(const char *path);
int path_is_absolute(const char *path);
void path_combine(char *dest, int dest_size,
const char *base_path,
const char *filename);
char *path_combine(const char *base_path, const char *filename);
int bdrv_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
int bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);

View File

@ -139,7 +139,42 @@ struct BlockDriver {
Error **errp);
int (*bdrv_make_empty)(BlockDriverState *bs);
void (*bdrv_refresh_filename)(BlockDriverState *bs, QDict *options);
/*
* Refreshes the bs->exact_filename field. If that is impossible,
* bs->exact_filename has to be left empty.
*/
void (*bdrv_refresh_filename)(BlockDriverState *bs);
/*
* Gathers the open options for all children into @target.
* A simple format driver (without backing file support) might
* implement this function like this:
*
* QINCREF(bs->file->bs->full_open_options);
* qdict_put(target, "file", bs->file->bs->full_open_options);
*
* If not specified, the generic implementation will simply put
* all children's options under their respective name.
*
* @backing_overridden is true when bs->backing seems not to be
* the child that would result from opening bs->backing_file.
* Therefore, if it is true, the backing child's options should be
* gathered; otherwise, there is no need since the backing child
* is the one implied by the image header.
*
* Note that ideally this function would not be needed. Every
* block driver which implements it is probably doing something
* shady regarding its runtime option structure.
*/
void (*bdrv_gather_child_options)(BlockDriverState *bs, QDict *target,
bool backing_overridden);
/*
* Returns an allocated string which is the directory name of this BDS: It
* will be used to make relative filenames absolute by prepending this
* function's return value to them.
*/
char *(*bdrv_dirname)(BlockDriverState *bs, Error **errp);
/* aio */
BlockAIOCB *(*bdrv_aio_preadv)(BlockDriverState *bs,
@ -510,6 +545,13 @@ struct BlockDriver {
void (*bdrv_register_buf)(BlockDriverState *bs, void *host, size_t size);
void (*bdrv_unregister_buf)(BlockDriverState *bs, void *host);
QLIST_ENTRY(BlockDriver) list;
/* Pointer to a NULL-terminated array of names of strong options
* that can be specified for bdrv_open(). A strong option is one
* that changes the data of a BDS.
* If this pointer is NULL, the array is considered empty.
* "filename" and "driver" are always considered strong. */
const char *const *strong_runtime_opts;
};
typedef struct BlockLimits {
@ -662,6 +704,11 @@ struct BdrvChild {
*/
uint64_t shared_perm;
/* backup of permissions during permission update procedure */
bool has_backup_perm;
uint64_t backup_perm;
uint64_t backup_shared_perm;
QLIST_ENTRY(BdrvChild) next;
QLIST_ENTRY(BdrvChild) next_parent;
};
@ -697,6 +744,10 @@ struct BlockDriverState {
char filename[PATH_MAX];
char backing_file[PATH_MAX]; /* if non zero, the image is a diff of
this file image */
/* The backing filename indicated by the image header; if we ever
* open this file, then this is replaced by the resulting BDS's
* filename (i.e. after a bdrv_refresh_filename() run). */
char auto_backing_file[PATH_MAX];
char backing_format[16]; /* if non-zero and backing_file exists */
QDict *full_open_options;

View File

@ -300,7 +300,8 @@ int nbd_receive_export_list(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info,
Error **errp);
int nbd_send_request(QIOChannel *ioc, NBDRequest *request);
int nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp);
int coroutine_fn nbd_receive_reply(BlockDriverState *bs, QIOChannel *ioc,
NBDReply *reply, Error **errp);
int nbd_client(int fd);
int nbd_disconnect(int fd);
int nbd_errno_to_system_errno(int err);

View File

@ -61,9 +61,6 @@ int bdrv_snapshot_delete(BlockDriverState *bs,
const char *snapshot_id,
const char *name,
Error **errp);
int bdrv_snapshot_delete_by_id_or_name(BlockDriverState *bs,
const char *id_or_name,
Error **errp);
int bdrv_snapshot_list(BlockDriverState *bs,
QEMUSnapshotInfo **psn_info);
int bdrv_snapshot_load_tmp(BlockDriverState *bs,

View File

@ -739,10 +739,13 @@ void qio_channel_detach_aio_context(QIOChannel *ioc);
* addition, no two coroutine can be waiting on the same condition
* and channel at the same time.
*
* This must only be called from coroutine context
* This must only be called from coroutine context. It is safe to
* reenter the coroutine externally while it is waiting; in this
* case the function will return even if @condition is not yet
* available.
*/
void qio_channel_yield(QIOChannel *ioc,
GIOCondition condition);
void coroutine_fn qio_channel_yield(QIOChannel *ioc,
GIOCondition condition);
/**
* qio_channel_wait:

View File

@ -156,6 +156,8 @@ int blk_co_pdiscard(BlockBackend *blk, int64_t offset, int bytes);
int blk_co_flush(BlockBackend *blk);
int blk_flush(BlockBackend *blk);
int blk_commit_all(void);
void blk_inc_in_flight(BlockBackend *blk);
void blk_dec_in_flight(BlockBackend *blk);
void blk_drain(BlockBackend *blk);
void blk_drain_all(void);
void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error,

View File

@ -400,15 +400,14 @@ off_t qio_channel_io_seek(QIOChannel *ioc,
}
static void qio_channel_set_aio_fd_handlers(QIOChannel *ioc);
static void qio_channel_restart_read(void *opaque)
{
QIOChannel *ioc = opaque;
Coroutine *co = ioc->read_coroutine;
ioc->read_coroutine = NULL;
qio_channel_set_aio_fd_handlers(ioc);
/* Assert that aio_co_wake() reenters the coroutine directly */
assert(qemu_get_current_aio_context() ==
qemu_coroutine_get_aio_context(co));
aio_co_wake(co);
}
@ -417,8 +416,9 @@ static void qio_channel_restart_write(void *opaque)
QIOChannel *ioc = opaque;
Coroutine *co = ioc->write_coroutine;
ioc->write_coroutine = NULL;
qio_channel_set_aio_fd_handlers(ioc);
/* Assert that aio_co_wake() reenters the coroutine directly */
assert(qemu_get_current_aio_context() ==
qemu_coroutine_get_aio_context(co));
aio_co_wake(co);
}
@ -469,6 +469,16 @@ void coroutine_fn qio_channel_yield(QIOChannel *ioc,
}
qio_channel_set_aio_fd_handlers(ioc);
qemu_coroutine_yield();
/* Allow interrupting the operation by reentering the coroutine other than
* through the aio_fd_handlers. */
if (condition == G_IO_IN && ioc->read_coroutine) {
ioc->read_coroutine = NULL;
qio_channel_set_aio_fd_handlers(ioc);
} else if (condition == G_IO_OUT && ioc->write_coroutine) {
ioc->write_coroutine = NULL;
qio_channel_set_aio_fd_handlers(ioc);
}
}

View File

@ -1387,17 +1387,65 @@ static int nbd_receive_structured_reply_chunk(QIOChannel *ioc,
return 0;
}
/* nbd_receive_reply
/* nbd_read_eof
* Tries to read @size bytes from @ioc.
* Returns 1 on success
* 0 on eof, when no data was read (errp is not set)
* negative errno on failure (errp is set)
*/
int nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp)
static inline int coroutine_fn
nbd_read_eof(BlockDriverState *bs, QIOChannel *ioc, void *buffer, size_t size,
Error **errp)
{
bool partial = false;
assert(size);
while (size > 0) {
struct iovec iov = { .iov_base = buffer, .iov_len = size };
ssize_t len;
len = qio_channel_readv(ioc, &iov, 1, errp);
if (len == QIO_CHANNEL_ERR_BLOCK) {
bdrv_dec_in_flight(bs);
qio_channel_yield(ioc, G_IO_IN);
bdrv_inc_in_flight(bs);
continue;
} else if (len < 0) {
return -EIO;
} else if (len == 0) {
if (partial) {
error_setg(errp,
"Unexpected end-of-file before all bytes were read");
return -EIO;
} else {
return 0;
}
}
partial = true;
size -= len;
buffer = (uint8_t*) buffer + len;
}
return 1;
}
/* nbd_receive_reply
*
* Decreases bs->in_flight while waiting for a new reply. This yield is where
* we wait indefinitely and the coroutine must be able to be safely reentered
* for nbd_client_attach_aio_context().
*
* Returns 1 on success
* 0 on eof, when no data was read (errp is not set)
* negative errno on failure (errp is set)
*/
int coroutine_fn nbd_receive_reply(BlockDriverState *bs, QIOChannel *ioc,
NBDReply *reply, Error **errp)
{
int ret;
const char *type;
ret = nbd_read_eof(ioc, &reply->magic, sizeof(reply->magic), errp);
ret = nbd_read_eof(bs, ioc, &reply->magic, sizeof(reply->magic), errp);
if (ret <= 0) {
return ret;
}

View File

@ -64,25 +64,6 @@
#define NBD_SET_TIMEOUT _IO(0xab, 9)
#define NBD_SET_FLAGS _IO(0xab, 10)
/* nbd_read_eof
* Tries to read @size bytes from @ioc.
* Returns 1 on success
* 0 on eof, when no data was read (errp is not set)
* negative errno on failure (errp is set)
*/
static inline int nbd_read_eof(QIOChannel *ioc, void *buffer, size_t size,
Error **errp)
{
int ret;
assert(size);
ret = qio_channel_read_all_eof(ioc, buffer, size, errp);
if (ret < 0) {
ret = -EIO;
}
return ret;
}
/* nbd_write
* Writes @size bytes to @ioc. Returns 0 on success.
*/

View File

@ -503,7 +503,7 @@ static int img_create(int argc, char **argv)
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
NULL, NULL)) {
NULL, &error_fatal)) {
goto fail;
}
@ -753,7 +753,7 @@ static int img_check(int argc, char **argv)
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
NULL, NULL)) {
NULL, &error_fatal)) {
return 1;
}
@ -966,7 +966,7 @@ static int img_commit(int argc, char **argv)
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
NULL, NULL)) {
NULL, &error_fatal)) {
return 1;
}
@ -1349,7 +1349,7 @@ static int img_compare(int argc, char **argv)
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
NULL, NULL)) {
NULL, &error_fatal)) {
ret = 2;
goto out4;
}
@ -2153,7 +2153,7 @@ static int img_convert(int argc, char **argv)
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
NULL, NULL)) {
NULL, &error_fatal)) {
goto fail_getopt;
}
@ -2707,7 +2707,7 @@ static int img_info(int argc, char **argv)
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
NULL, NULL)) {
NULL, &error_fatal)) {
return 1;
}
@ -2784,6 +2784,7 @@ static int get_block_status(BlockDriverState *bs, int64_t offset,
BlockDriverState *file;
bool has_offset;
int64_t map;
char *filename = NULL;
/* As an optimization, we could cache the current range of unallocated
* clusters in each file of the chain, and avoid querying the same
@ -2811,6 +2812,11 @@ static int get_block_status(BlockDriverState *bs, int64_t offset,
has_offset = !!(ret & BDRV_BLOCK_OFFSET_VALID);
if (file && has_offset) {
bdrv_refresh_filename(file);
filename = file->filename;
}
*e = (MapEntry) {
.start = offset,
.length = bytes,
@ -2819,8 +2825,8 @@ static int get_block_status(BlockDriverState *bs, int64_t offset,
.offset = map,
.has_offset = has_offset,
.depth = depth,
.has_filename = file && has_offset,
.filename = file && has_offset ? file->filename : NULL,
.has_filename = filename,
.filename = filename,
};
return 0;
@ -2926,7 +2932,7 @@ static int img_map(int argc, char **argv)
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
NULL, NULL)) {
NULL, &error_fatal)) {
return 1;
}
@ -3075,7 +3081,7 @@ static int img_snapshot(int argc, char **argv)
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
NULL, NULL)) {
NULL, &error_fatal)) {
return 1;
}
@ -3117,11 +3123,18 @@ static int img_snapshot(int argc, char **argv)
break;
case SNAPSHOT_DELETE:
bdrv_snapshot_delete_by_id_or_name(bs, snapshot_name, &err);
if (err) {
error_reportf_err(err, "Could not delete snapshot '%s': ",
snapshot_name);
ret = bdrv_snapshot_find(bs, &sn, snapshot_name);
if (ret < 0) {
error_report("Could not delete snapshot '%s': snapshot not "
"found", snapshot_name);
ret = 1;
} else {
ret = bdrv_snapshot_delete(bs, sn.id_str, sn.name, &err);
if (ret < 0) {
error_reportf_err(err, "Could not delete snapshot '%s': ",
snapshot_name);
ret = 1;
}
}
break;
}
@ -3235,7 +3248,7 @@ static int img_rebase(int argc, char **argv)
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
NULL, NULL)) {
NULL, &error_fatal)) {
return 1;
}
@ -3321,20 +3334,17 @@ static int img_rebase(int argc, char **argv)
qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true);
}
bdrv_refresh_filename(bs);
overlay_filename = bs->exact_filename[0] ? bs->exact_filename
: bs->filename;
out_real_path = g_malloc(PATH_MAX);
bdrv_get_full_backing_filename_from_filename(overlay_filename,
out_baseimg,
out_real_path,
PATH_MAX,
&local_err);
out_real_path =
bdrv_get_full_backing_filename_from_filename(overlay_filename,
out_baseimg,
&local_err);
if (local_err) {
error_reportf_err(local_err,
"Could not resolve backing filename: ");
ret = -1;
g_free(out_real_path);
goto out;
}
@ -3615,7 +3625,7 @@ static int img_resize(int argc, char **argv)
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
NULL, NULL)) {
NULL, &error_fatal)) {
return 1;
}
@ -3859,7 +3869,7 @@ static int img_amend(int argc, char **argv)
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
NULL, NULL)) {
NULL, &error_fatal)) {
ret = -1;
goto out_no_progress;
}
@ -4503,7 +4513,7 @@ static int img_dd(int argc, char **argv)
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
NULL, NULL)) {
NULL, &error_fatal)) {
ret = -1;
goto out;
}
@ -4780,7 +4790,7 @@ static int img_measure(int argc, char **argv)
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
NULL, NULL)) {
NULL, &error_fatal)) {
goto out;
}

View File

@ -144,10 +144,9 @@ class QEMUMachine(object):
return False
# This can be used to add an unused monitor instance.
def add_monitor_telnet(self, ip, port):
args = 'tcp:%s:%d,server,nowait,telnet' % (ip, port)
def add_monitor_null(self):
self._args.append('-monitor')
self._args.append(args)
self._args.append('null')
def add_fd(self, fd, fdset, opaque, opts=''):
"""

View File

@ -70,6 +70,7 @@ check-unit-y += tests/test-throttle$(EXESUF)
check-unit-y += tests/test-thread-pool$(EXESUF)
check-unit-y += tests/test-hbitmap$(EXESUF)
check-unit-y += tests/test-bdrv-drain$(EXESUF)
check-unit-y += tests/test-bdrv-graph-mod$(EXESUF)
check-unit-y += tests/test-blockjob$(EXESUF)
check-unit-y += tests/test-blockjob-txn$(EXESUF)
check-unit-y += tests/test-block-backend$(EXESUF)
@ -561,6 +562,7 @@ tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y)
tests/test-aio-multithread$(EXESUF): tests/test-aio-multithread.o $(test-block-obj-y)
tests/test-throttle$(EXESUF): tests/test-throttle.o $(test-block-obj-y)
tests/test-bdrv-drain$(EXESUF): tests/test-bdrv-drain.o $(test-block-obj-y) $(test-util-obj-y)
tests/test-bdrv-graph-mod$(EXESUF): tests/test-bdrv-graph-mod.o $(test-block-obj-y) $(test-util-obj-y)
tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-util-obj-y)
tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y)
tests/test-block-backend$(EXESUF): tests/test-block-backend.o $(test-block-obj-y) $(test-util-obj-y)

View File

@ -132,7 +132,7 @@ class TestSCMFd(iotests.QMPTestCase):
qemu_img('create', '-f', iotests.imgfmt, image0, '128K')
# Add an unused monitor, to verify it works fine when two monitor
# instances present
self.vm.add_monitor_telnet("0",4445)
self.vm.add_monitor_null()
self.vm.launch()
def tearDown(self):

View File

@ -82,7 +82,7 @@ QEMU X.Y.Z monitor - type 'help' for more information
Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig,if=none,id=drive0 -nodefaults
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) info block
drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.orig"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2)
Removable device: not locked, tray closed
Cache mode: writeback
Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1)
@ -172,7 +172,7 @@ QEMU_PROG: -drive driver=null-co,cache=invalid_value: invalid cache option
Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) info block
drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2)
Removable device: not locked, tray closed
Cache mode: writeback
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
@ -192,7 +192,7 @@ backing-file: TEST_DIR/t.qcow2.base (file, read-only)
Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) info block
drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2)
Removable device: not locked, tray closed
Cache mode: writethrough
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
@ -212,7 +212,7 @@ backing-file: TEST_DIR/t.qcow2.base (file, read-only)
Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) info block
drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2)
Removable device: not locked, tray closed
Cache mode: writeback, ignore flushes
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)

View File

@ -82,7 +82,7 @@ QEMU X.Y.Z monitor - type 'help' for more information
Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig,if=none,id=drive0 -nodefaults
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) info block
drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.orig"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2)
Removable device: not locked, tray closed
Cache mode: writeback
Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1)
@ -244,7 +244,7 @@ QEMU_PROG: -drive driver=null-co,cache=invalid_value: invalid cache option
Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) info block
drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2)
Removable device: not locked, tray closed
Cache mode: writeback
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
@ -264,7 +264,7 @@ backing-file: TEST_DIR/t.qcow2.base (file, read-only)
Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) info block
drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2)
Removable device: not locked, tray closed
Cache mode: writethrough
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
@ -284,7 +284,7 @@ backing-file: TEST_DIR/t.qcow2.base (file, read-only)
Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) info block
drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2.base"}}, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}} (qcow2)
Removable device: not locked, tray closed
Cache mode: writeback, ignore flushes
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)

View File

@ -29,6 +29,7 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
rm -f "$TEST_IMG.copy"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@ -60,7 +61,8 @@ echo '=== Non-reconstructable filename ==='
echo
# Across blkdebug without a config file, you cannot reconstruct filenames, so
# qemu is incapable of knowing the directory of the top image
# qemu is incapable of knowing the directory of the top image from the filename
# alone. However, using bdrv_dirname(), it should still work.
TEST_IMG="json:{
'driver': '$IMGFMT',
'file': {
@ -85,6 +87,31 @@ echo
# omit the image size; it should work anyway
_make_test_img -b "$TEST_IMG_REL.base"
echo
echo '=== Nodes without a common directory ==='
echo
cp "$TEST_IMG" "$TEST_IMG.copy"
# Should inform us that the actual path of the backing file cannot be determined
TEST_IMG="json:{
'driver': '$IMGFMT',
'file': {
'driver': 'quorum',
'vote-threshold': 1,
'children': [
{
'driver': 'file',
'filename': '$TEST_IMG'
},
{
'driver': 'file',
'filename': '$TEST_IMG.copy'
}
]
}
}" _img_info | _filter_img_info
# success, all done
echo '*** done'

View File

@ -14,9 +14,16 @@ backing file: t.IMGFMT.base (actual path: TEST_DIR/t.IMGFMT.base)
image: json:{"driver": "IMGFMT", "file": {"set-state.0.event": "read_aio", "image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "set-state.0.new_state": 42}}
file format: IMGFMT
virtual size: 64M (67108864 bytes)
backing file: t.IMGFMT.base (cannot determine actual path)
backing file: t.IMGFMT.base (actual path: TEST_DIR/t.IMGFMT.base)
=== Backing name is always relative to the backed image ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=t.IMGFMT.base
=== Nodes without a common directory ===
image: json:{"driver": "IMGFMT", "file": {"children": [{"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, {"driver": "file", "filename": "TEST_DIR/t.IMGFMT.copy"}], "driver": "quorum", "vote-threshold": 1}}
file format: IMGFMT
virtual size: 64M (67108864 bytes)
backing file: t.IMGFMT.base (cannot determine actual path)
*** done

View File

@ -142,6 +142,14 @@ for ofmt in human json; do
# The backing file doesn't need to exist :)
$QEMU_IMG measure --output=$ofmt -o backing_file=x \
-f "$fmt" -O "$IMGFMT" "$TEST_IMG"
echo
echo "== $fmt input image and LUKS encryption =="
echo
$QEMU_IMG measure --output=$ofmt \
--object secret,id=sec0,data=base \
-o encrypt.format=luks,encrypt.key-secret=sec0,encrypt.iter-time=10 \
-f "$fmt" -O "$IMGFMT" "$TEST_IMG"
fi
echo

View File

@ -68,6 +68,11 @@ converted image file size in bytes: 458752
required size: 1074135040
fully allocated size: 1074135040
== qcow2 input image and LUKS encryption ==
required size: 2686976
fully allocated size: 1076232192
== qcow2 input image and preallocation (human) ==
required size: 1074135040
@ -114,6 +119,11 @@ converted image file size in bytes: 524288
required size: 1074135040
fully allocated size: 1074135040
== raw input image and LUKS encryption ==
required size: 2686976
fully allocated size: 1076232192
== raw input image and preallocation (human) ==
required size: 1074135040
@ -205,6 +215,13 @@ converted image file size in bytes: 458752
"fully-allocated": 1074135040
}
== qcow2 input image and LUKS encryption ==
{
"required": 2686976,
"fully-allocated": 1076232192
}
== qcow2 input image and preallocation (json) ==
{
@ -263,6 +280,13 @@ converted image file size in bytes: 524288
"fully-allocated": 1074135040
}
== raw input image and LUKS encryption ==
{
"required": 2686976,
"fully-allocated": 1076232192
}
== raw input image and preallocation (json) ==
{

View File

@ -1,13 +1,13 @@
=== Successful image creation (defaults) ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "node_name": "imgfile"}}
{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "node-name": "imgfile"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "imgfile", "size": 134217728}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "imgfile", "size": 134217728}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -24,12 +24,12 @@ Format specific information:
=== Successful image creation (inline blockdev-add, explicit defaults) ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": false, "preallocation": "off", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": false, "preallocation": "off", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 65536, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": false, "preallocation": "off", "refcount-bits": 16, "size": 67108864, "version": "v3"}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 65536, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": false, "preallocation": "off", "refcount-bits": 16, "size": 67108864, "version": "v3"}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -46,12 +46,12 @@ Format specific information:
=== Successful image creation (v3 non-default options) ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": true, "preallocation": "falloc", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "nocow": true, "preallocation": "falloc", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 2097152, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": true, "preallocation": "metadata", "refcount-bits": 1, "size": 33554432, "version": "v3"}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 2097152, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "lazy-refcounts": true, "preallocation": "metadata", "refcount-bits": 1, "size": 33554432, "version": "v3"}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -68,12 +68,12 @@ Format specific information:
=== Successful image creation (v2 non-default options) ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"backing-file": "TEST_DIR/PID-t.qcow2.base", "backing-fmt": "qcow2", "cluster-size": 512, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "size": 33554432, "version": "v2"}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"backing-file": "TEST_DIR/PID-t.qcow2.base", "backing-fmt": "qcow2", "cluster-size": 512, "driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "size": 33554432, "version": "v2"}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -90,7 +90,7 @@ Format specific information:
=== Successful image creation (encrypted) ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "encrypt": {"cipher-alg": "twofish-128", "cipher-mode": "ctr", "format": "luks", "hash-alg": "sha1", "iter-time": 10, "ivgen-alg": "plain64", "ivgen-hash-alg": "md5", "key-secret": "keysec0"}, "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "size": 33554432}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "encrypt": {"cipher-alg": "twofish-128", "cipher-mode": "ctr", "format": "luks", "hash-alg": "sha1", "iter-time": 10, "ivgen-alg": "plain64", "ivgen-hash-alg": "md5", "key-secret": "keysec0"}, "file": {"driver": "file", "filename": "TEST_DIR/PID-t.qcow2"}, "size": 33554432}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -144,111 +144,111 @@ Format specific information:
=== Invalid BlockdevRef ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "this doesn't exist", "size": 33554432}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "this doesn't exist", "size": 33554432}}}
{"return": {}}
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
=== Invalid sizes ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 1234}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 1234}}}
{"return": {}}
Job failed: Image size must be a multiple of 512 bytes
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 18446744073709551104}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 18446744073709551104}}}
{"return": {}}
Job failed: Could not resize image: Image size cannot be negative
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775808}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775808}}}
{"return": {}}
Job failed: Could not resize image: Image size cannot be negative
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775296}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775296}}}
{"return": {}}
Job failed: Could not resize image: Failed to grow the L1 table: File too large
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
=== Invalid version ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 67108864, "version": "v1"}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 67108864, "version": "v1"}}}
{"error": {"class": "GenericError", "desc": "Invalid parameter 'v1'"}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "lazy-refcounts": true, "size": 67108864, "version": "v2"}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "lazy-refcounts": true, "size": 67108864, "version": "v2"}}}
{"return": {}}
Job failed: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater)
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 8, "size": 67108864, "version": "v2"}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 8, "size": 67108864, "version": "v2"}}}
{"return": {}}
Job failed: Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater)
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
=== Invalid backing file options ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"backing-file": "/dev/null", "driver": "qcow2", "file": "node0", "preallocation": "full", "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"backing-file": "/dev/null", "driver": "qcow2", "file": "node0", "preallocation": "full", "size": 67108864}}}
{"return": {}}
Job failed: Backing file and preallocation cannot be used at the same time
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"backing-fmt": "qcow2", "driver": "qcow2", "file": "node0", "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"backing-fmt": "qcow2", "driver": "qcow2", "file": "node0", "size": 67108864}}}
{"return": {}}
Job failed: Backing format cannot be used without backing file
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
=== Invalid cluster size ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 1234, "driver": "qcow2", "file": "node0", "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 1234, "driver": "qcow2", "file": "node0", "size": 67108864}}}
{"return": {}}
Job failed: Cluster size must be a power of two between 512 and 2048k
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 128, "driver": "qcow2", "file": "node0", "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 128, "driver": "qcow2", "file": "node0", "size": 67108864}}}
{"return": {}}
Job failed: Cluster size must be a power of two between 512 and 2048k
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 4194304, "driver": "qcow2", "file": "node0", "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 4194304, "driver": "qcow2", "file": "node0", "size": 67108864}}}
{"return": {}}
Job failed: Cluster size must be a power of two between 512 and 2048k
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 0, "driver": "qcow2", "file": "node0", "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 0, "driver": "qcow2", "file": "node0", "size": 67108864}}}
{"return": {}}
Job failed: Cluster size must be a power of two between 512 and 2048k
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 512, "driver": "qcow2", "file": "node0", "size": 281474976710656}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 512, "driver": "qcow2", "file": "node0", "size": 281474976710656}}}
{"return": {}}
Job failed: Could not resize image: Failed to grow the L1 table: File too large
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
=== Invalid refcount width ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 128, "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 128, "size": 67108864}}}
{"return": {}}
Job failed: Refcount width must be a power of two and may not exceed 64 bits
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 0, "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 0, "size": 67108864}}}
{"return": {}}
Job failed: Refcount width must be a power of two and may not exceed 64 bits
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 7, "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "refcount-bits": 7, "size": 67108864}}}
{"return": {}}
Job failed: Refcount width must be a power of two and may not exceed 64 bits
{"execute": "job-dismiss", "arguments": {"id": "job0"}}

View File

@ -27,12 +27,16 @@ import re
iotests.verify_image_format(supported_fmts=['raw'])
iotests.verify_protocol(supported=['ssh'])
def filter_hash(msg):
return re.sub('"hash": "[0-9a-f]+"', '"hash": HASH', msg)
def filter_hash(qmsg):
def _filter(key, value):
if key == 'hash' and re.match('[0-9a-f]+', value):
return 'HASH'
return value
return iotests.filter_qmp(qmsg, _filter)
def blockdev_create(vm, options):
result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
filters=[iotests.filter_testfiles, filter_hash])
filters=[iotests.filter_qmp_testfiles, filter_hash])
if 'return' in result:
assert result['return'] == {}

View File

@ -1,6 +1,6 @@
=== Successful image creation (defaults) ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -16,7 +16,7 @@ virtual size: 4.0M (4194304 bytes)
=== Test host-key-check options ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -25,7 +25,7 @@ image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.po
file format: IMGFMT
virtual size: 8.0M (8388608 bytes)
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "known_hosts"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "known_hosts"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -34,13 +34,13 @@ image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.po
file format: IMGFMT
virtual size: 4.0M (4194304 bytes)
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "wrong", "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 2097152}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "wrong", "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 2097152}}}
{"return": {}}
Job failed: remote host key does not match host_key_check 'wrong'
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": HASH, "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "HASH", "mode": "hash", "type": "md5"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 8388608}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -49,13 +49,13 @@ image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.po
file format: IMGFMT
virtual size: 8.0M (8388608 bytes)
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "wrong", "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 2097152}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "wrong", "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 2097152}}}
{"return": {}}
Job failed: remote host key does not match host_key_check 'wrong'
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": HASH, "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"hash": "HASH", "mode": "hash", "type": "sha1"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -66,13 +66,13 @@ virtual size: 4.0M (4194304 bytes)
=== Invalid path and user ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "/this/is/not/an/existing/path", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "/this/is/not/an/existing/path", "server": {"host": "127.0.0.1", "port": "22"}}, "size": 4194304}}}
{"return": {}}
Job failed: failed to open remote file '/this/is/not/an/existing/path': Failed opening remote file (libssh2 error code: -31)
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}, "user": "invalid user"}, "size": 4194304}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}, "user": "invalid user"}, "size": 4194304}}}
{"return": {}}
Job failed: failed to authenticate using publickey authentication and the identities held by your ssh-agent
{"execute": "job-dismiss", "arguments": {"id": "job0"}}

View File

@ -27,7 +27,8 @@ iotests.verify_image_format(supported_fmts=['luks'])
iotests.verify_protocol(supported=['file'])
def blockdev_create(vm, options):
result = vm.qmp_log('blockdev-create', job_id='job0', options=options)
result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
filters=[iotests.filter_qmp_testfiles])
if 'return' in result:
assert result['return'] == {}
@ -53,7 +54,7 @@ with iotests.FilePath('t.luks') as disk_path, \
'size': 0 })
vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
node_name='imgfile')
node_name='imgfile', filters=[iotests.filter_qmp_testfiles])
blockdev_create(vm, { 'driver': imgfmt,
'file': 'imgfile',

View File

@ -1,13 +1,13 @@
=== Successful image creation (defaults) ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "node_name": "imgfile"}}
{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "node-name": "imgfile"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "imgfile", "iter-time": 10, "key-secret": "keysec0", "size": 134217728}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "imgfile", "iter-time": 10, "key-secret": "keysec0", "size": 134217728}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -54,12 +54,12 @@ Format specific information:
=== Successful image creation (with non-default options) ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.luks", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cipher-alg": "twofish-128", "cipher-mode": "ctr", "driver": "luks", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.luks"}, "hash-alg": "sha1", "iter-time": 10, "ivgen-alg": "plain64", "ivgen-hash-alg": "md5", "key-secret": "keysec0", "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cipher-alg": "twofish-128", "cipher-mode": "ctr", "driver": "luks", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.luks"}, "hash-alg": "sha1", "iter-time": 10, "ivgen-alg": "plain64", "ivgen-hash-alg": "md5", "key-secret": "keysec0", "size": 67108864}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -106,7 +106,7 @@ Format specific information:
=== Invalid BlockdevRef ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "this doesn't exist", "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "this doesn't exist", "size": 67108864}}}
{"return": {}}
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
@ -114,7 +114,7 @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi
=== Zero size ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "node0", "iter-time": 10, "key-secret": "keysec0", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "node0", "iter-time": 10, "key-secret": "keysec0", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -161,19 +161,19 @@ Format specific information:
=== Invalid sizes ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 18446744073709551104}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 18446744073709551104}}}
{"return": {}}
Job failed: The requested file size is too large
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 9223372036854775808}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 9223372036854775808}}}
{"return": {}}
Job failed: The requested file size is too large
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 9223372036854775296}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "luks", "file": "node0", "key-secret": "keysec0", "size": 9223372036854775296}}}
{"return": {}}
Job failed: The requested file size is too large
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
@ -181,13 +181,13 @@ Job failed: The requested file size is too large
=== Resize image with invalid sizes ===
{"execute": "block_resize", "arguments": {"node_name": "node1", "size": 9223372036854775296}}
{"execute": "block_resize", "arguments": {"node-name": "node1", "size": 9223372036854775296}}
{"error": {"class": "GenericError", "desc": "The requested file size is too large"}}
{"execute": "block_resize", "arguments": {"node_name": "node1", "size": 9223372036854775808}}
{"execute": "block_resize", "arguments": {"node-name": "node1", "size": 9223372036854775808}}
{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}}
{"execute": "block_resize", "arguments": {"node_name": "node1", "size": 18446744073709551104}}
{"execute": "block_resize", "arguments": {"node-name": "node1", "size": 18446744073709551104}}
{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'size', expected: integer"}}
{"execute": "block_resize", "arguments": {"node_name": "node1", "size": -9223372036854775808}}
{"execute": "block_resize", "arguments": {"node-name": "node1", "size": -9223372036854775808}}
{"error": {"class": "GenericError", "desc": "Parameter 'size' expects a >0 size"}}
image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_IMG"}, "key-secret": "keysec0"}
file format: IMGFMT

View File

@ -27,11 +27,14 @@ iotests.verify_image_format(supported_fmts=['vdi'])
iotests.verify_protocol(supported=['file'])
def blockdev_create(vm, options):
result = vm.qmp_log('blockdev-create', job_id='job0', options=options)
result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
filters=[iotests.filter_qmp_testfiles])
if 'return' in result:
assert result['return'] == {}
vm.run_job('job0')
error = vm.run_job('job0')
if error and 'Could not allocate bmap' in error:
iotests.notrun('Insufficient memory')
iotests.log("")
with iotests.FilePath('t.vdi') as disk_path, \
@ -51,7 +54,7 @@ with iotests.FilePath('t.vdi') as disk_path, \
'size': 0 })
vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
node_name='imgfile')
node_name='imgfile', filters=[iotests.filter_qmp_testfiles])
blockdev_create(vm, { 'driver': imgfmt,
'file': 'imgfile',

View File

@ -1,13 +1,13 @@
=== Successful image creation (defaults) ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "node_name": "imgfile"}}
{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "node-name": "imgfile"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "imgfile", "size": 134217728}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "imgfile", "size": 134217728}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -21,12 +21,12 @@ cluster_size: 1048576
=== Successful image creation (explicit defaults) ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi"}, "preallocation": "off", "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi"}, "preallocation": "off", "size": 67108864}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -40,12 +40,12 @@ cluster_size: 1048576
=== Successful image creation (with non-default options) ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi"}, "preallocation": "metadata", "size": 33554432}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi"}, "preallocation": "metadata", "size": 33554432}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -60,7 +60,7 @@ cluster_size: 1048576
=== Invalid BlockdevRef ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "this doesn't exist", "size": 33554432}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "this doesn't exist", "size": 33554432}}}
{"return": {}}
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
@ -68,7 +68,7 @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi
=== Zero size ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -80,7 +80,7 @@ cluster_size: 1048576
=== Maximum size ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 562949819203584}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 562949819203584}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -92,19 +92,19 @@ cluster_size: 1048576
=== Invalid sizes ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 18446744073709551104}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 18446744073709551104}}}
{"return": {}}
Job failed: Unsupported VDI image size (size is 0xfffffffffffffe00, max supported is 0x1fffff8000000)
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 9223372036854775808}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 9223372036854775808}}}
{"return": {}}
Job failed: Unsupported VDI image size (size is 0x8000000000000000, max supported is 0x1fffff8000000)
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 562949819203585}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "node0", "size": 562949819203585}}}
{"return": {}}
Job failed: Unsupported VDI image size (size is 0x1fffff8000001, max supported is 0x1fffff8000000)
{"execute": "job-dismiss", "arguments": {"id": "job0"}}

View File

@ -27,7 +27,8 @@ iotests.verify_image_format(supported_fmts=['parallels'])
iotests.verify_protocol(supported=['file'])
def blockdev_create(vm, options):
result = vm.qmp_log('blockdev-create', job_id='job0', options=options)
result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
filters=[iotests.filter_qmp_testfiles])
if 'return' in result:
assert result['return'] == {}
@ -51,7 +52,7 @@ with iotests.FilePath('t.parallels') as disk_path, \
'size': 0 })
vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
node_name='imgfile')
node_name='imgfile', filters=[iotests.filter_qmp_testfiles])
blockdev_create(vm, { 'driver': imgfmt,
'file': 'imgfile',

View File

@ -1,13 +1,13 @@
=== Successful image creation (defaults) ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "node_name": "imgfile"}}
{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "node-name": "imgfile"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "imgfile", "size": 134217728}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "imgfile", "size": 134217728}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -18,12 +18,12 @@ virtual size: 128M (134217728 bytes)
=== Successful image creation (explicit defaults) ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 1048576, "driver": "parallels", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels"}, "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 1048576, "driver": "parallels", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels"}, "size": 67108864}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -34,12 +34,12 @@ virtual size: 64M (67108864 bytes)
=== Successful image creation (with non-default options) ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 65536, "driver": "parallels", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels"}, "size": 33554432}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 65536, "driver": "parallels", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.parallels"}, "size": 33554432}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -50,7 +50,7 @@ virtual size: 32M (33554432 bytes)
=== Invalid BlockdevRef ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "this doesn't exist", "size": 33554432}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "this doesn't exist", "size": 33554432}}}
{"return": {}}
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
@ -58,7 +58,7 @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi
=== Zero size ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -69,7 +69,7 @@ virtual size: 0 (0 bytes)
=== Maximum size ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 4503599627369984}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 4503599627369984}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -80,31 +80,31 @@ virtual size: 4096T (4503599627369984 bytes)
=== Invalid sizes ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 1234}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 1234}}}
{"return": {}}
Job failed: Image size must be a multiple of 512 bytes
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 18446744073709551104}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 18446744073709551104}}}
{"return": {}}
Job failed: Image size is too large for this cluster size
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 9223372036854775808}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 9223372036854775808}}}
{"return": {}}
Job failed: Image size is too large for this cluster size
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 9223372036854775296}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 9223372036854775296}}}
{"return": {}}
Job failed: Image size is too large for this cluster size
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 4503599627370497}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "parallels", "file": "node0", "size": 4503599627370497}}}
{"return": {}}
Job failed: Image size is too large for this cluster size
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
@ -112,43 +112,43 @@ Job failed: Image size is too large for this cluster size
=== Invalid cluster size ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 1234, "driver": "parallels", "file": "node0", "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 1234, "driver": "parallels", "file": "node0", "size": 67108864}}}
{"return": {}}
Job failed: Cluster size must be a multiple of 512 bytes
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 128, "driver": "parallels", "file": "node0", "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 128, "driver": "parallels", "file": "node0", "size": 67108864}}}
{"return": {}}
Job failed: Cluster size must be a multiple of 512 bytes
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 4294967296, "driver": "parallels", "file": "node0", "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 4294967296, "driver": "parallels", "file": "node0", "size": 67108864}}}
{"return": {}}
Job failed: Cluster size is too large
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 9223372036854775808, "driver": "parallels", "file": "node0", "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 9223372036854775808, "driver": "parallels", "file": "node0", "size": 67108864}}}
{"return": {}}
Job failed: Cluster size is too large
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 18446744073709551104, "driver": "parallels", "file": "node0", "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 18446744073709551104, "driver": "parallels", "file": "node0", "size": 67108864}}}
{"return": {}}
Job failed: Cluster size is too large
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 0, "driver": "parallels", "file": "node0", "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 0, "driver": "parallels", "file": "node0", "size": 67108864}}}
{"return": {}}
Job failed: Image size is too large for this cluster size
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"cluster-size": 512, "driver": "parallels", "file": "node0", "size": 281474976710656}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"cluster-size": 512, "driver": "parallels", "file": "node0", "size": 281474976710656}}}
{"return": {}}
Job failed: Image size is too large for this cluster size
{"execute": "job-dismiss", "arguments": {"id": "job0"}}

View File

@ -27,7 +27,8 @@ iotests.verify_image_format(supported_fmts=['vhdx'])
iotests.verify_protocol(supported=['file'])
def blockdev_create(vm, options):
result = vm.qmp_log('blockdev-create', job_id='job0', options=options)
result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
filters=[iotests.filter_qmp_testfiles])
if 'return' in result:
assert result['return'] == {}
@ -51,7 +52,7 @@ with iotests.FilePath('t.vhdx') as disk_path, \
'size': 0 })
vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
node_name='imgfile')
node_name='imgfile', filters=[iotests.filter_qmp_testfiles])
blockdev_create(vm, { 'driver': imgfmt,
'file': 'imgfile',

View File

@ -1,13 +1,13 @@
=== Successful image creation (defaults) ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "node_name": "imgfile"}}
{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "node-name": "imgfile"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "imgfile", "size": 134217728}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "imgfile", "size": 134217728}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -19,12 +19,12 @@ cluster_size: 8388608
=== Successful image creation (explicit defaults) ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 8388608, "block-state-zero": true, "driver": "vhdx", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx"}, "log-size": 1048576, "size": 67108864, "subformat": "dynamic"}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 8388608, "block-state-zero": true, "driver": "vhdx", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx"}, "log-size": 1048576, "size": 67108864, "subformat": "dynamic"}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -36,12 +36,12 @@ cluster_size: 8388608
=== Successful image creation (with non-default options) ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 268435456, "block-state-zero": false, "driver": "vhdx", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx"}, "log-size": 8388608, "size": 33554432, "subformat": "fixed"}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 268435456, "block-state-zero": false, "driver": "vhdx", "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vhdx"}, "log-size": 8388608, "size": 33554432, "subformat": "fixed"}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -53,7 +53,7 @@ cluster_size: 268435456
=== Invalid BlockdevRef ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "this doesn't exist", "size": 33554432}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "this doesn't exist", "size": 33554432}}}
{"return": {}}
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
@ -61,7 +61,7 @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi
=== Zero size ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -73,7 +73,7 @@ cluster_size: 8388608
=== Maximum size ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 70368744177664}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 70368744177664}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -85,25 +85,25 @@ cluster_size: 67108864
=== Invalid sizes ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 18446744073709551104}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 18446744073709551104}}}
{"return": {}}
Job failed: Image size too large; max of 64TB
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 9223372036854775808}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 9223372036854775808}}}
{"return": {}}
Job failed: Image size too large; max of 64TB
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 9223372036854775296}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 9223372036854775296}}}
{"return": {}}
Job failed: Image size too large; max of 64TB
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 70368744177665}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "size": 70368744177665}}}
{"return": {}}
Job failed: Image size too large; max of 64TB
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
@ -111,31 +111,31 @@ Job failed: Image size too large; max of 64TB
=== Invalid block size ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 1234567, "driver": "vhdx", "file": "node0", "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 1234567, "driver": "vhdx", "file": "node0", "size": 67108864}}}
{"return": {}}
Job failed: Block size must be a multiple of 1 MB
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 128, "driver": "vhdx", "file": "node0", "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 128, "driver": "vhdx", "file": "node0", "size": 67108864}}}
{"return": {}}
Job failed: Block size must be a multiple of 1 MB
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 3145728, "driver": "vhdx", "file": "node0", "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 3145728, "driver": "vhdx", "file": "node0", "size": 67108864}}}
{"return": {}}
Job failed: Block size must be a power of two
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 536870912, "driver": "vhdx", "file": "node0", "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 536870912, "driver": "vhdx", "file": "node0", "size": 67108864}}}
{"return": {}}
Job failed: Block size must not exceed 268435456
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"block-size": 0, "driver": "vhdx", "file": "node0", "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"block-size": 0, "driver": "vhdx", "file": "node0", "size": 67108864}}}
{"return": {}}
Job failed: Block size must be a multiple of 1 MB
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
@ -143,25 +143,25 @@ Job failed: Block size must be a multiple of 1 MB
=== Invalid log size ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 1234567, "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 1234567, "size": 67108864}}}
{"return": {}}
Job failed: Log size must be a multiple of 1 MB
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 128, "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 128, "size": 67108864}}}
{"return": {}}
Job failed: Log size must be a multiple of 1 MB
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 4294967296, "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 4294967296, "size": 67108864}}}
{"return": {}}
Job failed: Log size must be smaller than 4 GB
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 0, "size": 67108864}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vhdx", "file": "node0", "log-size": 0, "size": 67108864}}}
{"return": {}}
Job failed: Log size must be a multiple of 1 MB
{"execute": "job-dismiss", "arguments": {"id": "job0"}}

139
tests/qemu-iotests/224 Executable file
View File

@ -0,0 +1,139 @@
#!/usr/bin/env python
#
# Test json:{} filenames with qemu-internal BDSs
# (the one of commit, to be precise)
#
# Copyright (C) 2018 Red Hat, Inc.
#
# 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: Max Reitz <mreitz@redhat.com>
import iotests
from iotests import log, qemu_img, qemu_io_silent, filter_qmp_testfiles, \
filter_qmp_imgfmt
import json
# Need backing file support (for arbitrary backing formats)
iotests.verify_image_format(supported_fmts=['qcow2', 'qcow', 'qed'])
iotests.verify_platform(['linux'])
# There are two variations of this test:
# (1) We do not set filter_node_name. In that case, the commit_top
# driver should not appear anywhere.
# (2) We do set filter_node_name. In that case, it should appear.
#
# This for loop executes both.
for filter_node_name in False, True:
log('')
log('--- filter_node_name: %s ---' % filter_node_name)
log('')
with iotests.FilePath('base.img') as base_img_path, \
iotests.FilePath('mid.img') as mid_img_path, \
iotests.FilePath('top.img') as top_img_path, \
iotests.VM() as vm:
assert qemu_img('create', '-f', iotests.imgfmt,
base_img_path, '64M') == 0
assert qemu_img('create', '-f', iotests.imgfmt, '-b', base_img_path,
mid_img_path) == 0
assert qemu_img('create', '-f', iotests.imgfmt, '-b', mid_img_path,
top_img_path) == 0
# Something to commit
assert qemu_io_silent(mid_img_path, '-c', 'write -P 1 0 1M') == 0
vm.launch()
# Change the bottom-most image's backing file (to null-co://)
# to enforce json:{} filenames
vm.qmp_log('blockdev-add',
node_name='top',
driver=iotests.imgfmt,
file={
'driver': 'file',
'filename': top_img_path
},
backing={
'node-name': 'mid',
'driver': iotests.imgfmt,
'file': {
'driver': 'file',
'filename': mid_img_path
},
'backing': {
'node-name': 'base',
'driver': iotests.imgfmt,
'file': {
'driver': 'file',
'filename': base_img_path
},
'backing': {
'driver': 'null-co'
}
}
},
filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
# As long as block-commit does not accept node names, we have to
# get our mid/base filenames here
mid_name = vm.node_info('mid')['image']['filename']
base_name = vm.node_info('base')['image']['filename']
assert mid_name[:5] == 'json:'
assert base_name[:5] == 'json:'
# Start the block job
if filter_node_name:
vm.qmp_log('block-commit',
job_id='commit',
device='top',
filter_node_name='filter_node',
top=mid_name,
base=base_name,
speed=1,
filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
else:
vm.qmp_log('block-commit',
job_id='commit',
device='top',
top=mid_name,
base=base_name,
speed=1,
filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
vm.qmp_log('job-pause', id='commit')
# Get and parse top's json:{} filename
top_name = vm.node_info('top')['image']['filename']
vm.shutdown()
assert top_name[:5] == 'json:'
top_options = json.loads(top_name[5:])
if filter_node_name:
# This should be present and set
assert top_options['backing']['driver'] == 'commit_top'
# And the mid image is commit_top's backing image
mid_options = top_options['backing']['backing']
else:
# The mid image should appear as the immediate backing BDS
# of top
mid_options = top_options['backing']
assert mid_options['driver'] == iotests.imgfmt
assert mid_options['file']['filename'] == mid_img_path

View File

@ -0,0 +1,18 @@
--- filter_node_name: False ---
{"execute": "blockdev-add", "arguments": {"backing": {"backing": {"backing": {"driver": "null-co"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}, "node-name": "base"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-mid.img"}, "node-name": "mid"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "top"}}
{"return": {}}
{"execute": "block-commit", "arguments": {"base": "json:{\"backing\": {\"driver\": \"null-co\"}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-base.img\"}}", "device": "top", "job-id": "commit", "speed": 1, "top": "json:{\"backing\": {\"backing\": {\"driver\": \"null-co\"}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-base.img\"}}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-mid.img\"}}"}}
{"return": {}}
{"execute": "job-pause", "arguments": {"id": "commit"}}
{"return": {}}
--- filter_node_name: True ---
{"execute": "blockdev-add", "arguments": {"backing": {"backing": {"backing": {"driver": "null-co"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}, "node-name": "base"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-mid.img"}, "node-name": "mid"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "top"}}
{"return": {}}
{"execute": "block-commit", "arguments": {"base": "json:{\"backing\": {\"driver\": \"null-co\"}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-base.img\"}}", "device": "top", "filter-node-name": "filter_node", "job-id": "commit", "speed": 1, "top": "json:{\"backing\": {\"backing\": {\"driver\": \"null-co\"}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-base.img\"}}, \"driver\": \"IMGFMT\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/PID-mid.img\"}}"}}
{"return": {}}
{"execute": "job-pause", "arguments": {"id": "commit"}}
{"return": {}}

239
tests/qemu-iotests/228 Executable file
View File

@ -0,0 +1,239 @@
#!/usr/bin/env python
#
# Test for when a backing file is considered overridden (thus, a
# json:{} filename is generated for the overlay) and when it is not
#
# Copyright (C) 2018 Red Hat, Inc.
#
# 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: Max Reitz <mreitz@redhat.com>
import iotests
from iotests import log, qemu_img, filter_testfiles, filter_imgfmt, \
filter_qmp_testfiles, filter_qmp_imgfmt
# Need backing file and change-backing-file support
iotests.verify_image_format(supported_fmts=['qcow2', 'qed'])
iotests.verify_platform(['linux'])
def log_node_info(node):
log('')
log('bs->filename: ' + node['image']['filename'],
filters=[filter_testfiles, filter_imgfmt])
log('bs->backing_file: ' + node['backing_file'],
filters=[filter_testfiles, filter_imgfmt])
if 'backing-image' in node['image']:
log('bs->backing->bs->filename: ' +
node['image']['backing-image']['filename'],
filters=[filter_testfiles, filter_imgfmt])
else:
log('bs->backing: (none)')
log('')
with iotests.FilePath('base.img') as base_img_path, \
iotests.FilePath('top.img') as top_img_path, \
iotests.VM() as vm:
assert qemu_img('create', '-f', iotests.imgfmt, base_img_path, '64M') == 0
# Choose a funny way to describe the backing filename
assert qemu_img('create', '-f', iotests.imgfmt, '-b',
'file:' + base_img_path, top_img_path) == 0
vm.launch()
log('--- Implicit backing file ---')
log('')
vm.qmp_log('blockdev-add',
node_name='node0',
driver=iotests.imgfmt,
file={
'driver': 'file',
'filename': top_img_path
},
filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
# Filename should be plain, and the backing filename should not
# contain the "file:" prefix
log_node_info(vm.node_info('node0'))
vm.qmp_log('blockdev-del', node_name='node0')
log('')
log('--- change-backing-file ---')
log('')
vm.qmp_log('blockdev-add',
node_name='node0',
driver=iotests.imgfmt,
file={
'driver': 'file',
'filename': top_img_path
},
filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
# Changing the backing file to a qemu-reported filename should
# result in qemu accepting the corresponding BDS as the implicit
# backing BDS (and thus not generate a json:{} filename).
# So, first, query the backing filename.
backing_filename = \
vm.node_info('node0')['image']['backing-image']['filename']
# Next, change the backing file to something different
vm.qmp_log('change-backing-file',
image_node_name='node0',
device='node0',
backing_file='null-co://',
filters=[filter_qmp_testfiles])
# Now, verify that we get a json:{} filename
# (Image header says "null-co://", actual backing file still is
# base_img_path)
log_node_info(vm.node_info('node0'))
# Change it back
# (To get header and backing file in sync)
vm.qmp_log('change-backing-file',
image_node_name='node0',
device='node0',
backing_file=backing_filename,
filters=[filter_qmp_testfiles])
# And verify that we get our original results
log_node_info(vm.node_info('node0'))
# Finally, try a "file:" prefix. While this is actually what we
# originally had in the image header, qemu will not reopen the
# backing file here, so it cannot verify that this filename
# "resolves" to the actual backing BDS's filename and will thus
# consider both to be different.
# (This may be fixed in the future.)
vm.qmp_log('change-backing-file',
image_node_name='node0',
device='node0',
backing_file=('file:' + backing_filename),
filters=[filter_qmp_testfiles])
# So now we should get a json:{} filename
log_node_info(vm.node_info('node0'))
# Remove and re-attach so we can see that (as in our first try),
# opening the image anew helps qemu resolve the header backing
# filename.
vm.qmp_log('blockdev-del', node_name='node0')
vm.qmp_log('blockdev-add',
node_name='node0',
driver=iotests.imgfmt,
file={
'driver': 'file',
'filename': top_img_path
},
filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
log_node_info(vm.node_info('node0'))
vm.qmp_log('blockdev-del', node_name='node0')
log('')
log('--- Override backing file ---')
log('')
# For this test, we need the plain filename in the image header
# (because qemu cannot "canonicalize"/"resolve" the backing
# filename unless the backing file is opened implicitly with the
# overlay)
assert qemu_img('create', '-f', iotests.imgfmt, '-b', base_img_path,
top_img_path) == 0
# You can only reliably override backing options by using a node
# reference (or by specifying file.filename, but, well...)
vm.qmp_log('blockdev-add', node_name='null', driver='null-co')
vm.qmp_log('blockdev-add',
node_name='node0',
driver=iotests.imgfmt,
file={
'driver': 'file',
'filename': top_img_path
},
backing='null',
filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
# Should get a json:{} filename (and bs->backing_file is
# null-co://, because that field actually has not much to do
# with the header backing filename (except that it is changed by
# change-backing-file))
log_node_info(vm.node_info('node0'))
# Detach the backing file by reopening the whole thing
vm.qmp_log('blockdev-del', node_name='node0')
vm.qmp_log('blockdev-del', node_name='null')
vm.qmp_log('blockdev-add',
node_name='node0',
driver=iotests.imgfmt,
file={
'driver': 'file',
'filename': top_img_path
},
backing=None,
filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
# Should get a json:{} filename (because we overrode the backing
# file to not be there)
log_node_info(vm.node_info('node0'))
# Open the original backing file
vm.qmp_log('blockdev-add',
node_name='original-backing',
driver=iotests.imgfmt,
file={
'driver': 'file',
'filename': base_img_path
},
filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
# Attach the original backing file to its overlay
vm.qmp_log('blockdev-snapshot',
node='original-backing',
overlay='node0')
# This should give us the original plain result
log_node_info(vm.node_info('node0'))
vm.qmp_log('blockdev-del', node_name='node0')
vm.qmp_log('blockdev-del', node_name='original-backing')
vm.shutdown()

View File

@ -0,0 +1,84 @@
--- Implicit backing file ---
{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "node0"}}
{"return": {}}
bs->filename: TEST_DIR/PID-top.img
bs->backing_file: TEST_DIR/PID-base.img
bs->backing->bs->filename: TEST_DIR/PID-base.img
{"execute": "blockdev-del", "arguments": {"node-name": "node0"}}
{"return": {}}
--- change-backing-file ---
{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "node0"}}
{"return": {}}
{"execute": "change-backing-file", "arguments": {"backing-file": "null-co://", "device": "node0", "image-node-name": "node0"}}
{"return": {}}
bs->filename: json:{"backing": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}}
bs->backing_file: null-co://
bs->backing->bs->filename: TEST_DIR/PID-base.img
{"execute": "change-backing-file", "arguments": {"backing-file": "TEST_DIR/PID-base.img", "device": "node0", "image-node-name": "node0"}}
{"return": {}}
bs->filename: TEST_DIR/PID-top.img
bs->backing_file: TEST_DIR/PID-base.img
bs->backing->bs->filename: TEST_DIR/PID-base.img
{"execute": "change-backing-file", "arguments": {"backing-file": "file:TEST_DIR/PID-base.img", "device": "node0", "image-node-name": "node0"}}
{"return": {}}
bs->filename: json:{"backing": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}}
bs->backing_file: file:TEST_DIR/PID-base.img
bs->backing->bs->filename: TEST_DIR/PID-base.img
{"execute": "blockdev-del", "arguments": {"node-name": "node0"}}
{"return": {}}
{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "node0"}}
{"return": {}}
bs->filename: TEST_DIR/PID-top.img
bs->backing_file: TEST_DIR/PID-base.img
bs->backing->bs->filename: TEST_DIR/PID-base.img
{"execute": "blockdev-del", "arguments": {"node-name": "node0"}}
{"return": {}}
--- Override backing file ---
{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "null"}}
{"return": {}}
{"execute": "blockdev-add", "arguments": {"backing": "null", "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "node0"}}
{"return": {}}
bs->filename: json:{"backing": {"driver": "null-co"}, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}}
bs->backing_file: null-co://
bs->backing->bs->filename: null-co://
{"execute": "blockdev-del", "arguments": {"node-name": "node0"}}
{"return": {}}
{"execute": "blockdev-del", "arguments": {"node-name": "null"}}
{"return": {}}
{"execute": "blockdev-add", "arguments": {"backing": null, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}, "node-name": "node0"}}
{"return": {}}
bs->filename: json:{"backing": null, "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top.img"}}
bs->backing_file: TEST_DIR/PID-base.img
bs->backing: (none)
{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-base.img"}, "node-name": "original-backing"}}
{"return": {}}
{"execute": "blockdev-snapshot", "arguments": {"node": "original-backing", "overlay": "node0"}}
{"return": {}}
bs->filename: TEST_DIR/PID-top.img
bs->backing_file: TEST_DIR/PID-base.img
bs->backing->bs->filename: TEST_DIR/PID-base.img
{"execute": "blockdev-del", "arguments": {"node-name": "node0"}}
{"return": {}}
{"execute": "blockdev-del", "arguments": {"node-name": "original-backing"}}
{"return": {}}

View File

@ -29,7 +29,6 @@ status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
rm -f $TEST_IMG.snap
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@ -70,6 +69,10 @@ size=128M
_make_test_img $size
if [ -n "$TEST_IMG_FILE" ]; then
TEST_IMG=$TEST_IMG_FILE
fi
echo
echo "=== -drive with read-write image: read-only/auto-read-only combinations ==="
echo

View File

@ -27,7 +27,8 @@ from iotests import imgfmt
iotests.verify_image_format(supported_fmts=['vmdk'])
def blockdev_create(vm, options):
result = vm.qmp_log('blockdev-create', job_id='job0', options=options)
result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
filters=[iotests.filter_qmp_testfiles])
if 'return' in result:
assert result['return'] == {}
@ -54,7 +55,7 @@ with iotests.FilePath('t.vmdk') as disk_path, \
'size': 0 })
vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
node_name='imgfile')
node_name='imgfile', filters=[iotests.filter_qmp_testfiles])
blockdev_create(vm, { 'driver': imgfmt,
'file': 'imgfile',
@ -223,7 +224,7 @@ with iotests.FilePath('t.vmdk') as disk_path, \
iotests.log("= %s %d =" % (subfmt, size))
iotests.log("")
num_extents = math.ceil(size / 2.0**31)
num_extents = int(math.ceil(size / 2.0**31))
extents = [ "ext%d" % (i) for i in range(1, num_extents + 1) ]
vm.launch()

View File

@ -1,13 +1,13 @@
=== Successful image creation (defaults) ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "node_name": "imgfile"}}
{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "node-name": "imgfile"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "file": "imgfile", "size": 5368709120}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "file": "imgfile", "size": 5368709120}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -29,12 +29,12 @@ Format specific information:
=== Successful image creation (inline blockdev-add, explicit defaults) ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "ide", "driver": "vmdk", "extents": [], "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk"}, "hwversion": "4", "size": 67108864, "subformat": "monolithicSparse", "zeroed-grain": false}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "ide", "driver": "vmdk", "extents": [], "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk"}, "hwversion": "4", "size": 67108864, "subformat": "monolithicSparse", "zeroed-grain": false}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -56,12 +56,12 @@ Format specific information:
=== Successful image creation (with non-default options) ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "buslogic", "driver": "vmdk", "extents": [], "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk"}, "size": 33554432, "subformat": "monolithicSparse", "zeroed-grain": true}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "buslogic", "driver": "vmdk", "extents": [], "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk"}, "size": 33554432, "subformat": "monolithicSparse", "zeroed-grain": true}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -83,7 +83,7 @@ Format specific information:
=== Invalid BlockdevRef ===
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "file": "this doesn't exist", "size": 33554432}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "file": "this doesn't exist", "size": 33554432}}}
{"return": {}}
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
@ -93,38 +93,38 @@ Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exi
== Valid adapter types ==
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "ide", "driver": "vmdk", "file": "node0", "size": 33554432}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "ide", "driver": "vmdk", "file": "node0", "size": 33554432}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "buslogic", "driver": "vmdk", "file": "node0", "size": 33554432}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "buslogic", "driver": "vmdk", "file": "node0", "size": 33554432}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "lsilogic", "driver": "vmdk", "file": "node0", "size": 33554432}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "lsilogic", "driver": "vmdk", "file": "node0", "size": 33554432}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "legacyESX", "driver": "vmdk", "file": "node0", "size": 33554432}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "legacyESX", "driver": "vmdk", "file": "node0", "size": 33554432}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
== Invalid adapter types ==
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "foo", "driver": "vmdk", "file": "node0", "size": 33554432}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "foo", "driver": "vmdk", "file": "node0", "size": 33554432}}}
{"error": {"class": "GenericError", "desc": "Invalid parameter 'foo'"}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "IDE", "driver": "vmdk", "file": "node0", "size": 33554432}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "IDE", "driver": "vmdk", "file": "node0", "size": 33554432}}}
{"error": {"class": "GenericError", "desc": "Invalid parameter 'IDE'"}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "legacyesx", "driver": "vmdk", "file": "node0", "size": 33554432}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": "legacyesx", "driver": "vmdk", "file": "node0", "size": 33554432}}}
{"error": {"class": "GenericError", "desc": "Invalid parameter 'legacyesx'"}}
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": 1, "driver": "vmdk", "file": "node0", "size": 33554432}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"adapter-type": 1, "driver": "vmdk", "file": "node0", "size": 33554432}}}
{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'options.adapter-type', expected: string"}}
=== Other subformats ===
@ -137,7 +137,7 @@ Formatting 'TEST_DIR/PID-t.vmdk.3', fmt=vmdk size=0 compat6=off hwversion=undefi
== Missing extent ==
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "file": "node0", "size": 33554432, "subformat": "monolithicFlat"}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "file": "node0", "size": 33554432, "subformat": "monolithicFlat"}}}
{"return": {}}
Job failed: Extent [0] not specified
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
@ -145,14 +145,14 @@ Job failed: Extent [0] not specified
== Correct extent ==
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 33554432, "subformat": "monolithicFlat"}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 33554432, "subformat": "monolithicFlat"}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
== Extra extent ==
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 512, "subformat": "monolithicFlat"}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 512, "subformat": "monolithicFlat"}}}
{"return": {}}
Job failed: List of extents contains unused extents
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
@ -162,7 +162,7 @@ Job failed: List of extents contains unused extents
= twoGbMaxExtentFlat 512 =
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentFlat"}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentFlat"}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -182,7 +182,7 @@ Format specific information:
= twoGbMaxExtentSparse 512 =
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentSparse"}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentSparse"}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -204,7 +204,7 @@ Format specific information:
= twoGbMaxExtentFlat 1073741824 =
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentFlat"}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentFlat"}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -224,7 +224,7 @@ Format specific information:
= twoGbMaxExtentSparse 1073741824 =
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentSparse"}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentSparse"}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -246,7 +246,7 @@ Format specific information:
= twoGbMaxExtentFlat 2147483648 =
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentFlat"}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentFlat"}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -266,7 +266,7 @@ Format specific information:
= twoGbMaxExtentSparse 2147483648 =
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentSparse"}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentSparse"}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -288,7 +288,7 @@ Format specific information:
= twoGbMaxExtentFlat 5368709120 =
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 5368709120, "subformat": "twoGbMaxExtentFlat"}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 5368709120, "subformat": "twoGbMaxExtentFlat"}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
@ -316,7 +316,7 @@ Format specific information:
= twoGbMaxExtentSparse 5368709120 =
{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 5368709120, "subformat": "twoGbMaxExtentSparse"}}}
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 5368709120, "subformat": "twoGbMaxExtentSparse"}}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}

View File

@ -145,6 +145,7 @@ else
TEST_IMG="nbd:127.0.0.1:10810"
elif [ "$IMGPROTO" = "ssh" ]; then
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
REMOTE_TEST_DIR="ssh://127.0.0.1$TEST_DIR"
TEST_IMG="ssh://127.0.0.1$TEST_IMG_FILE"
elif [ "$IMGPROTO" = "nfs" ]; then
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT

View File

@ -224,9 +224,11 @@
221 rw auto quick
222 rw auto quick
223 rw auto quick
224 rw auto quick
225 rw auto quick
226 auto quick
227 auto quick
228 rw auto quick
229 auto quick
231 auto quick
232 auto quick

View File

@ -76,14 +76,16 @@ def qemu_img(*args):
sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args))))
return exitcode
def ordered_qmp(qmsg):
def ordered_qmp(qmsg, conv_keys=True):
# Dictionaries are not ordered prior to 3.6, therefore:
if isinstance(qmsg, list):
return [ordered_qmp(atom) for atom in qmsg]
if isinstance(qmsg, dict):
od = OrderedDict()
for k, v in sorted(qmsg.items()):
od[k] = ordered_qmp(v)
if conv_keys:
k = k.replace('_', '-')
od[k] = ordered_qmp(v, conv_keys=False)
return od
return qmsg
@ -236,6 +238,12 @@ def image_size(img):
r = qemu_img_pipe('info', '--output=json', '-f', imgfmt, img)
return json.loads(r)['virtual-size']
def is_str(val):
if sys.version_info.major >= 3:
return isinstance(val, str)
else:
return isinstance(val, str) or isinstance(val, unicode)
test_dir_re = re.compile(r"%s" % test_dir)
def filter_test_dir(msg):
return test_dir_re.sub("TEST_DIR", msg)
@ -283,7 +291,7 @@ def filter_testfiles(msg):
def filter_qmp_testfiles(qmsg):
def _filter(key, value):
if key == 'filename' or key == 'backing-file':
if is_str(value):
return filter_testfiles(value)
return value
return filter_qmp(qmsg, _filter)
@ -304,6 +312,16 @@ def filter_img_info(output, filename):
lines.append(line)
return '\n'.join(lines)
def filter_imgfmt(msg):
return msg.replace(imgfmt, 'IMGFMT')
def filter_qmp_imgfmt(qmsg):
def _filter(key, value):
if is_str(value):
return filter_imgfmt(value)
return value
return filter_qmp(qmsg, _filter)
def log(msg, filters=[], indent=None):
'''Logs either a string message or a JSON serializable message (like QMP).
If indent is provided, JSON serializable messages are pretty-printed.'''
@ -514,7 +532,9 @@ class VM(qtest.QEMUQtestMachine):
log(result, filters, indent=indent)
return result
# Returns None on success, and an error string on failure
def run_job(self, job, auto_finalize=True, auto_dismiss=False):
error = None
while True:
for ev in self.get_qmp_events_filtered(wait=True):
if ev['event'] == 'JOB_STATUS_CHANGE':
@ -523,16 +543,24 @@ class VM(qtest.QEMUQtestMachine):
result = self.qmp('query-jobs')
for j in result['return']:
if j['id'] == job:
error = j['error']
log('Job failed: %s' % (j['error']))
elif status == 'pending' and not auto_finalize:
self.qmp_log('job-finalize', id=job)
elif status == 'concluded' and not auto_dismiss:
self.qmp_log('job-dismiss', id=job)
elif status == 'null':
return
return error
else:
iotests.log(ev)
def node_info(self, node_name):
nodes = self.qmp('query-named-block-nodes')
for x in nodes['return']:
if x['node-name'] == node_name:
return x
return None
index_re = re.compile(r'([^\[]+)\[([^\]]+)\]')

View File

@ -1501,6 +1501,36 @@ static void test_append_to_drained(void)
blk_unref(blk);
}
static void test_set_aio_context(void)
{
BlockDriverState *bs;
IOThread *a = iothread_new();
IOThread *b = iothread_new();
AioContext *ctx_a = iothread_get_aio_context(a);
AioContext *ctx_b = iothread_get_aio_context(b);
bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
&error_abort);
bdrv_drained_begin(bs);
bdrv_set_aio_context(bs, ctx_a);
aio_context_acquire(ctx_a);
bdrv_drained_end(bs);
bdrv_drained_begin(bs);
bdrv_set_aio_context(bs, ctx_b);
aio_context_release(ctx_a);
aio_context_acquire(ctx_b);
bdrv_set_aio_context(bs, qemu_get_aio_context());
aio_context_release(ctx_b);
bdrv_drained_end(bs);
bdrv_unref(bs);
iothread_join(a);
iothread_join(b);
}
int main(int argc, char **argv)
{
int ret;
@ -1582,6 +1612,8 @@ int main(int argc, char **argv)
g_test_add_func("/bdrv-drain/attach/drain", test_append_to_drained);
g_test_add_func("/bdrv-drain/set_aio_context", test_set_aio_context);
ret = g_test_run();
qemu_event_destroy(&done_event);
return ret;

198
tests/test-bdrv-graph-mod.c Normal file
View File

@ -0,0 +1,198 @@
/*
* Block node graph modifications tests
*
* Copyright (c) 2019 Virtuozzo International GmbH. All rights reserved.
*
* 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/>.
*
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "block/block_int.h"
#include "sysemu/block-backend.h"
static BlockDriver bdrv_pass_through = {
.format_name = "pass-through",
.bdrv_child_perm = bdrv_filter_default_perms,
};
static void no_perm_default_perms(BlockDriverState *bs, BdrvChild *c,
const BdrvChildRole *role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
{
*nperm = 0;
*nshared = BLK_PERM_ALL;
}
static BlockDriver bdrv_no_perm = {
.format_name = "no-perm",
.bdrv_child_perm = no_perm_default_perms,
};
static BlockDriverState *no_perm_node(const char *name)
{
return bdrv_new_open_driver(&bdrv_no_perm, name, BDRV_O_RDWR, &error_abort);
}
static BlockDriverState *pass_through_node(const char *name)
{
return bdrv_new_open_driver(&bdrv_pass_through, name,
BDRV_O_RDWR, &error_abort);
}
/*
* test_update_perm_tree
*
* When checking node for a possibility to update permissions, it's subtree
* should be correctly checked too. New permissions for each node should be
* calculated and checked in context of permissions of other nodes. If we
* check new permissions of the node only in context of old permissions of
* its neighbors, we can finish up with wrong permission graph.
*
* This test firstly create the following graph:
* +--------+
* | root |
* +--------+
* |
* | perm: write, read
* | shared: except write
* v
* +-------------------+ +----------------+
* | passtrough filter |---------->| null-co node |
* +-------------------+ +----------------+
*
*
* and then, tries to append filter under node. Expected behavior: fail.
* Otherwise we'll get the following picture, with two BdrvChild'ren, having
* write permission to one node, without actually sharing it.
*
* +--------+
* | root |
* +--------+
* |
* | perm: write, read
* | shared: except write
* v
* +-------------------+
* | passtrough filter |
* +-------------------+
* | |
* perm: write, read | | perm: write, read
* shared: except write | | shared: except write
* v v
* +----------------+
* | null co node |
* +----------------+
*/
static void test_update_perm_tree(void)
{
Error *local_err = NULL;
BlockBackend *root = blk_new(BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ,
BLK_PERM_ALL & ~BLK_PERM_WRITE);
BlockDriverState *bs = no_perm_node("node");
BlockDriverState *filter = pass_through_node("filter");
blk_insert_bs(root, bs, &error_abort);
bdrv_attach_child(filter, bs, "child", &child_file, &error_abort);
bdrv_append(filter, bs, &local_err);
g_assert_nonnull(local_err);
bdrv_unref(bs);
blk_unref(root);
}
/*
* test_should_update_child
*
* Test that bdrv_replace_node, and concretely should_update_child
* do the right thing, i.e. not creating loops on the graph.
*
* The test does the following:
* 1. initial graph:
*
* +------+ +--------+
* | root | | filter |
* +------+ +--------+
* | |
* root| target|
* v v
* +------+ +--------+
* | node |<---------| target |
* +------+ backing +--------+
*
* 2. Append @filter above @node. If should_update_child works correctly,
* it understands, that backing child of @target should not be updated,
* as it will create a loop on node graph. Resulting picture should
* be the left one, not the right:
*
* +------+ +------+
* | root | | root |
* +------+ +------+
* | |
* root| root|
* v v
* +--------+ target +--------+ target
* | filter |--------------+ | filter |--------------+
* +--------+ | +--------+ |
* | | | ^ v
* backing| | backing| | +--------+
* v v | +-----------| target |
* +------+ +--------+ v backing +--------+
* | node |<---------| target | +------+
* +------+ backing +--------+ | node |
* +------+
*
* (good picture) (bad picture)
*
*/
static void test_should_update_child(void)
{
BlockBackend *root = blk_new(0, BLK_PERM_ALL);
BlockDriverState *bs = no_perm_node("node");
BlockDriverState *filter = no_perm_node("filter");
BlockDriverState *target = no_perm_node("target");
blk_insert_bs(root, bs, &error_abort);
bdrv_set_backing_hd(target, bs, &error_abort);
g_assert(target->backing->bs == bs);
bdrv_attach_child(filter, target, "target", &child_file, &error_abort);
bdrv_append(filter, bs, &error_abort);
g_assert(target->backing->bs == bs);
bdrv_unref(bs);
blk_unref(root);
}
int main(int argc, char *argv[])
{
bdrv_init();
qemu_init_main_loop(&error_abort);
g_test_init(&argc, &argv, NULL);
g_test_add_func("/bdrv-graph-mod/update-perm-tree", test_update_perm_tree);
g_test_add_func("/bdrv-graph-mod/should-update-child",
test_should_update_child);
return g_test_run();
}

View File

@ -613,6 +613,8 @@ bool aio_poll(AioContext *ctx, bool blocking)
int64_t timeout;
int64_t start = 0;
assert(in_aio_context_home_thread(ctx));
/* aio_notify can avoid the expensive event_notifier_set if
* everything (file descriptors, bottom halves, timers) will
* be re-evaluated before the next blocking poll(). This is
@ -621,7 +623,6 @@ bool aio_poll(AioContext *ctx, bool blocking)
* so disable the optimization now.
*/
if (blocking) {
assert(in_aio_context_home_thread(ctx));
atomic_add(&ctx->notify_me, 2);
}