QAPI patches for 2017-07-18
-----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJZddzIAAoJEDhwtADrkYZTNWcQALGul4VFe3NobBGAyv0tOT13 1a1dtILD99IwC2aR5/ADqZyejMO7PiCNav7aQmQn3G7tFEleWMBZCj/zG0O756DF UDxBLF9xpEu5i1uV9PAsW8K/FfZcsibAkDFCHpPJImOUtbijqJnhM2L++m+ctPvM GlI0VRD8MA34qjmcra2QtapHSHPfi4SF33dcxiUxc3bTSKAJjarE4mhdR7Z8pj74 r1iu0w/2FvNs94LPIp1Ma7WtwRw4K1IypPf6815aaNNB49ahOWi/bHk9zNz4wYKG Kt63zAAie3WxzaPUH238ZXh7AtGpIYTKYNCAF93URqf28ZrfkFrlaYX08hRvWeSr U17KA/1ud/9xdNMW2uKs9ANE+vuWpZ543in4xO9FC0Jmdbq7PBp4TzHNRq5qTvNm zAc2Q2d7dUhd2uYqkzYdgo9MR9qx9TY66RqPw050Il6oLxQoOjFp02Fgg9Z2WF9Q pOOPr6uuvLw8MoesEK0IQVtUxCWK2113VTSUgdw5Mr0KEaWMIVDigV47kkItWjw/ 2mcwI+d/ZEEgagSaYhmw1qGUEVrZQ2qWQNLwcGpjfSHSAkG2V7lv3JEUmdQLFOLA VXr2dtVHXRT/ZsxdoTze8O8At4tI1SDAIFI00H8oXi8Nbwtp3w0C40JApFNQHnku bSJo536xTMeQbCiPbrst =DCKd -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2017-07-18-v2' into staging QAPI patches for 2017-07-18 # gpg: Signature made Mon 24 Jul 2017 12:40:56 BST # gpg: using RSA key 0x3870B400EB918653 # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" # Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653 * remotes/armbru/tags/pull-qapi-2017-07-18-v2: migration: Use JSON null instead of "" to reset parameter to default migration: Unshare MigrationParameters struct for now migration: Add TODO comments on duplication of QAPI_CLONE() migration: Clean up around tls_creds, tls_hostname hmp: Clean up and simplify hmp_migrate_set_parameter() block: Use JSON null instead of "" to disable backing file tests/test-qobject-input-visitor: Drop redundant test qapi: Introduce a first class 'null' type qapi: Use QNull for a more regular visit_type_null() qapi: Separate type QNull from QObject Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
cf44d31d35
14
blockdev.c
14
blockdev.c
@ -3887,6 +3887,7 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
|||||||
QObject *obj;
|
QObject *obj;
|
||||||
Visitor *v = qobject_output_visitor_new(&obj);
|
Visitor *v = qobject_output_visitor_new(&obj);
|
||||||
QDict *qdict;
|
QDict *qdict;
|
||||||
|
const QDictEntry *ent;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
visit_type_BlockdevOptions(v, NULL, &options, &local_err);
|
visit_type_BlockdevOptions(v, NULL, &options, &local_err);
|
||||||
@ -3900,6 +3901,19 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
|||||||
|
|
||||||
qdict_flatten(qdict);
|
qdict_flatten(qdict);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Rewrite "backing": null to "backing": ""
|
||||||
|
* TODO Rewrite "" to null instead, and perhaps not even here
|
||||||
|
*/
|
||||||
|
for (ent = qdict_first(qdict); ent; ent = qdict_next(qdict, ent)) {
|
||||||
|
char *dot = strrchr(ent->key, '.');
|
||||||
|
|
||||||
|
if (!strcmp(dot ? dot + 1 : ent->key, "backing")
|
||||||
|
&& qobject_type(ent->value) == QTYPE_QNULL) {
|
||||||
|
qdict_put(qdict, ent->key, qstring_new());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!qdict_get_try_str(qdict, "node-name")) {
|
if (!qdict_get_try_str(qdict, "node-name")) {
|
||||||
error_setg(errp, "'node-name' must be specified for the root node");
|
error_setg(errp, "'node-name' must be specified for the root node");
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -282,6 +282,7 @@ The following types are predefined, and map to C as follows:
|
|||||||
size uint64_t like uint64_t, except StringInputVisitor
|
size uint64_t like uint64_t, except StringInputVisitor
|
||||||
accepts size suffixes
|
accepts size suffixes
|
||||||
bool bool JSON true or false
|
bool bool JSON true or false
|
||||||
|
null QNull * JSON null
|
||||||
any QObject * any JSON value
|
any QObject * any JSON value
|
||||||
QType QType JSON string matching enum QType values
|
QType QType JSON string matching enum QType values
|
||||||
|
|
||||||
@ -536,10 +537,11 @@ can only express a choice between types represented differently in
|
|||||||
JSON. If a branch is typed as the 'bool' built-in, the alternate
|
JSON. If a branch is typed as the 'bool' built-in, the alternate
|
||||||
accepts true and false; if it is typed as any of the various numeric
|
accepts true and false; if it is typed as any of the various numeric
|
||||||
built-ins, it accepts a JSON number; if it is typed as a 'str'
|
built-ins, it accepts a JSON number; if it is typed as a 'str'
|
||||||
built-in or named enum type, it accepts a JSON string; and if it is
|
built-in or named enum type, it accepts a JSON string; if it is typed
|
||||||
typed as a complex type (struct or union), it accepts a JSON object.
|
as the 'null' built-in, it accepts JSON null; and if it is typed as a
|
||||||
Two different complex types, for instance, aren't permitted, because
|
complex type (struct or union), it accepts a JSON object. Two
|
||||||
both are represented as a JSON object.
|
different complex types, for instance, aren't permitted, because both
|
||||||
|
are represented as a JSON object.
|
||||||
|
|
||||||
The example alternate declaration above allows using both of the
|
The example alternate declaration above allows using both of the
|
||||||
following example objects:
|
following example objects:
|
||||||
|
84
hmp.c
84
hmp.c
@ -313,12 +313,14 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict)
|
|||||||
monitor_printf(mon, "%s: %" PRId64 "\n",
|
monitor_printf(mon, "%s: %" PRId64 "\n",
|
||||||
MigrationParameter_lookup[MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT],
|
MigrationParameter_lookup[MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT],
|
||||||
params->cpu_throttle_increment);
|
params->cpu_throttle_increment);
|
||||||
|
assert(params->has_tls_creds);
|
||||||
monitor_printf(mon, "%s: '%s'\n",
|
monitor_printf(mon, "%s: '%s'\n",
|
||||||
MigrationParameter_lookup[MIGRATION_PARAMETER_TLS_CREDS],
|
MigrationParameter_lookup[MIGRATION_PARAMETER_TLS_CREDS],
|
||||||
params->has_tls_creds ? params->tls_creds : "");
|
params->tls_creds);
|
||||||
|
assert(params->has_tls_hostname);
|
||||||
monitor_printf(mon, "%s: '%s'\n",
|
monitor_printf(mon, "%s: '%s'\n",
|
||||||
MigrationParameter_lookup[MIGRATION_PARAMETER_TLS_HOSTNAME],
|
MigrationParameter_lookup[MIGRATION_PARAMETER_TLS_HOSTNAME],
|
||||||
params->has_tls_hostname ? params->tls_hostname : "");
|
params->tls_hostname);
|
||||||
assert(params->has_max_bandwidth);
|
assert(params->has_max_bandwidth);
|
||||||
monitor_printf(mon, "%s: %" PRId64 " bytes/second\n",
|
monitor_printf(mon, "%s: %" PRId64 " bytes/second\n",
|
||||||
MigrationParameter_lookup[MIGRATION_PARAMETER_MAX_BANDWIDTH],
|
MigrationParameter_lookup[MIGRATION_PARAMETER_MAX_BANDWIDTH],
|
||||||
@ -1554,90 +1556,79 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
|
|||||||
const char *param = qdict_get_str(qdict, "parameter");
|
const char *param = qdict_get_str(qdict, "parameter");
|
||||||
const char *valuestr = qdict_get_str(qdict, "value");
|
const char *valuestr = qdict_get_str(qdict, "value");
|
||||||
Visitor *v = string_input_visitor_new(valuestr);
|
Visitor *v = string_input_visitor_new(valuestr);
|
||||||
|
MigrateSetParameters *p = g_new0(MigrateSetParameters, 1);
|
||||||
uint64_t valuebw = 0;
|
uint64_t valuebw = 0;
|
||||||
int64_t valueint = 0;
|
|
||||||
bool valuebool = false;
|
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
bool use_int_value = false;
|
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
|
||||||
for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) {
|
for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) {
|
||||||
if (strcmp(param, MigrationParameter_lookup[i]) == 0) {
|
if (strcmp(param, MigrationParameter_lookup[i]) == 0) {
|
||||||
MigrationParameters p = { 0 };
|
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case MIGRATION_PARAMETER_COMPRESS_LEVEL:
|
case MIGRATION_PARAMETER_COMPRESS_LEVEL:
|
||||||
p.has_compress_level = true;
|
p->has_compress_level = true;
|
||||||
use_int_value = true;
|
visit_type_int(v, param, &p->compress_level, &err);
|
||||||
break;
|
break;
|
||||||
case MIGRATION_PARAMETER_COMPRESS_THREADS:
|
case MIGRATION_PARAMETER_COMPRESS_THREADS:
|
||||||
p.has_compress_threads = true;
|
p->has_compress_threads = true;
|
||||||
use_int_value = true;
|
visit_type_int(v, param, &p->compress_threads, &err);
|
||||||
break;
|
break;
|
||||||
case MIGRATION_PARAMETER_DECOMPRESS_THREADS:
|
case MIGRATION_PARAMETER_DECOMPRESS_THREADS:
|
||||||
p.has_decompress_threads = true;
|
p->has_decompress_threads = true;
|
||||||
use_int_value = true;
|
visit_type_int(v, param, &p->decompress_threads, &err);
|
||||||
break;
|
break;
|
||||||
case MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL:
|
case MIGRATION_PARAMETER_CPU_THROTTLE_INITIAL:
|
||||||
p.has_cpu_throttle_initial = true;
|
p->has_cpu_throttle_initial = true;
|
||||||
use_int_value = true;
|
visit_type_int(v, param, &p->cpu_throttle_initial, &err);
|
||||||
break;
|
break;
|
||||||
case MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT:
|
case MIGRATION_PARAMETER_CPU_THROTTLE_INCREMENT:
|
||||||
p.has_cpu_throttle_increment = true;
|
p->has_cpu_throttle_increment = true;
|
||||||
use_int_value = true;
|
visit_type_int(v, param, &p->cpu_throttle_increment, &err);
|
||||||
break;
|
break;
|
||||||
case MIGRATION_PARAMETER_TLS_CREDS:
|
case MIGRATION_PARAMETER_TLS_CREDS:
|
||||||
p.has_tls_creds = true;
|
p->has_tls_creds = true;
|
||||||
p.tls_creds = (char *) valuestr;
|
p->tls_creds = g_new0(StrOrNull, 1);
|
||||||
|
p->tls_creds->type = QTYPE_QSTRING;
|
||||||
|
visit_type_str(v, param, &p->tls_creds->u.s, &err);
|
||||||
break;
|
break;
|
||||||
case MIGRATION_PARAMETER_TLS_HOSTNAME:
|
case MIGRATION_PARAMETER_TLS_HOSTNAME:
|
||||||
p.has_tls_hostname = true;
|
p->has_tls_hostname = true;
|
||||||
p.tls_hostname = (char *) valuestr;
|
p->tls_hostname = g_new0(StrOrNull, 1);
|
||||||
|
p->tls_hostname->type = QTYPE_QSTRING;
|
||||||
|
visit_type_str(v, param, &p->tls_hostname->u.s, &err);
|
||||||
break;
|
break;
|
||||||
case MIGRATION_PARAMETER_MAX_BANDWIDTH:
|
case MIGRATION_PARAMETER_MAX_BANDWIDTH:
|
||||||
p.has_max_bandwidth = true;
|
p->has_max_bandwidth = true;
|
||||||
|
/*
|
||||||
|
* Can't use visit_type_size() here, because it
|
||||||
|
* defaults to Bytes rather than Mebibytes.
|
||||||
|
*/
|
||||||
ret = qemu_strtosz_MiB(valuestr, NULL, &valuebw);
|
ret = qemu_strtosz_MiB(valuestr, NULL, &valuebw);
|
||||||
if (ret < 0 || valuebw > INT64_MAX
|
if (ret < 0 || valuebw > INT64_MAX
|
||||||
|| (size_t)valuebw != valuebw) {
|
|| (size_t)valuebw != valuebw) {
|
||||||
error_setg(&err, "Invalid size %s", valuestr);
|
error_setg(&err, "Invalid size %s", valuestr);
|
||||||
goto cleanup;
|
break;
|
||||||
}
|
}
|
||||||
p.max_bandwidth = valuebw;
|
p->max_bandwidth = valuebw;
|
||||||
break;
|
break;
|
||||||
case MIGRATION_PARAMETER_DOWNTIME_LIMIT:
|
case MIGRATION_PARAMETER_DOWNTIME_LIMIT:
|
||||||
p.has_downtime_limit = true;
|
p->has_downtime_limit = true;
|
||||||
use_int_value = true;
|
visit_type_int(v, param, &p->downtime_limit, &err);
|
||||||
break;
|
break;
|
||||||
case MIGRATION_PARAMETER_X_CHECKPOINT_DELAY:
|
case MIGRATION_PARAMETER_X_CHECKPOINT_DELAY:
|
||||||
p.has_x_checkpoint_delay = true;
|
p->has_x_checkpoint_delay = true;
|
||||||
use_int_value = true;
|
visit_type_int(v, param, &p->x_checkpoint_delay, &err);
|
||||||
break;
|
break;
|
||||||
case MIGRATION_PARAMETER_BLOCK_INCREMENTAL:
|
case MIGRATION_PARAMETER_BLOCK_INCREMENTAL:
|
||||||
p.has_block_incremental = true;
|
p->has_block_incremental = true;
|
||||||
visit_type_bool(v, param, &valuebool, &err);
|
visit_type_bool(v, param, &p->block_incremental, &err);
|
||||||
if (err) {
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
p.block_incremental = valuebool;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_int_value) {
|
|
||||||
visit_type_int(v, param, &valueint, &err);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
/* Set all integers; only one has_FOO will be set, and
|
|
||||||
* the code ignores the remaining values */
|
|
||||||
p.compress_level = valueint;
|
|
||||||
p.compress_threads = valueint;
|
|
||||||
p.decompress_threads = valueint;
|
|
||||||
p.cpu_throttle_initial = valueint;
|
|
||||||
p.cpu_throttle_increment = valueint;
|
|
||||||
p.downtime_limit = valueint;
|
|
||||||
p.x_checkpoint_delay = valueint;
|
|
||||||
}
|
|
||||||
|
|
||||||
qmp_migrate_set_parameters(&p, &err);
|
qmp_migrate_set_parameters(p, &err);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1647,6 +1638,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
qapi_free_MigrateSetParameters(p);
|
||||||
visit_free(v);
|
visit_free(v);
|
||||||
if (err) {
|
if (err) {
|
||||||
error_report_err(err);
|
error_report_err(err);
|
||||||
|
@ -297,12 +297,14 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name,
|
|||||||
void *opaque, Error **errp)
|
void *opaque, Error **errp)
|
||||||
{
|
{
|
||||||
sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
|
sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
|
||||||
|
QNull *null = NULL;
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
int fdt_offset_next, fdt_offset, fdt_depth;
|
int fdt_offset_next, fdt_offset, fdt_depth;
|
||||||
void *fdt;
|
void *fdt;
|
||||||
|
|
||||||
if (!drc->fdt) {
|
if (!drc->fdt) {
|
||||||
visit_type_null(v, NULL, errp);
|
visit_type_null(v, NULL, &null, errp);
|
||||||
|
QDECREF(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,11 +93,15 @@ static inline QType qobject_type(const QObject *obj)
|
|||||||
return obj->type;
|
return obj->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern QObject qnull_;
|
struct QNull {
|
||||||
|
QObject base;
|
||||||
|
};
|
||||||
|
|
||||||
static inline QObject *qnull(void)
|
extern QNull qnull_;
|
||||||
|
|
||||||
|
static inline QNull *qnull(void)
|
||||||
{
|
{
|
||||||
qobject_incref(&qnull_);
|
QINCREF(&qnull_);
|
||||||
return &qnull_;
|
return &qnull_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +103,8 @@ struct Visitor
|
|||||||
Error **errp);
|
Error **errp);
|
||||||
|
|
||||||
/* Must be set to visit explicit null values. */
|
/* Must be set to visit explicit null values. */
|
||||||
void (*type_null)(Visitor *v, const char *name, Error **errp);
|
void (*type_null)(Visitor *v, const char *name, QNull **obj,
|
||||||
|
Error **errp);
|
||||||
|
|
||||||
/* Must be set for input visitors to visit structs, optional otherwise.
|
/* Must be set for input visitors to visit structs, optional otherwise.
|
||||||
The core takes care of the return type in the public interface. */
|
The core takes care of the return type in the public interface. */
|
||||||
|
@ -618,10 +618,10 @@ void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp);
|
|||||||
* @name expresses the relationship of the null value to its parent
|
* @name expresses the relationship of the null value to its parent
|
||||||
* container; see the general description of @name above.
|
* container; see the general description of @name above.
|
||||||
*
|
*
|
||||||
* Unlike all other visit_type_* functions, no obj parameter is
|
* @obj must be non-NULL. Input visitors set *@obj to the value;
|
||||||
* needed; rather, this is a witness that an explicit null value is
|
* other visitors ignore *@obj.
|
||||||
* expected rather than any other type.
|
|
||||||
*/
|
*/
|
||||||
void visit_type_null(Visitor *v, const char *name, Error **errp);
|
void visit_type_null(Visitor *v, const char *name, QNull **obj,
|
||||||
|
Error **errp);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -89,6 +89,7 @@ typedef struct QEMUSGList QEMUSGList;
|
|||||||
typedef struct QEMUTimer QEMUTimer;
|
typedef struct QEMUTimer QEMUTimer;
|
||||||
typedef struct QEMUTimerListGroup QEMUTimerListGroup;
|
typedef struct QEMUTimerListGroup QEMUTimerListGroup;
|
||||||
typedef struct QObject QObject;
|
typedef struct QObject QObject;
|
||||||
|
typedef struct QNull QNull;
|
||||||
typedef struct RAMBlock RAMBlock;
|
typedef struct RAMBlock RAMBlock;
|
||||||
typedef struct Range Range;
|
typedef struct Range Range;
|
||||||
typedef struct SerialState SerialState;
|
typedef struct SerialState SerialState;
|
||||||
|
@ -433,6 +433,7 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
|
|||||||
MigrationParameters *params;
|
MigrationParameters *params;
|
||||||
MigrationState *s = migrate_get_current();
|
MigrationState *s = migrate_get_current();
|
||||||
|
|
||||||
|
/* TODO use QAPI_CLONE() instead of duplicating it inline */
|
||||||
params = g_malloc0(sizeof(*params));
|
params = g_malloc0(sizeof(*params));
|
||||||
params->has_compress_level = true;
|
params->has_compress_level = true;
|
||||||
params->compress_level = s->parameters.compress_level;
|
params->compress_level = s->parameters.compress_level;
|
||||||
@ -444,9 +445,9 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
|
|||||||
params->cpu_throttle_initial = s->parameters.cpu_throttle_initial;
|
params->cpu_throttle_initial = s->parameters.cpu_throttle_initial;
|
||||||
params->has_cpu_throttle_increment = true;
|
params->has_cpu_throttle_increment = true;
|
||||||
params->cpu_throttle_increment = s->parameters.cpu_throttle_increment;
|
params->cpu_throttle_increment = s->parameters.cpu_throttle_increment;
|
||||||
params->has_tls_creds = !!s->parameters.tls_creds;
|
params->has_tls_creds = true;
|
||||||
params->tls_creds = g_strdup(s->parameters.tls_creds);
|
params->tls_creds = g_strdup(s->parameters.tls_creds);
|
||||||
params->has_tls_hostname = !!s->parameters.tls_hostname;
|
params->has_tls_hostname = true;
|
||||||
params->tls_hostname = g_strdup(s->parameters.tls_hostname);
|
params->tls_hostname = g_strdup(s->parameters.tls_hostname);
|
||||||
params->has_max_bandwidth = true;
|
params->has_max_bandwidth = true;
|
||||||
params->max_bandwidth = s->parameters.max_bandwidth;
|
params->max_bandwidth = s->parameters.max_bandwidth;
|
||||||
@ -741,10 +742,66 @@ static bool migrate_params_check(MigrationParameters *params, Error **errp)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void migrate_params_apply(MigrationParameters *params)
|
static void migrate_params_test_apply(MigrateSetParameters *params,
|
||||||
|
MigrationParameters *dest)
|
||||||
|
{
|
||||||
|
*dest = migrate_get_current()->parameters;
|
||||||
|
|
||||||
|
/* TODO use QAPI_CLONE() instead of duplicating it inline */
|
||||||
|
|
||||||
|
if (params->has_compress_level) {
|
||||||
|
dest->compress_level = params->compress_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->has_compress_threads) {
|
||||||
|
dest->compress_threads = params->compress_threads;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->has_decompress_threads) {
|
||||||
|
dest->decompress_threads = params->decompress_threads;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->has_cpu_throttle_initial) {
|
||||||
|
dest->cpu_throttle_initial = params->cpu_throttle_initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->has_cpu_throttle_increment) {
|
||||||
|
dest->cpu_throttle_increment = params->cpu_throttle_increment;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->has_tls_creds) {
|
||||||
|
assert(params->tls_creds->type == QTYPE_QSTRING);
|
||||||
|
dest->tls_creds = g_strdup(params->tls_creds->u.s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->has_tls_hostname) {
|
||||||
|
assert(params->tls_hostname->type == QTYPE_QSTRING);
|
||||||
|
dest->tls_hostname = g_strdup(params->tls_hostname->u.s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->has_max_bandwidth) {
|
||||||
|
dest->max_bandwidth = params->max_bandwidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->has_downtime_limit) {
|
||||||
|
dest->downtime_limit = params->downtime_limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->has_x_checkpoint_delay) {
|
||||||
|
dest->x_checkpoint_delay = params->x_checkpoint_delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->has_block_incremental) {
|
||||||
|
dest->block_incremental = params->block_incremental;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void migrate_params_apply(MigrateSetParameters *params)
|
||||||
{
|
{
|
||||||
MigrationState *s = migrate_get_current();
|
MigrationState *s = migrate_get_current();
|
||||||
|
|
||||||
|
/* TODO use QAPI_CLONE() instead of duplicating it inline */
|
||||||
|
|
||||||
if (params->has_compress_level) {
|
if (params->has_compress_level) {
|
||||||
s->parameters.compress_level = params->compress_level;
|
s->parameters.compress_level = params->compress_level;
|
||||||
}
|
}
|
||||||
@ -767,12 +824,14 @@ static void migrate_params_apply(MigrationParameters *params)
|
|||||||
|
|
||||||
if (params->has_tls_creds) {
|
if (params->has_tls_creds) {
|
||||||
g_free(s->parameters.tls_creds);
|
g_free(s->parameters.tls_creds);
|
||||||
s->parameters.tls_creds = g_strdup(params->tls_creds);
|
assert(params->tls_creds->type == QTYPE_QSTRING);
|
||||||
|
s->parameters.tls_creds = g_strdup(params->tls_creds->u.s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params->has_tls_hostname) {
|
if (params->has_tls_hostname) {
|
||||||
g_free(s->parameters.tls_hostname);
|
g_free(s->parameters.tls_hostname);
|
||||||
s->parameters.tls_hostname = g_strdup(params->tls_hostname);
|
assert(params->tls_hostname->type == QTYPE_QSTRING);
|
||||||
|
s->parameters.tls_hostname = g_strdup(params->tls_hostname->u.s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params->has_max_bandwidth) {
|
if (params->has_max_bandwidth) {
|
||||||
@ -799,9 +858,28 @@ static void migrate_params_apply(MigrationParameters *params)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
|
void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp)
|
||||||
{
|
{
|
||||||
if (!migrate_params_check(params, errp)) {
|
MigrationParameters tmp;
|
||||||
|
|
||||||
|
/* TODO Rewrite "" to null instead */
|
||||||
|
if (params->has_tls_creds
|
||||||
|
&& params->tls_creds->type == QTYPE_QNULL) {
|
||||||
|
QDECREF(params->tls_creds->u.n);
|
||||||
|
params->tls_creds->type = QTYPE_QSTRING;
|
||||||
|
params->tls_creds->u.s = strdup("");
|
||||||
|
}
|
||||||
|
/* TODO Rewrite "" to null instead */
|
||||||
|
if (params->has_tls_hostname
|
||||||
|
&& params->tls_hostname->type == QTYPE_QNULL) {
|
||||||
|
QDECREF(params->tls_hostname->u.n);
|
||||||
|
params->tls_hostname->type = QTYPE_QSTRING;
|
||||||
|
params->tls_hostname->u.s = strdup("");
|
||||||
|
}
|
||||||
|
|
||||||
|
migrate_params_test_apply(params, &tmp);
|
||||||
|
|
||||||
|
if (!migrate_params_check(&tmp, errp)) {
|
||||||
/* Invalid parameter */
|
/* Invalid parameter */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1237,7 +1315,7 @@ int64_t qmp_query_migrate_cache_size(Error **errp)
|
|||||||
|
|
||||||
void qmp_migrate_set_speed(int64_t value, Error **errp)
|
void qmp_migrate_set_speed(int64_t value, Error **errp)
|
||||||
{
|
{
|
||||||
MigrationParameters p = {
|
MigrateSetParameters p = {
|
||||||
.has_max_bandwidth = true,
|
.has_max_bandwidth = true,
|
||||||
.max_bandwidth = value,
|
.max_bandwidth = value,
|
||||||
};
|
};
|
||||||
@ -1257,7 +1335,7 @@ void qmp_migrate_set_downtime(double value, Error **errp)
|
|||||||
value *= 1000; /* Convert to milliseconds */
|
value *= 1000; /* Convert to milliseconds */
|
||||||
value = MAX(0, MIN(INT64_MAX, value));
|
value = MAX(0, MIN(INT64_MAX, value));
|
||||||
|
|
||||||
MigrationParameters p = {
|
MigrateSetParameters p = {
|
||||||
.has_downtime_limit = true,
|
.has_downtime_limit = true,
|
||||||
.downtime_limit = value,
|
.downtime_limit = value,
|
||||||
};
|
};
|
||||||
|
108
qapi-schema.json
108
qapi-schema.json
@ -115,6 +115,22 @@
|
|||||||
##
|
##
|
||||||
{ 'command': 'qmp_capabilities' }
|
{ 'command': 'qmp_capabilities' }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @StrOrNull:
|
||||||
|
#
|
||||||
|
# This is a string value or the explicit lack of a string (null
|
||||||
|
# pointer in C). Intended for cases when 'optional absent' already
|
||||||
|
# has a different meaning.
|
||||||
|
#
|
||||||
|
# @s: the string value
|
||||||
|
# @n: no string value
|
||||||
|
#
|
||||||
|
# Since: 2.10
|
||||||
|
##
|
||||||
|
{ 'alternate': 'StrOrNull',
|
||||||
|
'data': { 's': 'str',
|
||||||
|
'n': 'null' } }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @LostTickPolicy:
|
# @LostTickPolicy:
|
||||||
#
|
#
|
||||||
@ -1034,6 +1050,77 @@
|
|||||||
'tls-creds', 'tls-hostname', 'max-bandwidth',
|
'tls-creds', 'tls-hostname', 'max-bandwidth',
|
||||||
'downtime-limit', 'x-checkpoint-delay', 'block-incremental' ] }
|
'downtime-limit', 'x-checkpoint-delay', 'block-incremental' ] }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @MigrateSetParameters:
|
||||||
|
#
|
||||||
|
# @compress-level: compression level
|
||||||
|
#
|
||||||
|
# @compress-threads: compression thread count
|
||||||
|
#
|
||||||
|
# @decompress-threads: decompression thread count
|
||||||
|
#
|
||||||
|
# @cpu-throttle-initial: Initial percentage of time guest cpus are
|
||||||
|
# throttled when migration auto-converge is activated.
|
||||||
|
# The default value is 20. (Since 2.7)
|
||||||
|
#
|
||||||
|
# @cpu-throttle-increment: throttle percentage increase each time
|
||||||
|
# auto-converge detects that migration is not making
|
||||||
|
# progress. The default value is 10. (Since 2.7)
|
||||||
|
#
|
||||||
|
# @tls-creds: ID of the 'tls-creds' object that provides credentials
|
||||||
|
# for establishing a TLS connection over the migration data
|
||||||
|
# channel. On the outgoing side of the migration, the credentials
|
||||||
|
# must be for a 'client' endpoint, while for the incoming side the
|
||||||
|
# credentials must be for a 'server' endpoint. Setting this
|
||||||
|
# to a non-empty string enables TLS for all migrations.
|
||||||
|
# An empty string means that QEMU will use plain text mode for
|
||||||
|
# migration, rather than TLS (Since 2.9)
|
||||||
|
# Previously (since 2.7), this was reported by omitting
|
||||||
|
# tls-creds instead.
|
||||||
|
#
|
||||||
|
# @tls-hostname: hostname of the target host for the migration. This
|
||||||
|
# is required when using x509 based TLS credentials and the
|
||||||
|
# migration URI does not already include a hostname. For
|
||||||
|
# example if using fd: or exec: based migration, the
|
||||||
|
# hostname must be provided so that the server's x509
|
||||||
|
# certificate identity can be validated. (Since 2.7)
|
||||||
|
# An empty string means that QEMU will use the hostname
|
||||||
|
# associated with the migration URI, if any. (Since 2.9)
|
||||||
|
# Previously (since 2.7), this was reported by omitting
|
||||||
|
# tls-hostname instead.
|
||||||
|
#
|
||||||
|
# @max-bandwidth: to set maximum speed for migration. maximum speed in
|
||||||
|
# bytes per second. (Since 2.8)
|
||||||
|
#
|
||||||
|
# @downtime-limit: set maximum tolerated downtime for migration. maximum
|
||||||
|
# downtime in milliseconds (Since 2.8)
|
||||||
|
#
|
||||||
|
# @x-checkpoint-delay: the delay time between two COLO checkpoints. (Since 2.8)
|
||||||
|
#
|
||||||
|
# @block-incremental: Affects how much storage is migrated when the
|
||||||
|
# block migration capability is enabled. When false, the entire
|
||||||
|
# storage backing chain is migrated into a flattened image at
|
||||||
|
# the destination; when true, only the active qcow2 layer is
|
||||||
|
# migrated and the destination must already have access to the
|
||||||
|
# same backing chain as was used on the source. (since 2.10)
|
||||||
|
#
|
||||||
|
# Since: 2.4
|
||||||
|
##
|
||||||
|
# TODO either fuse back into MigrationParameters, or make
|
||||||
|
# MigrationParameters members mandatory
|
||||||
|
{ 'struct': 'MigrateSetParameters',
|
||||||
|
'data': { '*compress-level': 'int',
|
||||||
|
'*compress-threads': 'int',
|
||||||
|
'*decompress-threads': 'int',
|
||||||
|
'*cpu-throttle-initial': 'int',
|
||||||
|
'*cpu-throttle-increment': 'int',
|
||||||
|
'*tls-creds': 'StrOrNull',
|
||||||
|
'*tls-hostname': 'StrOrNull',
|
||||||
|
'*max-bandwidth': 'int',
|
||||||
|
'*downtime-limit': 'int',
|
||||||
|
'*x-checkpoint-delay': 'int',
|
||||||
|
'*block-incremental': 'bool' } }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @migrate-set-parameters:
|
# @migrate-set-parameters:
|
||||||
#
|
#
|
||||||
@ -1048,15 +1135,12 @@
|
|||||||
#
|
#
|
||||||
##
|
##
|
||||||
{ 'command': 'migrate-set-parameters', 'boxed': true,
|
{ 'command': 'migrate-set-parameters', 'boxed': true,
|
||||||
'data': 'MigrationParameters' }
|
'data': 'MigrateSetParameters' }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @MigrationParameters:
|
# @MigrationParameters:
|
||||||
#
|
#
|
||||||
# Optional members can be omitted on input ('migrate-set-parameters')
|
# The optional members aren't actually optional.
|
||||||
# but most members will always be present on output
|
|
||||||
# ('query-migrate-parameters'), with the exception of tls-creds and
|
|
||||||
# tls-hostname.
|
|
||||||
#
|
#
|
||||||
# @compress-level: compression level
|
# @compress-level: compression level
|
||||||
#
|
#
|
||||||
@ -1065,22 +1149,21 @@
|
|||||||
# @decompress-threads: decompression thread count
|
# @decompress-threads: decompression thread count
|
||||||
#
|
#
|
||||||
# @cpu-throttle-initial: Initial percentage of time guest cpus are
|
# @cpu-throttle-initial: Initial percentage of time guest cpus are
|
||||||
# throttledwhen migration auto-converge is activated.
|
# throttled when migration auto-converge is activated.
|
||||||
# The default value is 20. (Since 2.7)
|
# (Since 2.7)
|
||||||
#
|
#
|
||||||
# @cpu-throttle-increment: throttle percentage increase each time
|
# @cpu-throttle-increment: throttle percentage increase each time
|
||||||
# auto-converge detects that migration is not making
|
# auto-converge detects that migration is not making
|
||||||
# progress. The default value is 10. (Since 2.7)
|
# progress. (Since 2.7)
|
||||||
#
|
#
|
||||||
# @tls-creds: ID of the 'tls-creds' object that provides credentials
|
# @tls-creds: ID of the 'tls-creds' object that provides credentials
|
||||||
# for establishing a TLS connection over the migration data
|
# for establishing a TLS connection over the migration data
|
||||||
# channel. On the outgoing side of the migration, the credentials
|
# channel. On the outgoing side of the migration, the credentials
|
||||||
# must be for a 'client' endpoint, while for the incoming side the
|
# must be for a 'client' endpoint, while for the incoming side the
|
||||||
# credentials must be for a 'server' endpoint. Setting this
|
# credentials must be for a 'server' endpoint.
|
||||||
# will enable TLS for all migrations. The default is unset,
|
|
||||||
# resulting in unsecured migration at the QEMU level. (Since 2.7)
|
|
||||||
# An empty string means that QEMU will use plain text mode for
|
# An empty string means that QEMU will use plain text mode for
|
||||||
# migration, rather than TLS (Since 2.9)
|
# migration, rather than TLS (Since 2.7)
|
||||||
|
# Note: 2.8 reports this by omitting tls-creds instead.
|
||||||
#
|
#
|
||||||
# @tls-hostname: hostname of the target host for the migration. This
|
# @tls-hostname: hostname of the target host for the migration. This
|
||||||
# is required when using x509 based TLS credentials and the
|
# is required when using x509 based TLS credentials and the
|
||||||
@ -1090,6 +1173,7 @@
|
|||||||
# certificate identity can be validated. (Since 2.7)
|
# certificate identity can be validated. (Since 2.7)
|
||||||
# An empty string means that QEMU will use the hostname
|
# An empty string means that QEMU will use the hostname
|
||||||
# associated with the migration URI, if any. (Since 2.9)
|
# associated with the migration URI, if any. (Since 2.9)
|
||||||
|
# Note: 2.8 reports this by omitting tls-hostname instead.
|
||||||
#
|
#
|
||||||
# @max-bandwidth: to set maximum speed for migration. maximum speed in
|
# @max-bandwidth: to set maximum speed for migration. maximum speed in
|
||||||
# bytes per second. (Since 2.8)
|
# bytes per second. (Since 2.8)
|
||||||
|
@ -2273,15 +2273,14 @@
|
|||||||
# besides their data source and an optional backing file.
|
# besides their data source and an optional backing file.
|
||||||
#
|
#
|
||||||
# @backing: reference to or definition of the backing file block
|
# @backing: reference to or definition of the backing file block
|
||||||
# device (if missing, taken from the image file content). It is
|
# device, null disables the backing file entirely.
|
||||||
# allowed to pass an empty string here in order to disable the
|
# Defaults to the backing file stored the image file.
|
||||||
# default backing file.
|
|
||||||
#
|
#
|
||||||
# Since: 2.9
|
# Since: 2.9
|
||||||
##
|
##
|
||||||
{ 'struct': 'BlockdevOptionsGenericCOWFormat',
|
{ 'struct': 'BlockdevOptionsGenericCOWFormat',
|
||||||
'base': 'BlockdevOptionsGenericFormat',
|
'base': 'BlockdevOptionsGenericFormat',
|
||||||
'data': { '*backing': 'BlockdevRef' } }
|
'data': { '*backing': 'BlockdevRefOrNull' } }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @Qcow2OverlapCheckMode:
|
# @Qcow2OverlapCheckMode:
|
||||||
@ -3120,9 +3119,7 @@
|
|||||||
# Reference to a block device.
|
# Reference to a block device.
|
||||||
#
|
#
|
||||||
# @definition: defines a new block device inline
|
# @definition: defines a new block device inline
|
||||||
# @reference: references the ID of an existing block device. An
|
# @reference: references the ID of an existing block device
|
||||||
# empty string means that no block device should be
|
|
||||||
# referenced.
|
|
||||||
#
|
#
|
||||||
# Since: 2.9
|
# Since: 2.9
|
||||||
##
|
##
|
||||||
@ -3130,6 +3127,24 @@
|
|||||||
'data': { 'definition': 'BlockdevOptions',
|
'data': { 'definition': 'BlockdevOptions',
|
||||||
'reference': 'str' } }
|
'reference': 'str' } }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @BlockdevRefOrNull:
|
||||||
|
#
|
||||||
|
# Reference to a block device.
|
||||||
|
#
|
||||||
|
# @definition: defines a new block device inline
|
||||||
|
# @reference: references the ID of an existing block device.
|
||||||
|
# An empty string means that no block device should
|
||||||
|
# be referenced. Deprecated; use null instead.
|
||||||
|
# @null: No block device should be referenced (since 2.10)
|
||||||
|
#
|
||||||
|
# Since: 2.9
|
||||||
|
##
|
||||||
|
{ 'alternate': 'BlockdevRefOrNull',
|
||||||
|
'data': { 'definition': 'BlockdevOptions',
|
||||||
|
'reference': 'str',
|
||||||
|
'null': 'null' } }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @blockdev-add:
|
# @blockdev-add:
|
||||||
#
|
#
|
||||||
|
@ -127,12 +127,13 @@ static void qapi_clone_type_number(Visitor *v, const char *name, double *obj,
|
|||||||
/* Value was already cloned by g_memdup() */
|
/* Value was already cloned by g_memdup() */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qapi_clone_type_null(Visitor *v, const char *name, Error **errp)
|
static void qapi_clone_type_null(Visitor *v, const char *name, QNull **obj,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
QapiCloneVisitor *qcv = to_qcv(v);
|
QapiCloneVisitor *qcv = to_qcv(v);
|
||||||
|
|
||||||
assert(qcv->depth);
|
assert(qcv->depth);
|
||||||
/* Nothing to do */
|
*obj = qnull();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qapi_clone_free(Visitor *v)
|
static void qapi_clone_free(Visitor *v)
|
||||||
|
@ -103,8 +103,12 @@ static void qapi_dealloc_type_anything(Visitor *v, const char *name,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qapi_dealloc_type_null(Visitor *v, const char *name, Error **errp)
|
static void qapi_dealloc_type_null(Visitor *v, const char *name,
|
||||||
|
QNull **obj, Error **errp)
|
||||||
{
|
{
|
||||||
|
if (obj) {
|
||||||
|
QDECREF(*obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qapi_dealloc_free(Visitor *v)
|
static void qapi_dealloc_free(Visitor *v)
|
||||||
|
@ -325,10 +325,11 @@ void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp)
|
|||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit_type_null(Visitor *v, const char *name, Error **errp)
|
void visit_type_null(Visitor *v, const char *name, QNull **obj,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
trace_visit_type_null(v, name);
|
trace_visit_type_null(v, name, obj);
|
||||||
v->type_null(v, name, errp);
|
v->type_null(v, name, obj, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_type_enum(Visitor *v, const char *name, int *obj,
|
static void output_type_enum(Visitor *v, const char *name, int *obj,
|
||||||
|
@ -587,11 +587,13 @@ static void qobject_input_type_any(Visitor *v, const char *name, QObject **obj,
|
|||||||
*obj = qobj;
|
*obj = qobj;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qobject_input_type_null(Visitor *v, const char *name, Error **errp)
|
static void qobject_input_type_null(Visitor *v, const char *name,
|
||||||
|
QNull **obj, Error **errp)
|
||||||
{
|
{
|
||||||
QObjectInputVisitor *qiv = to_qiv(v);
|
QObjectInputVisitor *qiv = to_qiv(v);
|
||||||
QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
|
QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
|
||||||
|
|
||||||
|
*obj = NULL;
|
||||||
if (!qobj) {
|
if (!qobj) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -599,7 +601,9 @@ static void qobject_input_type_null(Visitor *v, const char *name, Error **errp)
|
|||||||
if (qobject_type(qobj) != QTYPE_QNULL) {
|
if (qobject_type(qobj) != QTYPE_QNULL) {
|
||||||
error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
|
error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
|
||||||
full_name(qiv, name), "null");
|
full_name(qiv, name), "null");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
*obj = qnull();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qobject_input_type_size_keyval(Visitor *v, const char *name,
|
static void qobject_input_type_size_keyval(Visitor *v, const char *name,
|
||||||
|
@ -187,10 +187,11 @@ static void qobject_output_type_any(Visitor *v, const char *name,
|
|||||||
qobject_output_add_obj(qov, name, *obj);
|
qobject_output_add_obj(qov, name, *obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qobject_output_type_null(Visitor *v, const char *name, Error **errp)
|
static void qobject_output_type_null(Visitor *v, const char *name,
|
||||||
|
QNull **obj, Error **errp)
|
||||||
{
|
{
|
||||||
QObjectOutputVisitor *qov = to_qov(v);
|
QObjectOutputVisitor *qov = to_qov(v);
|
||||||
qobject_output_add_obj(qov, name, qnull());
|
qobject_output_add(qov, name, qnull());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finish building, and return the root object.
|
/* Finish building, and return the root object.
|
||||||
|
@ -326,14 +326,20 @@ static void parse_type_number(Visitor *v, const char *name, double *obj,
|
|||||||
*obj = val;
|
*obj = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_type_null(Visitor *v, const char *name, Error **errp)
|
static void parse_type_null(Visitor *v, const char *name, QNull **obj,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
StringInputVisitor *siv = to_siv(v);
|
StringInputVisitor *siv = to_siv(v);
|
||||||
|
|
||||||
|
*obj = NULL;
|
||||||
|
|
||||||
if (!siv->string || siv->string[0]) {
|
if (!siv->string || siv->string[0]) {
|
||||||
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
|
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
|
||||||
"null");
|
"null");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*obj = qnull();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void string_input_free(Visitor *v)
|
static void string_input_free(Visitor *v)
|
||||||
|
@ -256,7 +256,8 @@ static void print_type_number(Visitor *v, const char *name, double *obj,
|
|||||||
string_output_set(sov, g_strdup_printf("%f", *obj));
|
string_output_set(sov, g_strdup_printf("%f", *obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_type_null(Visitor *v, const char *name, Error **errp)
|
static void print_type_null(Visitor *v, const char *name, QNull **obj,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
StringOutputVisitor *sov = to_sov(v);
|
StringOutputVisitor *sov = to_sov(v);
|
||||||
char *out;
|
char *out;
|
||||||
|
@ -31,4 +31,4 @@ visit_type_bool(void *v, const char *name, bool *obj) "v=%p name=%s obj=%p"
|
|||||||
visit_type_str(void *v, const char *name, char **obj) "v=%p name=%s obj=%p"
|
visit_type_str(void *v, const char *name, char **obj) "v=%p name=%s obj=%p"
|
||||||
visit_type_number(void *v, const char *name, double *obj) "v=%p name=%s obj=%p"
|
visit_type_number(void *v, const char *name, double *obj) "v=%p name=%s obj=%p"
|
||||||
visit_type_any(void *v, const char *name, void *obj) "v=%p name=%s obj=%p"
|
visit_type_any(void *v, const char *name, void *obj) "v=%p name=%s obj=%p"
|
||||||
visit_type_null(void *v, const char *name) "v=%p name=%s"
|
visit_type_null(void *v, const char *name, void *obj) "v=%p name=%s obj=%p"
|
||||||
|
@ -445,7 +445,7 @@ static QObject *parse_keyword(JSONParserContext *ctxt)
|
|||||||
} else if (!strcmp(token->str, "false")) {
|
} else if (!strcmp(token->str, "false")) {
|
||||||
return QOBJECT(qbool_from_bool(false));
|
return QOBJECT(qbool_from_bool(false));
|
||||||
} else if (!strcmp(token->str, "null")) {
|
} else if (!strcmp(token->str, "null")) {
|
||||||
return qnull();
|
return QOBJECT(qnull());
|
||||||
}
|
}
|
||||||
parse_error(ctxt, token, "invalid keyword '%s'", token->str);
|
parse_error(ctxt, token, "invalid keyword '%s'", token->str);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -14,7 +14,9 @@
|
|||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "qapi/qmp/qobject.h"
|
#include "qapi/qmp/qobject.h"
|
||||||
|
|
||||||
QObject qnull_ = {
|
QNull qnull_ = {
|
||||||
|
.base = {
|
||||||
.type = QTYPE_QNULL,
|
.type = QTYPE_QNULL,
|
||||||
.refcnt = 1,
|
.refcnt = 1,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@ -20,6 +20,7 @@ import sys
|
|||||||
from ordereddict import OrderedDict
|
from ordereddict import OrderedDict
|
||||||
|
|
||||||
builtin_types = {
|
builtin_types = {
|
||||||
|
'null': 'QTYPE_QNULL',
|
||||||
'str': 'QTYPE_QSTRING',
|
'str': 'QTYPE_QSTRING',
|
||||||
'int': 'QTYPE_QNUM',
|
'int': 'QTYPE_QNUM',
|
||||||
'number': 'QTYPE_QNUM',
|
'number': 'QTYPE_QNUM',
|
||||||
@ -1056,6 +1057,7 @@ class QAPISchemaType(QAPISchemaEntity):
|
|||||||
|
|
||||||
def alternate_qtype(self):
|
def alternate_qtype(self):
|
||||||
json2qtype = {
|
json2qtype = {
|
||||||
|
'null': 'QTYPE_QNULL',
|
||||||
'string': 'QTYPE_QSTRING',
|
'string': 'QTYPE_QSTRING',
|
||||||
'number': 'QTYPE_QNUM',
|
'number': 'QTYPE_QNUM',
|
||||||
'int': 'QTYPE_QNUM',
|
'int': 'QTYPE_QNUM',
|
||||||
@ -1515,7 +1517,8 @@ class QAPISchema(object):
|
|||||||
('uint64', 'int', 'uint64_t'),
|
('uint64', 'int', 'uint64_t'),
|
||||||
('size', 'int', 'uint64_t'),
|
('size', 'int', 'uint64_t'),
|
||||||
('bool', 'boolean', 'bool'),
|
('bool', 'boolean', 'bool'),
|
||||||
('any', 'value', 'QObject' + pointer_suffix)]:
|
('any', 'value', 'QObject' + pointer_suffix),
|
||||||
|
('null', 'null', 'QNull' + pointer_suffix)]:
|
||||||
self._def_builtin_type(*t)
|
self._def_builtin_type(*t)
|
||||||
self.the_empty_object_type = QAPISchemaObjectType(
|
self.the_empty_object_type = QAPISchemaObjectType(
|
||||||
'q_empty', None, None, None, [], None)
|
'q_empty', None, None, None, [], None)
|
||||||
|
@ -2442,7 +2442,7 @@ static QDict *x86_cpu_static_props(void)
|
|||||||
|
|
||||||
d = qdict_new();
|
d = qdict_new();
|
||||||
for (i = 0; props[i]; i++) {
|
for (i = 0; props[i]; i++) {
|
||||||
qdict_put_obj(d, props[i], qnull());
|
qdict_put(d, props[i], qnull());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (w = 0; w < FEATURE_WORDS; w++) {
|
for (w = 0; w < FEATURE_WORDS; w++) {
|
||||||
@ -2452,7 +2452,7 @@ static QDict *x86_cpu_static_props(void)
|
|||||||
if (!fi->feat_names[bit]) {
|
if (!fi->feat_names[bit]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
qdict_put_obj(d, fi->feat_names[bit], qnull());
|
qdict_put(d, fi->feat_names[bit], qnull());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8428,11 +8428,14 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
|
|||||||
static void getset_compat_deprecated(Object *obj, Visitor *v, const char *name,
|
static void getset_compat_deprecated(Object *obj, Visitor *v, const char *name,
|
||||||
void *opaque, Error **errp)
|
void *opaque, Error **errp)
|
||||||
{
|
{
|
||||||
|
QNull *null = NULL;
|
||||||
|
|
||||||
if (!qtest_enabled()) {
|
if (!qtest_enabled()) {
|
||||||
error_report("CPU 'compat' property is deprecated and has no effect; "
|
error_report("CPU 'compat' property is deprecated and has no effect; "
|
||||||
"use max-cpu-compat machine property instead");
|
"use max-cpu-compat machine property instead");
|
||||||
}
|
}
|
||||||
visit_type_null(v, name, NULL);
|
visit_type_null(v, name, &null, NULL);
|
||||||
|
QDECREF(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const PropertyInfo ppc_compat_deprecated_propinfo = {
|
static const PropertyInfo ppc_compat_deprecated_propinfo = {
|
||||||
|
@ -1012,7 +1012,7 @@ static void keyword_literal(void)
|
|||||||
{
|
{
|
||||||
QObject *obj;
|
QObject *obj;
|
||||||
QBool *qbool;
|
QBool *qbool;
|
||||||
QObject *null;
|
QNull *null;
|
||||||
QString *str;
|
QString *str;
|
||||||
|
|
||||||
obj = qobject_from_json("true", &error_abort);
|
obj = qobject_from_json("true", &error_abort);
|
||||||
@ -1053,10 +1053,10 @@ static void keyword_literal(void)
|
|||||||
g_assert(qobject_type(obj) == QTYPE_QNULL);
|
g_assert(qobject_type(obj) == QTYPE_QNULL);
|
||||||
|
|
||||||
null = qnull();
|
null = qnull();
|
||||||
g_assert(null == obj);
|
g_assert(QOBJECT(null) == obj);
|
||||||
|
|
||||||
qobject_decref(obj);
|
qobject_decref(obj);
|
||||||
qobject_decref(null);
|
QDECREF(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct LiteralQDictEntry LiteralQDictEntry;
|
typedef struct LiteralQDictEntry LiteralQDictEntry;
|
||||||
|
@ -24,20 +24,21 @@ static void qnull_ref_test(void)
|
|||||||
{
|
{
|
||||||
QObject *obj;
|
QObject *obj;
|
||||||
|
|
||||||
g_assert(qnull_.refcnt == 1);
|
g_assert(qnull_.base.refcnt == 1);
|
||||||
obj = qnull();
|
obj = QOBJECT(qnull());
|
||||||
g_assert(obj);
|
g_assert(obj);
|
||||||
g_assert(obj == &qnull_);
|
g_assert(obj == QOBJECT(&qnull_));
|
||||||
g_assert(qnull_.refcnt == 2);
|
g_assert(qnull_.base.refcnt == 2);
|
||||||
g_assert(qobject_type(obj) == QTYPE_QNULL);
|
g_assert(qobject_type(obj) == QTYPE_QNULL);
|
||||||
qobject_decref(obj);
|
qobject_decref(obj);
|
||||||
g_assert(qnull_.refcnt == 1);
|
g_assert(qnull_.base.refcnt == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qnull_visit_test(void)
|
static void qnull_visit_test(void)
|
||||||
{
|
{
|
||||||
QObject *obj;
|
QObject *obj;
|
||||||
Visitor *v;
|
Visitor *v;
|
||||||
|
QNull *null;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Most tests of interactions between QObject and visitors are in
|
* Most tests of interactions between QObject and visitors are in
|
||||||
@ -45,21 +46,25 @@ static void qnull_visit_test(void)
|
|||||||
* depend on layering violations to check qnull_ refcnt.
|
* depend on layering violations to check qnull_ refcnt.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
g_assert(qnull_.refcnt == 1);
|
g_assert(qnull_.base.refcnt == 1);
|
||||||
obj = qnull();
|
obj = QOBJECT(qnull());
|
||||||
v = qobject_input_visitor_new(obj);
|
v = qobject_input_visitor_new(obj);
|
||||||
qobject_decref(obj);
|
qobject_decref(obj);
|
||||||
visit_type_null(v, NULL, &error_abort);
|
visit_type_null(v, NULL, &null, &error_abort);
|
||||||
|
g_assert(obj == QOBJECT(&qnull_));
|
||||||
|
QDECREF(null);
|
||||||
visit_free(v);
|
visit_free(v);
|
||||||
|
|
||||||
|
null = NULL;
|
||||||
v = qobject_output_visitor_new(&obj);
|
v = qobject_output_visitor_new(&obj);
|
||||||
visit_type_null(v, NULL, &error_abort);
|
visit_type_null(v, NULL, &null, &error_abort);
|
||||||
visit_complete(v, &obj);
|
visit_complete(v, &obj);
|
||||||
g_assert(obj == &qnull_);
|
g_assert(obj == QOBJECT(&qnull_));
|
||||||
|
QDECREF(null);
|
||||||
qobject_decref(obj);
|
qobject_decref(obj);
|
||||||
visit_free(v);
|
visit_free(v);
|
||||||
|
|
||||||
g_assert(qnull_.refcnt == 1);
|
g_assert(qnull_.base.refcnt == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
|
@ -93,7 +93,8 @@
|
|||||||
{ 'struct': 'WrapAlternate',
|
{ 'struct': 'WrapAlternate',
|
||||||
'data': { 'alt': 'UserDefAlternate' } }
|
'data': { 'alt': 'UserDefAlternate' } }
|
||||||
{ 'alternate': 'UserDefAlternate',
|
{ 'alternate': 'UserDefAlternate',
|
||||||
'data': { 'udfu': 'UserDefFlatUnion', 'e': 'EnumOne', 'i': 'int' } }
|
'data': { 'udfu': 'UserDefFlatUnion', 'e': 'EnumOne', 'i': 'int',
|
||||||
|
'n': 'null' } }
|
||||||
|
|
||||||
{ 'struct': 'UserDefC',
|
{ 'struct': 'UserDefC',
|
||||||
'data': { 'string1': 'str', 'string2': 'str' } }
|
'data': { 'string1': 'str', 'string2': 'str' } }
|
||||||
|
@ -64,6 +64,7 @@ alternate UserDefAlternate
|
|||||||
case udfu: UserDefFlatUnion
|
case udfu: UserDefFlatUnion
|
||||||
case e: EnumOne
|
case e: EnumOne
|
||||||
case i: int
|
case i: int
|
||||||
|
case n: null
|
||||||
object UserDefB
|
object UserDefB
|
||||||
member intb: int optional=False
|
member intb: int optional=False
|
||||||
member a-b: bool optional=True
|
member a-b: bool optional=True
|
||||||
|
@ -106,7 +106,7 @@ function add_snapshot_image()
|
|||||||
snapshot_file="${TEST_DIR}/${1}-${snapshot_virt0}"
|
snapshot_file="${TEST_DIR}/${1}-${snapshot_virt0}"
|
||||||
_make_test_img -u -b "${base_image}" "$size"
|
_make_test_img -u -b "${base_image}" "$size"
|
||||||
mv "${TEST_IMG}" "${snapshot_file}"
|
mv "${TEST_IMG}" "${snapshot_file}"
|
||||||
do_blockdev_add "$1" "'backing': '', " "${snapshot_file}"
|
do_blockdev_add "$1" "'backing': null, " "${snapshot_file}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ${1}: unique identifier for the snapshot filename
|
# ${1}: unique identifier for the snapshot filename
|
||||||
|
@ -69,7 +69,7 @@ class TestBlockdevDel(iotests.QMPTestCase):
|
|||||||
'-b', base_img, new_img, '1M')
|
'-b', base_img, new_img, '1M')
|
||||||
opts = {'driver': iotests.imgfmt,
|
opts = {'driver': iotests.imgfmt,
|
||||||
'node-name': node,
|
'node-name': node,
|
||||||
'backing': '',
|
'backing': None,
|
||||||
'file': {'driver': 'file',
|
'file': {'driver': 'file',
|
||||||
'filename': new_img}}
|
'filename': new_img}}
|
||||||
result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
|
result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
|
||||||
|
@ -510,6 +510,7 @@ static void test_visitor_in_null(TestInputVisitorData *data,
|
|||||||
{
|
{
|
||||||
Visitor *v;
|
Visitor *v;
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
QNull *null;
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -524,12 +525,15 @@ static void test_visitor_in_null(TestInputVisitorData *data,
|
|||||||
v = visitor_input_test_init_full(data, false,
|
v = visitor_input_test_init_full(data, false,
|
||||||
"{ 'a': null, 'b': '' }");
|
"{ 'a': null, 'b': '' }");
|
||||||
visit_start_struct(v, NULL, NULL, 0, &error_abort);
|
visit_start_struct(v, NULL, NULL, 0, &error_abort);
|
||||||
visit_type_null(v, "a", &error_abort);
|
visit_type_null(v, "a", &null, &error_abort);
|
||||||
visit_type_null(v, "b", &err);
|
g_assert(qobject_type(QOBJECT(null)) == QTYPE_QNULL);
|
||||||
|
QDECREF(null);
|
||||||
|
visit_type_null(v, "b", &null, &err);
|
||||||
error_free_or_abort(&err);
|
error_free_or_abort(&err);
|
||||||
|
g_assert(!null);
|
||||||
visit_type_str(v, "c", &tmp, &err);
|
visit_type_str(v, "c", &tmp, &err);
|
||||||
g_assert(!tmp);
|
|
||||||
error_free_or_abort(&err);
|
error_free_or_abort(&err);
|
||||||
|
g_assert(!tmp);
|
||||||
visit_check_struct(v, &error_abort);
|
visit_check_struct(v, &error_abort);
|
||||||
visit_end_struct(v, NULL);
|
visit_end_struct(v, NULL);
|
||||||
}
|
}
|
||||||
@ -563,7 +567,6 @@ static void test_visitor_in_alternate(TestInputVisitorData *data,
|
|||||||
const void *unused)
|
const void *unused)
|
||||||
{
|
{
|
||||||
Visitor *v;
|
Visitor *v;
|
||||||
Error *err = NULL;
|
|
||||||
UserDefAlternate *tmp;
|
UserDefAlternate *tmp;
|
||||||
WrapAlternate *wrap;
|
WrapAlternate *wrap;
|
||||||
|
|
||||||
@ -579,6 +582,11 @@ static void test_visitor_in_alternate(TestInputVisitorData *data,
|
|||||||
g_assert_cmpint(tmp->u.e, ==, ENUM_ONE_VALUE1);
|
g_assert_cmpint(tmp->u.e, ==, ENUM_ONE_VALUE1);
|
||||||
qapi_free_UserDefAlternate(tmp);
|
qapi_free_UserDefAlternate(tmp);
|
||||||
|
|
||||||
|
v = visitor_input_test_init(data, "null");
|
||||||
|
visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort);
|
||||||
|
g_assert_cmpint(tmp->type, ==, QTYPE_QNULL);
|
||||||
|
qapi_free_UserDefAlternate(tmp);
|
||||||
|
|
||||||
v = visitor_input_test_init(data, "{'integer':1, 'string':'str', "
|
v = visitor_input_test_init(data, "{'integer':1, 'string':'str', "
|
||||||
"'enum1':'value1', 'boolean':true}");
|
"'enum1':'value1', 'boolean':true}");
|
||||||
visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort);
|
visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort);
|
||||||
@ -590,11 +598,6 @@ static void test_visitor_in_alternate(TestInputVisitorData *data,
|
|||||||
g_assert_cmpint(tmp->u.udfu.u.value1.has_a_b, ==, false);
|
g_assert_cmpint(tmp->u.udfu.u.value1.has_a_b, ==, false);
|
||||||
qapi_free_UserDefAlternate(tmp);
|
qapi_free_UserDefAlternate(tmp);
|
||||||
|
|
||||||
v = visitor_input_test_init(data, "false");
|
|
||||||
visit_type_UserDefAlternate(v, NULL, &tmp, &err);
|
|
||||||
error_free_or_abort(&err);
|
|
||||||
qapi_free_UserDefAlternate(tmp);
|
|
||||||
|
|
||||||
v = visitor_input_test_init(data, "{ 'alt': 42 }");
|
v = visitor_input_test_init(data, "{ 'alt': 42 }");
|
||||||
visit_type_WrapAlternate(v, NULL, &wrap, &error_abort);
|
visit_type_WrapAlternate(v, NULL, &wrap, &error_abort);
|
||||||
g_assert_cmpint(wrap->alt->type, ==, QTYPE_QNUM);
|
g_assert_cmpint(wrap->alt->type, ==, QTYPE_QNUM);
|
||||||
@ -1087,6 +1090,7 @@ static void test_visitor_in_fail_struct_missing(TestInputVisitorData *data,
|
|||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
Visitor *v;
|
Visitor *v;
|
||||||
QObject *any;
|
QObject *any;
|
||||||
|
QNull *null;
|
||||||
GenericAlternate *alt;
|
GenericAlternate *alt;
|
||||||
bool present;
|
bool present;
|
||||||
int en;
|
int en;
|
||||||
@ -1120,7 +1124,7 @@ static void test_visitor_in_fail_struct_missing(TestInputVisitorData *data,
|
|||||||
error_free_or_abort(&err);
|
error_free_or_abort(&err);
|
||||||
visit_type_any(v, "any", &any, &err);
|
visit_type_any(v, "any", &any, &err);
|
||||||
error_free_or_abort(&err);
|
error_free_or_abort(&err);
|
||||||
visit_type_null(v, "null", &err);
|
visit_type_null(v, "null", &null, &err);
|
||||||
error_free_or_abort(&err);
|
error_free_or_abort(&err);
|
||||||
visit_start_list(v, "sub", NULL, 0, &error_abort);
|
visit_start_list(v, "sub", NULL, 0, &error_abort);
|
||||||
visit_start_struct(v, NULL, NULL, 0, &error_abort);
|
visit_start_struct(v, NULL, NULL, 0, &error_abort);
|
||||||
|
@ -422,6 +422,16 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data,
|
|||||||
|
|
||||||
qapi_free_UserDefAlternate(tmp);
|
qapi_free_UserDefAlternate(tmp);
|
||||||
|
|
||||||
|
visitor_reset(data);
|
||||||
|
tmp = g_new0(UserDefAlternate, 1);
|
||||||
|
tmp->type = QTYPE_QNULL;
|
||||||
|
tmp->u.n = qnull();
|
||||||
|
|
||||||
|
visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort);
|
||||||
|
g_assert_cmpint(qobject_type(visitor_get(data)), ==, QTYPE_QNULL);
|
||||||
|
|
||||||
|
qapi_free_UserDefAlternate(tmp);
|
||||||
|
|
||||||
visitor_reset(data);
|
visitor_reset(data);
|
||||||
tmp = g_new0(UserDefAlternate, 1);
|
tmp = g_new0(UserDefAlternate, 1);
|
||||||
tmp->type = QTYPE_QDICT;
|
tmp->type = QTYPE_QDICT;
|
||||||
@ -445,11 +455,12 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data,
|
|||||||
static void test_visitor_out_null(TestOutputVisitorData *data,
|
static void test_visitor_out_null(TestOutputVisitorData *data,
|
||||||
const void *unused)
|
const void *unused)
|
||||||
{
|
{
|
||||||
|
QNull *null = NULL;
|
||||||
QDict *qdict;
|
QDict *qdict;
|
||||||
QObject *nil;
|
QObject *nil;
|
||||||
|
|
||||||
visit_start_struct(data->ov, NULL, NULL, 0, &error_abort);
|
visit_start_struct(data->ov, NULL, NULL, 0, &error_abort);
|
||||||
visit_type_null(data->ov, "a", &error_abort);
|
visit_type_null(data->ov, "a", &null, &error_abort);
|
||||||
visit_check_struct(data->ov, &error_abort);
|
visit_check_struct(data->ov, &error_abort);
|
||||||
visit_end_struct(data->ov, NULL);
|
visit_end_struct(data->ov, NULL);
|
||||||
qdict = qobject_to_qdict(visitor_get(data));
|
qdict = qobject_to_qdict(visitor_get(data));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user