Block patches:

- 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-----
 
 iQEcBAABAgAGBQJcc/gXAAoJEPQH2wBh1c9AhjAH/1gUdXvTFv+twotwdbd4bCV7
 Q95dFIvz2mxuPQdtBq1xzhFw/IDs/BKgoCqHwU7M/mp5dIxXVAOZMFd8g8ztMEqp
 4Hqci5N8/iAjvDijC6ft9KWTr4TIPwjTL3AzIO4sLlnzeGqzEK6dDP3UBItF9e4J
 i4xv1UuU1oQyVESnk+IBQjevfFDLf7OZKxde+PPPBsTX+aKureoZGmfxWCVuE/JR
 dWE1+75aV094qfp0EUnIDDlKZheI/X2+e++EyaGj/jdcK9NNORmq8nrLnFdZ5kjb
 dZOU2s7kobvkNuPncKxE3z8G/7PXdbihHeCJUXU+wCI99SnLKzfqobUsbr+yt6c=
 =+q6f
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'mreitz/tags/pull-block-2019-02-25' into queue-block

Block patches:
- 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 Feb 25 15:13:43 2019 CET
# gpg:                using RSA key F407DB0061D5CF40
# gpg: Good signature from "Max Reitz <mreitz@redhat.com>"
# Primary key fingerprint: 91BE B60A 30DB 3E88 57D1  1829 F407 DB00 61D5 CF40

