diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2017-07-14 12:16:09 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2017-07-14 12:16:09 +0100 |
commit | 6c6076662d98c068059983d411cb2a8987ba5670 (patch) | |
tree | b3a180eb5eab8474c5557b8a77c2589faa980f8e /chardev/char.c | |
parent | 7d367e7002c3ca78531653105bd4fccd55e426a8 (diff) | |
parent | 68c761e19c2ea453f880dbbd04e867d34d1468b8 (diff) |
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
* gdbstub fixes (Alex)
* IOMMU MemoryRegion subclass (Alexey)
* Chardev hotswap (Anton)
* NBD_OPT_GO support (Eric)
* Misc bugfixes
* DEFINE_PROP_LINK (minus the ARM patches - Fam)
* MAINTAINERS updates (Philippe)
# gpg: Signature made Fri 14 Jul 2017 11:06:27 BST
# gpg: using RSA key 0xBFFBD25F78C7AE83
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>"
# gpg: aka "Paolo Bonzini <pbonzini@redhat.com>"
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1
# Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83
* remotes/bonzini/tags/for-upstream: (55 commits)
spapr_rng: Convert to DEFINE_PROP_LINK
cpu: Convert to DEFINE_PROP_LINK
mips_cmgcr: Convert to DEFINE_PROP_LINK
ivshmem: Convert to DEFINE_PROP_LINK
dimm: Convert to DEFINE_PROP_LINK
virtio-crypto: Convert to DEFINE_PROP_LINK
virtio-rng: Convert to DEFINE_PROP_LINK
virtio-scsi: Convert to DEFINE_PROP_LINK
virtio-blk: Convert to DEFINE_PROP_LINK
qdev: Add const qualifier to PropertyInfo definitions
qmp: Use ObjectProperty.type if present
qdev: Introduce DEFINE_PROP_LINK
qdev: Introduce PropertyInfo.create
qom: enforce readonly nature of link's check callback
translate-all: remove redundant !tcg_enabled check in dump_exec_info
vl: fix breakage of -tb-size
nbd: Implement NBD_INFO_BLOCK_SIZE on client
nbd: Implement NBD_INFO_BLOCK_SIZE on server
nbd: Implement NBD_OPT_GO on client
nbd: Implement NBD_OPT_GO on server
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'chardev/char.c')
-rw-r--r-- | chardev/char.c | 164 |
1 files changed, 134 insertions, 30 deletions
diff --git a/chardev/char.c b/chardev/char.c index 2b679a2295..c34b44abc9 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -556,17 +556,23 @@ help_string_append(const char *name, void *opaque) g_string_append_printf(str, "\n%s", name); } -Chardev *qemu_chr_new_from_opts(QemuOpts *opts, - Error **errp) +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) { + return chardev_alias_table[i].typename; + } + } + return name; +} + +ChardevBackend *qemu_chr_parse_opts(QemuOpts *opts, Error **errp) { Error *local_err = NULL; const ChardevClass *cc; - Chardev *chr; - int i; ChardevBackend *backend = NULL; - const char *name = qemu_opt_get(opts, "backend"); - const char *id = qemu_opts_id(opts); - char *bid = NULL; + const char *name = chardev_alias_translate(qemu_opt_get(opts, "backend")); if (name == NULL) { error_setg(errp, "chardev: \"%s\" missing backend", @@ -574,7 +580,40 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts, return NULL; } - if (is_help_option(name)) { + cc = char_get_class(name, errp); + if (cc == NULL) { + return NULL; + } + + backend = g_new0(ChardevBackend, 1); + backend->type = CHARDEV_BACKEND_KIND_NULL; + + if (cc->parse) { + cc->parse(opts, backend, &local_err); + if (local_err) { + error_propagate(errp, local_err); + qapi_free_ChardevBackend(backend); + return NULL; + } + } else { + ChardevCommon *ccom = g_new0(ChardevCommon, 1); + qemu_chr_parse_common(opts, ccom); + backend->u.null.data = ccom; /* Any ChardevCommon member would work */ + } + + return backend; +} + +Chardev *qemu_chr_new_from_opts(QemuOpts *opts, Error **errp) +{ + const ChardevClass *cc; + Chardev *chr = NULL; + ChardevBackend *backend = NULL; + const char *name = chardev_alias_translate(qemu_opt_get(opts, "backend")); + const char *id = qemu_opts_id(opts); + char *bid = NULL; + + if (name && is_help_option(name)) { GString *str = g_string_new(""); chardev_name_foreach(help_string_append, str); @@ -589,38 +628,20 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts, return NULL; } - for (i = 0; i < (int)ARRAY_SIZE(chardev_alias_table); i++) { - if (g_strcmp0(chardev_alias_table[i].alias, name) == 0) { - name = chardev_alias_table[i].typename; - break; - } + backend = qemu_chr_parse_opts(opts, errp); + if (backend == NULL) { + return NULL; } cc = char_get_class(name, errp); if (cc == NULL) { - return NULL; + goto out; } - backend = g_new0(ChardevBackend, 1); - backend->type = CHARDEV_BACKEND_KIND_NULL; - if (qemu_opt_get_bool(opts, "mux", 0)) { bid = g_strdup_printf("%s-base", id); } - chr = NULL; - if (cc->parse) { - cc->parse(opts, backend, &local_err); - if (local_err) { - error_propagate(errp, local_err); - goto out; - } - } else { - ChardevCommon *ccom = g_new0(ChardevCommon, 1); - qemu_chr_parse_common(opts, ccom); - backend->u.null.data = ccom; /* Any ChardevCommon member would work */ - } - chr = qemu_chardev_new(bid ? bid : id, object_class_get_name(OBJECT_CLASS(cc)), backend, errp); @@ -930,6 +951,89 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, return ret; } +ChardevReturn *qmp_chardev_change(const char *id, ChardevBackend *backend, + Error **errp) +{ + CharBackend *be; + const ChardevClass *cc; + Chardev *chr, *chr_new; + bool closed_sent = false; + ChardevReturn *ret; + + chr = qemu_chr_find(id); + if (!chr) { + error_setg(errp, "Chardev '%s' does not exist", id); + return NULL; + } + + if (CHARDEV_IS_MUX(chr)) { + error_setg(errp, "Mux device hotswap not supported yet"); + return NULL; + } + + if (qemu_chr_replay(chr)) { + error_setg(errp, + "Chardev '%s' cannot be changed in record/replay mode", id); + return NULL; + } + + be = chr->be; + if (!be) { + /* easy case */ + object_unparent(OBJECT(chr)); + return qmp_chardev_add(id, backend, errp); + } + + if (!be->chr_be_change) { + error_setg(errp, "Chardev user does not support chardev hotswap"); + return NULL; + } + + cc = char_get_class(ChardevBackendKind_lookup[backend->type], errp); + if (!cc) { + return NULL; + } + + chr_new = qemu_chardev_new(NULL, object_class_get_name(OBJECT_CLASS(cc)), + backend, errp); + if (!chr_new) { + return NULL; + } + chr_new->label = g_strdup(id); + + if (chr->be_open && !chr_new->be_open) { + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); + closed_sent = true; + } + + chr->be = NULL; + qemu_chr_fe_init(be, chr_new, &error_abort); + + if (be->chr_be_change(be->opaque) < 0) { + error_setg(errp, "Chardev '%s' change failed", chr_new->label); + chr_new->be = NULL; + qemu_chr_fe_init(be, chr, &error_abort); + if (closed_sent) { + qemu_chr_be_event(chr, CHR_EVENT_OPENED); + } + object_unref(OBJECT(chr_new)); + return NULL; + } + + object_unparent(OBJECT(chr)); + object_property_add_child(get_chardevs_root(), chr_new->label, + OBJECT(chr_new), &error_abort); + object_unref(OBJECT(chr_new)); + + ret = g_new0(ChardevReturn, 1); + if (CHARDEV_IS_PTY(chr_new)) { + ret->pty = g_strdup(chr_new->filename + 4); + ret->has_pty = true; + } + + return ret; +} + void qmp_chardev_remove(const char *id, Error **errp) { Chardev *chr; |