It is very useful to use the ringbuf chardev for writing test cases and even more useful if the state of the ringbuf is migrated with the guest. Otherwise it's hard to detect data loss in a test case.
Signed-off-by: Anthony Liguori <aligu...@us.ibm.com> --- qapi-schema.json | 3 ++- qemu-char.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/qapi-schema.json b/qapi-schema.json index a80ee40..90602d1 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3280,10 +3280,11 @@ # Configuration info for memory chardevs # # @size: #optional Ringbuffer size, must be power of two, default is 65536 +# @save: #optional Register a savevm handler, default false # # Since: 1.5 ## -{ 'type': 'ChardevMemory', 'data': { '*size' : 'int' } } +{ 'type': 'ChardevMemory', 'data': { '*size' : 'int', '*save': 'bool' } } ## # @ChardevBackend: diff --git a/qemu-char.c b/qemu-char.c index 2c3cfe6..87ba24f 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2793,7 +2793,32 @@ static void ringbuf_chr_close(struct CharDriverState *chr) chr->opaque = NULL; } -static CharDriverState *qemu_chr_open_memory(ChardevMemory *opts, +static void ringbuf_save(QEMUFile *f, void *opaque) +{ + CharDriverState *chr = opaque; + RingBufCharDriver *d = chr->opaque; + + qemu_put_be32(f, d->prod); + qemu_put_be32(f, d->cons); + qemu_put_be32(f, d->size); + qemu_put_buffer(f, d->cbuf, d->size); +} + +static int ringbuf_load(QEMUFile *f, void *opaque, int version_id) +{ + CharDriverState *chr = opaque; + RingBufCharDriver *d = chr->opaque; + + d->prod = qemu_get_be32(f); + d->cons = qemu_get_be32(f); + d->size = qemu_get_be32(f); + qemu_get_buffer(f, d->cbuf, d->size); + + return 0; +} + +static CharDriverState *qemu_chr_open_memory(const char *id, + ChardevMemory *opts, Error **errp) { CharDriverState *chr; @@ -2804,6 +2829,14 @@ static CharDriverState *qemu_chr_open_memory(ChardevMemory *opts, d->size = opts->has_size ? opts->size : 65536; + if (opts->has_save && opts->save) { + char *idstr; + + g_assert(id != NULL); + idstr = g_strdup_printf("memchar-%s", id); + register_savevm(NULL, idstr, 0, 1, ringbuf_save, ringbuf_load, chr); + } + /* The size must be power of 2 */ if (d->size & (d->size - 1)) { error_setg(errp, "size of memory chardev must be power of two"); @@ -3120,6 +3153,11 @@ static void qemu_chr_parse_memory(QemuOpts *opts, ChardevBackend *backend, backend->memory->has_size = true; backend->memory->size = val; } + + if (qemu_opt_get_bool(opts, "save", false)) { + backend->memory->has_save = true; + backend->memory->save = true; + } } typedef struct CharDriver { @@ -3489,6 +3527,9 @@ QemuOptsList qemu_chardev_opts = { },{ .name = "size", .type = QEMU_OPT_SIZE, + }, { + .name = "save", + .type = QEMU_OPT_BOOL, }, { /* end of list */ } }, @@ -3711,7 +3752,7 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, chr = vc_init(backend->vc); break; case CHARDEV_BACKEND_KIND_MEMORY: - chr = qemu_chr_open_memory(backend->memory, errp); + chr = qemu_chr_open_memory(id, backend->memory, errp); break; default: error_setg(errp, "unknown chardev backend (%d)", backend->kind); -- 1.8.0