* mreitz/tags/pull-block-2019-02-25: (45 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: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Kevin Wolf 2019-02-25 15:16:57 +01:00
commit 1b967e9f34
63 changed files with 1709 additions and 576 deletions

469
block.c
View File

@ -152,22 +152,19 @@ int path_is_absolute(const char *path)
#endif #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 path to it by considering it is relative to base_path. URL are
supported. */ supported. */
void path_combine(char *dest, int dest_size, char *path_combine(const char *base_path, const char *filename)
const char *base_path,
const char *filename)
{ {
const char *protocol_stripped = NULL;
const char *p, *p1; const char *p, *p1;
char *result;
int len; int len;
if (dest_size <= 0)
return;
if (path_is_absolute(filename)) { if (path_is_absolute(filename)) {
pstrcpy(dest, dest_size, filename); return g_strdup(filename);
} else { }
const char *protocol_stripped = NULL;
if (path_has_protocol(base_path)) { if (path_has_protocol(base_path)) {
protocol_stripped = strchr(base_path, ':'); protocol_stripped = strchr(base_path, ':');
@ -182,23 +179,26 @@ void path_combine(char *dest, int dest_size,
{ {
const char *p2; const char *p2;
p2 = strrchr(base_path, '\\'); p2 = strrchr(base_path, '\\');
if (!p1 || p2 > p1) if (!p1 || p2 > p1) {
p1 = p2; 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);
} }
#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; return -EACCES;
} }
void bdrv_get_full_backing_filename_from_filename(const char *backed, /*
* 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, const char *backing,
char *dest, size_t sz,
Error **errp) Error **errp)
{ {
if (backing[0] == '\0' || path_has_protocol(backing) || if (backing[0] == '\0') {
path_is_absolute(backing)) return NULL;
{ } else if (path_has_protocol(backing) || path_is_absolute(backing)) {
pstrcpy(dest, sz, backing); return g_strdup(backing);
} else if (backed[0] == '\0' || strstart(backed, "json:", NULL)) { } else if (backed[0] == '\0' || strstart(backed, "json:", NULL)) {
error_setg(errp, "Cannot use relative backing file names for '%s'", error_setg(errp, "Cannot use relative backing file names for '%s'",
backed); backed);
return NULL;
} else { } 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, if (!filename || filename[0] == '\0') {
dest, sz, errp); 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) void bdrv_register(BlockDriver *bdrv)
@ -1004,6 +1035,8 @@ static void bdrv_backing_attach(BdrvChild *c)
"node is used as backing hd of '%s'", "node is used as backing hd of '%s'",
bdrv_get_device_or_node_name(parent)); bdrv_get_device_or_node_name(parent));
bdrv_refresh_filename(backing_hd);
parent->open_flags &= ~BDRV_O_NO_BACKING; parent->open_flags &= ~BDRV_O_NO_BACKING;
pstrcpy(parent->backing_file, sizeof(parent->backing_file), pstrcpy(parent->backing_file, sizeof(parent->backing_file),
backing_hd->filename); backing_hd->filename);
@ -1413,6 +1446,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
} }
if (file != NULL) { if (file != NULL) {
bdrv_refresh_filename(blk_bs(file));
filename = blk_bs(file)->filename; filename = blk_bs(file)->filename;
} else { } else {
/* /*
@ -2334,8 +2368,6 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
bdrv_unref(backing_hd); bdrv_unref(backing_hd);
} }
bdrv_refresh_filename(bs);
out: out:
bdrv_refresh_limits(bs, NULL); bdrv_refresh_limits(bs, NULL);
} }
@ -2353,10 +2385,11 @@ out:
int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
const char *bdref_key, Error **errp) const char *bdref_key, Error **errp)
{ {
char *backing_filename = g_malloc0(PATH_MAX); char *backing_filename = NULL;
char *bdref_key_dot; char *bdref_key_dot;
const char *reference = NULL; const char *reference = NULL;
int ret = 0; int ret = 0;
bool implicit_backing = false;
BlockDriverState *backing_hd; BlockDriverState *backing_hd;
QDict *options; QDict *options;
QDict *tmp_parent_options = NULL; QDict *tmp_parent_options = NULL;
@ -2387,13 +2420,22 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
*/ */
reference = qdict_get_try_str(parent_options, bdref_key); reference = qdict_get_try_str(parent_options, bdref_key);
if (reference || qdict_haskey(options, "file.filename")) { 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) { } else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) {
qobject_unref(options); qobject_unref(options);
goto free_exit; goto free_exit;
} else { } else {
bdrv_get_full_backing_filename(bs, backing_filename, PATH_MAX, if (qdict_size(options) == 0) {
&local_err); /* 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) { if (local_err) {
ret = -EINVAL; ret = -EINVAL;
error_propagate(errp, local_err); error_propagate(errp, local_err);
@ -2414,9 +2456,8 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
qdict_put_str(options, "driver", bs->backing_format); qdict_put_str(options, "driver", bs->backing_format);
} }
backing_hd = bdrv_open_inherit(*backing_filename ? backing_filename : NULL, backing_hd = bdrv_open_inherit(backing_filename, reference, options, 0, bs,
reference, options, 0, bs, &child_backing, &child_backing, errp);
errp);
if (!backing_hd) { if (!backing_hd) {
bs->open_flags |= BDRV_O_NO_BACKING; bs->open_flags |= BDRV_O_NO_BACKING;
error_prepend(errp, "Could not open backing file: "); error_prepend(errp, "Could not open backing file: ");
@ -2425,6 +2466,12 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
} }
bdrv_set_aio_context(backing_hd, bdrv_get_aio_context(bs)); 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 /* Hook up the backing file link; drop our reference, bs owns the
* backing_hd reference now */ * backing_hd reference now */
bdrv_set_backing_hd(bs, backing_hd, &local_err); bdrv_set_backing_hd(bs, backing_hd, &local_err);
@ -2864,8 +2911,6 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
g_free(child_key_dot); g_free(child_key_dot);
} }
bdrv_refresh_filename(bs);
/* Check if any unknown options were used */ /* Check if any unknown options were used */
if (qdict_size(options) != 0) { if (qdict_size(options) != 0) {
const QDictEntry *entry = qdict_first(options); const QDictEntry *entry = qdict_first(options);
@ -3310,6 +3355,7 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
if (local_err != NULL) { if (local_err != NULL) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
} else { } else {
bdrv_refresh_filename(reopen_state->bs);
error_setg(errp, "failed while preparing to reopen image '%s'", error_setg(errp, "failed while preparing to reopen image '%s'",
reopen_state->bs->filename); reopen_state->bs->filename);
} }
@ -3845,6 +3891,8 @@ int bdrv_change_backing_file(BlockDriverState *bs,
if (ret == 0) { if (ret == 0) {
pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_file ?: ""); pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_file ?: "");
pstrcpy(bs->backing_format, sizeof(bs->backing_format), backing_fmt ?: ""); pstrcpy(bs->backing_format, sizeof(bs->backing_format), backing_fmt ?: "");
pstrcpy(bs->auto_backing_file, sizeof(bs->auto_backing_file),
backing_file ?: "");
} }
return ret; return ret;
} }
@ -3937,7 +3985,10 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
/* success - we can delete the intermediate states, and link top->base */ /* success - we can delete the intermediate states, and link top->base */
/* TODO Check graph modification op blockers (BLK_PERM_GRAPH_MOD) once /* TODO Check graph modification op blockers (BLK_PERM_GRAPH_MOD) once
* we've figured out how they should work. */ * 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) { QLIST_FOREACH_SAFE(c, &top->parents, next_parent, next) {
/* Check whether we are allowed to switch c from top to base */ /* Check whether we are allowed to switch c from top to base */
@ -4485,16 +4536,6 @@ bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs)
return bs->supported_zero_flags & BDRV_REQ_MAY_UNMAP; 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, void bdrv_get_backing_filename(BlockDriverState *bs,
char *filename, int filename_size) char *filename, int filename_size)
{ {
@ -4603,7 +4644,6 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
int is_protocol = 0; int is_protocol = 0;
BlockDriverState *curr_bs = NULL; BlockDriverState *curr_bs = NULL;
BlockDriverState *retval = NULL; BlockDriverState *retval = NULL;
Error *local_error = NULL;
if (!bs || !bs->drv || !backing_file) { if (!bs || !bs->drv || !backing_file) {
return NULL; return NULL;
@ -4611,7 +4651,6 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
filename_full = g_malloc(PATH_MAX); filename_full = g_malloc(PATH_MAX);
backing_file_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); is_protocol = path_has_protocol(backing_file);
@ -4620,41 +4659,43 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
/* If either of the filename paths is actually a protocol, then /* If either of the filename paths is actually a protocol, then
* compare unmodified paths; otherwise make paths relative */ * compare unmodified paths; otherwise make paths relative */
if (is_protocol || path_has_protocol(curr_bs->backing_file)) { if (is_protocol || path_has_protocol(curr_bs->backing_file)) {
char *backing_file_full_ret;
if (strcmp(backing_file, curr_bs->backing_file) == 0) { if (strcmp(backing_file, curr_bs->backing_file) == 0) {
retval = curr_bs->backing->bs; retval = curr_bs->backing->bs;
break; break;
} }
/* Also check against the full backing filename for the image */ /* Also check against the full backing filename for the image */
bdrv_get_full_backing_filename(curr_bs, backing_file_full, PATH_MAX, backing_file_full_ret = bdrv_get_full_backing_filename(curr_bs,
&local_error); NULL);
if (local_error == NULL) { if (backing_file_full_ret) {
if (strcmp(backing_file, backing_file_full) == 0) { bool equal = strcmp(backing_file, backing_file_full_ret) == 0;
g_free(backing_file_full_ret);
if (equal) {
retval = curr_bs->backing->bs; retval = curr_bs->backing->bs;
break; break;
} }
} else {
error_free(local_error);
local_error = NULL;
} }
} else { } else {
/* If not an absolute filename path, make it relative to the current /* If not an absolute filename path, make it relative to the current
* image's filename path */ * image's filename path */
path_combine(filename_tmp, PATH_MAX, curr_bs->filename, filename_tmp = bdrv_make_absolute_filename(curr_bs, backing_file,
backing_file); NULL);
/* We are going to compare canonicalized absolute pathnames */
/* We are going to compare absolute pathnames */ if (!filename_tmp || !realpath(filename_tmp, filename_full)) {
if (!realpath(filename_tmp, filename_full)) { g_free(filename_tmp);
continue; continue;
} }
g_free(filename_tmp);
/* We need to make sure the backing filename we are comparing against /* We need to make sure the backing filename we are comparing against
* is relative to the current image filename (or absolute) */ * is relative to the current image filename (or absolute) */
path_combine(filename_tmp, PATH_MAX, curr_bs->filename, filename_tmp = bdrv_get_full_backing_filename(curr_bs, NULL);
curr_bs->backing_file); if (!filename_tmp || !realpath(filename_tmp, backing_file_full)) {
g_free(filename_tmp);
if (!realpath(filename_tmp, backing_file_full)) {
continue; continue;
} }
g_free(filename_tmp);
if (strcmp(backing_file_full, filename_full) == 0) { if (strcmp(backing_file_full, filename_full) == 0) {
retval = curr_bs->backing->bs; retval = curr_bs->backing->bs;
@ -4665,7 +4706,6 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
g_free(filename_full); g_free(filename_full);
g_free(backing_file_full); g_free(backing_file_full);
g_free(filename_tmp);
return retval; return retval;
} }
@ -5152,17 +5192,17 @@ void bdrv_img_create(const char *filename, const char *fmt,
size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, img_size); size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, img_size);
if (backing_file && !(flags & BDRV_O_NO_BACKING)) { if (backing_file && !(flags & BDRV_O_NO_BACKING)) {
BlockDriverState *bs; BlockDriverState *bs;
char *full_backing = g_new0(char, PATH_MAX); char *full_backing;
int back_flags; int back_flags;
QDict *backing_options = NULL; QDict *backing_options = NULL;
full_backing =
bdrv_get_full_backing_filename_from_filename(filename, backing_file, bdrv_get_full_backing_filename_from_filename(filename, backing_file,
full_backing, PATH_MAX,
&local_err); &local_err);
if (local_err) { if (local_err) {
g_free(full_backing);
goto out; goto out;
} }
assert(full_backing);
/* backing files always opened read-only */ /* backing files always opened read-only */
back_flags = flags; back_flags = flags;
@ -5495,33 +5535,113 @@ out:
return to_replace_bs; 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; static const char *const global_options[] = {
QemuOptDesc *desc; "driver", "filename", NULL
bool found_any = false; };
for (entry = qdict_first(bs->options); entry; if (!curopt) {
entry = qdict_next(bs->options, entry)) return &global_options[0];
{
/* Exclude all non-driver-specific options */
for (desc = bdrv_runtime_opts.desc; desc->name; desc++) {
if (!strcmp(qdict_entry_key(entry), desc->name)) {
break;
} }
curopt++;
if (curopt == &global_options[ARRAY_SIZE(global_options) - 1] && bs->drv) {
curopt = bs->drv->strong_runtime_opts;
} }
if (desc->name) {
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; 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), qdict_put_obj(d, qdict_entry_key(entry),
qobject_ref(qdict_entry_value(entry))); qobject_ref(qdict_entry_value(entry)));
option_given = 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; 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; 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: /* Updates the following BDS fields:
* - exact_filename: A filename which may be used for opening a block device * - exact_filename: A filename which may be used for opening a block device
* which (mostly) equals the given BDS (even without any * which (mostly) equals the given BDS (even without any
@ -5537,92 +5657,108 @@ static bool append_open_options(QDict *d, BlockDriverState *bs)
void bdrv_refresh_filename(BlockDriverState *bs) void bdrv_refresh_filename(BlockDriverState *bs)
{ {
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
BdrvChild *child;
QDict *opts; QDict *opts;
bool backing_overridden;
bool generate_json_filename; /* Whether our default implementation should
fill exact_filename (false) or not (true) */
if (!drv) { if (!drv) {
return; return;
} }
/* This BDS's file name will most probably depend on its file's name, so /* This BDS's file name may depend on any of its children's file names, so
* refresh that first */ * refresh those first */
if (bs->file) { QLIST_FOREACH(child, &bs->children, next) {
bdrv_refresh_filename(bs->file->bs); 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) { if (drv->bdrv_refresh_filename) {
/* Obsolete information is of no use here, so drop the old file name /* Obsolete information is of no use here, so drop the old file name
* information before refreshing it */ * information before refreshing it */
bs->exact_filename[0] = '\0'; bs->exact_filename[0] = '\0';
if (bs->full_open_options) {
qobject_unref(bs->full_open_options);
bs->full_open_options = NULL;
}
opts = qdict_new(); drv->bdrv_refresh_filename(bs);
append_open_options(opts, bs);
drv->bdrv_refresh_filename(bs, opts);
qobject_unref(opts);
} else if (bs->file) { } else if (bs->file) {
/* Try to reconstruct valid information from the underlying file */ /* Try to reconstruct valid information from the underlying file */
bool has_open_options;
bs->exact_filename[0] = '\0'; 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); * We can use the underlying file's filename if:
* - it has a filename,
/* If no specific options have been given for this BDS, the filename of * - the file is a protocol BDS, and
* the underlying file should suffice for this one as well */ * - opening that file (as this BDS's format) will automatically create
if (bs->file->bs->exact_filename[0] && !has_open_options) { * 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); 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]) { if (bs->exact_filename[0]) {
pstrcpy(bs->filename, sizeof(bs->filename), bs->exact_filename); 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)); QString *json = qobject_to_json(QOBJECT(bs->full_open_options));
snprintf(bs->filename, sizeof(bs->filename), "json:%s", snprintf(bs->filename, sizeof(bs->filename), "json:%s",
qstring_get_str(json)); qstring_get_str(json));
@ -5630,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 * 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 * it is broken and take a new child online

View File

@ -811,51 +811,37 @@ static int64_t blkdebug_getlength(BlockDriverState *bs)
return bdrv_getlength(bs->file->bs); 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; BDRVBlkdebugState *s = bs->opaque;
QDict *opts;
const QDictEntry *e; const QDictEntry *e;
bool force_json = false; int ret;
for (e = qdict_first(options); e; e = qdict_next(options, e)) { if (!bs->file->bs->exact_filename[0]) {
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 */
return; return;
} }
if (!force_json && bs->file->bs->exact_filename[0]) { for (e = qdict_first(bs->full_open_options); e;
int ret = snprintf(bs->exact_filename, sizeof(bs->exact_filename), e = qdict_next(bs->full_open_options, e))
"blkdebug:%s:%s", s->config_file ?: "", {
bs->file->bs->exact_filename); /* 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;
}
}
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)) { if (ret >= sizeof(bs->exact_filename)) {
/* An overflow makes the filename unusable, so do not report any */ /* An overflow makes the filename unusable, so do not report any */
bs->exact_filename[0] = 0; bs->exact_filename[0] = 0;
} }
}
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)));
}
}
bs->full_open_options = opts;
} }
static void blkdebug_refresh_limits(BlockDriverState *bs, Error **errp) static void blkdebug_refresh_limits(BlockDriverState *bs, Error **errp)
@ -888,6 +874,20 @@ static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state,
return 0; 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 = { static BlockDriver bdrv_blkdebug = {
.format_name = "blkdebug", .format_name = "blkdebug",
.protocol_name = "blkdebug", .protocol_name = "blkdebug",
@ -917,6 +917,8 @@ static BlockDriver bdrv_blkdebug = {
= blkdebug_debug_remove_breakpoint, = blkdebug_debug_remove_breakpoint,
.bdrv_debug_resume = blkdebug_debug_resume, .bdrv_debug_resume = blkdebug_debug_resume,
.bdrv_debug_is_suspended = blkdebug_debug_is_suspended, .bdrv_debug_is_suspended = blkdebug_debug_is_suspended,
.strong_runtime_opts = blkdebug_strong_runtime_opts,
}; };
static void bdrv_blkdebug_init(void) static void bdrv_blkdebug_init(void)

View File

@ -280,30 +280,6 @@ static int64_t blk_log_writes_getlength(BlockDriverState *bs)
return bdrv_getlength(bs->file->bs); 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, static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c,
const BdrvChildRole *role, const BdrvChildRole *role,
BlockReopenQueue *ro_q, BlockReopenQueue *ro_q,
@ -520,6 +496,13 @@ blk_log_writes_co_pdiscard(BlockDriverState *bs, int64_t offset, int count)
LOG_DISCARD_FLAG, false); 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 = { static BlockDriver bdrv_blk_log_writes = {
.format_name = "blklogwrites", .format_name = "blklogwrites",
.instance_size = sizeof(BDRVBlkLogWritesState), .instance_size = sizeof(BDRVBlkLogWritesState),
@ -527,7 +510,6 @@ static BlockDriver bdrv_blk_log_writes = {
.bdrv_open = blk_log_writes_open, .bdrv_open = blk_log_writes_open,
.bdrv_close = blk_log_writes_close, .bdrv_close = blk_log_writes_close,
.bdrv_getlength = blk_log_writes_getlength, .bdrv_getlength = blk_log_writes_getlength,
.bdrv_refresh_filename = blk_log_writes_refresh_filename,
.bdrv_child_perm = blk_log_writes_child_perm, .bdrv_child_perm = blk_log_writes_child_perm,
.bdrv_refresh_limits = blk_log_writes_refresh_limits, .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, .bdrv_co_block_status = bdrv_co_block_status_from_file,
.is_filter = true, .is_filter = true,
.strong_runtime_opts = blk_log_writes_strong_runtime_opts,
}; };
static void bdrv_blk_log_writes_init(void) static void bdrv_blk_log_writes_init(void)

View File

@ -281,27 +281,10 @@ static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs,
return bdrv_recurse_is_first_non_filter(s->test_file->bs, candidate); 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; 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] if (bs->file->bs->exact_filename[0]
&& s->test_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 = { static BlockDriver bdrv_blkverify = {
.format_name = "blkverify", .format_name = "blkverify",
.protocol_name = "blkverify", .protocol_name = "blkverify",
@ -327,6 +319,7 @@ static BlockDriver bdrv_blkverify = {
.bdrv_child_perm = bdrv_filter_default_perms, .bdrv_child_perm = bdrv_filter_default_perms,
.bdrv_getlength = blkverify_getlength, .bdrv_getlength = blkverify_getlength,
.bdrv_refresh_filename = blkverify_refresh_filename, .bdrv_refresh_filename = blkverify_refresh_filename,
.bdrv_dirname = blkverify_dirname,
.bdrv_co_preadv = blkverify_co_preadv, .bdrv_co_preadv = blkverify_co_preadv,
.bdrv_co_pwritev = blkverify_co_pwritev, .bdrv_co_pwritev = blkverify_co_pwritev,

View File

@ -230,9 +230,8 @@ static int coroutine_fn bdrv_commit_top_preadv(BlockDriverState *bs,
return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags); 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), pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
bs->backing->bs->filename); bs->backing->bs->filename);
} }

