mirror of https://github.com/xemu-project/xemu.git
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:
commit
adf2e451f3
22
MAINTAINERS
22
MAINTAINERS
|
@ -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
613
block.c
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
55
block/curl.c
55
block/curl.c
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ typedef struct NBDClientSession {
|
|||
|
||||
NBDClientRequest requests[MAX_NBD_REQUESTS];
|
||||
NBDReply reply;
|
||||
BlockDriverState *bs;
|
||||
bool quit;
|
||||
} NBDClientSession;
|
||||
|
||||
|
|
50
block/nbd.c
50
block/nbd.c
|
@ -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)
|
||||
|
|
54
block/nfs.c
54
block/nfs.c
|
@ -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,
|
||||
|
|
30
block/null.c
30
block/null.c
|
@ -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)
|
||||
|
|
29
block/nvme.c
29
block/nvme.c
|
@ -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,
|
||||
|
|
16
block/qapi.c
16
block/qapi.c
|
@ -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. */
|
||||
|
|
14
block/qcow.c
14
block/qcow.c
|
@ -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)
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
14
block/rbd.c
14
block/rbd.c
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
12
block/ssh.c
12
block/ssh.c
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 "
|
||||
|
|
46
block/vmdk.c
46
block/vmdk.c
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
11
block/vxhs.c
11
block/vxhs.c
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
22
io/channel.c
22
io/channel.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
54
nbd/client.c
54
nbd/client.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
64
qemu-img.c
64
qemu-img.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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=''):
|
||||
"""
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) ==
|
||||
|
||||
{
|
||||
|
|
|
@ -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"}}
|
||||
|
|
|
@ -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'] == {}
|
||||
|
|
|
@ -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"}}
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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"}}
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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"}}
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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"}}
|
||||
|
|
|
@ -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
|
|
@ -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": {}}
|
|
@ -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()
|
|
@ -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": {}}
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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": {}}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'([^\[]+)\[([^\]]+)\]')
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue