Block layer patches and object-add QAPIfication

- QAPIfy object-add and --object
 - stream: Fail gracefully if permission is denied
 - storage-daemon: Fix crash on quit when job is still running
 - curl: Fix use after free
 - char: Deprecate backend aliases, fix QMP query-chardev-backends
 - Fix image creation option defaults that exist in both the format and
   the protocol layer (e.g. 'cluster_size' in qcow2 and rbd; the qcow2
   default was incorrectly applied to the rbd layer)
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAmBUbF4RHGt3b2xmQHJl
 ZGhhdC5jb20ACgkQfwmycsiPL9YX2Q//Ve6++hRulIuJVuh8QDxlmGWERqey/ClX
 mUqGDOkSSXfftPTDPCYSUFE7QD6HD25oJmUTix2B2P89AIyDcvqvthMDU/j8clor
 X3Kx03ky3NLJilZNdYZ2GOMyljgNP3JSrDHBjc/tZx+1e7C5tPNVxXOUW946wIC9
 no6xTAarAANl/GS23ZI+vJ3PBEggzAbu6t/hwT//WAB0WB9wFhkCCzWPXIkdBXwP
 QpG8chTwuwFAW1c52F0OeQV5FpM0bcMtxYASuNq0HPL6B8qUdKOusTRgTB/fjLLV
 tYMhc6tzPLUlin1mGD4m0P+9tRMBFtF/flZVwbd4S+avcAbV2L5S6Xq0QsiNTbx2
 oQUk6N2/IWBOMC6D8aBTBwZ7CCasgEg0imtLUdJ8gKp6T44C7cqg1oZwT2dOyYuI
 jS+3T+DcZZn3mHmp61nowL/2/2LDAVaLmOfbsvmvlbuX5j8QHj/Lvt6udRjqpelJ
 n0jV9Ay0myu7dSK5ng7WNQUlSrba5I/W3CAjuH0CDp90ADCymWSp2jktvv5rSO/R
 bQpz58kRY72y4dEwOy0zkWc/EClqh3p4abq5HDBCIkO+EO8CjJhnEnT+oOrFF5C/
 LU93bFPyp6ZJoXzsKnjEjSzMzgDT6XuGTAgrh6upZy52ssjkG8zACbNOmXZTYmAg
 hg3OlpdEUvM=
 =zZCm
 -----END PGP SIGNATURE-----

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

Block layer patches and object-add QAPIfication

- QAPIfy object-add and --object
- stream: Fail gracefully if permission is denied
- storage-daemon: Fix crash on quit when job is still running
- curl: Fix use after free
- char: Deprecate backend aliases, fix QMP query-chardev-backends
- Fix image creation option defaults that exist in both the format and
  the protocol layer (e.g. 'cluster_size' in qcow2 and rbd; the qcow2
  default was incorrectly applied to the rbd layer)

# gpg: Signature made Fri 19 Mar 2021 09:18:22 GMT
# gpg:                using RSA key DC3DEB159A9AF95D3D7456FE7F09B272C88F2FD6
# gpg:                issuer "kwolf@redhat.com"
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full]
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74  56FE 7F09 B272 C88F 2FD6

* remotes/kevin/tags/for-upstream: (42 commits)
  vl: allow passing JSON to -object
  qom: move user_creatable_add_opts logic to vl.c and QAPIfy it
  tests: convert check-qom-proplist to keyval
  qom: Support JSON in HMP object_add and tools --object
  char: Simplify chardev_name_foreach()
  char: Deprecate backend aliases 'tty' and 'parport'
  char: Skip CLI aliases in query-chardev-backends
  qom: Add user_creatable_parse_str()
  hmp: QAPIfy object_add
  qemu-img: Use user_creatable_process_cmdline() for --object
  qom: Add user_creatable_add_from_str()
  qemu-nbd: Use user_creatable_process_cmdline() for --object
  qemu-io: Use user_creatable_process_cmdline() for --object
  qom: Factor out user_creatable_process_cmdline()
  qom: Remove user_creatable_add_dict()
  qemu-storage-daemon: Implement --object with qmp_object_add()
  qom: Make "object" QemuOptsList optional
  qapi/qom: QAPIfy object-add
  qapi/qom: Add ObjectOptions for x-remote-object
  qapi/qom: Add ObjectOptions for input-*
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2021-03-19 11:27:40 +00:00
commit 92566947b3
35 changed files with 1517 additions and 681 deletions

36
block.c
View File

@ -670,14 +670,48 @@ out:
int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp)
{
QemuOpts *protocol_opts;
BlockDriver *drv;
QDict *qdict;
int ret;
drv = bdrv_find_protocol(filename, true, errp);
if (drv == NULL) {
return -ENOENT;
}
return bdrv_create(drv, filename, opts, errp);
if (!drv->create_opts) {
error_setg(errp, "Driver '%s' does not support image creation",
drv->format_name);
return -ENOTSUP;
}
/*
* 'opts' contains a QemuOptsList with a combination of format and protocol
* default values.
*
* The format properly removes its options, but the default values remain
* in 'opts->list'. So if the protocol has options with the same name
* (e.g. rbd has 'cluster_size' as qcow2), it will see the default values
* of the format, since for overlapping options, the format wins.
*
* To avoid this issue, lets convert QemuOpts to QDict, in this way we take
* only the set options, and then convert it back to QemuOpts, using the
* create_opts of the protocol. So the new QemuOpts, will contain only the
* protocol defaults.
*/
qdict = qemu_opts_to_qdict(opts, NULL);
protocol_opts = qemu_opts_from_qdict(drv->create_opts, qdict, errp);
if (protocol_opts == NULL) {
ret = -EINVAL;
goto out;
}
ret = bdrv_create(drv, filename, protocol_opts, errp);
out:
qemu_opts_del(protocol_opts);
qobject_unref(qdict);
return ret;
}
int coroutine_fn bdrv_co_delete_file(BlockDriverState *bs, Error **errp)

View File