View File

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

View File

@ -61,8 +61,6 @@ static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
#define CURL_NUM_STATES 8 #define CURL_NUM_STATES 8
#define CURL_NUM_ACB 8 #define CURL_NUM_ACB 8
#define READ_AHEAD_DEFAULT (256 * 1024)
#define CURL_TIMEOUT_DEFAULT 5
#define CURL_TIMEOUT_MAX 10000 #define CURL_TIMEOUT_MAX 10000
#define CURL_BLOCK_OPT_URL "url" #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_USERNAME "proxy-username"
#define CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET "proxy-password-secret" #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; struct BDRVCURLState;
static bool libcurl_initialized; 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, 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) { if ((s->readahead_size & 0x1ff) != 0) {
error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512", error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512",
s->readahead_size); 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, 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) { if (s->timeout > CURL_TIMEOUT_MAX) {
error_setg(errp, "timeout parameter is too large or negative"); error_setg(errp, "timeout parameter is too large or negative");
goto out_noclean; 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 = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE);
cookie_secret = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE_SECRET); 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; 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 = { static BlockDriver bdrv_http = {
.format_name = "http", .format_name = "http",
.protocol_name = "http", .protocol_name = "http",
@ -961,6 +994,9 @@ static BlockDriver bdrv_http = {
.bdrv_detach_aio_context = curl_detach_aio_context, .bdrv_detach_aio_context = curl_detach_aio_context,
.bdrv_attach_aio_context = curl_attach_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 = { static BlockDriver bdrv_https = {
@ -977,6 +1013,9 @@ static BlockDriver bdrv_https = {
.bdrv_detach_aio_context = curl_detach_aio_context, .bdrv_detach_aio_context = curl_detach_aio_context,
.bdrv_attach_aio_context = curl_attach_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 = { static BlockDriver bdrv_ftp = {
@ -993,6 +1032,9 @@ static BlockDriver bdrv_ftp = {
.bdrv_detach_aio_context = curl_detach_aio_context, .bdrv_detach_aio_context = curl_detach_aio_context,
.bdrv_attach_aio_context = curl_attach_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 = { static BlockDriver bdrv_ftps = {
@ -1009,6 +1051,9 @@ static BlockDriver bdrv_ftps = {
.bdrv_detach_aio_context = curl_detach_aio_context, .bdrv_detach_aio_context = curl_detach_aio_context,
.bdrv_attach_aio_context = curl_attach_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) static void curl_block_init(void)

View File

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

View File

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

View File

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

View File

@ -477,12 +477,9 @@ static void nbd_attach_aio_context(BlockDriverState *bs,
nbd_client_attach_aio_context(bs, new_context); 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; BDRVNBDState *s = bs->opaque;
QDict *opts = qdict_new();
QObject *saddr_qdict;
Visitor *ov;
const char *host = NULL, *port = NULL, *path = NULL; const char *host = NULL, *port = NULL, *path = NULL;
if (s->saddr->type == SOCKET_ADDRESS_TYPE_INET) { 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; path = s->saddr->u.q_unix.path;
} /* else can't represent as pseudo-filename */ } /* else can't represent as pseudo-filename */
qdict_put_str(opts, "driver", "nbd");
if (path && s->export) { if (path && s->export) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename), snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nbd+unix:///%s?socket=%s", s->export, path); "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), snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nbd://%s:%s", host, port); "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 = { static BlockDriver bdrv_nbd = {
.format_name = "nbd", .format_name = "nbd",
.protocol_name = "nbd", .protocol_name = "nbd",
@ -546,6 +546,8 @@ static BlockDriver bdrv_nbd = {
.bdrv_attach_aio_context = nbd_attach_aio_context, .bdrv_attach_aio_context = nbd_attach_aio_context,
.bdrv_refresh_filename = nbd_refresh_filename, .bdrv_refresh_filename = nbd_refresh_filename,
.bdrv_co_block_status = nbd_client_co_block_status, .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 = { static BlockDriver bdrv_nbd_tcp = {
@ -566,6 +568,8 @@ static BlockDriver bdrv_nbd_tcp = {
.bdrv_attach_aio_context = nbd_attach_aio_context, .bdrv_attach_aio_context = nbd_attach_aio_context,
.bdrv_refresh_filename = nbd_refresh_filename, .bdrv_refresh_filename = nbd_refresh_filename,
.bdrv_co_block_status = nbd_client_co_block_status, .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 = { static BlockDriver bdrv_nbd_unix = {
@ -586,6 +590,8 @@ static BlockDriver bdrv_nbd_unix = {
.bdrv_attach_aio_context = nbd_attach_aio_context, .bdrv_attach_aio_context = nbd_attach_aio_context,
.bdrv_refresh_filename = nbd_refresh_filename, .bdrv_refresh_filename = nbd_refresh_filename,
.bdrv_co_block_status = nbd_client_co_block_status, .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) static void bdrv_nbd_init(void)

View File

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

View File

@ -239,19 +239,33 @@ static int coroutine_fn null_co_block_status(BlockDriverState *bs,
return ret; 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)) { for (e = qdict_first(bs->full_open_options); e;
snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://", e = qdict_next(bs->full_open_options, e))
bs->drv->format_name); {
/* 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); snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://",
bs->full_open_options = qobject_ref(opts); bs->drv->format_name);
} }
static const char *const null_strong_runtime_opts[] = {
BLOCK_OPT_SIZE,
NULL_OPT_ZEROES,
NULL
};
static BlockDriver bdrv_null_co = { static BlockDriver bdrv_null_co = {
.format_name = "null-co", .format_name = "null-co",
.protocol_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_co_block_status = null_co_block_status,
.bdrv_refresh_filename = null_refresh_filename, .bdrv_refresh_filename = null_refresh_filename,
.strong_runtime_opts = null_strong_runtime_opts,
}; };
static BlockDriver bdrv_null_aio = { static BlockDriver bdrv_null_aio = {
@ -288,6 +303,7 @@ static BlockDriver bdrv_null_aio = {
.bdrv_co_block_status = null_co_block_status, .bdrv_co_block_status = null_co_block_status,
.bdrv_refresh_filename = null_refresh_filename, .bdrv_refresh_filename = null_refresh_filename,
.strong_runtime_opts = null_strong_runtime_opts,
}; };
static void bdrv_null_init(void) static void bdrv_null_init(void)

View File

@ -111,6 +111,9 @@ typedef struct {
/* Total size of mapped qiov, accessed under dma_map_lock */ /* Total size of mapped qiov, accessed under dma_map_lock */
int dma_map_count; int dma_map_count;
/* PCI address (required for nvme_refresh_filename()) */
char *device;
} BDRVNVMeState; } BDRVNVMeState;
#define NVME_BLOCK_OPT_DEVICE "device" #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_mutex_init(&s->dma_map_lock);
qemu_co_queue_init(&s->dma_flush_queue); qemu_co_queue_init(&s->dma_flush_queue);
s->device = g_strdup(device);
s->nsid = namespace; s->nsid = namespace;
s->aio_context = bdrv_get_aio_context(bs); s->aio_context = bdrv_get_aio_context(bs);
ret = event_notifier_init(&s->irq_notifier, 0); ret = event_notifier_init(&s->irq_notifier, 0);
@ -729,6 +733,8 @@ static void nvme_close(BlockDriverState *bs)
event_notifier_cleanup(&s->irq_notifier); event_notifier_cleanup(&s->irq_notifier);
qemu_vfio_pci_unmap_bar(s->vfio, 0, (void *)s->regs, 0, NVME_BAR_SIZE); qemu_vfio_pci_unmap_bar(s->vfio, 0, (void *)s->regs, 0, NVME_BAR_SIZE);
qemu_vfio_close(s->vfio); qemu_vfio_close(s->vfio);
g_free(s->device);
} }
static int nvme_file_open(BlockDriverState *bs, QDict *options, int flags, 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; 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), "nvme://%s/%i",
snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://", s->device, s->nsid);
bs->drv->format_name);
}
qdict_put_str(opts, "driver", bs->drv->format_name);
bs->full_open_options = qobject_ref(opts);
} }
static void nvme_refresh_limits(BlockDriverState *bs, Error **errp) 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); 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 = { static BlockDriver bdrv_nvme = {
.format_name = "nvme", .format_name = "nvme",
.protocol_name = "nvme", .protocol_name = "nvme",
@ -1153,6 +1161,7 @@ static BlockDriver bdrv_nvme = {
.bdrv_refresh_filename = nvme_refresh_filename, .bdrv_refresh_filename = nvme_refresh_filename,
.bdrv_refresh_limits = nvme_refresh_limits, .bdrv_refresh_limits = nvme_refresh_limits,
.strong_runtime_opts = nvme_strong_runtime_opts,
.bdrv_detach_aio_context = nvme_detach_aio_context, .bdrv_detach_aio_context = nvme_detach_aio_context,
.bdrv_attach_aio_context = nvme_attach_aio_context, .bdrv_attach_aio_context = nvme_attach_aio_context,

View File

@ -51,6 +51,8 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
return NULL; return NULL;
} }
bdrv_refresh_filename(bs);
info = g_malloc0(sizeof(*info)); info = g_malloc0(sizeof(*info));
info->file = g_strdup(bs->filename); info->file = g_strdup(bs->filename);
info->ro = bs->read_only; info->ro = bs->read_only;
@ -264,6 +266,8 @@ void bdrv_query_image_info(BlockDriverState *bs,
goto out; goto out;
} }
bdrv_refresh_filename(bs);
info = g_new0(ImageInfo, 1); info = g_new0(ImageInfo, 1);
info->filename = g_strdup(bs->filename); info->filename = g_strdup(bs->filename);
info->format = g_strdup(bdrv_get_format_name(bs)); 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; backing_filename = bs->backing_file;
if (backing_filename[0] != '\0') { if (backing_filename[0] != '\0') {
char *backing_filename2 = g_malloc0(PATH_MAX); char *backing_filename2;
info->backing_filename = g_strdup(backing_filename); info->backing_filename = g_strdup(backing_filename);
info->has_backing_filename = true; info->has_backing_filename = true;
bdrv_get_full_backing_filename(bs, backing_filename2, PATH_MAX, &err); backing_filename2 = bdrv_get_full_backing_filename(bs, NULL);
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;
}
/* Always report the full_backing_filename if present, even if it's the /* Always report the full_backing_filename if present, even if it's the
* same as backing_filename. That they are same is useful info. */ * same as backing_filename. That they are same is useful info. */

View File

@ -31,6 +31,7 @@
#include "qemu/module.h" #include "qemu/module.h"
#include "qemu/option.h" #include "qemu/option.h"
#include "qemu/bswap.h" #include "qemu/bswap.h"
#include "qemu/cutils.h"
#include <zlib.h> #include <zlib.h>
#include "qapi/qmp/qdict.h" #include "qapi/qmp/qdict.h"
#include "qapi/qmp/qstring.h" #include "qapi/qmp/qstring.h"
@ -295,11 +296,13 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
goto fail; goto fail;
} }
ret = bdrv_pread(bs->file, header.backing_file_offset, ret = bdrv_pread(bs->file, header.backing_file_offset,
bs->backing_file, len); bs->auto_backing_file, len);
if (ret < 0) { if (ret < 0) {
goto fail; 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 */ /* Disable migration when qcow images are used */
@ -1183,6 +1186,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 = { static BlockDriver bdrv_qcow = {
.format_name = "qcow", .format_name = "qcow",
.instance_size = sizeof(BDRVQcowState), .instance_size = sizeof(BDRVQcowState),
@ -1206,6 +1215,7 @@ static BlockDriver bdrv_qcow = {
.bdrv_get_info = qcow_get_info, .bdrv_get_info = qcow_get_info,
.create_opts = &qcow_create_opts, .create_opts = &qcow_create_opts,
.strong_runtime_opts = qcow_strong_runtime_opts,
}; };
static void bdrv_qcow_init(void) static void bdrv_qcow_init(void)

View File

@ -1474,13 +1474,15 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
goto fail; goto fail;
} }
ret = bdrv_pread(bs->file, header.backing_file_offset, ret = bdrv_pread(bs->file, header.backing_file_offset,
bs->backing_file, len); bs->auto_backing_file, len);
if (ret < 0) { if (ret < 0) {
error_setg_errno(errp, -ret, "Could not read backing file name"); error_setg_errno(errp, -ret, "Could not read backing file name");
goto fail; goto fail;
} }
bs->backing_file[len] = '\0'; bs->auto_backing_file[len] = '\0';
s->image_backing_file = g_strdup(bs->backing_file); pstrcpy(bs->backing_file, sizeof(bs->backing_file),
bs->auto_backing_file);
s->image_backing_file = g_strdup(bs->auto_backing_file);
} }
/* Internal snapshots */ /* Internal snapshots */
@ -2518,6 +2520,8 @@ static int qcow2_change_backing_file(BlockDriverState *bs,
return -EINVAL; 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_file, sizeof(bs->backing_file), backing_file ?: "");
pstrcpy(bs->backing_format, sizeof(bs->backing_format), backing_fmt ?: ""); pstrcpy(bs->backing_format, sizeof(bs->backing_format), backing_fmt ?: "");
@ -4232,6 +4236,60 @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs)
return ret; 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, static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
Error **errp) Error **errp)
{ {
@ -4241,11 +4299,13 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
uint64_t virtual_size; /* disk size as seen by guest */ uint64_t virtual_size; /* disk size as seen by guest */
uint64_t refcount_bits; uint64_t refcount_bits;
uint64_t l2_tables; uint64_t l2_tables;
uint64_t luks_payload_size = 0;
size_t cluster_size; size_t cluster_size;
int version; int version;
char *optstr; char *optstr;
PreallocMode prealloc; PreallocMode prealloc;
bool has_backing_file; bool has_backing_file;
bool has_luks;
/* Parse image creation options */ /* Parse image creation options */
cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err); cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err);
@ -4275,6 +4335,20 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
has_backing_file = !!optstr; has_backing_file = !!optstr;
g_free(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 = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
virtual_size = ROUND_UP(virtual_size, cluster_size); virtual_size = ROUND_UP(virtual_size, cluster_size);
@ -4345,7 +4419,7 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
info = g_new(BlockMeasureInfo, 1); info = g_new(BlockMeasureInfo, 1);
info->fully_allocated = info->fully_allocated =
qcow2_calc_prealloc_size(virtual_size, cluster_size, 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 /* Remove data clusters that are not required. This overestimates the
* required size because metadata needed for the fully allocated file is * required size because metadata needed for the fully allocated file is
@ -4932,6 +5006,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 = { BlockDriver bdrv_qcow2 = {
.format_name = "qcow2", .format_name = "qcow2",
.instance_size = sizeof(BDRVQcow2State), .instance_size = sizeof(BDRVQcow2State),
@ -4980,6 +5060,7 @@ BlockDriver bdrv_qcow2 = {
.bdrv_inactivate = qcow2_inactivate, .bdrv_inactivate = qcow2_inactivate,
.create_opts = &qcow2_create_opts, .create_opts = &qcow2_create_opts,
.strong_runtime_opts = qcow2_strong_runtime_opts,
.bdrv_co_check = qcow2_co_check, .bdrv_co_check = qcow2_co_check,
.bdrv_amend_options = qcow2_amend_options, .bdrv_amend_options = qcow2_amend_options,

View File

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

View File

@ -1065,36 +1065,64 @@ static void quorum_del_child(BlockDriverState *bs, BdrvChild *child,
bdrv_drained_end(bs); 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; BDRVQuorumState *s = bs->opaque;
QDict *opts; QList *children_list;
QList *children;
int i; int i;
for (i = 0; i < s->num_children; i++) { /*
bdrv_refresh_filename(s->children[i]->bs); * The generic implementation for gathering child options in
if (!s->children[i]->bs->full_open_options) { * bdrv_refresh_filename() would use the names of the children
return; * 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++) { for (i = 0; i < s->num_children; i++) {
qlist_append(children, qlist_append(children_list,
qobject_ref(s->children[i]->bs->full_open_options)); 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 = { static BlockDriver bdrv_quorum = {
.format_name = "quorum", .format_name = "quorum",
@ -1102,7 +1130,8 @@ static BlockDriver bdrv_quorum = {
.bdrv_open = quorum_open, .bdrv_open = quorum_open,
.bdrv_close = quorum_close, .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, .bdrv_co_flush_to_disk = quorum_co_flush,
@ -1118,6 +1147,8 @@ static BlockDriver bdrv_quorum = {
.is_filter = true, .is_filter = true,
.bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter, .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) static void bdrv_quorum_init(void)

View File

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

View File

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

View File

@ -616,8 +616,6 @@ static void replication_done(void *opaque, int ret)
if (ret == 0) { if (ret == 0) {
s->stage = BLOCK_REPLICATION_DONE; s->stage = BLOCK_REPLICATION_DONE;
/* refresh top bs's filename */
bdrv_refresh_filename(bs);
s->active_disk = NULL; s->active_disk = NULL;
s->secondary_disk = NULL; s->secondary_disk = NULL;
s->hidden_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); aio_context_release(aio_context);
} }
static const char *const replication_strong_runtime_opts[] = {
REPLICATION_MODE,
REPLICATION_TOP_ID,
NULL
};
BlockDriver bdrv_replication = { BlockDriver bdrv_replication = {
.format_name = "replication", .format_name = "replication",
.instance_size = sizeof(BDRVReplicationState), .instance_size = sizeof(BDRVReplicationState),
@ -694,6 +699,7 @@ BlockDriver bdrv_replication = {
.bdrv_recurse_is_first_non_filter = replication_recurse_is_first_non_filter, .bdrv_recurse_is_first_non_filter = replication_recurse_is_first_non_filter,
.has_variable_length = true, .has_variable_length = true,
.strong_runtime_opts = replication_strong_runtime_opts,
}; };
static void bdrv_replication_init(void) static void bdrv_replication_init(void)

View File

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

View File

@ -1254,6 +1254,17 @@ static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset,
return ssh_grow_file(s, offset, errp); 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 = { static BlockDriver bdrv_ssh = {
.format_name = "ssh", .format_name = "ssh",
.protocol_name = "ssh", .protocol_name = "ssh",
@ -1270,6 +1281,7 @@ static BlockDriver bdrv_ssh = {
.bdrv_co_truncate = ssh_co_truncate, .bdrv_co_truncate = ssh_co_truncate,
.bdrv_co_flush_to_disk = ssh_co_flush, .bdrv_co_flush_to_disk = ssh_co_flush,
.create_opts = &ssh_create_opts, .create_opts = &ssh_create_opts,
.strong_runtime_opts = ssh_strong_runtime_opts,
}; };
static void bdrv_ssh_init(void) static void bdrv_ssh_init(void)

View File

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

View File

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

View File

@ -27,6 +27,7 @@
#include "qapi/error.h" #include "qapi/error.h"
#include "block/block_int.h" #include "block/block_int.h"
#include "sysemu/block-backend.h" #include "sysemu/block-backend.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qerror.h" #include "qapi/qmp/qerror.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qemu/module.h" #include "qemu/module.h"
@ -386,12 +387,14 @@ static int vmdk_parent_open(BlockDriverState *bs)
ret = -EINVAL; ret = -EINVAL;
goto out; 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; ret = -EINVAL;
goto out; 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: out:
@ -479,6 +482,7 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
extent->l1_table, extent->l1_table,
l1_size); l1_size);
if (ret < 0) { if (ret < 0) {
bdrv_refresh_filename(extent->file->bs);
error_setg_errno(errp, -ret, error_setg_errno(errp, -ret,
"Could not read l1 table from extent '%s'", "Could not read l1 table from extent '%s'",
extent->file->bs->filename); extent->file->bs->filename);
@ -499,6 +503,7 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
extent->l1_backup_table, extent->l1_backup_table,
l1_size); l1_size);
if (ret < 0) { if (ret < 0) {
bdrv_refresh_filename(extent->file->bs);
error_setg_errno(errp, -ret, error_setg_errno(errp, -ret,
"Could not read l1 backup table from extent '%s'", "Could not read l1 backup table from extent '%s'",
extent->file->bs->filename); 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)); ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header));
if (ret < 0) { if (ret < 0) {
bdrv_refresh_filename(file->bs);
error_setg_errno(errp, -ret, error_setg_errno(errp, -ret,
"Could not read header from file '%s'", "Could not read header from file '%s'",
file->bs->filename); file->bs->filename);
@ -607,6 +613,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header)); ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header));
if (ret < 0) { if (ret < 0) {
bdrv_refresh_filename(file->bs);
error_setg_errno(errp, -ret, error_setg_errno(errp, -ret,
"Could not read header from file '%s'", "Could not read header from file '%s'",
file->bs->filename); 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) && if (!path_is_absolute(fname) && !path_has_protocol(fname) &&
!desc_file_path[0]) !desc_file_path[0])
{ {
bdrv_refresh_filename(bs->file->bs);
error_setg(errp, "Cannot use relative extent paths with VMDK " error_setg(errp, "Cannot use relative extent paths with VMDK "
"descriptor file '%s'", bs->file->bs->filename); "descriptor file '%s'", bs->file->bs->filename);
return -EINVAL; return -EINVAL;
} }
extent_path = g_malloc0(PATH_MAX); extent_path = path_combine(desc_file_path, fname);
path_combine(extent_path, PATH_MAX, desc_file_path, fname);
ret = snprintf(extent_opt_prefix, 32, "extents.%d", s->num_extents); ret = snprintf(extent_opt_prefix, 32, "extents.%d", s->num_extents);
assert(ret < 32); assert(ret < 32);
@ -2072,16 +2079,16 @@ static int coroutine_fn vmdk_co_do_create(int64_t size,
if (backing_file) { if (backing_file) {
BlockBackend *backing; BlockBackend *backing;
char *full_backing = g_new0(char, PATH_MAX); char *full_backing =
bdrv_get_full_backing_filename_from_filename(blk_bs(blk)->filename, backing_file, bdrv_get_full_backing_filename_from_filename(blk_bs(blk)->filename,
full_backing, PATH_MAX, backing_file,
&local_err); &local_err);
if (local_err) { if (local_err) {
g_free(full_backing);
error_propagate(errp, local_err); error_propagate(errp, local_err);
ret = -ENOENT; ret = -ENOENT;
goto exit; goto exit;
} }
assert(full_backing);
backing = blk_new_open(full_backing, NULL, NULL, backing = blk_new_open(full_backing, NULL, NULL,
BDRV_O_NO_BACKING, errp); BDRV_O_NO_BACKING, errp);
@ -2260,7 +2267,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); compat6 = qemu_opt_get_bool_del(opts, BLOCK_OPT_COMPAT6, false);
if (strcmp(hw_version, "undefined") == 0) { if (strcmp(hw_version, "undefined") == 0) {
g_free(hw_version); g_free(hw_version);
hw_version = g_strdup("4"); hw_version = NULL;
} }
fmt = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT); fmt = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT);
zeroed_grain = qemu_opt_get_bool_del(opts, BLOCK_OPT_ZEROED_GRAIN, false); zeroed_grain = qemu_opt_get_bool_del(opts, BLOCK_OPT_ZEROED_GRAIN, false);
@ -2470,6 +2477,7 @@ static ImageInfo *vmdk_get_extent_info(VmdkExtent *extent)
{ {
ImageInfo *info = g_new0(ImageInfo, 1); ImageInfo *info = g_new0(ImageInfo, 1);
bdrv_refresh_filename(extent->file->bs);
*info = (ImageInfo){ *info = (ImageInfo){
.filename = g_strdup(extent->file->bs->filename), .filename = g_strdup(extent->file->bs->filename),
.format = g_strdup(extent->type), .format = g_strdup(extent->type),
@ -2601,6 +2609,23 @@ static int vmdk_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
return 0; 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 = { static QemuOptsList vmdk_create_opts = {
.name = "vmdk-create-opts", .name = "vmdk-create-opts",
.head = QTAILQ_HEAD_INITIALIZER(vmdk_create_opts.head), .head = QTAILQ_HEAD_INITIALIZER(vmdk_create_opts.head),
@ -2672,6 +2697,7 @@ static BlockDriver bdrv_vmdk = {
.bdrv_get_specific_info = vmdk_get_specific_info, .bdrv_get_specific_info = vmdk_get_specific_info,
.bdrv_refresh_limits = vmdk_refresh_limits, .bdrv_refresh_limits = vmdk_refresh_limits,
.bdrv_get_info = vmdk_get_info, .bdrv_get_info = vmdk_get_info,
.bdrv_gather_child_options = vmdk_gather_child_options,
.supports_backing = true, .supports_backing = true,
.create_opts = &vmdk_create_opts, .create_opts = &vmdk_create_opts,

View File

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

View File

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

View File

@ -556,6 +556,16 @@ static int64_t vxhs_getlength(BlockDriverState *bs)
return vdisk_size; 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 = { static BlockDriver bdrv_vxhs = {
.format_name = "vxhs", .format_name = "vxhs",
.protocol_name = "vxhs", .protocol_name = "vxhs",
@ -567,6 +577,7 @@ static BlockDriver bdrv_vxhs = {
.bdrv_getlength = vxhs_getlength, .bdrv_getlength = vxhs_getlength,
.bdrv_aio_preadv = vxhs_aio_preadv, .bdrv_aio_preadv = vxhs_aio_preadv,
.bdrv_aio_pwritev = vxhs_aio_pwritev, .bdrv_aio_pwritev = vxhs_aio_pwritev,
.strong_runtime_opts = vxhs_strong_runtime_opts,
}; };
static void bdrv_vxhs_init(void) static void bdrv_vxhs_init(void)

View File

@ -1627,6 +1627,7 @@ static void external_snapshot_prepare(BlkActionState *common,
error_setg_errno(errp, -size, "bdrv_getlength failed"); error_setg_errno(errp, -size, "bdrv_getlength failed");
goto out; goto out;
} }
bdrv_refresh_filename(state->old_bs);
bdrv_img_create(new_image_file, format, bdrv_img_create(new_image_file, format,
state->old_bs->filename, state->old_bs->filename,
state->old_bs->drv->format_name, 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; goto out;
} }
assert(bdrv_get_aio_context(base_bs) == aio_context); assert(bdrv_get_aio_context(base_bs) == aio_context);
bdrv_refresh_filename(base_bs);
base_name = base_bs->filename; 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; goto out;
} }
} else if (has_top && top) { } 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) { if (strcmp(bs->filename, top) != 0) {
top_bs = bdrv_find_backing_image(bs, top); 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) { if (backup->mode != NEW_IMAGE_MODE_EXISTING) {
assert(backup->format); assert(backup->format);
if (source) { if (source) {
bdrv_refresh_filename(source);
bdrv_img_create(backup->target, backup->format, source->filename, bdrv_img_create(backup->target, backup->format, source->filename,
source->drv->format_name, NULL, source->drv->format_name, NULL,
size, flags, false, &local_err); size, flags, false, &local_err);
@ -3889,6 +3896,7 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
break; break;
case NEW_IMAGE_MODE_ABSOLUTE_PATHS: case NEW_IMAGE_MODE_ABSOLUTE_PATHS:
/* create new image with backing file */ /* create new image with backing file */
bdrv_refresh_filename(source);
bdrv_img_create(arg->target, format, bdrv_img_create(arg->target, format,
source->filename, source->filename,
source->drv->format_name, source->drv->format_name,

View File

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

View File

@ -139,7 +139,42 @@ struct BlockDriver {
Error **errp); Error **errp);
int (*bdrv_make_empty)(BlockDriverState *bs); 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 */ /* aio */
BlockAIOCB *(*bdrv_aio_preadv)(BlockDriverState *bs, 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_register_buf)(BlockDriverState *bs, void *host, size_t size);
void (*bdrv_unregister_buf)(BlockDriverState *bs, void *host); void (*bdrv_unregister_buf)(BlockDriverState *bs, void *host);
QLIST_ENTRY(BlockDriver) list; 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 { typedef struct BlockLimits {
@ -702,6 +744,10 @@ struct BlockDriverState {
char filename[PATH_MAX]; char filename[PATH_MAX];
char backing_file[PATH_MAX]; /* if non zero, the image is a diff of char backing_file[PATH_MAX]; /* if non zero, the image is a diff of
this file image */ 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 */ char backing_format[16]; /* if non-zero and backing_file exists */
QDict *full_open_options; QDict *full_open_options;

View File

@ -2790,6 +2790,7 @@ static int get_block_status(BlockDriverState *bs, int64_t offset,
BlockDriverState *file; BlockDriverState *file;
bool has_offset; bool has_offset;
int64_t map; int64_t map;
char *filename = NULL;
/* As an optimization, we could cache the current range of unallocated /* As an optimization, we could cache the current range of unallocated
* clusters in each file of the chain, and avoid querying the same * clusters in each file of the chain, and avoid querying the same
@ -2817,6 +2818,11 @@ static int get_block_status(BlockDriverState *bs, int64_t offset,
has_offset = !!(ret & BDRV_BLOCK_OFFSET_VALID); has_offset = !!(ret & BDRV_BLOCK_OFFSET_VALID);
if (file && has_offset) {
bdrv_refresh_filename(file);
filename = file->filename;
}
*e = (MapEntry) { *e = (MapEntry) {
.start = offset, .start = offset,
.length = bytes, .length = bytes,
@ -2825,8 +2831,8 @@ static int get_block_status(BlockDriverState *bs, int64_t offset,
.offset = map, .offset = map,
.has_offset = has_offset, .has_offset = has_offset,
.depth = depth, .depth = depth,
.has_filename = file && has_offset, .has_filename = filename,
.filename = file && has_offset ? file->filename : NULL, .filename = filename,
}; };
return 0; return 0;
@ -3334,20 +3340,17 @@ static int img_rebase(int argc, char **argv)
qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true); qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true);
} }
bdrv_refresh_filename(bs);
overlay_filename = bs->exact_filename[0] ? bs->exact_filename overlay_filename = bs->exact_filename[0] ? bs->exact_filename
: bs->filename; : bs->filename;
out_real_path = g_malloc(PATH_MAX); out_real_path =
bdrv_get_full_backing_filename_from_filename(overlay_filename, bdrv_get_full_backing_filename_from_filename(overlay_filename,
out_baseimg, out_baseimg,
out_real_path,
PATH_MAX,
&local_err); &local_err);
if (local_err) { if (local_err) {
error_reportf_err(local_err, error_reportf_err(local_err,
"Could not resolve backing filename: "); "Could not resolve backing filename: ");
ret = -1; ret = -1;
g_free(out_real_path);
goto out; goto out;
} }

View File

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

View File

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

View File

@ -82,7 +82,7 @@ QEMU X.Y.Z monitor - type 'help' for more information
Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig,if=none,id=drive0 -nodefaults 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 X.Y.Z monitor - type 'help' for more information
(qemu) info block (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 Removable device: not locked, tray closed
Cache mode: writeback Cache mode: writeback
Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1) 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 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 X.Y.Z monitor - type 'help' for more information
(qemu) info block (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 Removable device: not locked, tray closed
Cache mode: writeback Cache mode: writeback
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) 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 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 X.Y.Z monitor - type 'help' for more information
(qemu) info block (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 Removable device: not locked, tray closed
Cache mode: writethrough Cache mode: writethrough
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) 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 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 X.Y.Z monitor - type 'help' for more information
(qemu) info block (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 Removable device: not locked, tray closed
Cache mode: writeback, ignore flushes Cache mode: writeback, ignore flushes
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)

View File

@ -82,7 +82,7 @@ QEMU X.Y.Z monitor - type 'help' for more information
Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig,if=none,id=drive0 -nodefaults 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 X.Y.Z monitor - type 'help' for more information
(qemu) info block (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 Removable device: not locked, tray closed
Cache mode: writeback Cache mode: writeback
Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1) 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 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 X.Y.Z monitor - type 'help' for more information
(qemu) info block (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 Removable device: not locked, tray closed
Cache mode: writeback Cache mode: writeback
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) 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 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 X.Y.Z monitor - type 'help' for more information
(qemu) info block (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 Removable device: not locked, tray closed
Cache mode: writethrough Cache mode: writethrough
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) 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 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 X.Y.Z monitor - type 'help' for more information
(qemu) info block (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 Removable device: not locked, tray closed
Cache mode: writeback, ignore flushes Cache mode: writeback, ignore flushes
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)

View File

@ -29,6 +29,7 @@ status=1 # failure is the default!
_cleanup() _cleanup()
{ {
_cleanup_test_img _cleanup_test_img
rm -f "$TEST_IMG.copy"
} }
trap "_cleanup; exit \$status" 0 1 2 3 15 trap "_cleanup; exit \$status" 0 1 2 3 15
@ -60,7 +61,8 @@ echo '=== Non-reconstructable filename ==='
echo echo
# Across blkdebug without a config file, you cannot reconstruct filenames, so # 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:{ TEST_IMG="json:{
'driver': '$IMGFMT', 'driver': '$IMGFMT',
'file': { 'file': {
@ -85,6 +87,31 @@ echo
# omit the image size; it should work anyway # omit the image size; it should work anyway
_make_test_img -b "$TEST_IMG_REL.base" _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 # success, all done
echo '*** done' echo '*** done'

View File

@ -14,9 +14,16 @@ backing file: t.IMGFMT.base (actual path: TEST_DIR/t.IMGFMT.base)
image: json:{"driver": "IMGFMT", "file": {"set-state.0.event": "read_aio", "image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "set-state.0.new_state": 42}} 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 file format: IMGFMT
virtual size: 64M (67108864 bytes) 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 === === Backing name is always relative to the backed image ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=t.IMGFMT.base 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 *** done

View File

@ -142,6 +142,14 @@ for ofmt in human json; do
# The backing file doesn't need to exist :) # The backing file doesn't need to exist :)
$QEMU_IMG measure --output=$ofmt -o backing_file=x \ $QEMU_IMG measure --output=$ofmt -o backing_file=x \
-f "$fmt" -O "$IMGFMT" "$TEST_IMG" -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 fi
echo echo

View File

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

View File

@ -1,13 +1,13 @@
=== Successful image creation (defaults) === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -24,12 +24,12 @@ Format specific information:
=== Successful image creation (inline blockdev-add, explicit defaults) === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -46,12 +46,12 @@ Format specific information:
=== Successful image creation (v3 non-default options) === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -68,12 +68,12 @@ Format specific information:
=== Successful image creation (v2 non-default options) === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -90,7 +90,7 @@ Format specific information:
=== Successful image creation (encrypted) === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -144,111 +144,111 @@ Format specific information:
=== Invalid BlockdevRef === === 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": {}} {"return": {}}
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
=== Invalid sizes === === 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": {}} {"return": {}}
Job failed: Image size must be a multiple of 512 bytes Job failed: Image size must be a multiple of 512 bytes
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Could not resize image: Image size cannot be negative Job failed: Could not resize image: Image size cannot be negative
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Could not resize image: Image size cannot be negative Job failed: Could not resize image: Image size cannot be negative
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Could not resize image: Failed to grow the L1 table: File too large Job failed: Could not resize image: Failed to grow the L1 table: File too large
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
=== Invalid version === === 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'"}} {"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": {}} {"return": {}}
Job failed: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater) Job failed: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater)
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater) 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"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
=== Invalid backing file options === === 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": {}} {"return": {}}
Job failed: Backing file and preallocation cannot be used at the same time Job failed: Backing file and preallocation cannot be used at the same time
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Backing format cannot be used without backing file Job failed: Backing format cannot be used without backing file
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
=== Invalid cluster size === === 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": {}} {"return": {}}
Job failed: Cluster size must be a power of two between 512 and 2048k Job failed: Cluster size must be a power of two between 512 and 2048k
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Cluster size must be a power of two between 512 and 2048k Job failed: Cluster size must be a power of two between 512 and 2048k
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Cluster size must be a power of two between 512 and 2048k Job failed: Cluster size must be a power of two between 512 and 2048k
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Cluster size must be a power of two between 512 and 2048k Job failed: Cluster size must be a power of two between 512 and 2048k
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Could not resize image: Failed to grow the L1 table: File too large Job failed: Could not resize image: Failed to grow the L1 table: File too large
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
=== Invalid refcount width === === 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": {}} {"return": {}}
Job failed: Refcount width must be a power of two and may not exceed 64 bits Job failed: Refcount width must be a power of two and may not exceed 64 bits
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Refcount width must be a power of two and may not exceed 64 bits Job failed: Refcount width must be a power of two and may not exceed 64 bits
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Refcount width must be a power of two and may not exceed 64 bits Job failed: Refcount width must be a power of two and may not exceed 64 bits
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}

View File

@ -27,12 +27,16 @@ import re
iotests.verify_image_format(supported_fmts=['raw']) iotests.verify_image_format(supported_fmts=['raw'])
iotests.verify_protocol(supported=['ssh']) iotests.verify_protocol(supported=['ssh'])
def filter_hash(msg): def filter_hash(qmsg):
return re.sub('"hash": "[0-9a-f]+"', '"hash": HASH', msg) 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): 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_testfiles, filter_hash]) filters=[iotests.filter_qmp_testfiles, filter_hash])
if 'return' in result: if 'return' in result:
assert result['return'] == {} assert result['return'] == {}

View File

@ -1,6 +1,6 @@
=== Successful image creation (defaults) === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -16,7 +16,7 @@ virtual size: 4.0M (4194304 bytes)
=== Test host-key-check options === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -25,7 +25,7 @@ image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.po
file format: IMGFMT file format: IMGFMT
virtual size: 8.0M (8388608 bytes) 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -34,13 +34,13 @@ image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.po
file format: IMGFMT file format: IMGFMT
virtual size: 4.0M (4194304 bytes) 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": {}} {"return": {}}
Job failed: remote host key does not match host_key_check 'wrong' Job failed: remote host key does not match host_key_check 'wrong'
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -49,13 +49,13 @@ image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.po
file format: IMGFMT file format: IMGFMT
virtual size: 8.0M (8388608 bytes) 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": {}} {"return": {}}
Job failed: remote host key does not match host_key_check 'wrong' Job failed: remote host key does not match host_key_check 'wrong'
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -66,13 +66,13 @@ virtual size: 4.0M (4194304 bytes)
=== Invalid path and user === === 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": {}} {"return": {}}
Job failed: failed to open remote file '/this/is/not/an/existing/path': Failed opening remote file (libssh2 error code: -31) 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"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: failed to authenticate using publickey authentication and the identities held by your ssh-agent Job failed: failed to authenticate using publickey authentication and the identities held by your ssh-agent
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}

View File

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

View File

@ -1,13 +1,13 @@
=== Successful image creation (defaults) === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -54,12 +54,12 @@ Format specific information:
=== Successful image creation (with non-default options) === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -106,7 +106,7 @@ Format specific information:
=== Invalid BlockdevRef === === 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": {}} {"return": {}}
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"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 === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -161,19 +161,19 @@ Format specific information:
=== Invalid sizes === === 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": {}} {"return": {}}
Job failed: The requested file size is too large Job failed: The requested file size is too large
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: The requested file size is too large Job failed: The requested file size is too large
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: The requested file size is too large Job failed: The requested file size is too large
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
@ -181,13 +181,13 @@ Job failed: The requested file size is too large
=== Resize image with invalid sizes === === 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"}} {"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"}} {"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"}} {"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"}} {"error": {"class": "GenericError", "desc": "Parameter 'size' expects a >0 size"}}
image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_IMG"}, "key-secret": "keysec0"} image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_IMG"}, "key-secret": "keysec0"}
file format: IMGFMT file format: IMGFMT

View File

@ -27,11 +27,14 @@ iotests.verify_image_format(supported_fmts=['vdi'])
iotests.verify_protocol(supported=['file']) iotests.verify_protocol(supported=['file'])
def blockdev_create(vm, options): 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: if 'return' in result:
assert result['return'] == {} 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("") iotests.log("")
with iotests.FilePath('t.vdi') as disk_path, \ with iotests.FilePath('t.vdi') as disk_path, \
@ -51,7 +54,7 @@ with iotests.FilePath('t.vdi') as disk_path, \
'size': 0 }) 'size': 0 })
vm.qmp_log('blockdev-add', driver='file', filename=disk_path, 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, blockdev_create(vm, { 'driver': imgfmt,
'file': 'imgfile', 'file': 'imgfile',

View File

@ -1,13 +1,13 @@
=== Successful image creation (defaults) === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -21,12 +21,12 @@ cluster_size: 1048576
=== Successful image creation (explicit defaults) === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -40,12 +40,12 @@ cluster_size: 1048576
=== Successful image creation (with non-default options) === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -60,7 +60,7 @@ cluster_size: 1048576
=== Invalid BlockdevRef === === 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": {}} {"return": {}}
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"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 === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -80,7 +80,7 @@ cluster_size: 1048576
=== Maximum size === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -92,19 +92,19 @@ cluster_size: 1048576
=== Invalid sizes === === 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": {}} {"return": {}}
Job failed: Unsupported VDI image size (size is 0xfffffffffffffe00, max supported is 0x1fffff8000000) Job failed: Unsupported VDI image size (size is 0xfffffffffffffe00, max supported is 0x1fffff8000000)
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Unsupported VDI image size (size is 0x8000000000000000, max supported is 0x1fffff8000000) Job failed: Unsupported VDI image size (size is 0x8000000000000000, max supported is 0x1fffff8000000)
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Unsupported VDI image size (size is 0x1fffff8000001, max supported is 0x1fffff8000000) Job failed: Unsupported VDI image size (size is 0x1fffff8000001, max supported is 0x1fffff8000000)
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}

View File

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

View File

@ -1,13 +1,13 @@
=== Successful image creation (defaults) === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -18,12 +18,12 @@ virtual size: 128M (134217728 bytes)
=== Successful image creation (explicit defaults) === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -34,12 +34,12 @@ virtual size: 64M (67108864 bytes)
=== Successful image creation (with non-default options) === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -50,7 +50,7 @@ virtual size: 32M (33554432 bytes)
=== Invalid BlockdevRef === === 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": {}} {"return": {}}
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"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 === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -69,7 +69,7 @@ virtual size: 0 (0 bytes)
=== Maximum size === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -80,31 +80,31 @@ virtual size: 4096T (4503599627369984 bytes)
=== Invalid sizes === === 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": {}} {"return": {}}
Job failed: Image size must be a multiple of 512 bytes Job failed: Image size must be a multiple of 512 bytes
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Image size is too large for this cluster size Job failed: Image size is too large for this cluster size
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Image size is too large for this cluster size Job failed: Image size is too large for this cluster size
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Image size is too large for this cluster size Job failed: Image size is too large for this cluster size
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Image size is too large for this cluster size Job failed: Image size is too large for this cluster size
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
@ -112,43 +112,43 @@ Job failed: Image size is too large for this cluster size
=== Invalid 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": {}} {"return": {}}
Job failed: Cluster size must be a multiple of 512 bytes Job failed: Cluster size must be a multiple of 512 bytes
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Cluster size must be a multiple of 512 bytes Job failed: Cluster size must be a multiple of 512 bytes
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Cluster size is too large Job failed: Cluster size is too large
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Cluster size is too large Job failed: Cluster size is too large
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Cluster size is too large Job failed: Cluster size is too large
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Image size is too large for this cluster size Job failed: Image size is too large for this cluster size
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Image size is too large for this cluster size Job failed: Image size is too large for this cluster size
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}

View File

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

View File

@ -1,13 +1,13 @@
=== Successful image creation (defaults) === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -19,12 +19,12 @@ cluster_size: 8388608
=== Successful image creation (explicit defaults) === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -36,12 +36,12 @@ cluster_size: 8388608
=== Successful image creation (with non-default options) === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -53,7 +53,7 @@ cluster_size: 268435456
=== Invalid BlockdevRef === === 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": {}} {"return": {}}
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"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 === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -73,7 +73,7 @@ cluster_size: 8388608
=== Maximum size === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -85,25 +85,25 @@ cluster_size: 67108864
=== Invalid sizes === === 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": {}} {"return": {}}
Job failed: Image size too large; max of 64TB Job failed: Image size too large; max of 64TB
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Image size too large; max of 64TB Job failed: Image size too large; max of 64TB
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Image size too large; max of 64TB Job failed: Image size too large; max of 64TB
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Image size too large; max of 64TB Job failed: Image size too large; max of 64TB
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
@ -111,31 +111,31 @@ Job failed: Image size too large; max of 64TB
=== Invalid block size === === 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": {}} {"return": {}}
Job failed: Block size must be a multiple of 1 MB Job failed: Block size must be a multiple of 1 MB
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Block size must be a multiple of 1 MB Job failed: Block size must be a multiple of 1 MB
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Block size must be a power of two Job failed: Block size must be a power of two
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Block size must not exceed 268435456 Job failed: Block size must not exceed 268435456
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Block size must be a multiple of 1 MB Job failed: Block size must be a multiple of 1 MB
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
@ -143,25 +143,25 @@ Job failed: Block size must be a multiple of 1 MB
=== Invalid log size === === 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": {}} {"return": {}}
Job failed: Log size must be a multiple of 1 MB Job failed: Log size must be a multiple of 1 MB
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Log size must be a multiple of 1 MB Job failed: Log size must be a multiple of 1 MB
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Log size must be smaller than 4 GB Job failed: Log size must be smaller than 4 GB
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
Job failed: Log size must be a multiple of 1 MB Job failed: Log size must be a multiple of 1 MB
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}

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

@ -0,0 +1,139 @@
#!/usr/bin/env python
#
# Test json:{} filenames with qemu-internal BDSs
# (the one of commit, to be precise)
#
# Copyright (C) 2018 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Creator/Owner: Max Reitz <mreitz@redhat.com>
import iotests
from iotests import log, qemu_img, qemu_io_silent, filter_qmp_testfiles, \
filter_qmp_imgfmt
import json
# Need backing file support (for arbitrary backing formats)
iotests.verify_image_format(supported_fmts=['qcow2', 'qcow', 'qed'])
iotests.verify_platform(['linux'])
# There are two variations of this test:
# (1) We do not set filter_node_name. In that case, the commit_top
# driver should not appear anywhere.
# (2) We do set filter_node_name. In that case, it should appear.
#
# This for loop executes both.
for filter_node_name in False, True:
log('')
log('--- filter_node_name: %s ---' % filter_node_name)
log('')
with iotests.FilePath('base.img') as base_img_path, \
iotests.FilePath('mid.img') as mid_img_path, \
iotests.FilePath('top.img') as top_img_path, \
iotests.VM() as vm:
assert qemu_img('create', '-f', iotests.imgfmt,
base_img_path, '64M') == 0
assert qemu_img('create', '-f', iotests.imgfmt, '-b', base_img_path,
mid_img_path) == 0
assert qemu_img('create', '-f', iotests.imgfmt, '-b', mid_img_path,
top_img_path) == 0
# Something to commit
assert qemu_io_silent(mid_img_path, '-c', 'write -P 1 0 1M') == 0
vm.launch()
# Change the bottom-most image's backing file (to null-co://)
# to enforce json:{} filenames
vm.qmp_log('blockdev-add',
node_name='top',
driver=iotests.imgfmt,
file={
'driver': 'file',
'filename': top_img_path
},
backing={
'node-name': 'mid',
'driver': iotests.imgfmt,
'file': {
'driver': 'file',
'filename': mid_img_path
},
'backing': {
'node-name': 'base',
'driver': iotests.imgfmt,
'file': {
'driver': 'file',
'filename': base_img_path
},
'backing': {
'driver': 'null-co'
}
}
},
filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
# As long as block-commit does not accept node names, we have to
# get our mid/base filenames here
mid_name = vm.node_info('mid')['image']['filename']
base_name = vm.node_info('base')['image']['filename']
assert mid_name[:5] == 'json:'
assert base_name[:5] == 'json:'
# Start the block job
if filter_node_name:
vm.qmp_log('block-commit',
job_id='commit',
device='top',
filter_node_name='filter_node',
top=mid_name,
base=base_name,
speed=1,
filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
else:
vm.qmp_log('block-commit',
job_id='commit',
device='top',
top=mid_name,
base=base_name,
speed=1,
filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
vm.qmp_log('job-pause', id='commit')
# Get and parse top's json:{} filename
top_name = vm.node_info('top')['image']['filename']
vm.shutdown()
assert top_name[:5] == 'json:'
top_options = json.loads(top_name[5:])
if filter_node_name:
# This should be present and set
assert top_options['backing']['driver'] == 'commit_top'
# And the mid image is commit_top's backing image
mid_options = top_options['backing']['backing']
else:
# The mid image should appear as the immediate backing BDS
# of top
mid_options = top_options['backing']
assert mid_options['driver'] == iotests.imgfmt
assert mid_options['file']['filename'] == mid_img_path

View File

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

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

@ -0,0 +1,239 @@
#!/usr/bin/env python
#
# Test for when a backing file is considered overridden (thus, a
# json:{} filename is generated for the overlay) and when it is not
#
# Copyright (C) 2018 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Creator/Owner: Max Reitz <mreitz@redhat.com>
import iotests
from iotests import log, qemu_img, filter_testfiles, filter_imgfmt, \
filter_qmp_testfiles, filter_qmp_imgfmt
# Need backing file and change-backing-file support
iotests.verify_image_format(supported_fmts=['qcow2', 'qed'])
iotests.verify_platform(['linux'])
def log_node_info(node):
log('')
log('bs->filename: ' + node['image']['filename'],
filters=[filter_testfiles, filter_imgfmt])
log('bs->backing_file: ' + node['backing_file'],
filters=[filter_testfiles, filter_imgfmt])
if 'backing-image' in node['image']:
log('bs->backing->bs->filename: ' +
node['image']['backing-image']['filename'],
filters=[filter_testfiles, filter_imgfmt])
else:
log('bs->backing: (none)')
log('')
with iotests.FilePath('base.img') as base_img_path, \
iotests.FilePath('top.img') as top_img_path, \
iotests.VM() as vm:
assert qemu_img('create', '-f', iotests.imgfmt, base_img_path, '64M') == 0
# Choose a funny way to describe the backing filename
assert qemu_img('create', '-f', iotests.imgfmt, '-b',
'file:' + base_img_path, top_img_path) == 0
vm.launch()
log('--- Implicit backing file ---')
log('')
vm.qmp_log('blockdev-add',
node_name='node0',
driver=iotests.imgfmt,
file={
'driver': 'file',
'filename': top_img_path
},
filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
# Filename should be plain, and the backing filename should not
# contain the "file:" prefix
log_node_info(vm.node_info('node0'))
vm.qmp_log('blockdev-del', node_name='node0')
log('')
log('--- change-backing-file ---')
log('')
vm.qmp_log('blockdev-add',
node_name='node0',
driver=iotests.imgfmt,
file={
'driver': 'file',
'filename': top_img_path
},
filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
# Changing the backing file to a qemu-reported filename should
# result in qemu accepting the corresponding BDS as the implicit
# backing BDS (and thus not generate a json:{} filename).
# So, first, query the backing filename.
backing_filename = \
vm.node_info('node0')['image']['backing-image']['filename']
# Next, change the backing file to something different
vm.qmp_log('change-backing-file',
image_node_name='node0',
device='node0',
backing_file='null-co://',
filters=[filter_qmp_testfiles])
# Now, verify that we get a json:{} filename
# (Image header says "null-co://", actual backing file still is
# base_img_path)
log_node_info(vm.node_info('node0'))
# Change it back
# (To get header and backing file in sync)
vm.qmp_log('change-backing-file',
image_node_name='node0',
device='node0',
backing_file=backing_filename,
filters=[filter_qmp_testfiles])
# And verify that we get our original results
log_node_info(vm.node_info('node0'))
# Finally, try a "file:" prefix. While this is actually what we
# originally had in the image header, qemu will not reopen the
# backing file here, so it cannot verify that this filename
# "resolves" to the actual backing BDS's filename and will thus
# consider both to be different.
# (This may be fixed in the future.)
vm.qmp_log('change-backing-file',
image_node_name='node0',
device='node0',
backing_file=('file:' + backing_filename),
filters=[filter_qmp_testfiles])
# So now we should get a json:{} filename
log_node_info(vm.node_info('node0'))
# Remove and re-attach so we can see that (as in our first try),
# opening the image anew helps qemu resolve the header backing
# filename.
vm.qmp_log('blockdev-del', node_name='node0')
vm.qmp_log('blockdev-add',
node_name='node0',
driver=iotests.imgfmt,
file={
'driver': 'file',
'filename': top_img_path
},
filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
log_node_info(vm.node_info('node0'))
vm.qmp_log('blockdev-del', node_name='node0')
log('')
log('--- Override backing file ---')
log('')
# For this test, we need the plain filename in the image header
# (because qemu cannot "canonicalize"/"resolve" the backing
# filename unless the backing file is opened implicitly with the
# overlay)
assert qemu_img('create', '-f', iotests.imgfmt, '-b', base_img_path,
top_img_path) == 0
# You can only reliably override backing options by using a node
# reference (or by specifying file.filename, but, well...)
vm.qmp_log('blockdev-add', node_name='null', driver='null-co')
vm.qmp_log('blockdev-add',
node_name='node0',
driver=iotests.imgfmt,
file={
'driver': 'file',
'filename': top_img_path
},
backing='null',
filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
# Should get a json:{} filename (and bs->backing_file is
# null-co://, because that field actually has not much to do
# with the header backing filename (except that it is changed by
# change-backing-file))
log_node_info(vm.node_info('node0'))
# Detach the backing file by reopening the whole thing
vm.qmp_log('blockdev-del', node_name='node0')
vm.qmp_log('blockdev-del', node_name='null')
vm.qmp_log('blockdev-add',
node_name='node0',
driver=iotests.imgfmt,
file={
'driver': 'file',
'filename': top_img_path
},
backing=None,
filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
# Should get a json:{} filename (because we overrode the backing
# file to not be there)
log_node_info(vm.node_info('node0'))
# Open the original backing file
vm.qmp_log('blockdev-add',
node_name='original-backing',
driver=iotests.imgfmt,
file={
'driver': 'file',
'filename': base_img_path
},
filters=[filter_qmp_testfiles, filter_qmp_imgfmt])
# Attach the original backing file to its overlay
vm.qmp_log('blockdev-snapshot',
node='original-backing',
overlay='node0')
# This should give us the original plain result
log_node_info(vm.node_info('node0'))
vm.qmp_log('blockdev-del', node_name='node0')
vm.qmp_log('blockdev-del', node_name='original-backing')
vm.shutdown()

View File

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

View File

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

View File

@ -27,7 +27,8 @@ from iotests import imgfmt
iotests.verify_image_format(supported_fmts=['vmdk']) iotests.verify_image_format(supported_fmts=['vmdk'])
def blockdev_create(vm, options): 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: if 'return' in result:
assert result['return'] == {} assert result['return'] == {}
@ -54,7 +55,7 @@ with iotests.FilePath('t.vmdk') as disk_path, \
'size': 0 }) 'size': 0 })
vm.qmp_log('blockdev-add', driver='file', filename=disk_path, 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, blockdev_create(vm, { 'driver': imgfmt,
'file': 'imgfile', 'file': 'imgfile',
@ -223,7 +224,7 @@ with iotests.FilePath('t.vmdk') as disk_path, \
iotests.log("= %s %d =" % (subfmt, size)) iotests.log("= %s %d =" % (subfmt, size))
iotests.log("") 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) ] extents = [ "ext%d" % (i) for i in range(1, num_extents + 1) ]
vm.launch() vm.launch()

View File

@ -1,13 +1,13 @@
=== Successful image creation (defaults) === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -29,12 +29,12 @@ Format specific information:
=== Successful image creation (inline blockdev-add, explicit defaults) === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -56,12 +56,12 @@ Format specific information:
=== Successful image creation (with non-default options) === === 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -83,7 +83,7 @@ Format specific information:
=== Invalid BlockdevRef === === 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": {}} {"return": {}}
Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"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 == == 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
== Invalid adapter types == == 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'"}} {"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'"}} {"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'"}} {"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"}} {"error": {"class": "GenericError", "desc": "Invalid parameter type for 'options.adapter-type', expected: string"}}
=== Other subformats === === Other subformats ===
@ -137,7 +137,7 @@ Formatting 'TEST_DIR/PID-t.vmdk.3', fmt=vmdk size=0 compat6=off hwversion=undefi
== Missing extent == == 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": {}} {"return": {}}
Job failed: Extent [0] not specified Job failed: Extent [0] not specified
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
@ -145,14 +145,14 @@ Job failed: Extent [0] not specified
== Correct extent == == 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
== Extra extent == == 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": {}} {"return": {}}
Job failed: List of extents contains unused extents Job failed: List of extents contains unused extents
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
@ -162,7 +162,7 @@ Job failed: List of extents contains unused extents
= twoGbMaxExtentFlat 512 = = 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -182,7 +182,7 @@ Format specific information:
= twoGbMaxExtentSparse 512 = = 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -204,7 +204,7 @@ Format specific information:
= twoGbMaxExtentFlat 1073741824 = = 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -224,7 +224,7 @@ Format specific information:
= twoGbMaxExtentSparse 1073741824 = = 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -246,7 +246,7 @@ Format specific information:
= twoGbMaxExtentFlat 2147483648 = = 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -266,7 +266,7 @@ Format specific information:
= twoGbMaxExtentSparse 2147483648 = = 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -288,7 +288,7 @@ Format specific information:
= twoGbMaxExtentFlat 5368709120 = = 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}
@ -316,7 +316,7 @@ Format specific information:
= twoGbMaxExtentSparse 5368709120 = = 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": {}} {"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}} {"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}} {"return": {}}

View File

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

View File

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

View File

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