@ -78,8 +78,7 @@ typedef struct CURLAIOCB {
typedef struct CURLSocket {
int fd;
struct CURLState *state;
QLIST_ENTRY(CURLSocket) next;
struct BDRVCURLState *s;
} CURLSocket;
typedef struct CURLState
@ -87,7 +86,6 @@ typedef struct CURLState
struct BDRVCURLState *s;
CURLAIOCB *acb[CURL_NUM_ACB];
CURL *curl;
QLIST_HEAD(, CURLSocket) sockets;
char *orig_buf;
uint64_t buf_start;
size_t buf_off;
@ -102,6 +100,7 @@ typedef struct BDRVCURLState {
QEMUTimer timer;
uint64_t len;
CURLState states[CURL_NUM_STATES];
GHashTable *sockets; /* GINT_TO_POINTER(fd) -> socket */
char *url;
size_t readahead_size;
bool sslverify;
@ -120,6 +119,21 @@ typedef struct BDRVCURLState {
static void curl_clean_state(CURLState *s);
static void curl_multi_do(void *arg);
static gboolean curl_drop_socket(void *key, void *value, void *opaque)
{
CURLSocket *socket = value;
BDRVCURLState *s = socket->s;
aio_set_fd_handler(s->aio_context, socket->fd, false,
NULL, NULL, NULL, NULL);
return true;
}
static void curl_drop_all_sockets(GHashTable *sockets)
{
g_hash_table_foreach_remove(sockets, curl_drop_socket, NULL);
}
/* Called from curl_multi_do_locked, with s->mutex held. */
static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
{
@ -147,16 +161,12 @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&state);
s = state->s;
QLIST_FOREACH(socket, &state->sockets, next) {
if (socket->fd == fd) {
break;
}
}
socket = g_hash_table_lookup(s->sockets, GINT_TO_POINTER(fd));
if (!socket) {
socket = g_new0(CURLSocket, 1);
socket->fd = fd;
socket->state = state;
QLIST_INSERT_HEAD(&state->sockets, socket, next);
socket->s = s;
g_hash_table_insert(s->sockets, GINT_TO_POINTER(fd), socket);
}
trace_curl_sock_cb(action, (int)fd);
@ -180,8 +190,7 @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
}
if (action == CURL_POLL_REMOVE) {
QLIST_REMOVE(socket, next);
g_free(socket);
g_hash_table_remove(s->sockets, GINT_TO_POINTER(fd));
}
return 0;
@ -385,7 +394,7 @@ static void curl_multi_check_completion(BDRVCURLState *s)
/* Called with s->mutex held. */
static void curl_multi_do_locked(CURLSocket *socket)
{
BDRVCURLState *s = socket->state->s;
BDRVCURLState *s = socket->s;
int running;
int r;
@ -401,7 +410,7 @@ static void curl_multi_do_locked(CURLSocket *socket)
static void curl_multi_do(void *arg)
{
CURLSocket *socket = arg;
BDRVCURLState *s = socket->state->s;
BDRVCURLState *s = socket->s;
qemu_mutex_lock(&s->mutex);
curl_multi_do_locked(socket);
@ -498,7 +507,6 @@ static int curl_init_state(BDRVCURLState *s, CURLState *state)
#endif
}
QLIST_INIT(&state->sockets);
state->s = s;
return 0;
@ -515,13 +523,6 @@ static void curl_clean_state(CURLState *s)
if (s->s->multi)
curl_multi_remove_handle(s->s->multi, s->curl);
while (!QLIST_EMPTY(&s->sockets)) {
CURLSocket *socket = QLIST_FIRST(&s->sockets);
QLIST_REMOVE(socket, next);
g_free(socket);
}
s->in_use = 0;
qemu_co_enter_next(&s->s->free_state_waitq, &s->s->mutex);
@ -539,6 +540,7 @@ static void curl_detach_aio_context(BlockDriverState *bs)
int i;
WITH_QEMU_LOCK_GUARD(&s->mutex) {
curl_drop_all_sockets(s->sockets);
for (i = 0; i < CURL_NUM_STATES; i++) {
if (s->states[i].in_use) {
curl_clean_state(&s->states[i]);
@ -745,6 +747,7 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
qemu_co_queue_init(&s->free_state_waitq);
s->aio_context = bdrv_get_aio_context(bs);
s->url = g_strdup(file);
s->sockets = g_hash_table_new_full(NULL, NULL, NULL, g_free);
qemu_mutex_lock(&s->mutex);
state = curl_find_state(s);
qemu_mutex_unlock(&s->mutex);
@ -818,6 +821,8 @@ out_noclean:
g_free(s->username);
g_free(s->proxyusername);
g_free(s->proxypassword);
curl_drop_all_sockets(s->sockets);
g_hash_table_destroy(s->sockets);
qemu_opts_del(opts);
return -EINVAL;
}
@ -916,6 +921,7 @@ static void curl_close(BlockDriverState *bs)
curl_detach_aio_context(bs);
qemu_mutex_destroy(&s->mutex);
g_hash_table_destroy(s->sockets);
g_free(s->cookie);
g_free(s->url);
g_free(s->username);

View File

@ -345,8 +345,7 @@ static uint64_t vu_blk_get_features(VuDev *dev)
static uint64_t vu_blk_get_protocol_features(VuDev *dev)
{
return 1ull << VHOST_USER_PROTOCOL_F_CONFIG |
1ull << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD;
return 1ull << VHOST_USER_PROTOCOL_F_CONFIG;
}
static int

View File

@ -206,7 +206,7 @@ void stream_start(const char *job_id, BlockDriverState *bs,
const char *filter_node_name,
Error **errp)
{
StreamBlockJob *s;
StreamBlockJob *s = NULL;
BlockDriverState *iter;
bool bs_read_only;
int basic_flags = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED;
@ -214,6 +214,7 @@ void stream_start(const char *job_id, BlockDriverState *bs,
BlockDriverState *cor_filter_bs = NULL;
BlockDriverState *above_base;
QDict *opts;
int ret;
assert(!(base && bottom));
assert(!(backing_file_str && bottom));
@ -303,7 +304,7 @@ void stream_start(const char *job_id, BlockDriverState *bs,
* queried only at the job start and then cached.
*/
if (block_job_add_bdrv(&s->common, "active node", bs, 0,
basic_flags | BLK_PERM_WRITE, &error_abort)) {
basic_flags | BLK_PERM_WRITE, errp)) {
goto fail;
}
@ -320,8 +321,11 @@ void stream_start(const char *job_id, BlockDriverState *bs,
for (iter = bdrv_filter_or_cow_bs(bs); iter != base;
iter = bdrv_filter_or_cow_bs(iter))
{
block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
basic_flags, &error_abort);
ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
basic_flags, errp);
if (ret < 0) {
goto fail;
}
}
s->base_overlay = base_overlay;
@ -337,6 +341,9 @@ void stream_start(const char *job_id, BlockDriverState *bs,
return;
fail:
if (s) {
job_early_fail(&s->common.job);
}
if (cor_filter_bs) {
bdrv_cor_filter_drop(cor_filter_bs);
}

View File

@ -534,9 +534,10 @@ static const ChardevClass *char_get_class(const char *driver, Error **errp)
return cc;
}
static const struct ChardevAlias {
static struct ChardevAlias {
const char *typename;
const char *alias;
bool deprecation_warning_printed;
} chardev_alias_table[] = {
#ifdef HAVE_CHARDEV_PARPORT
{ "parallel", "parport" },
@ -565,16 +566,12 @@ chardev_class_foreach(ObjectClass *klass, void *opaque)
}
static void
chardev_name_foreach(void (*fn)(const char *name, void *opaque), void *opaque)
chardev_name_foreach(void (*fn)(const char *name, void *opaque),
void *opaque)
{
ChadevClassFE fe = { .fn = fn, .opaque = opaque };
int i;
object_class_foreach(chardev_class_foreach, TYPE_CHARDEV, false, &fe);
for (i = 0; i < (int)ARRAY_SIZE(chardev_alias_table); i++) {
fn(chardev_alias_table[i].alias, opaque);
}
}
static void
@ -590,6 +587,11 @@ static const char *chardev_alias_translate(const char *name)
int i;
for (i = 0; i < (int)ARRAY_SIZE(chardev_alias_table); i++) {
if (g_strcmp0(chardev_alias_table[i].alias, name) == 0) {
if (!chardev_alias_table[i].deprecation_warning_printed) {
warn_report("The alias '%s' is deprecated, use '%s' instead",
name, chardev_alias_table[i].typename);
chardev_alias_table[i].deprecation_warning_printed = true;
}
return chardev_alias_table[i].typename;
}
}
@ -801,8 +803,9 @@ static void
qmp_prepend_backend(const char *name, void *opaque)
{
ChardevBackendInfoList **list = opaque;
ChardevBackendInfo *value = g_new0(ChardevBackendInfo, 1);
ChardevBackendInfo *value;
value = g_new0(ChardevBackendInfo, 1);
value->name = g_strdup(name);
QAPI_LIST_PREPEND(*list, value);
}

View File

@ -46,6 +46,12 @@ needs two devices (``-device intel-hda -device hda-duplex``) and
``pcspk`` which can be activated using ``-machine
pcspk-audiodev=<name>``.
``-chardev`` backend aliases ``tty`` and ``parport`` (since 6.0)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
``tty`` and ``parport`` are aliases that will be removed. Instead, the
actual backend names ``serial`` and ``parallel`` should be used.
RISC-V ``-bios`` (since 5.1)
''''''''''''''''''''''''''''
@ -153,6 +159,26 @@ the process listing. This is replaced by the new ``password-secret``
option which lets the password be securely provided on the command
line using a ``secret`` object instance.
``opened`` property of ``rng-*`` objects (since 6.0.0)
''''''''''''''''''''''''''''''''''''''''''''''''''''''
The only effect of specifying ``opened=on`` in the command line or QMP
``object-add`` is that the device is opened immediately, possibly before all
other options have been processed. This will either have no effect (if
``opened`` was the last option) or cause errors. The property is therefore
useless and should not be specified.
``loaded`` property of ``secret`` and ``secret_keyring`` objects (since 6.0.0)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
The only effect of specifying ``loaded=on`` in the command line or QMP
``object-add`` is that the secret is loaded immediately, possibly before all
other options have been processed. This will either have no effect (if
``loaded`` was the last option) or cause options to be effectively ignored as
if they were not given. The property is therefore useless and should not be
specified.
QEMU Machine Protocol (QMP) commands
------------------------------------
@ -186,11 +212,6 @@ Use argument value ``null`` instead.
Use arguments ``base-node`` and ``top-node`` instead.
``object-add`` option ``props`` (since 5.0)
'''''''''''''''''''''''''''''''''''''''''''
Specify the properties for the object as top-level arguments instead.
``nbd-server-add`` and ``nbd-server-remove`` (since 5.2)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''

View File

@ -143,6 +143,11 @@ field of the ``BlockDeviceInfo`` struct should be used instead, which is the
type of the ``inserted`` field in query-block replies, as well as the
type of array items in query-named-block-nodes.
``object-add`` option ``props`` (removed in 6.0)
''''''''''''''''''''''''''''''''''''''''''''''''
Specify the properties for the object as top-level arguments instead.
Human Monitor Protocol (HMP) commands
-------------------------------------

View File

@ -404,7 +404,7 @@ Command description:
The following table sumarizes all exit codes of the compare subcommand:
0
Images are identical
Images are identical (or requested help was printed)
1
Images differ
2

View File

@ -1292,7 +1292,7 @@ ERST
{
.name = "object_add",
.args_type = "object:O",
.args_type = "object:S",
.params = "[qom-type=]type,id=str[,prop=value][,...]",
.help = "create QOM object",
.cmd = hmp_object_add,

View File

@ -836,17 +836,17 @@ static XenBlockIOThread *xen_block_iothread_create(const char *id,
{
ERRP_GUARD();
XenBlockIOThread *iothread = g_new(XenBlockIOThread, 1);
QDict *opts;
QObject *ret_data = NULL;
ObjectOptions *opts;
iothread->id = g_strdup(id);
opts = qdict_new();
qdict_put_str(opts, "qom-type", TYPE_IOTHREAD);
qdict_put_str(opts, "id", id);
qmp_object_add(opts, &ret_data, errp);
qobject_unref(opts);
qobject_unref(ret_data);
opts = g_new(ObjectOptions, 1);
*opts = (ObjectOptions) {
.qom_type = OBJECT_TYPE_IOTHREAD,
.id = g_strdup(id),
};
qmp_object_add(opts, errp);
qapi_free_ObjectOptions(opts);
if (*errp) {
g_free(iothread->id);

View File

@ -2,6 +2,7 @@
#define OBJECT_INTERFACES_H
#include "qom/object.h"
#include "qapi/qapi-types-qom.h"
#include "qapi/visitor.h"
#define TYPE_USER_CREATABLE "user-creatable"
@ -87,67 +88,60 @@ Object *user_creatable_add_type(const char *type, const char *id,
Visitor *v, Error **errp);
/**
* user_creatable_add_dict:
* @qdict: the object definition
* @keyval: if true, use a keyval visitor for processing @qdict (i.e.
* assume that all @qdict values are strings); otherwise, use
* the normal QObject visitor (i.e. assume all @qdict values
* have the QType expected by the QOM object type)
* user_creatable_add_qapi:
* @options: the object definition
* @errp: if an error occurs, a pointer to an area to store the error
*
* Create an instance of the user creatable object that is defined by
* @qdict. The object type is taken from the QDict key 'qom-type', its
* ID from the key 'id'. The remaining entries in @qdict are used to
* initialize the object properties.
*
* Returns: %true on success, %false on failure.
* Create an instance of the user creatable object according to the
* options passed in @opts as described in the QAPI schema documentation.
*/
bool user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp);
void user_creatable_add_qapi(ObjectOptions *options, Error **errp);
/**
* user_creatable_add_opts:
* @opts: the object definition
* user_creatable_parse_str:
* @optarg: the object definition string as passed on the command line
* @errp: if an error occurs, a pointer to an area to store the error
*
* Create an instance of the user creatable object whose type
* is defined in @opts by the 'qom-type' option, placing it
* in the object composition tree with name provided by the
* 'id' field. The remaining options in @opts are used to
* initialize the object properties.
* Parses the option for the user creatable object with a keyval parser and
* implicit key 'qom-type', converting the result to ObjectOptions.
*
* Returns: the newly created object or NULL on error
* If a help option is given, print help instead.
*
* Returns: ObjectOptions on success, NULL when an error occurred (*errp is set
* then) or help was printed (*errp is not set).
*/
Object *user_creatable_add_opts(QemuOpts *opts, Error **errp);
ObjectOptions *user_creatable_parse_str(const char *optarg, Error **errp);
/**
* user_creatable_add_opts_predicate:
* @type: the QOM type to be added
* user_creatable_add_from_str:
* @optarg: the object definition string as passed on the command line
* @errp: if an error occurs, a pointer to an area to store the error
*
* A callback function to determine whether an object
* of type @type should be created. Instances of this
* callback should be passed to user_creatable_add_opts_foreach
* Create an instance of the user creatable object by parsing optarg
* with a keyval parser and implicit key 'qom-type', converting the
* result to ObjectOptions and calling into qmp_object_add().
*
* If a help option is given, print help instead.
*
* Returns: true when an object was successfully created, false when an error
* occurred (*errp is set then) or help was printed (*errp is not set).
*/
typedef bool (*user_creatable_add_opts_predicate)(const char *type);
bool user_creatable_add_from_str(const char *optarg, Error **errp);
/**
* user_creatable_add_opts_foreach:
* @opaque: a user_creatable_add_opts_predicate callback or NULL
* @opts: options to create
* @errp: unused
* user_creatable_process_cmdline:
* @optarg: the object definition string as passed on the command line
*
* An iterator callback to be used in conjunction with
* the qemu_opts_foreach() method for creating a list of
* objects from a set of QemuOpts
* Create an instance of the user creatable object by parsing optarg
* with a keyval parser and implicit key 'qom-type', converting the
* result to ObjectOptions and calling into qmp_object_add().
*
* The @opaque parameter can be passed a user_creatable_add_opts_predicate
* callback to filter which types of object are created during iteration.
* When it fails, report the error.
* If a help option is given, print help instead and exit.
*
* Returns: 0 on success, -1 when an error was reported.
* This function is only meant to be called during command line parsing.
* It exits the process on failure or after printing help.
*/
int user_creatable_add_opts_foreach(void *opaque,
QemuOpts *opts, Error **errp);
void user_creatable_process_cmdline(const char *optarg);
/**
* user_creatable_print_help:
@ -163,19 +157,6 @@ int user_creatable_add_opts_foreach(void *opaque,
*/
bool user_creatable_print_help(const char *type, QemuOpts *opts);
/**
* user_creatable_print_help_from_qdict:
* @args: options to create
*
* Prints help considering the other options given in @args (if "qom-type" is
* given and valid, print properties for the type, otherwise print valid types)
*
* In contrast to user_creatable_print_help(), this function can't return that
* no help was requested. It should only be called if we know that help is
* requested and it will always print some help.
*/
void user_creatable_print_help_from_qdict(QDict *args);
/**
* user_creatable_del:
* @id: the unique ID for the object
@ -196,11 +177,4 @@ bool user_creatable_del(const char *id, Error **errp);
*/
void user_creatable_cleanup(void);
/**
* qmp_object_add:
*
* QMP command handler for object-add. See the QAPI schema for documentation.
*/
void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp);
#endif

View File

@ -1636,24 +1636,11 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict)
void hmp_object_add(Monitor *mon, const QDict *qdict)
{
const char *options = qdict_get_str(qdict, "object");
Error *err = NULL;
QemuOpts *opts;
Object *obj = NULL;
opts = qemu_opts_from_qdict(qemu_find_opts("object"), qdict, &err);
if (err) {
goto end;
}
obj = user_creatable_add_opts(opts, &err);
qemu_opts_del(opts);
end:
user_creatable_add_from_str(options, &err);
hmp_handle_error(mon, err);
if (obj) {
object_unref(obj);
}
}
void hmp_getfd(Monitor *mon, const QDict *qdict)

View File

@ -235,8 +235,6 @@ static void monitor_init_qmp_commands(void)
qmp_query_qmp_schema, QCO_ALLOW_PRECONFIG);
qmp_register_command(&qmp_commands, "device_add", qmp_device_add,
QCO_NO_OPTIONS);
qmp_register_command(&qmp_commands, "object-add", qmp_object_add,
QCO_NO_OPTIONS);
QTAILQ_INIT(&qmp_cap_negotiation_commands);
qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities",

View File

@ -50,12 +50,63 @@
'*format': 'QAuthZListFormat'}}
##
# @QAuthZListRuleListHack:
# @AuthZListProperties:
#
# Not exposed via QMP; hack to generate QAuthZListRuleList
# for use internally by the code.
# Properties for authz-list objects.
#
# @policy: Default policy to apply when no rule matches (default: deny)
#
# @rules: Authorization rules based on matching user
#
# Since: 4.0
##
{ 'struct': 'QAuthZListRuleListHack',
'data': { 'unused': ['QAuthZListRule'] } }
{ 'struct': 'AuthZListProperties',
'data': { '*policy': 'QAuthZListPolicy',
'*rules': ['QAuthZListRule'] } }
##
# @AuthZListFileProperties:
#
# Properties for authz-listfile objects.
#
# @filename: File name to load the configuration from. The file must
# contain valid JSON for AuthZListProperties.
#
# @refresh: If true, inotify is used to monitor the file, automatically
# reloading changes. If an error occurs during reloading, all
# authorizations will fail until the file is next successfully
# loaded. (default: true if the binary was built with
# CONFIG_INOTIFY1, false otherwise)
#
# Since: 4.0
##
{ 'struct': 'AuthZListFileProperties',
'data': { 'filename': 'str',
'*refresh': 'bool' } }
##
# @AuthZPAMProperties:
#
# Properties for authz-pam objects.
#
# @service: PAM service name to use for authorization
#
# Since: 4.0
##
{ 'struct': 'AuthZPAMProperties',
'data': { 'service': 'str' } }
##
# @AuthZSimpleProperties:
#
# Properties for authz-simple objects.
#
# @identity: Identifies the allowed user. Its format depends on the network
# service that authorization object is associated with. For
# authorizing based on TLS x509 certificates, the identity must be
# the x509 distinguished name.
#
# Since: 4.0
##
{ 'struct': 'AuthZSimpleProperties',
'data': { 'identity': 'str' } }

View File

@ -2442,6 +2442,33 @@
'*bps-write-max' : 'int', '*bps-write-max-length' : 'int',
'*iops-size' : 'int' } }
##
# @ThrottleGroupProperties:
#
# Properties for throttle-group objects.
#
# The options starting with x- are aliases for the same key without x- in
# the @limits object. As indicated by the x- prefix, this is not a stable
# interface and may be removed or changed incompatibly in the future. Use
# @limits for a supported stable interface.
#
# @limits: limits to apply for this throttle group
#
# Since: 2.11
##
{ 'struct': 'ThrottleGroupProperties',
'data': { '*limits': 'ThrottleLimits',
'*x-iops-total' : 'int', '*x-iops-total-max' : 'int',
'*x-iops-total-max-length' : 'int', '*x-iops-read' : 'int',
'*x-iops-read-max' : 'int', '*x-iops-read-max-length' : 'int',
'*x-iops-write' : 'int', '*x-iops-write-max' : 'int',
'*x-iops-write-max-length' : 'int', '*x-bps-total' : 'int',
'*x-bps-total-max' : 'int', '*x-bps-total-max-length' : 'int',
'*x-bps-read' : 'int', '*x-bps-read-max' : 'int',
'*x-bps-read-max-length' : 'int', '*x-bps-write' : 'int',
'*x-bps-write-max' : 'int', '*x-bps-write-max-length' : 'int',
'*x-iops-size' : 'int' } }
##
# @block-stream:
#

View File

@ -145,3 +145,55 @@
##
{ 'enum': 'PCIELinkWidth',
'data': [ '1', '2', '4', '8', '12', '16', '32' ] }
##
# @HostMemPolicy:
#
# Host memory policy types
#
# @default: restore default policy, remove any nondefault policy
#
# @preferred: set the preferred host nodes for allocation
#
# @bind: a strict policy that restricts memory allocation to the
# host nodes specified
#
# @interleave: memory allocations are interleaved across the set
# of host nodes specified
#
# Since: 2.1
##
{ 'enum': 'HostMemPolicy',
'data': [ 'default', 'preferred', 'bind', 'interleave' ] }
##
# @NetFilterDirection:
#
# Indicates whether a netfilter is attached to a netdev's transmit queue or
# receive queue or both.
#
# @all: the filter is attached both to the receive and the transmit
# queue of the netdev (default).
#
# @rx: the filter is attached to the receive queue of the netdev,
# where it will receive packets sent to the netdev.
#
# @tx: the filter is attached to the transmit queue of the netdev,
# where it will receive packets sent by the netdev.
#
# Since: 2.5
##
{ 'enum': 'NetFilterDirection',
'data': [ 'all', 'rx', 'tx' ] }
##
# @GrabToggleKeys:
#
# Keys to toggle input-linux between host and guest.
#
# Since: 4.0
#
##
{ 'enum': 'GrabToggleKeys',
'data': [ 'ctrl-ctrl', 'alt-alt', 'shift-shift','meta-meta', 'scrolllock',
'ctrl-scrolllock' ] }

View File

@ -381,3 +381,162 @@
'discriminator': 'format',
'data': {
'luks': 'QCryptoBlockAmendOptionsLUKS' } }
##
# @SecretCommonProperties:
#
# Properties for objects of classes derived from secret-common.
#
# @loaded: if true, the secret is loaded immediately when applying this option
# and will probably fail when processing the next option. Don't use;
# only provided for compatibility. (default: false)
#
# @format: the data format that the secret is provided in (default: raw)
#
# @keyid: the name of another secret that should be used to decrypt the
# provided data. If not present, the data is assumed to be unencrypted.
#
# @iv: the random initialization vector used for encryption of this particular
# secret. Should be a base64 encrypted string of the 16-byte IV. Mandatory
# if @keyid is given. Ignored if @keyid is absent.
#
# Features:
# @deprecated: Member @loaded is deprecated. Setting true doesn't make sense,
# and false is already the default.
#
# Since: 2.6
##
{ 'struct': 'SecretCommonProperties',
'data': { '*loaded': { 'type': 'bool', 'features': ['deprecated'] },
'*format': 'QCryptoSecretFormat',
'*keyid': 'str',
'*iv': 'str' } }
##
# @SecretProperties:
#
# Properties for secret objects.
#
# Either @data or @file must be provided, but not both.
#
# @data: the associated with the secret from
#
# @file: the filename to load the data associated with the secret from
#
# Since: 2.6
##
{ 'struct': 'SecretProperties',
'base': 'SecretCommonProperties',
'data': { '*data': 'str',
'*file': 'str' } }
##
# @SecretKeyringProperties:
#
# Properties for secret_keyring objects.
#
# @serial: serial number that identifies a key to get from the kernel
#
# Since: 5.1
##
{ 'struct': 'SecretKeyringProperties',
'base': 'SecretCommonProperties',
'data': { 'serial': 'int32' } }
##
# @TlsCredsProperties:
#
# Properties for objects of classes derived from tls-creds.
#
# @verify-peer: if true the peer credentials will be verified once the
# handshake is completed. This is a no-op for anonymous
# credentials. (default: true)
#
# @dir: the path of the directory that contains the credential files
#
# @endpoint: whether the QEMU network backend that uses the credentials will be
# acting as a client or as a server (default: client)
#
# @priority: a gnutls priority string as described at
# https://gnutls.org/manual/html_node/Priority-Strings.html
#
# Since: 2.5
##
{ 'struct': 'TlsCredsProperties',
'data': { '*verify-peer': 'bool',
'*dir': 'str',
'*endpoint': 'QCryptoTLSCredsEndpoint',
'*priority': 'str' } }
##
# @TlsCredsAnonProperties:
#
# Properties for tls-creds-anon objects.
#
# @loaded: if true, the credentials are loaded immediately when applying this
# option and will ignore options that are processed later. Don't use;
# only provided for compatibility. (default: false)
#
# Features:
# @deprecated: Member @loaded is deprecated. Setting true doesn't make sense,
# and false is already the default.
#
# Since: 2.5
##
{ 'struct': 'TlsCredsAnonProperties',
'base': 'TlsCredsProperties',
'data': { '*loaded': { 'type': 'bool', 'features': ['deprecated'] } } }
##
# @TlsCredsPskProperties:
#
# Properties for tls-creds-psk objects.
#
# @loaded: if true, the credentials are loaded immediately when applying this
# option and will ignore options that are processed later. Don't use;
# only provided for compatibility. (default: false)
#
# @username: the username which will be sent to the server. For clients only.
# If absent, "qemu" is sent and the property will read back as an
# empty string.
#
# Features:
# @deprecated: Member @loaded is deprecated. Setting true doesn't make sense,
# and false is already the default.
#
# Since: 3.0
##
{ 'struct': 'TlsCredsPskProperties',
'base': 'TlsCredsProperties',
'data': { '*loaded': { 'type': 'bool', 'features': ['deprecated'] },
'*username': 'str' } }
##
# @TlsCredsX509Properties:
#
# Properties for tls-creds-x509 objects.
#
# @loaded: if true, the credentials are loaded immediately when applying this
# option and will ignore options that are processed later. Don't use;
# only provided for compatibility. (default: false)
#
# @sanity-check: if true, perform some sanity checks before using the
# credentials (default: true)
#
# @passwordid: For the server-key.pem and client-key.pem files which contain
# sensitive private keys, it is possible to use an encrypted
# version by providing the @passwordid parameter. This provides
# the ID of a previously created secret object containing the
# password for decryption.
#
# Features:
# @deprecated: Member @loaded is deprecated. Setting true doesn't make sense,
# and false is already the default.
#
# Since: 2.5
##
{ 'struct': 'TlsCredsX509Properties',
'base': 'TlsCredsProperties',
'data': { '*loaded': { 'type': 'bool', 'features': ['deprecated'] },
'*sanity-check': 'bool',
'*passwordid': 'str' } }

View File

@ -8,6 +8,8 @@
# = Machines
##
{ 'include': 'common.json' }
##
# @SysEmuTarget:
#
@ -718,26 +720,6 @@
'policy': 'HmatCacheWritePolicy',
'line': 'uint16' }}
##
# @HostMemPolicy:
#
# Host memory policy types
#
# @default: restore default policy, remove any nondefault policy
#
# @preferred: set the preferred host nodes for allocation
#
# @bind: a strict policy that restricts memory allocation to the
# host nodes specified
#
# @interleave: memory allocations are interleaved across the set
# of host nodes specified
#
# Since: 2.1
##
{ 'enum': 'HostMemPolicy',
'data': [ 'default', 'preferred', 'bind', 'interleave' ] }
##
# @memsave:
#

View File

@ -492,26 +492,6 @@
'vhost-user': 'NetdevVhostUserOptions',
'vhost-vdpa': 'NetdevVhostVDPAOptions' } }
##
# @NetFilterDirection:
#
# Indicates whether a netfilter is attached to a netdev's transmit queue or
# receive queue or both.
#
# @all: the filter is attached both to the receive and the transmit
# queue of the netdev (default).
#
# @rx: the filter is attached to the receive queue of the netdev,
# where it will receive packets sent to the netdev.
#
# @tx: the filter is attached to the transmit queue of the netdev,
# where it will receive packets sent by the netdev.
#
# Since: 2.5
##
{ 'enum': 'NetFilterDirection',
'data': [ 'all', 'rx', 'tx' ] }
##
# @RxState:
#

View File

@ -4,6 +4,11 @@
# This work is licensed under the terms of the GNU GPL, version 2 or later.
# See the COPYING file in the top-level directory.
{ 'include': 'authz.json' }
{ 'include': 'block-core.json' }
{ 'include': 'common.json' }
{ 'include': 'crypto.json' }
##
# = QEMU Object Model (QOM)
##
@ -203,20 +208,643 @@
'allow-preconfig': true }
##
# @object-add:
# @CanHostSocketcanProperties:
#
# Create a QOM object.
# Properties for can-host-socketcan objects.
#
# @if: interface name of the host system CAN bus to connect to
#
# @canbus: object ID of the can-bus object to connect to the host interface
#
# Since: 2.12
##
{ 'struct': 'CanHostSocketcanProperties',
'data': { 'if': 'str',
'canbus': 'str' } }
##
# @ColoCompareProperties:
#
# Properties for colo-compare objects.
#
# @primary_in: name of the character device backend to use for the primary
# input (incoming packets are redirected to @outdev)
#
# @secondary_in: name of the character device backend to use for secondary
# input (incoming packets are only compared to the input on
# @primary_in and then dropped)
#
# @outdev: name of the character device backend to use for output
#
# @iothread: name of the iothread to run in
#
# @notify_dev: name of the character device backend to be used to communicate
# with the remote colo-frame (only for Xen COLO)
#
# @compare_timeout: the maximum time to hold a packet from @primary_in for
# comparison with an incoming packet on @secondary_in in
# milliseconds (default: 3000)
#
# @expired_scan_cycle: the interval at which colo-compare checks whether
# packets from @primary have timed out, in milliseconds
# (default: 3000)
#
# @max_queue_size: the maximum number of packets to keep in the queue for
# comparing with incoming packets from @secondary_in. If the
# queue is full and addtional packets are received, the
# addtional packets are dropped. (default: 1024)
#
# @vnet_hdr_support: if true, vnet header support is enabled (default: false)
#
# Since: 2.8
##
{ 'struct': 'ColoCompareProperties',
'data': { 'primary_in': 'str',
'secondary_in': 'str',
'outdev': 'str',
'iothread': 'str',
'*notify_dev': 'str',
'*compare_timeout': 'uint64',
'*expired_scan_cycle': 'uint32',
'*max_queue_size': 'uint32',
'*vnet_hdr_support': 'bool' } }
##
# @CryptodevBackendProperties:
#
# Properties for cryptodev-backend and cryptodev-backend-builtin objects.
#
# @queues: the number of queues for the cryptodev backend. Ignored for
# cryptodev-backend and must be 1 for cryptodev-backend-builtin.
# (default: 1)
#
# Since: 2.8
##
{ 'struct': 'CryptodevBackendProperties',
'data': { '*queues': 'uint32' } }
##
# @CryptodevVhostUserProperties:
#
# Properties for cryptodev-vhost-user objects.
#
# @chardev: the name of a Unix domain socket character device that connects to
# the vhost-user server
#
# Since: 2.12
##
{ 'struct': 'CryptodevVhostUserProperties',
'base': 'CryptodevBackendProperties',
'data': { 'chardev': 'str' } }
##
# @DBusVMStateProperties:
#
# Properties for dbus-vmstate objects.
#
# @addr: the name of the DBus bus to connect to
#
# @id-list: a comma separated list of DBus IDs of helpers whose data should be
# included in the VM state on migration
#
# Since: 5.0
##
{ 'struct': 'DBusVMStateProperties',
'data': { 'addr': 'str' ,
'*id-list': 'str' } }
##
# @NetfilterInsert:
#
# Indicates where to insert a netfilter relative to a given other filter.
#
# @before: insert before the specified filter
#
# @behind: insert behind the specified filter
#
# Since: 5.0
##
{ 'enum': 'NetfilterInsert',
'data': [ 'before', 'behind' ] }
##
# @NetfilterProperties:
#
# Properties for objects of classes derived from netfilter.
#
# @netdev: id of the network device backend to filter
#
# @queue: indicates which queue(s) to filter (default: all)
#
# @status: indicates whether the filter is enabled ("on") or disabled ("off")
# (default: "on")
#
# @position: specifies where the filter should be inserted in the filter list.
# "head" means the filter is inserted at the head of the filter list,
# before any existing filters.
# "tail" means the filter is inserted at the tail of the filter list,
# behind any existing filters (default).
# "id=<id>" means the filter is inserted before or behind the filter
# specified by <id>, depending on the @insert property.
# (default: "tail")
#
# @insert: where to insert the filter relative to the filter given in @position.
# Ignored if @position is "head" or "tail". (default: behind)
#
# Since: 2.5
##
{ 'struct': 'NetfilterProperties',
'data': { 'netdev': 'str',
'*queue': 'NetFilterDirection',
'*status': 'str',
'*position': 'str',
'*insert': 'NetfilterInsert' } }
##
# @FilterBufferProperties:
#
# Properties for filter-buffer objects.
#
# @interval: a non-zero interval in microseconds. All packets arriving in the
# given interval are delayed until the end of the interval.
#
# Since: 2.5
##
{ 'struct': 'FilterBufferProperties',
'base': 'NetfilterProperties',
'data': { 'interval': 'uint32' } }
##
# @FilterDumpProperties:
#
# Properties for filter-dump objects.
#
# @file: the filename where the dumped packets should be stored
#
# @maxlen: maximum number of bytes in a packet that are stored (default: 65536)
#
# Since: 2.5
##
{ 'struct': 'FilterDumpProperties',
'base': 'NetfilterProperties',
'data': { 'file': 'str',
'*maxlen': 'uint32' } }
##
# @FilterMirrorProperties:
#
# Properties for filter-mirror objects.
#
# @outdev: the name of a character device backend to which all incoming packets
# are mirrored
#
# @vnet_hdr_support: if true, vnet header support is enabled (default: false)
#
# Since: 2.6
##
{ 'struct': 'FilterMirrorProperties',
'base': 'NetfilterProperties',
'data': { 'outdev': 'str',
'*vnet_hdr_support': 'bool' } }
##
# @FilterRedirectorProperties:
#
# Properties for filter-redirector objects.
#
# At least one of @indev or @outdev must be present. If both are present, they
# must not refer to the same character device backend.
#
# @indev: the name of a character device backend from which packets are
# received and redirected to the filtered network device
#
# @outdev: the name of a character device backend to which all incoming packets
# are redirected
#
# @vnet_hdr_support: if true, vnet header support is enabled (default: false)
#
# Since: 2.6
##
{ 'struct': 'FilterRedirectorProperties',
'base': 'NetfilterProperties',
'data': { '*indev': 'str',
'*outdev': 'str',
'*vnet_hdr_support': 'bool' } }
##
# @FilterRewriterProperties:
#
# Properties for filter-rewriter objects.
#
# @vnet_hdr_support: if true, vnet header support is enabled (default: false)
#
# Since: 2.8
##
{ 'struct': 'FilterRewriterProperties',
'base': 'NetfilterProperties',
'data': { '*vnet_hdr_support': 'bool' } }
##
# @InputBarrierProperties:
#
# Properties for input-barrier objects.
#
# @name: the screen name as declared in the screens section of barrier.conf
#
# @server: hostname of the Barrier server (default: "localhost")
#
# @port: TCP port of the Barrier server (default: "24800")
#
# @x-origin: x coordinate of the leftmost pixel on the guest screen
# (default: "0")
#
# @y-origin: y coordinate of the topmost pixel on the guest screen
# (default: "0")
#
# @width: the width of secondary screen in pixels (default: "1920")
#
# @height: the height of secondary screen in pixels (default: "1080")
#
# Since: 4.2
##
{ 'struct': 'InputBarrierProperties',
'data': { 'name': 'str',
'*server': 'str',
'*port': 'str',
'*x-origin': 'str',
'*y-origin': 'str',
'*width': 'str',
'*height': 'str' } }
##
# @InputLinuxProperties:
#
# Properties for input-linux objects.
#
# @evdev: the path of the host evdev device to use
#
# @grab_all: if true, grab is toggled for all devices (e.g. both keyboard and
# mouse) instead of just one device (default: false)
#
# @repeat: enables auto-repeat events (default: false)
#
# @grab-toggle: the key or key combination that toggles device grab
# (default: ctrl-ctrl)
#
# Since: 2.6
##
{ 'struct': 'InputLinuxProperties',
'data': { 'evdev': 'str',
'*grab_all': 'bool',
'*repeat': 'bool',
'*grab-toggle': 'GrabToggleKeys' } }
##
# @IothreadProperties:
#
# Properties for iothread objects.
#
# @poll-max-ns: the maximum number of nanoseconds to busy wait for events.
# 0 means polling is disabled (default: 32768 on POSIX hosts,
# 0 otherwise)
#
# @poll-grow: the multiplier used to increase the polling time when the
# algorithm detects it is missing events due to not polling long
# enough. 0 selects a default behaviour (default: 0)
#
# @poll-shrink: the divisor used to decrease the polling time when the
# algorithm detects it is spending too long polling without
# encountering events. 0 selects a default behaviour (default: 0)
#
# Since: 2.0
##
{ 'struct': 'IothreadProperties',
'data': { '*poll-max-ns': 'int',
'*poll-grow': 'int',
'*poll-shrink': 'int' } }
##
# @MemoryBackendProperties:
#
# Properties for objects of classes derived from memory-backend.
#
# @merge: if true, mark the memory as mergeable (default depends on the machine
# type)
#
# @dump: if true, include the memory in core dumps (default depends on the
# machine type)
#
# @host-nodes: the list of NUMA host nodes to bind the memory to
#
# @policy: the NUMA policy (default: 'default')
#
# @prealloc: if true, preallocate memory (default: false)
#
# @prealloc-threads: number of CPU threads to use for prealloc (default: 1)
#
# @share: if false, the memory is private to QEMU; if true, it is shared
# (default: false)
#
# @size: size of the memory region in bytes
#
# @x-use-canonical-path-for-ramblock-id: if true, the canoncial path is used
# for ramblock-id. Disable this for 4.0
# machine types or older to allow
# migration with newer QEMU versions.
# This option is considered stable
# despite the x- prefix. (default:
# false generally, but true for machine
# types <= 4.0)
#
# Since: 2.1
##
{ 'struct': 'MemoryBackendProperties',
'data': { '*dump': 'bool',
'*host-nodes': ['uint16'],
'*merge': 'bool',
'*policy': 'HostMemPolicy',
'*prealloc': 'bool',
'*prealloc-threads': 'uint32',
'*share': 'bool',
'size': 'size',
'*x-use-canonical-path-for-ramblock-id': 'bool' } }
##
# @MemoryBackendFileProperties:
#
# Properties for memory-backend-file objects.
#
# @align: the base address alignment when QEMU mmap(2)s @mem-path. Some
# backend stores specified by @mem-path require an alignment different
# than the default one used by QEMU, e.g. the device DAX /dev/dax0.0
# requires 2M alignment rather than 4K. In such cases, users can
# specify the required alignment via this option.
# 0 selects a default alignment (currently the page size). (default: 0)
#
# @discard-data: if true, the file contents can be destroyed when QEMU exits,
# to avoid unnecessarily flushing data to the backing file. Note
# that ``discard-data`` is only an optimization, and QEMU might
# not discard file contents if it aborts unexpectedly or is
# terminated using SIGKILL. (default: false)
#
# @mem-path: the path to either a shared memory or huge page filesystem mount
#
# @pmem: specifies whether the backing file specified by @mem-path is in
# host persistent memory that can be accessed using the SNIA NVM
# programming model (e.g. Intel NVDIMM).
#
# @readonly: if true, the backing file is opened read-only; if false, it is
# opened read-write. (default: false)
#
# Since: 2.1
##
{ 'struct': 'MemoryBackendFileProperties',
'base': 'MemoryBackendProperties',
'data': { '*align': 'size',
'*discard-data': 'bool',
'mem-path': 'str',
'*pmem': { 'type': 'bool', 'if': 'defined(CONFIG_LIBPMEM)' },
'*readonly': 'bool' } }
##
# @MemoryBackendMemfdProperties:
#
# Properties for memory-backend-memfd objects.
#
# The @share boolean option is true by default with memfd.
#
# @hugetlb: if true, the file to be created resides in the hugetlbfs filesystem
# (default: false)
#
# @hugetlbsize: the hugetlb page size on systems that support multiple hugetlb
# page sizes (it must be a power of 2 value supported by the
# system). 0 selects a default page size. This option is ignored
# if @hugetlb is false. (default: 0)
#
# @seal: if true, create a sealed-file, which will block further resizing of
# the memory (default: true)
#
# Since: 2.12
##
{ 'struct': 'MemoryBackendMemfdProperties',
'base': 'MemoryBackendProperties',
'data': { '*hugetlb': 'bool',
'*hugetlbsize': 'size',
'*seal': 'bool' } }
##
# @PrManagerHelperProperties:
#
# Properties for pr-manager-helper objects.
#
# @path: the path to a Unix domain socket for connecting to the external helper
#
# Since: 2.11
##
{ 'struct': 'PrManagerHelperProperties',
'data': { 'path': 'str' } }
##
# @RemoteObjectProperties:
#
# Properties for x-remote-object objects.
#
# @fd: file descriptor name previously passed via 'getfd' command
#
# @devid: the id of the device to be associated with the file descriptor
#
# Since: 6.0
##
{ 'struct': 'RemoteObjectProperties',
'data': { 'fd': 'str', 'devid': 'str' } }
##
# @RngProperties:
#
# Properties for objects of classes derived from rng.
#
# @opened: if true, the device is opened immediately when applying this option
# and will probably fail when processing the next option. Don't use;
# only provided for compatibility. (default: false)
#
# Features:
# @deprecated: Member @opened is deprecated. Setting true doesn't make sense,
# and false is already the default.
#
# Since: 1.3
##
{ 'struct': 'RngProperties',
'data': { '*opened': { 'type': 'bool', 'features': ['deprecated'] } } }
##
# @RngEgdProperties:
#
# Properties for rng-egd objects.
#
# @chardev: the name of a character device backend that provides the connection
# to the RNG daemon
#
# Since: 1.3
##
{ 'struct': 'RngEgdProperties',
'base': 'RngProperties',
'data': { 'chardev': 'str' } }
##
# @RngRandomProperties:
#
# Properties for rng-random objects.
#
# @filename: the filename of the device on the host to obtain entropy from
# (default: "/dev/urandom")
#
# Since: 1.3
##
{ 'struct': 'RngRandomProperties',
'base': 'RngProperties',
'data': { '*filename': 'str' } }
##
# @SevGuestProperties:
#
# Properties for sev-guest objects.
#
# @sev-device: SEV device to use (default: "/dev/sev")
#
# @dh-cert-file: guest owners DH certificate (encoded with base64)
#
# @session-file: guest owners session parameters (encoded with base64)
#
# @policy: SEV policy value (default: 0x1)
#
# @handle: SEV firmware handle (default: 0)
#
# @cbitpos: C-bit location in page table entry (default: 0)
#
# @reduced-phys-bits: number of bits in physical addresses that become
# unavailable when SEV is enabled
#
# Since: 2.12
##
{ 'struct': 'SevGuestProperties',
'data': { '*sev-device': 'str',
'*dh-cert-file': 'str',
'*session-file': 'str',
'*policy': 'uint32',
'*handle': 'uint32',
'*cbitpos': 'uint32',
'reduced-phys-bits': 'uint32' },
'if': 'defined(CONFIG_SEV)' }
##
# @ObjectType:
#
# Since: 6.0
##
{ 'enum': 'ObjectType',
'data': [
'authz-list',
'authz-listfile',
'authz-pam',
'authz-simple',
'can-bus',
'can-host-socketcan',
'colo-compare',
'cryptodev-backend',
'cryptodev-backend-builtin',
{ 'name': 'cryptodev-vhost-user',
'if': 'defined(CONFIG_VIRTIO_CRYPTO) && defined(CONFIG_VHOST_CRYPTO)' },
'dbus-vmstate',
'filter-buffer',
'filter-dump',
'filter-mirror',
'filter-redirector',
'filter-replay',
'filter-rewriter',
'input-barrier',
'input-linux',
'iothread',
'memory-backend-file',
{ 'name': 'memory-backend-memfd',
'if': 'defined(CONFIG_LINUX)' },
'memory-backend-ram',
{'name': 'pef-guest', 'if': 'defined(CONFIG_PSERIES)' },
'pr-manager-helper',
'rng-builtin',
'rng-egd',
'rng-random',
'secret',
'secret_keyring',
{'name': 'sev-guest', 'if': 'defined(CONFIG_SEV)' },
's390-pv-guest',
'throttle-group',
'tls-creds-anon',
'tls-creds-psk',
'tls-creds-x509',
'tls-cipher-suites',
'x-remote-object'
] }
##
# @ObjectOptions:
#
# Describes the options of a user creatable QOM object.
#
# @qom-type: the class name for the object to be created
#
# @id: the name of the new object
#
# @props: a dictionary of properties to be passed to the backend. Deprecated
# since 5.0, specify the properties on the top level instead. It is an
# error to specify the same option both on the top level and in @props.
# Since: 6.0
##
{ 'union': 'ObjectOptions',
'base': { 'qom-type': 'ObjectType',
'id': 'str' },
'discriminator': 'qom-type',
'data': {
'authz-list': 'AuthZListProperties',
'authz-listfile': 'AuthZListFileProperties',
'authz-pam': 'AuthZPAMProperties',
'authz-simple': 'AuthZSimpleProperties',
'can-host-socketcan': 'CanHostSocketcanProperties',
'colo-compare': 'ColoCompareProperties',
'cryptodev-backend': 'CryptodevBackendProperties',
'cryptodev-backend-builtin': 'CryptodevBackendProperties',
'cryptodev-vhost-user': { 'type': 'CryptodevVhostUserProperties',
'if': 'defined(CONFIG_VIRTIO_CRYPTO) && defined(CONFIG_VHOST_CRYPTO)' },
'dbus-vmstate': 'DBusVMStateProperties',
'filter-buffer': 'FilterBufferProperties',
'filter-dump': 'FilterDumpProperties',
'filter-mirror': 'FilterMirrorProperties',
'filter-redirector': 'FilterRedirectorProperties',
'filter-replay': 'NetfilterProperties',
'filter-rewriter': 'FilterRewriterProperties',
'input-barrier': 'InputBarrierProperties',
'input-linux': 'InputLinuxProperties',
'iothread': 'IothreadProperties',
'memory-backend-file': 'MemoryBackendFileProperties',
'memory-backend-memfd': { 'type': 'MemoryBackendMemfdProperties',
'if': 'defined(CONFIG_LINUX)' },
'memory-backend-ram': 'MemoryBackendProperties',
'pr-manager-helper': 'PrManagerHelperProperties',
'rng-builtin': 'RngProperties',
'rng-egd': 'RngEgdProperties',
'rng-random': 'RngRandomProperties',
'secret': 'SecretProperties',
'secret_keyring': 'SecretKeyringProperties',
'sev-guest': { 'type': 'SevGuestProperties',
'if': 'defined(CONFIG_SEV)' },
'throttle-group': 'ThrottleGroupProperties',
'tls-creds-anon': 'TlsCredsAnonProperties',
'tls-creds-psk': 'TlsCredsPskProperties',
'tls-creds-x509': 'TlsCredsX509Properties',
'tls-cipher-suites': 'TlsCredsProperties',
'x-remote-object': 'RemoteObjectProperties'
} }
##
# @object-add:
#
# Additional arguments depend on qom-type and are passed to the backend
# unchanged.
# Create a QOM object.
#
# Returns: Nothing on success
# Error if @qom-type is not a valid class name
@ -231,9 +859,7 @@
# <- { "return": {} }
#
##
{ 'command': 'object-add',
'data': {'qom-type': 'str', 'id': 'str', '*props': 'any'},
'gen': false } # so we can get the additional arguments
{ 'command': 'object-add', 'data': 'ObjectOptions', 'boxed': true }
##
# @object-del:

View File

@ -6,6 +6,7 @@
# = Remote desktop
##
{ 'include': 'common.json' }
{ 'include': 'sockets.json' }
##
@ -1021,18 +1022,6 @@
'*head' : 'int',
'events' : [ 'InputEvent' ] } }
##
# @GrabToggleKeys:
#
# Keys to toggle input-linux between host and guest.
#
# Since: 4.0
#
##
{ 'enum': 'GrabToggleKeys',
'data': [ 'ctrl-ctrl', 'alt-alt', 'shift-shift','meta-meta', 'scrolllock',
'ctrl-scrolllock' ] }
##
# @DisplayGTK:
#

View File

@ -226,23 +226,6 @@ static void QEMU_NORETURN help(void)
exit(EXIT_SUCCESS);
}
static QemuOptsList qemu_object_opts = {
.name = "object",
.implied_opt_name = "qom-type",
.head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head),
.desc = {
{ }
},
};
static bool qemu_img_object_print_help(const char *type, QemuOpts *opts)
{
if (user_creatable_print_help(type, opts)) {
exit(0);
}
return true;
}
/*
* Is @optarg safe for accumulate_options()?
* It is when multiple of them can be joined together separated by ','.
@ -566,14 +549,9 @@ static int img_create(int argc, char **argv)
case 'u':
flags |= BDRV_O_NO_BACKING;
break;
case OPTION_OBJECT: {
QemuOpts *opts;
opts = qemu_opts_parse_noisily(&qemu_object_opts,
optarg, true);
if (!opts) {
goto fail;
}
} break;
case OPTION_OBJECT:
user_creatable_process_cmdline(optarg);
break;
}
}
@ -589,12 +567,6 @@ static int img_create(int argc, char **argv)
}
optind++;
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
qemu_img_object_print_help, &error_fatal)) {
goto fail;
}
/* Get image size, if specified */
if (optind < argc) {
int64_t sval;
@ -804,14 +776,9 @@ static int img_check(int argc, char **argv)
case 'U':
force_share = true;
break;
case OPTION_OBJECT: {
QemuOpts *opts;
opts = qemu_opts_parse_noisily(&qemu_object_opts,
optarg, true);
if (!opts) {
return 1;
}
} break;
case OPTION_OBJECT:
user_creatable_process_cmdline(optarg);
break;
case OPTION_IMAGE_OPTS:
image_opts = true;
break;
@ -831,12 +798,6 @@ static int img_check(int argc, char **argv)
return 1;
}
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
qemu_img_object_print_help, &error_fatal)) {
return 1;
}
ret = bdrv_parse_cache_mode(cache, &flags, &writethrough);
if (ret < 0) {
error_report("Invalid source cache option: %s", cache);
@ -1034,14 +995,9 @@ static int img_commit(int argc, char **argv)
return 1;
}
break;
case OPTION_OBJECT: {
QemuOpts *opts;
opts = qemu_opts_parse_noisily(&qemu_object_opts,
optarg, true);
if (!opts) {
return 1;
}
} break;
case OPTION_OBJECT:
user_creatable_process_cmdline(optarg);
break;
case OPTION_IMAGE_OPTS:
image_opts = true;
break;
@ -1058,12 +1014,6 @@ static int img_commit(int argc, char **argv)
}
filename = argv[optind++];
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
qemu_img_object_print_help, &error_fatal)) {
return 1;
}
flags = BDRV_O_RDWR | BDRV_O_UNMAP;
ret = bdrv_parse_cache_mode(cache, &flags, &writethrough);
if (ret < 0) {
@ -1353,7 +1303,7 @@ static int check_empty_sectors(BlockBackend *blk, int64_t offset,
/*
* Compares two images. Exit codes:
*
* 0 - Images are identical
* 0 - Images are identical or the requested help was printed
* 1 - Images differ
* >1 - Error occurred
*/
@ -1423,15 +1373,21 @@ static int img_compare(int argc, char **argv)
case 'U':
force_share = true;
break;
case OPTION_OBJECT: {
QemuOpts *opts;
opts = qemu_opts_parse_noisily(&qemu_object_opts,
optarg, true);
if (!opts) {
ret = 2;
goto out4;
case OPTION_OBJECT:
{
Error *local_err = NULL;
if (!user_creatable_add_from_str(optarg, &local_err)) {
if (local_err) {
error_report_err(local_err);
exit(2);
} else {
/* Help was printed */
exit(EXIT_SUCCESS);
}
}
break;
}
} break;
case OPTION_IMAGE_OPTS:
image_opts = true;
break;
@ -1450,13 +1406,6 @@ static int img_compare(int argc, char **argv)
filename1 = argv[optind++];
filename2 = argv[optind++];
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
qemu_img_object_print_help, &error_fatal)) {
ret = 2;
goto out4;
}
/* Initialize before goto out */
qemu_progress_init(progress, 2.0);
@ -1641,7 +1590,6 @@ out2:
blk_unref(blk1);
out3:
qemu_progress_end();
out4:
return ret;
}
@ -2342,15 +2290,9 @@ static int img_convert(int argc, char **argv)
goto fail_getopt;
}
break;
case OPTION_OBJECT: {
QemuOpts *object_opts;
object_opts = qemu_opts_parse_noisily(&qemu_object_opts,
optarg, true);
if (!object_opts) {
goto fail_getopt;
}
case OPTION_OBJECT:
user_creatable_process_cmdline(optarg);
break;
}
case OPTION_IMAGE_OPTS:
image_opts = true;
break;
@ -2378,12 +2320,6 @@ static int img_convert(int argc, char **argv)
out_fmt = "raw";
}
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
qemu_img_object_print_help, &error_fatal)) {
goto fail_getopt;
}
if (s.compressed && s.copy_range) {
error_report("Cannot enable copy offloading when -c is used");
goto fail_getopt;
@ -2971,14 +2907,9 @@ static int img_info(int argc, char **argv)
case OPTION_BACKING_CHAIN:
chain = true;
break;
case OPTION_OBJECT: {
QemuOpts *opts;
opts = qemu_opts_parse_noisily(&qemu_object_opts,
optarg, true);
if (!opts) {
return 1;
}
} break;
case OPTION_OBJECT:
user_creatable_process_cmdline(optarg);
break;
case OPTION_IMAGE_OPTS:
image_opts = true;
break;
@ -2998,12 +2929,6 @@ static int img_info(int argc, char **argv)
return 1;
}
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
qemu_img_object_print_help, &error_fatal)) {
return 1;
}
list = collect_image_info_list(image_opts, filename, fmt, chain,
force_share);
if (!list) {
@ -3213,14 +3138,9 @@ static int img_map(int argc, char **argv)
return 1;
}
break;
case OPTION_OBJECT: {
QemuOpts *opts;
opts = qemu_opts_parse_noisily(&qemu_object_opts,
optarg, true);
if (!opts) {
return 1;
}
} break;
case OPTION_OBJECT:
user_creatable_process_cmdline(optarg);
break;
case OPTION_IMAGE_OPTS:
image_opts = true;
break;
@ -3240,12 +3160,6 @@ static int img_map(int argc, char **argv)
return 1;
}
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
qemu_img_object_print_help, &error_fatal)) {
return 1;
}
blk = img_open(image_opts, filename, fmt, 0, false, false, force_share);
if (!blk) {
return 1;
@ -3384,14 +3298,9 @@ static int img_snapshot(int argc, char **argv)
case 'U':
force_share = true;
break;
case OPTION_OBJECT: {
QemuOpts *opts;
opts = qemu_opts_parse_noisily(&qemu_object_opts,
optarg, true);
if (!opts) {
return 1;
}
} break;
case OPTION_OBJECT:
user_creatable_process_cmdline(optarg);
break;
case OPTION_IMAGE_OPTS:
image_opts = true;
break;
@ -3403,12 +3312,6 @@ static int img_snapshot(int argc, char **argv)
}
filename = argv[optind++];
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
qemu_img_object_print_help, &error_fatal)) {
return 1;
}
/* Open the image */
blk = img_open(image_opts, filename, NULL, bdrv_oflags, false, quiet,
force_share);
@ -3542,14 +3445,9 @@ static int img_rebase(int argc, char **argv)
case 'q':
quiet = true;
break;
case OPTION_OBJECT: {
QemuOpts *opts;
opts = qemu_opts_parse_noisily(&qemu_object_opts,
optarg, true);
if (!opts) {
return 1;
}
} break;
case OPTION_OBJECT:
user_creatable_process_cmdline(optarg);
break;
case OPTION_IMAGE_OPTS:
image_opts = true;
break;
@ -3571,12 +3469,6 @@ static int img_rebase(int argc, char **argv)
}
filename = argv[optind++];
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
qemu_img_object_print_help, &error_fatal)) {
return 1;
}
qemu_progress_init(progress, 2.0);
qemu_progress_print(0, 100);
@ -3967,14 +3859,9 @@ static int img_resize(int argc, char **argv)
case 'q':
quiet = true;
break;
case OPTION_OBJECT: {
QemuOpts *opts;
opts = qemu_opts_parse_noisily(&qemu_object_opts,
optarg, true);
if (!opts) {
return 1;
}
} break;
case OPTION_OBJECT:
user_creatable_process_cmdline(optarg);
break;
case OPTION_IMAGE_OPTS:
image_opts = true;
break;
@ -3996,12 +3883,6 @@ static int img_resize(int argc, char **argv)
}
filename = argv[optind++];
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
qemu_img_object_print_help, &error_fatal)) {
return 1;
}
/* Choose grow, shrink, or absolute resize mode */
switch (size[0]) {
case '+':
@ -4181,12 +4062,7 @@ static int img_amend(int argc, char **argv)
quiet = true;
break;
case OPTION_OBJECT:
opts = qemu_opts_parse_noisily(&qemu_object_opts,
optarg, true);
if (!opts) {
ret = -1;
goto out_no_progress;
}
user_creatable_process_cmdline(optarg);
break;
case OPTION_IMAGE_OPTS:
image_opts = true;
@ -4201,13 +4077,6 @@ static int img_amend(int argc, char **argv)
error_exit("Must specify options (-o)");
}
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
qemu_img_object_print_help, &error_fatal)) {
ret = -1;
goto out_no_progress;
}
if (quiet) {
progress = false;
}
@ -4760,10 +4629,7 @@ static int img_bitmap(int argc, char **argv)
merge = true;
break;
case OPTION_OBJECT:
opts = qemu_opts_parse_noisily(&qemu_object_opts, optarg, true);
if (!opts) {
goto out;
}
user_creatable_process_cmdline(optarg);
break;
case OPTION_IMAGE_OPTS:
image_opts = true;
@ -4771,12 +4637,6 @@ static int img_bitmap(int argc, char **argv)
}
}
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
qemu_img_object_print_help, &error_fatal)) {
goto out;
}
if (QSIMPLEQ_EMPTY(&actions)) {
error_report("Need at least one of --add, --remove, --clear, "
"--enable, --disable, or --merge");
@ -5034,10 +4894,7 @@ static int img_dd(int argc, char **argv)
force_share = true;
break;
case OPTION_OBJECT:
if (!qemu_opts_parse_noisily(&qemu_object_opts, optarg, true)) {
ret = -1;
goto out;
}
user_creatable_process_cmdline(optarg);
break;
case OPTION_IMAGE_OPTS:
image_opts = true;
@ -5084,13 +4941,6 @@ static int img_dd(int argc, char **argv)
goto out;
}
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
qemu_img_object_print_help, &error_fatal)) {
ret = -1;
goto out;
}
blk1 = img_open(image_opts, in.filename, fmt, 0, false, false,
force_share);
@ -5311,11 +5161,7 @@ static int img_measure(int argc, char **argv)
force_share = true;
break;
case OPTION_OBJECT:
object_opts = qemu_opts_parse_noisily(&qemu_object_opts,
optarg, true);
if (!object_opts) {
goto out;
}
user_creatable_process_cmdline(optarg);
break;
case OPTION_IMAGE_OPTS:
image_opts = true;
@ -5345,12 +5191,6 @@ static int img_measure(int argc, char **argv)
}
}
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
qemu_img_object_print_help, &error_fatal)) {
goto out;
}
if (argc - optind > 1) {
error_report("At most one filename argument is allowed.");
goto out;
@ -5490,7 +5330,6 @@ int main(int argc, char **argv)
error_exit("Not enough arguments");
}
qemu_add_opts(&qemu_object_opts);
qemu_add_opts(&qemu_source_opts);
qemu_add_opts(&qemu_trace_opts);

View File

@ -477,23 +477,6 @@ enum {
OPTION_IMAGE_OPTS = 257,
};
static QemuOptsList qemu_object_opts = {
.name = "object",
.implied_opt_name = "qom-type",
.head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head),
.desc = {
{ }
},
};
static bool qemu_io_object_print_help(const char *type, QemuOpts *opts)
{
if (user_creatable_print_help(type, opts)) {
exit(0);
}
return true;
}
static QemuOptsList file_opts = {
.name = "file",
.implied_opt_name = "file",
@ -550,7 +533,6 @@ int main(int argc, char **argv)
qcrypto_init(&error_fatal);
module_call_init(MODULE_INIT_QOM);
qemu_add_opts(&qemu_object_opts);
qemu_add_opts(&qemu_trace_opts);
bdrv_init();
@ -612,14 +594,9 @@ int main(int argc, char **argv)
case 'U':
force_share = true;
break;
case OPTION_OBJECT: {
QemuOpts *qopts;
qopts = qemu_opts_parse_noisily(&qemu_object_opts,
optarg, true);
if (!qopts) {
exit(1);
}
} break;
case OPTION_OBJECT:
user_creatable_process_cmdline(optarg);
break;
case OPTION_IMAGE_OPTS:
imageOpts = true;
break;
@ -644,10 +621,6 @@ int main(int argc, char **argv)
exit(1);
}
qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
qemu_io_object_print_help, &error_fatal);
if (!trace_init_backends()) {
exit(1);
}

View File

@ -401,24 +401,6 @@ static QemuOptsList file_opts = {
},
};
static QemuOptsList qemu_object_opts = {
.name = "object",
.implied_opt_name = "qom-type",
.head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head),
.desc = {
{ }
},
};
static bool qemu_nbd_object_print_help(const char *type, QemuOpts *opts)
{
if (user_creatable_print_help(type, opts)) {
exit(0);
}
return true;
}
static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, bool list,
Error **errp)
{
@ -594,7 +576,6 @@ int main(int argc, char **argv)
qcrypto_init(&error_fatal);
module_call_init(MODULE_INIT_QOM);
qemu_add_opts(&qemu_object_opts);
qemu_add_opts(&qemu_trace_opts);
qemu_init_exec_dir(argv[0]);
@ -747,14 +728,9 @@ int main(int argc, char **argv)
case '?':
error_report("Try `%s --help' for more information.", argv[0]);
exit(EXIT_FAILURE);
case QEMU_NBD_OPT_OBJECT: {
QemuOpts *opts;
opts = qemu_opts_parse_noisily(&qemu_object_opts,
optarg, true);
if (!opts) {
exit(EXIT_FAILURE);
}
} break;
case QEMU_NBD_OPT_OBJECT:
user_creatable_process_cmdline(optarg);
break;
case QEMU_NBD_OPT_TLSCREDS:
tlscredsid = optarg;
break;
@ -802,10 +778,6 @@ int main(int argc, char **argv)
export_name = "";
}
qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
qemu_nbd_object_print_help, &error_fatal);
if (!trace_init_backends()) {
exit(1);
}

View File

@ -2,15 +2,19 @@
#include "qemu/cutils.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-qom.h"
#include "qapi/qapi-visit-qom.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qerror.h"
#include "qapi/qmp/qjson.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/qobject-output-visitor.h"
#include "qom/object_interfaces.h"
#include "qemu/help_option.h"
#include "qemu/id.h"
#include "qemu/module.h"
#include "qemu/option.h"
#include "qemu/qemu-print.h"
#include "qapi/opts-visitor.h"
#include "qemu/config-file.h"
@ -113,90 +117,28 @@ out:
return obj;
}
bool user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp)
void user_creatable_add_qapi(ObjectOptions *options, Error **errp)
{
Visitor *v;
QObject *qobj;
QDict *props;
Object *obj;
g_autofree char *type = NULL;
g_autofree char *id = NULL;
type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
if (!type) {
error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
return false;
}
qdict_del(qdict, "qom-type");
id = g_strdup(qdict_get_try_str(qdict, "id"));
if (!id) {
error_setg(errp, QERR_MISSING_PARAMETER, "id");
return false;
}
qdict_del(qdict, "id");
if (keyval) {
v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
} else {
v = qobject_input_visitor_new(QOBJECT(qdict));
}
obj = user_creatable_add_type(type, id, qdict, v, errp);
visit_free(v);
object_unref(obj);
return !!obj;
}
Object *user_creatable_add_opts(QemuOpts *opts, Error **errp)
{
Visitor *v;
QDict *pdict;
Object *obj;
const char *id = qemu_opts_id(opts);
char *type = qemu_opt_get_del(opts, "qom-type");
if (!type) {
error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
return NULL;
}
if (!id) {
error_setg(errp, QERR_MISSING_PARAMETER, "id");
qemu_opt_set(opts, "qom-type", type, &error_abort);
g_free(type);
return NULL;
}
qemu_opts_set_id(opts, NULL);
pdict = qemu_opts_to_qdict(opts, NULL);
v = opts_visitor_new(opts);
obj = user_creatable_add_type(type, id, pdict, v, errp);
v = qobject_output_visitor_new(&qobj);
visit_type_ObjectOptions(v, NULL, &options, &error_abort);
visit_complete(v, &qobj);
visit_free(v);
qemu_opts_set_id(opts, (char *) id);
qemu_opt_set(opts, "qom-type", type, &error_abort);
g_free(type);
qobject_unref(pdict);
return obj;
}
props = qobject_to(QDict, qobj);
qdict_del(props, "qom-type");
qdict_del(props, "id");
int user_creatable_add_opts_foreach(void *opaque, QemuOpts *opts, Error **errp)
{
bool (*type_opt_predicate)(const char *, QemuOpts *) = opaque;
Object *obj = NULL;
const char *type;
type = qemu_opt_get(opts, "qom-type");
if (type && type_opt_predicate &&
!type_opt_predicate(type, opts)) {
return 0;
}
obj = user_creatable_add_opts(opts, errp);
if (!obj) {
return -1;
}
v = qobject_input_visitor_new(QOBJECT(props));
obj = user_creatable_add_type(ObjectType_str(options->qom_type),
options->id, props, v, errp);
object_unref(obj);
return 0;
qobject_unref(qobj);
visit_free(v);
}
char *object_property_help(const char *name, const char *type,
@ -227,11 +169,11 @@ static void user_creatable_print_types(void)
{
GSList *l, *list;
printf("List of user creatable objects:\n");
qemu_printf("List of user creatable objects:\n");
list = object_class_get_list_sorted(TYPE_USER_CREATABLE, false);
for (l = list; l != NULL; l = l->next) {
ObjectClass *oc = OBJECT_CLASS(l->data);
printf(" %s\n", object_class_get_name(oc));
qemu_printf(" %s\n", object_class_get_name(oc));
}
g_slist_free(list);
}
@ -262,12 +204,12 @@ static bool user_creatable_print_type_properites(const char *type)
}
g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
if (array->len > 0) {
printf("%s options:\n", type);
qemu_printf("%s options:\n", type);
} else {
printf("There are no options for %s.\n", type);
qemu_printf("There are no options for %s.\n", type);
}
for (i = 0; i < array->len; i++) {
printf("%s\n", (char *)array->pdata[i]);
qemu_printf("%s\n", (char *)array->pdata[i]);
}
g_ptr_array_set_free_func(array, g_free);
g_ptr_array_free(array, true);
@ -288,7 +230,7 @@ bool user_creatable_print_help(const char *type, QemuOpts *opts)
return false;
}
void user_creatable_print_help_from_qdict(QDict *args)
static void user_creatable_print_help_from_qdict(QDict *args)
{
const char *type = qdict_get_try_str(args, "qom-type");
@ -297,8 +239,68 @@ void user_creatable_print_help_from_qdict(QDict *args)
}
}
ObjectOptions *user_creatable_parse_str(const char *optarg, Error **errp)
{
ERRP_GUARD();
QObject *obj;
bool help;
Visitor *v;
ObjectOptions *options;
if (optarg[0] == '{') {
obj = qobject_from_json(optarg, errp);
if (!obj) {
return NULL;
}
v = qobject_input_visitor_new(obj);
} else {
QDict *args = keyval_parse(optarg, "qom-type", &help, errp);
if (*errp) {
return NULL;
}
if (help) {
user_creatable_print_help_from_qdict(args);
qobject_unref(args);
return NULL;
}
obj = QOBJECT(args);
v = qobject_input_visitor_new_keyval(obj);
}
visit_type_ObjectOptions(v, NULL, &options, errp);
visit_free(v);
qobject_unref(obj);
return options;
}
bool user_creatable_add_from_str(const char *optarg, Error **errp)
{
ERRP_GUARD();
ObjectOptions *options;
options = user_creatable_parse_str(optarg, errp);
if (!options) {
return false;
}
user_creatable_add_qapi(options, errp);
qapi_free_ObjectOptions(options);
return !*errp;
}
void user_creatable_process_cmdline(const char *optarg)
{
if (!user_creatable_add_from_str(optarg, &error_fatal)) {
/* Help was printed */
exit(EXIT_SUCCESS);
}
}
bool user_creatable_del(const char *id, Error **errp)
{
QemuOptsList *opts_list;
Object *container;
Object *obj;
@ -318,8 +320,10 @@ bool user_creatable_del(const char *id, Error **errp)
* if object was defined on the command-line, remove its corresponding
* option group entry
*/
qemu_opts_del(qemu_opts_find(qemu_find_opts_err("object", &error_abort),
id));
opts_list = qemu_find_opts_err("object", NULL);
if (opts_list) {
qemu_opts_del(qemu_opts_find(opts_list, id));
}
object_unparent(obj);
return true;

View File

@ -19,8 +19,11 @@
#include "qapi/error.h"
#include "qapi/qapi-commands-qdev.h"
#include "qapi/qapi-commands-qom.h"
#include "qapi/qapi-visit-qom.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qerror.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/qobject-output-visitor.h"
#include "qemu/cutils.h"
#include "qom/object_interfaces.h"
#include "qom/qom-qobject.h"
@ -223,30 +226,9 @@ ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename,
return prop_list;
}
void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
void qmp_object_add(ObjectOptions *options, Error **errp)
{
QObject *props;
QDict *pdict;
props = qdict_get(qdict, "props");
if (props) {
pdict = qobject_to(QDict, props);
if (!pdict) {
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
return;
}
qobject_ref(pdict);
qdict_del(qdict, "props");
qdict_join(qdict, pdict, false);
if (qdict_size(pdict) != 0) {
error_setg(errp, "Option in 'props' conflicts with top level");
qobject_unref(pdict);
return;
}
qobject_unref(pdict);
}
user_creatable_add_dict(qdict, false, errp);
user_creatable_add_qapi(options, errp);
}
void qmp_object_del(const char *id, Error **errp)

View File

@ -31,6 +31,7 @@
#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qjson.h"
#include "qemu-version.h"
#include "qemu/cutils.h"
#include "qemu/help_option.h"
@ -117,6 +118,7 @@
#include "qapi/qapi-commands-block-core.h"
#include "qapi/qapi-commands-migration.h"
#include "qapi/qapi-commands-misc.h"
#include "qapi/qapi-visit-qom.h"
#include "qapi/qapi-commands-ui.h"
#include "qapi/qmp/qerror.h"
#include "sysemu/iothread.h"
@ -132,10 +134,16 @@ typedef struct BlockdevOptionsQueueEntry {
typedef QSIMPLEQ_HEAD(, BlockdevOptionsQueueEntry) BlockdevOptionsQueue;
typedef struct ObjectOption {
ObjectOptions *opts;
QTAILQ_ENTRY(ObjectOption) next;
} ObjectOption;
static const char *cpu_option;
static const char *mem_path;
static const char *incoming;
static const char *loadvm;
static QTAILQ_HEAD(, ObjectOption) object_opts = QTAILQ_HEAD_INITIALIZER(object_opts);
static ram_addr_t maxram_size;
static uint64_t ram_slots;
static int display_remote;
@ -1683,6 +1691,58 @@ static int machine_set_property(void *opaque,
return object_parse_property_opt(opaque, name, value, "type", errp);
}
static void object_option_foreach_add(bool (*type_opt_predicate)(const char *))
{
ObjectOption *opt, *next;
QTAILQ_FOREACH_SAFE(opt, &object_opts, next, next) {
const char *type = ObjectType_str(opt->opts->qom_type);
if (type_opt_predicate(type)) {
user_creatable_add_qapi(opt->opts, &error_fatal);
qapi_free_ObjectOptions(opt->opts);
QTAILQ_REMOVE(&object_opts, opt, next);
g_free(opt);
}
}
}
static void object_option_parse(const char *optarg)
{
ObjectOption *opt;
QemuOpts *opts;
const char *type;
Visitor *v;
if (optarg[0] == '{') {
QObject *obj = qobject_from_json(optarg, &error_fatal);
v = qobject_input_visitor_new(obj);
qobject_unref(obj);
} else {
opts = qemu_opts_parse_noisily(qemu_find_opts("object"),
optarg, true);
if (!opts) {
exit(1);
}
type = qemu_opt_get(opts, "qom-type");
if (!type) {
error_setg(&error_fatal, QERR_MISSING_PARAMETER, "qom-type");
}
if (user_creatable_print_help(type, opts)) {
exit(0);
}
v = opts_visitor_new(opts);
}
opt = g_new0(ObjectOption, 1);
visit_type_ObjectOptions(v, NULL, &opt->opts, &error_fatal);
visit_free(v);
QTAILQ_INSERT_TAIL(&object_opts, opt, next);
}
/*
* Initial object creation happens before all other
* QEMU data types are created. The majority of objects
@ -1690,12 +1750,8 @@ static int machine_set_property(void *opaque,
* cannot be created here, as it depends on the chardev
* already existing.
*/
static bool object_create_early(const char *type, QemuOpts *opts)
static bool object_create_early(const char *type)
{
if (user_creatable_print_help(type, opts)) {
exit(0);
}
/*
* Objects should not be made "delayed" without a reason. If you
* add one, state the reason in a comment!
@ -1814,9 +1870,7 @@ static void qemu_create_early_backends(void)
exit(1);
}
qemu_opts_foreach(qemu_find_opts("object"),
user_creatable_add_opts_foreach,
object_create_early, &error_fatal);
object_option_foreach_add(object_create_early);
/* spice needs the timers to be initialized by this point */
/* spice must initialize before audio as it changes the default auiodev */
@ -1845,9 +1899,9 @@ static void qemu_create_early_backends(void)
* The remainder of object creation happens after the
* creation of chardev, fsdev, net clients and device data types.
*/
static bool object_create_late(const char *type, QemuOpts *opts)
static bool object_create_late(const char *type)
{
return !object_create_early(type, opts);
return !object_create_early(type);
}
static void qemu_create_late_backends(void)
@ -1858,9 +1912,7 @@ static void qemu_create_late_backends(void)
net_init_clients(&error_fatal);
qemu_opts_foreach(qemu_find_opts("object"),
user_creatable_add_opts_foreach,
object_create_late, &error_fatal);
object_option_foreach_add(object_create_late);
if (tpm_init() < 0) {
exit(1);
@ -3395,11 +3447,7 @@ void qemu_init(int argc, char **argv, char **envp)
#endif
break;
case QEMU_OPTION_object:
opts = qemu_opts_parse_noisily(qemu_find_opts("object"),
optarg, true);
if (!opts) {
exit(1);
}
object_option_parse(optarg);
break;
case QEMU_OPTION_overcommit:
opts = qemu_opts_parse_noisily(qemu_find_opts("overcommit"),

View File

@ -26,6 +26,7 @@
{ 'include': '../../qapi/crypto.json' }
{ 'include': '../../qapi/introspect.json' }
{ 'include': '../../qapi/job.json' }
{ 'include': '../../qapi/authz.json' }
{ 'include': '../../qapi/qom.json' }
{ 'include': '../../qapi/sockets.json' }
{ 'include': '../../qapi/transaction.json' }

View File

@ -134,22 +134,11 @@ enum {
extern QemuOptsList qemu_chardev_opts;
static QemuOptsList qemu_object_opts = {
.name = "object",
.implied_opt_name = "qom-type",
.head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head),
.desc = {
{ }
},
};
static void init_qmp_commands(void)
{
qmp_init_marshal(&qmp_commands);
qmp_register_command(&qmp_commands, "query-qmp-schema",
qmp_query_qmp_schema, QCO_ALLOW_PRECONFIG);
qmp_register_command(&qmp_commands, "object-add", qmp_object_add,
QCO_NO_OPTIONS);
QTAILQ_INIT(&qmp_cap_negotiation_commands);
qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities",
@ -281,19 +270,8 @@ static void process_options(int argc, char *argv[])
break;
}
case OPTION_OBJECT:
{
QDict *args;
bool help;
args = keyval_parse(optarg, "qom-type", &help, &error_fatal);
if (help) {
user_creatable_print_help_from_qdict(args);
exit(EXIT_SUCCESS);
}
user_creatable_add_dict(args, true, &error_fatal);
qobject_unref(args);
break;
}
user_creatable_process_cmdline(optarg);
break;
case OPTION_PIDFILE:
pid_file = optarg;
break;
@ -340,7 +318,6 @@ int main(int argc, char *argv[])
module_call_init(MODULE_INIT_QOM);
module_call_init(MODULE_INIT_TRACE);
qemu_add_opts(&qemu_object_opts);
qemu_add_opts(&qemu_trace_opts);
qcrypto_init(&error_fatal);
bdrv_init();
@ -368,6 +345,7 @@ int main(int argc, char *argv[])
blk_exp_close_all();
bdrv_drain_all_begin();
job_cancel_sync_all();
bdrv_close_all();
monitor_cleanup();

View File

@ -0,0 +1,86 @@
#!/usr/bin/env bash
# group: rw auto quick qsd
#
# Job tests related specifically to qemu-storage-daemon
#
# Copyright (C) 2021 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=kwolf@redhat.com
seq="$(basename $0)"
echo "QA output created by $seq"
status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
rm -f "$SOCK_DIR/nbd.sock"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
# get standard environment, filters and checks
cd ..
. ./common.rc
. ./common.filter
_supported_fmt qcow2
_supported_proto generic
size=128M
TEST_IMG="$TEST_IMG.base" _make_test_img $size
_make_test_img -b "$TEST_IMG.base" -F $IMGFMT
echo
echo "=== Job still present at shutdown ==="
echo
# Just make sure that this doesn't crash
$QSD --chardev stdio,id=stdio --monitor chardev=stdio \
--blockdev node-name=file0,driver=file,filename="$TEST_IMG" \
--blockdev node-name=fmt0,driver=qcow2,file=file0 <<EOF | _filter_qmp
{"execute":"qmp_capabilities"}
{"execute": "block-commit", "arguments": {"device": "fmt0", "job-id": "job0"}}
{"execute": "quit"}
EOF
echo
echo "=== Streaming can't get permission on base node ==="
echo
# Just make sure that this doesn't crash
$QSD --chardev stdio,id=stdio --monitor chardev=stdio \
--blockdev node-name=file_base,driver=file,filename="$TEST_IMG.base" \
--blockdev node-name=fmt_base,driver=qcow2,file=file_base \
--blockdev node-name=file_overlay,driver=file,filename="$TEST_IMG" \
--blockdev node-name=fmt_overlay,driver=qcow2,file=file_overlay,backing=fmt_base \
--nbd-server addr.type=unix,addr.path="$SOCK_DIR/nbd.sock" \
--export type=nbd,id=export1,node-name=fmt_base,writable=on,name=export1 \
<<EOF | _filter_qmp
{"execute": "qmp_capabilities"}
{"execute": "block-stream",
"arguments": {"device": "fmt_overlay", "job-id": "job0"}}
{"execute": "quit"}
EOF
# success, all done
echo "*** done"
rm -f $seq.full
status=0

View File

@ -0,0 +1,32 @@
QA output created by qsd-jobs
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
=== Job still present at shutdown ===
QMP_VERSION
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}}
=== Streaming can't get permission on base node ===
QMP_VERSION
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}}
{"error": {"class": "GenericError", "desc": "Conflicts with use by a block device as 'root', which uses 'write' on fmt_base"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "export1"}}
*** done

View File

@ -230,14 +230,14 @@ static void test_object_add_failure_modes(void)
/* attempt to create 2 objects with duplicate id */
resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':"
" {'qom-type': 'memory-backend-ram', 'id': 'ram1',"
" 'props': {'size': 1048576 } } }");
" 'size': 1048576 } }");
g_assert_nonnull(resp);
g_assert(qdict_haskey(resp, "return"));
qobject_unref(resp);
resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':"
" {'qom-type': 'memory-backend-ram', 'id': 'ram1',"
" 'props': {'size': 1048576 } } }");
" 'size': 1048576 } }");
g_assert_nonnull(resp);
qmp_expect_error_and_unref(resp, "GenericError");
@ -251,14 +251,14 @@ static void test_object_add_failure_modes(void)
/* attempt to create an object with a property of a wrong type */
resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':"
" {'qom-type': 'memory-backend-ram', 'id': 'ram1',"
" 'props': {'size': '1048576' } } }");
" 'size': '1048576' } }");
g_assert_nonnull(resp);
/* now do it right */
qmp_expect_error_and_unref(resp, "GenericError");
resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':"
" {'qom-type': 'memory-backend-ram', 'id': 'ram1',"
" 'props': {'size': 1048576 } } }");
" 'size': 1048576 } }");
g_assert_nonnull(resp);
g_assert(qdict_haskey(resp, "return"));
qobject_unref(resp);
@ -273,14 +273,14 @@ static void test_object_add_failure_modes(void)
/* attempt to create an object without the id */
resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':"
" {'qom-type': 'memory-backend-ram',"
" 'props': {'size': 1048576 } } }");
" 'size': 1048576 } }");
g_assert_nonnull(resp);
qmp_expect_error_and_unref(resp, "GenericError");
/* now do it right */
resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':"
" {'qom-type': 'memory-backend-ram', 'id': 'ram1',"
" 'props': {'size': 1048576 } } }");
" 'size': 1048576 } }");
g_assert_nonnull(resp);
g_assert(qdict_haskey(resp, "return"));
qobject_unref(resp);
@ -295,14 +295,14 @@ static void test_object_add_failure_modes(void)
/* attempt to set a non existing property */
resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':"
" {'qom-type': 'memory-backend-ram', 'id': 'ram1',"
" 'props': {'sized': 1048576 } } }");
" 'sized': 1048576 } }");
g_assert_nonnull(resp);
qmp_expect_error_and_unref(resp, "GenericError");
/* now do it right */
resp = qtest_qmp(qts, "{'execute': 'object-add', 'arguments':"
" {'qom-type': 'memory-backend-ram', 'id': 'ram1',"
" 'props': {'size': 1048576 } } }");
" 'size': 1048576 } }");
g_assert_nonnull(resp);
g_assert(qdict_haskey(resp, "return"));
qobject_unref(resp);

View File

@ -21,11 +21,10 @@ static void add_one_netfilter(void)
" 'arguments': {"
" 'qom-type': 'filter-buffer',"
" 'id': 'qtest-f0',"
" 'props': {"
" 'netdev': 'qtest-bn0',"
" 'queue': 'rx',"
" 'interval': 1000"
"}}}");
" 'netdev': 'qtest-bn0',"
" 'queue': 'rx',"
" 'interval': 1000"
"}}");
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
@ -49,11 +48,10 @@ static void remove_netdev_with_one_netfilter(void)
" 'arguments': {"
" 'qom-type': 'filter-buffer',"
" 'id': 'qtest-f0',"
" 'props': {"
" 'netdev': 'qtest-bn0',"
" 'queue': 'rx',"
" 'interval': 1000"
"}}}");
" 'netdev': 'qtest-bn0',"
" 'queue': 'rx',"
" 'interval': 1000"
"}}");
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
@ -87,11 +85,10 @@ static void add_multi_netfilter(void)
" 'arguments': {"
" 'qom-type': 'filter-buffer',"
" 'id': 'qtest-f0',"
" 'props': {"
" 'netdev': 'qtest-bn0',"
" 'queue': 'rx',"
" 'interval': 1000"
"}}}");
" 'netdev': 'qtest-bn0',"
" 'queue': 'rx',"
" 'interval': 1000"
"}}");
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
@ -101,11 +98,10 @@ static void add_multi_netfilter(void)
" 'arguments': {"
" 'qom-type': 'filter-buffer',"
" 'id': 'qtest-f1',"
" 'props': {"
" 'netdev': 'qtest-bn0',"
" 'queue': 'rx',"
" 'interval': 1000"
"}}}");
" 'netdev': 'qtest-bn0',"
" 'queue': 'rx',"
" 'interval': 1000"
"}}");
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
@ -137,11 +133,10 @@ static void remove_netdev_with_multi_netfilter(void)
" 'arguments': {"
" 'qom-type': 'filter-buffer',"
" 'id': 'qtest-f0',"
" 'props': {"
" 'netdev': 'qtest-bn0',"
" 'queue': 'rx',"
" 'interval': 1000"
"}}}");
" 'netdev': 'qtest-bn0',"
" 'queue': 'rx',"
" 'interval': 1000"
"}}");
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
@ -151,11 +146,10 @@ static void remove_netdev_with_multi_netfilter(void)
" 'arguments': {"
" 'qom-type': 'filter-buffer',"
" 'id': 'qtest-f1',"
" 'props': {"
" 'netdev': 'qtest-bn0',"
" 'queue': 'rx',"
" 'interval': 1000"
"}}}");
" 'netdev': 'qtest-bn0',"
" 'queue': 'rx',"
" 'interval': 1000"
"}}");
g_assert(response);
g_assert(!qdict_haskey(response, "error"));

View File

@ -21,6 +21,9 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qobject.h"
#include "qom/object.h"
#include "qemu/module.h"
#include "qemu/option.h"
@ -398,44 +401,74 @@ static void test_dummy_createlist(void)
object_unparent(OBJECT(dobj));
}
static bool test_create_obj(QDict *qdict, Error **errp)
{
Visitor *v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
Object *obj = user_creatable_add_type(TYPE_DUMMY, "dev0", qdict, v, errp);
visit_free(v);
object_unref(obj);
return !!obj;
}
static void test_dummy_createcmdl(void)
{
QemuOpts *opts;
QDict *qdict;
DummyObject *dobj;
Error *err = NULL;
const char *params = TYPE_DUMMY \
",id=dev0," \
"bv=yes,sv=Hiss hiss hiss,av=platypus";
bool created, help;
const char *params = "bv=yes,sv=Hiss hiss hiss,av=platypus";
/* Needed for user_creatable_del. */
qemu_add_opts(&qemu_object_opts);
opts = qemu_opts_parse(&qemu_object_opts, params, true, &err);
g_assert(err == NULL);
g_assert(opts);
dobj = DUMMY_OBJECT(user_creatable_add_opts(opts, &err));
qdict = keyval_parse(params, "qom-type", &help, &err);
g_assert(err == NULL);
g_assert(qdict);
g_assert(!help);
created = test_create_obj(qdict, &err);
g_assert(created);
g_assert(err == NULL);
qobject_unref(qdict);
dobj = DUMMY_OBJECT(object_resolve_path_component(object_get_objects_root(),
"dev0"));
g_assert(dobj);
g_assert_cmpstr(dobj->sv, ==, "Hiss hiss hiss");
g_assert(dobj->bv == true);
g_assert(dobj->av == DUMMY_PLATYPUS);
qdict = keyval_parse(params, "qom-type", &help, &err);
created = test_create_obj(qdict, &err);
g_assert(!created);
g_assert(err);
g_assert(object_resolve_path_component(object_get_objects_root(), "dev0")
== OBJECT(dobj));
qobject_unref(qdict);
error_free(err);
err = NULL;
qdict = keyval_parse(params, "qom-type", &help, &err);
user_creatable_del("dev0", &error_abort);
g_assert(object_resolve_path_component(object_get_objects_root(), "dev0")
== NULL);
object_unref(OBJECT(dobj));
created = test_create_obj(qdict, &err);
g_assert(created);
g_assert(err == NULL);
qobject_unref(qdict);
/*
* cmdline-parsing via qemu_opts_parse() results in a QemuOpts entry
* corresponding to the Object's ID to be added to the QemuOptsList
* for objects. To avoid having this entry conflict with future
* Objects using the same ID (which can happen in cases where
* qemu_opts_parse() is used to parse the object params, such as
* with hmp_object_add() at the time of this comment), we need to
* check for this in user_creatable_del() and remove the QemuOpts if
* it is present.
*
* The below check ensures this works as expected.
*/
g_assert_null(qemu_opts_find(&qemu_object_opts, "dev0"));
dobj = DUMMY_OBJECT(object_resolve_path_component(object_get_objects_root(),
"dev0"));
g_assert(dobj);
g_assert_cmpstr(dobj->sv, ==, "Hiss hiss hiss");
g_assert(dobj->bv == true);
g_assert(dobj->av == DUMMY_PLATYPUS);
g_assert(object_resolve_path_component(object_get_objects_root(), "dev0")
== OBJECT(dobj));
object_unparent(OBJECT(dobj));
}
static void test_dummy_badenum(void)

View File

@ -1199,12 +1199,6 @@ static void char_serial_test(void)
/* TODO: add more tests with a pty */
object_unparent(OBJECT(chr));
/* test tty alias */
qemu_opt_set(opts, "backend", "tty", &error_abort);
chr = qemu_chr_new_from_opts(opts, NULL, &error_abort);
g_assert_nonnull(chr);
object_unparent(OBJECT(chr));
qemu_opts_del(opts);
}
#endif