qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/4 V8] char: Add CirMemCharDriver and provide QMP interface
@ 2012-12-06 14:56 Lei Li
  2012-12-06 14:56 ` [Qemu-devel] [PATCH 1/4] qemu-char: Add new char backend CirMemCharDriver Lei Li
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Lei Li @ 2012-12-06 14:56 UTC (permalink / raw)
  To: aliguori; +Cc: qemu-devel, anthony, Lei Li

This patch series attempts to add new char backend CirMemCharDriver with
a circular buffer and expose it to users by introducing QMP interface
memchar-write and memchar-read and via the command line like the other
CharDriverStates.

Serial ports in qemu always use CharDriverStates as there backends,
Right now, all of our backends always try to write the data from the
guest to a socket or file. The concern from OpenStack is that this could
lead to unbounded disk space usage since they log the serial output.
For more detail of the background info:
https://bugs.launchpad.net/nova/+bug/832507

So we want to use a circular buffer in QEMU instead, and then OpenStack
can periodically read the buffer in QEMU and log it.

The QMP commands introduced like:

{ 'command': 'memchar-write',
  'data': {'chardev': 'str', 'size': 'int', 'data': 'str',
           'format': 'str' } }

{ 'command': 'memchar-read',
  'data': {'chardev': 'str', 'size': 'int', 'format': 'str' },
  'returns': 'str' }

Expose CirMemCharDriver via the command line like:

qemu -chardev memory,id=foo,maxcapacity=65536 -serial chardev:foo

Introduce HMP command 'console' like:

(qemu) console foo
foo: Input data

Note:
Now all of the feature were implemented, and the pervious comments
are fixed up too. Since this patch series have been for mailing list
for some time and missed 1.3, rebase it with minor fix.

Changes since v7:
  - Rebase the code and fix the format error pointed by Eric.
  - Modify the version info.

Changes since v6:
  - Improve the document based on Luiz's comments.
  - Keep pointing to the right position in cbuf for the case producer
    and consumer might overflow for long running VMs pointed by Luiz.
  - Limit the size of read_data to the amount of bytes available in the
    circular buffer.
  - Other fixups from Luiz.

Changes since v5:
  - Avoid writing the IAC information to the queue.
  - Grammar of the doc for command line options improved from Eric.

Changes since v4:
  - Get rid of all CongestionControl bits, and assume a dropping behavior
    based on Luiz's suggestion for now. Will add it when we add async
    support to QMP.
  - Squashed the patches about CirMemCharDriver in one.
  - Other fixups from Luiz.

Changes since v3:
  - Improve the algorithm of circular buffer based on Anthony's
    suggestion.
  - Some changes suggested by Luiz and Blue.
  - And other fixups.

Changes since v2:
  - Add congestion mechanism. For the 'block' option as sync command,
    will support it later when we gain the necessary infrastructure
    enhancement.
  - Add HMP 'console' command so that can interact with multiple
    chardevs via a single monitor socket.
  - Make the circular buffer backend and the current MemCharDriver
    live in parallel, expose a new char backend with circular buffer
    CirMemCharDriver suggested by Luiz.
  - Other fixs from Eric and Markus.

Changes since v1:
  - Exposing the MemCharDriver via command line.
  - Support base64 data format suggested by Anthony and Eric.
  - Follow the new rule for the name of qmp command from Eric.


Lei Li (4):
  qemu-char: Add new char backend CirMemCharDriver
  QAPI: Introduce memchar-write QMP command
  QAPI: Introduce memchar-read QMP command
  HMP: Introduce console command

 hmp-commands.hx  |   72 +++++++++++++++++++
 hmp.c            |   99 +++++++++++++++++++++++
 hmp.h            |    3 +
 monitor.c        |   15 ++++
 monitor.h        |    3 +
 qapi-schema.json |   96 +++++++++++++++++++++++++
 qemu-char.c      |  217 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qemu-config.c    |    3 +
 qemu-options.hx  |   10 +++
 qmp-commands.hx  |   89 +++++++++++++++++++++
 10 files changed, 607 insertions(+), 0 deletions(-)

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Qemu-devel] [PATCH 1/4] qemu-char: Add new char backend CirMemCharDriver
  2012-12-06 14:56 [Qemu-devel] [PATCH 0/4 V8] char: Add CirMemCharDriver and provide QMP interface Lei Li
@ 2012-12-06 14:56 ` Lei Li
  2012-12-06 14:56 ` [Qemu-devel] [PATCH 2/4] QAPI: Introduce memchar-write QMP command Lei Li
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Lei Li @ 2012-12-06 14:56 UTC (permalink / raw)
  To: aliguori; +Cc: qemu-devel, anthony, Lei Li

Signed-off-by: Lei Li <lilei@linux.vnet.ibm.com>
---
 qemu-char.c     |  131 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qemu-config.c   |    3 +
 qemu-options.hx |   10 ++++
 3 files changed, 144 insertions(+), 0 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index 242b799..3e45ce6 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -99,6 +99,7 @@
 #include "ui/qemu-spice.h"
 
 #define READ_BUF_LEN 4096
+#define CBUFF_SIZE 65536
 
 /***********************************************************/
 /* character device */
@@ -2599,6 +2600,130 @@ size_t qemu_chr_mem_osize(const CharDriverState *chr)
     return d->outbuf_size;
 }
 
+/*********************************************************/
+/*CircularMemory chardev*/
+
+typedef struct {
+    size_t size;
+    size_t head;
+    size_t count;
+    uint8_t *cbuf;
+} CirMemCharDriver;
+
+static bool cirmem_chr_is_empty(const CharDriverState *chr)
+{
+    const CirMemCharDriver *d = chr->opaque;
+
+    return d->count == 0;
+}
+
+static bool cirmem_chr_is_full(const CharDriverState *chr)
+{
+    const CirMemCharDriver *d = chr->opaque;
+
+    return d->count == d->size;
+}
+
+static size_t qemu_chr_cirmem_count(const CharDriverState *chr)
+{
+    const CirMemCharDriver *d = chr->opaque;
+
+    return d->count;
+}
+
+static int cirmem_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    CirMemCharDriver *d = chr->opaque;
+    int i;
+    int tail;
+
+    if (!buf || (len < 0)) {
+        return -1;
+    }
+
+    for (i = 0; i < len; i++ ) {
+        /* Avoid writing the IAC information to the queue. */
+        if ((unsigned char)buf[i] == IAC) {
+            continue;
+        }
+
+        tail = (d->head + d->count) % d->size;
+        d->cbuf[tail] = buf[i];
+        if (d->count == d->size) {
+            d->head = (d->head + 1) % d->size;
+        } else {
+            ++d->count;
+        }
+    }
+
+    return 0;
+}
+
+static int cirmem_chr_read(CharDriverState *chr, uint8_t *buf, int len)
+{
+    CirMemCharDriver *d = chr->opaque;
+    int i;
+
+    if (cirmem_chr_is_empty(chr) || len < 0) {
+        return -1;
+    }
+
+    for (i = 0; i < len; i++) {
+        buf[i] = d->cbuf[d->head];
+        d->head = (d->head + 1) % d->size;
+        d->count--;
+
+        if (cirmem_chr_is_empty(chr)) {
+            break;
+        }
+    }
+
+    return 0;
+}
+
+static void cirmem_chr_close(struct CharDriverState *chr)
+{
+    CirMemCharDriver *d = chr->opaque;
+
+    g_free(d->cbuf);
+    g_free(d);
+    chr->opaque = NULL;
+}
+
+static CharDriverState *qemu_chr_open_cirmemchr(QemuOpts *opts)
+{
+    CharDriverState *chr;
+    CirMemCharDriver *d;
+
+    chr = g_malloc0(sizeof(CharDriverState));
+    d = g_malloc(sizeof(*d));
+
+    d->size = qemu_opt_get_number(opts, "maxcapacity", 0);
+    if (d->size == 0) {
+        d->size = CBUFF_SIZE;
+    }
+
+    /* The size must be power of 2 */
+    if (d->size & (d->size - 1)) {
+        goto fail;
+    }
+
+    d->head = 0;
+    d->count = 0;
+    d->cbuf = g_malloc0(d->size);
+
+    chr->opaque = d;
+    chr->chr_write = cirmem_chr_write;
+    chr->chr_close = cirmem_chr_close;
+
+    return chr;
+
+fail:
+    g_free(d);
+    g_free(chr);
+    return NULL;
+}
+
 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
 {
     char host[65], port[33], width[8], height[8];
@@ -2663,6 +2788,11 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
         qemu_opt_set(opts, "path", p);
         return opts;
     }
+    if (strstart(filename, "memory", &p)) {
+        qemu_opt_set(opts, "backend", "memory");
+        qemu_opt_set(opts, "maxcapacity", p);
+        return opts;
+    }
     if (strstart(filename, "tcp:", &p) ||
         strstart(filename, "telnet:", &p)) {
         if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) {
@@ -2736,6 +2866,7 @@ static const struct {
     { .name = "udp",       .open = qemu_chr_open_udp },
     { .name = "msmouse",   .open = qemu_chr_open_msmouse },
     { .name = "vc",        .open = text_console_init },
+    { .name = "memory",    .open = qemu_chr_open_cirmemchr },
 #ifdef _WIN32
     { .name = "file",      .open = qemu_chr_open_win_file_out },
     { .name = "pipe",      .open = qemu_chr_open_win_pipe },
diff --git a/qemu-config.c b/qemu-config.c
index 10d1ba4..ddc2a2a 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -217,6 +217,9 @@ static QemuOptsList qemu_chardev_opts = {
         },{
             .name = "debug",
             .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "maxcapacity",
+            .type = QEMU_OPT_NUMBER,
         },
         { /* end of list */ }
     },
diff --git a/qemu-options.hx b/qemu-options.hx
index de43b1b..fb1bae4 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1728,6 +1728,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
     "-chardev msmouse,id=id[,mux=on|off]\n"
     "-chardev vc,id=id[[,width=width][,height=height]][[,cols=cols][,rows=rows]]\n"
     "         [,mux=on|off]\n"
+    "-chardev memory,id=id,maxcapacity=maxcapacity\n"
     "-chardev file,id=id,path=path[,mux=on|off]\n"
     "-chardev pipe,id=id,path=path[,mux=on|off]\n"
 #ifdef _WIN32
@@ -1766,6 +1767,7 @@ Backend is one of:
 @option{udp},
 @option{msmouse},
 @option{vc},
+@option{memory},
 @option{file},
 @option{pipe},
 @option{console},
@@ -1872,6 +1874,14 @@ the console, in pixels.
 @option{cols} and @option{rows} specify that the console be sized to fit a text
 console with the given dimensions.
 
+@item -chardev memory ,id=@var{id} ,maxcapacity=@var{maxcapacity}
+
+Create a circular buffer with fixed size indicated by optionally @option{maxcapacity}
+which will be default 64K if it is not given.
+
+@option{maxcapacity} specifies the max capacity of the size of circular buffer
+to create. Should be power of 2.
+
 @item -chardev file ,id=@var{id} ,path=@var{path}
 
 Log all traffic received from the guest to a file.
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [Qemu-devel] [PATCH 2/4] QAPI: Introduce memchar-write QMP command
  2012-12-06 14:56 [Qemu-devel] [PATCH 0/4 V8] char: Add CirMemCharDriver and provide QMP interface Lei Li
  2012-12-06 14:56 ` [Qemu-devel] [PATCH 1/4] qemu-char: Add new char backend CirMemCharDriver Lei Li
@ 2012-12-06 14:56 ` Lei Li
  2012-12-06 14:56 ` [Qemu-devel] [PATCH 3/4] QAPI: Introduce memchar-read " Lei Li
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Lei Li @ 2012-12-06 14:56 UTC (permalink / raw)
  To: aliguori; +Cc: qemu-devel, anthony, Lei Li

Signed-off-by: Lei Li <lilei@linux.vnet.ibm.com>
---
 hmp-commands.hx  |   15 +++++++++++++++
 hmp.c            |   13 +++++++++++++
 hmp.h            |    1 +
 qapi-schema.json |   41 +++++++++++++++++++++++++++++++++++++++++
 qemu-char.c      |   48 ++++++++++++++++++++++++++++++++++++++++++++++++
 qmp-commands.hx  |   34 ++++++++++++++++++++++++++++++++++
 6 files changed, 152 insertions(+), 0 deletions(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 010b8c9..a60ba69 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -840,6 +840,21 @@ Inject an NMI on the given CPU (x86 only).
 ETEXI
 
     {
+        .name       = "memchar_write",
+        .args_type  = "chardev:s,data:s",
+        .params     = "chardev data",
+        .mhandler.cmd = hmp_memchar_write,
+    },
+
+STEXI
+@item memchar_write @var{chardev} @var{data}
+@findex memchar_write
+Provide writing interface for CirMemCharDriver. Write @var{data}
+to char device 'memory'.
+
+ETEXI
+
+    {
         .name       = "migrate",
         .args_type  = "detach:-d,blk:-b,inc:-i,uri:s",
         .params     = "[-d] [-b] [-i] uri",
diff --git a/hmp.c b/hmp.c
index 180ba2b..05b8c21 100644
--- a/hmp.c
+++ b/hmp.c
@@ -683,6 +683,19 @@ void hmp_pmemsave(Monitor *mon, const QDict *qdict)
     hmp_handle_error(mon, &errp);
 }
 
+void hmp_memchar_write(Monitor *mon, const QDict *qdict)
+{
+    uint32_t size;
+    const char *chardev = qdict_get_str(qdict, "chardev");
+    const char *data = qdict_get_str(qdict, "data");
+    Error *errp = NULL;
+
+    size = strlen(data);
+    qmp_memchar_write(chardev, size, data, false, 0, &errp);
+
+    hmp_handle_error(mon, &errp);
+}
+
 static void hmp_cont_cb(void *opaque, int err)
 {
     if (!err) {
diff --git a/hmp.h b/hmp.h
index 0ab03be..3ea9896 100644
--- a/hmp.h
+++ b/hmp.h
@@ -43,6 +43,7 @@ void hmp_system_powerdown(Monitor *mon, const QDict *qdict);
 void hmp_cpu(Monitor *mon, const QDict *qdict);
 void hmp_memsave(Monitor *mon, const QDict *qdict);
 void hmp_pmemsave(Monitor *mon, const QDict *qdict);
+void hmp_memchar_write(Monitor *mon, const QDict *qdict);
 void hmp_cont(Monitor *mon, const QDict *qdict);
 void hmp_system_wakeup(Monitor *mon, const QDict *qdict);
 void hmp_inject_nmi(Monitor *mon, const QDict *qdict);
diff --git a/qapi-schema.json b/qapi-schema.json
index 5dfa052..d9fd635 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -325,6 +325,47 @@
 { 'command': 'query-chardev', 'returns': ['ChardevInfo'] }
 
 ##
+# @DataFormat:
+#
+# An enumeration of data format.
+#
+# @utf8: The data format is 'utf8'.
+#
+# @base64: The data format is 'base64'.
+#
+# Since: 1.4
+##
+{ 'enum': 'DataFormat'
+  'data': [ 'utf8', 'base64' ] }
+
+##
+# @memchar-write:
+#
+# Provide writing interface for memchardev. Write data to char
+# device 'memory'.
+#
+# @chardev: the name of the memory char device.
+#
+# @size: the size to write in bytes.
+#
+# @data: the source data write to memchar.
+#
+# @format: #optional the format of the data write to chardev 'memory',
+#          by default is 'utf8'.
+#
+# Returns: Nothing on success
+#          If @chardev is not a valid char device, DeviceNotFound
+#
+# Notes: For now assume 'drop' behaver, which would result in writes
+#        dropping queued data.
+#
+# Since: 1.4
+##
+{ 'command': 'memchar-write',
+  'data': {'chardev': 'str', 'size': 'int', 'data': 'str',
+           '*format': 'DataFormat'} }
+
+##
 # @CommandInfo:
 #
 # Information about a QMP command
diff --git a/qemu-char.c b/qemu-char.c
index 3e45ce6..a407087 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2724,6 +2724,54 @@ fail:
     return NULL;
 }
 
+static bool qemu_is_chr(const CharDriverState *chr, const char *filename)
+{
+    return strcmp(chr->filename, filename);
+}
+
+void qmp_memchar_write(const char *chardev, int64_t size,
+                       const char *data, bool has_format,
+                       enum DataFormat format,
+                       Error **errp)
+{
+    CharDriverState *chr;
+    guchar *write_data;
+    int ret;
+    gsize write_count;
+
+    chr = qemu_chr_find(chardev);
+    if (!chr) {
+        error_set(errp, QERR_DEVICE_NOT_FOUND, chardev);
+        return;
+    }
+
+    if (qemu_is_chr(chr, "memory")) {
+        error_setg(errp,"%s is not memory char device\n", chardev);
+        return;
+    }
+
+    /* XXX: Drop the coming data when the buffer is full. */
+    if (cirmem_chr_is_full(chr)) {
+        error_setg(errp, "Memory device %s is full", chardev);
+        return;
+    }
+
+    write_count = (gsize)size;
+
+    if (has_format && (format == DATA_FORMAT_BASE64)) {
+        write_data = g_base64_decode(data, &write_count);
+    } else {
+        write_data = (uint8_t *)data;
+    }
+
+    ret = cirmem_chr_write(chr, write_data, write_count);
+
+    if (ret < 0) {
+        error_setg(errp, "Failed to write to device %s", chardev);
+        return;
+    }
+}
+
 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
 {
     char host[65], port[33], width[8], height[8];
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 5c692d0..ae3ab5a 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -466,6 +466,40 @@ Note: inject-nmi fails when the guest doesn't support injecting.
 EQMP
 
     {
+        .name       = "memchar-write",
+        .args_type  = "chardev:s,size:i,data:s,format:s?",
+        .help       = "write size of data to memory chardev",
+        .mhandler.cmd_new = qmp_marshal_input_memchar_write,
+    },
+
+SQMP
+memchar-write
+-------------
+
+Provide writing interface for CirMemCharDriver. Write data to memory
+char device.
+
+Arguments:
+
+- "chardev": the name of the char device, must be unique (json-string)
+- "size": the memory size, in bytes, should be power of 2 (json-int)
+- "data": the source data write to memory (json-string)
+- "format": the data format write to memory, default is
+            utf8. (json-string, optional)
+          - Possible values: "utf8", "base64"
+
+Example:
+
+-> { "execute": "memchar-write",
+                "arguments": { "chardev": foo,
+                               "size": 8,
+                               "data": "abcdefgh",
+                               "format": "utf8" } }
+<- { "return": {} }
+
+EQMP
+
+    {
         .name       = "xen-save-devices-state",
         .args_type  = "filename:F",
     .mhandler.cmd_new = qmp_marshal_input_xen_save_devices_state,
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [Qemu-devel] [PATCH 3/4] QAPI: Introduce memchar-read QMP command
  2012-12-06 14:56 [Qemu-devel] [PATCH 0/4 V8] char: Add CirMemCharDriver and provide QMP interface Lei Li
  2012-12-06 14:56 ` [Qemu-devel] [PATCH 1/4] qemu-char: Add new char backend CirMemCharDriver Lei Li
  2012-12-06 14:56 ` [Qemu-devel] [PATCH 2/4] QAPI: Introduce memchar-write QMP command Lei Li
@ 2012-12-06 14:56 ` Lei Li
  2012-12-06 14:56 ` [Qemu-devel] [PATCH 4/4] HMP: Introduce console command Lei Li
  2013-01-18 10:50 ` [Qemu-devel] [PATCH 0/4 V8] char: Add CirMemCharDriver and provide QMP interface Lei Li
  4 siblings, 0 replies; 6+ messages in thread
From: Lei Li @ 2012-12-06 14:56 UTC (permalink / raw)
  To: aliguori; +Cc: qemu-devel, anthony, Lei Li

Signed-off-by: Lei Li <lilei@linux.vnet.ibm.com>
---
 hmp-commands.hx  |   19 ++++++++++++++++++
 hmp.c            |   17 ++++++++++++++++
 hmp.h            |    1 +
 qapi-schema.json |   25 +++++++++++++++++++++++
 qemu-char.c      |   57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qmp-commands.hx  |   34 ++++++++++++++++++++++++++++++++
 6 files changed, 153 insertions(+), 0 deletions(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index a60ba69..3975e22 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -855,6 +855,25 @@ to char device 'memory'.
 ETEXI
 
     {
+        .name       = "memchar_read",
+        .args_type  = "chardev:s,size:i",
+        .params     = "chardev size",
+        .mhandler.cmd = hmp_memchar_read,
+    },
+
+STEXI
+@item memchar_read @var{chardev}
+@findex memchar_read
+Provide read interface for CirMemCharDriver. Read from char device
+'memory' and return @var{size} of the data.
+
+@var{size} is the size of data want to read from. Refer to unencoded
+size of the raw data, would adjust to the init size of the memchar
+if the requested size is larger than it.
+
+ETEXI
+
+    {
         .name       = "migrate",
         .args_type  = "detach:-d,blk:-b,inc:-i,uri:s",
         .params     = "[-d] [-b] [-i] uri",
diff --git a/hmp.c b/hmp.c
index 05b8c21..413012f 100644
--- a/hmp.c
+++ b/hmp.c
@@ -696,6 +696,23 @@ void hmp_memchar_write(Monitor *mon, const QDict *qdict)
     hmp_handle_error(mon, &errp);
 }
 
+void hmp_memchar_read(Monitor *mon, const QDict *qdict)
+{
+    uint32_t size = qdict_get_int(qdict, "size");
+    const char *chardev = qdict_get_str(qdict, "chardev");
+    char *data;
+    Error *errp = NULL;
+
+    data = qmp_memchar_read(chardev, size, false, 0, &errp);
+    if (errp) {
+        monitor_printf(mon, "%s\n", error_get_pretty(errp));
+        error_free(errp);
+        return;
+    }
+
+    monitor_printf(mon, "%s\n", data);
+}
+
 static void hmp_cont_cb(void *opaque, int err)
 {
     if (!err) {
diff --git a/hmp.h b/hmp.h
index 3ea9896..22a6646 100644
--- a/hmp.h
+++ b/hmp.h
@@ -44,6 +44,7 @@ void hmp_cpu(Monitor *mon, const QDict *qdict);
 void hmp_memsave(Monitor *mon, const QDict *qdict);
 void hmp_pmemsave(Monitor *mon, const QDict *qdict);
 void hmp_memchar_write(Monitor *mon, const QDict *qdict);
+void hmp_memchar_read(Monitor *mon, const QDict *qdict);
 void hmp_cont(Monitor *mon, const QDict *qdict);
 void hmp_system_wakeup(Monitor *mon, const QDict *qdict);
 void hmp_inject_nmi(Monitor *mon, const QDict *qdict);
diff --git a/qapi-schema.json b/qapi-schema.json
index d9fd635..811377c 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -366,6 +366,31 @@
            '*format': 'DataFormat'} }
 
 ##
+# @memchar-read:
+#
+# Provide read interface for memchardev. Read from the char
+# device 'memory' and return the data.
+#
+# @chardev: the name of the memory char device.
+#
+# @size: the size to read in bytes.
+#
+# @format: #optional the format of the data want to read from
+#          memchardev, by default is 'utf8'.
+#
+# Returns: The data read from memchar as string
+#          If @chardev is not a valid memchr device, DeviceNotFound
+#
+# Notes: For now assume 'drop' behaver, which would result in reads
+#        returning empty strings.
+#
+# Since: 1.4
+##
+{ 'command': 'memchar-read',
+  'data': {'chardev': 'str', 'size': 'int', '*format': 'DataFormat'},
+  'returns': 'str' }
+
+##
 # @CommandInfo:
 #
 # Information about a QMP command
diff --git a/qemu-char.c b/qemu-char.c
index a407087..b69b9dc 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2772,6 +2772,63 @@ void qmp_memchar_write(const char *chardev, int64_t size,
     }
 }
 
+char *qmp_memchar_read(const char *chardev, int64_t size,
+                       bool has_format, enum DataFormat format,
+                       Error **errp)
+{
+    CharDriverState *chr;
+    guchar *read_data;
+    char *data = NULL;
+    int ret;
+    size_t count;
+
+    chr = qemu_chr_find(chardev);
+    if (!chr) {
+        error_set(errp, QERR_DEVICE_NOT_FOUND, chardev);
+        return NULL;
+    }
+
+    if (qemu_is_chr(chr, "memory")) {
+        error_setg(errp,"%s is not memory char device\n", chardev);
+        return NULL;
+    }
+
+    if (size <= 0) {
+        error_setg(errp, "Failed to read from device %s", chardev);
+        return NULL;
+    }
+
+    /* XXX: Return the empty strings when the buffer is empty. */
+    if (cirmem_chr_is_empty(chr)) {
+        error_setg(errp, "Memory device %s is empty", chardev);
+        return NULL;
+    }
+
+    count = qemu_chr_cirmem_count(chr);
+    size = size > count ? count : size;
+    read_data = g_malloc0(size + 1);
+
+    ret = cirmem_chr_read(chr, read_data, size);
+    if (ret < 0) {
+        error_setg(errp, "Failed to read from device %s", chardev);
+        goto fail;
+    }
+
+    if (has_format && (format == DATA_FORMAT_BASE64)) {
+       if (read_data) {
+           data = g_base64_encode(read_data, (size_t)size);
+       }
+    } else {
+        data = (char *)read_data;
+    }
+
+    return data;
+
+fail:
+    g_free(read_data);
+    return NULL;
+}
+
 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
 {
     char host[65], port[33], width[8], height[8];
diff --git a/qmp-commands.hx b/qmp-commands.hx
index ae3ab5a..2c91f96 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -500,6 +500,40 @@ Example:
 EQMP
 
     {
+        .name       = "memchar-read",
+        .args_type  = "chardev:s,size:i,format:s?",
+        .help       = "return the size of data from memchar chardev",
+        .mhandler.cmd_new = qmp_marshal_input_memchar_read,
+    },
+
+SQMP
+memchar-read
+-------------
+
+Provide read interface for CirMemCharDriver. Read from the char
+device memory and return the data.
+
+Arguments:
+
+- "chardev": the name of the char device, must be unique (json-string)
+- "size": the memory size wanted to read in bytes (refer to unencoded
+          size of the raw data), would adjust to the init size of the
+          memchar if the requested size is larger than it. (json-int)
+- "format": the data format write to memchardev, default is
+            utf8. (json-string, optional)
+          - Possible values: "utf8", "base64"
+
+Example:
+
+-> { "execute": "memchar-read",
+                "arguments": { "chardev": foo,
+                               "size": 1000,
+                               "format": "utf8" } }
+<- { "return": "data string..." }
+
+EQMP
+
+    {
         .name       = "xen-save-devices-state",
         .args_type  = "filename:F",
     .mhandler.cmd_new = qmp_marshal_input_xen_save_devices_state,
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [Qemu-devel] [PATCH 4/4] HMP: Introduce console command
  2012-12-06 14:56 [Qemu-devel] [PATCH 0/4 V8] char: Add CirMemCharDriver and provide QMP interface Lei Li
                   ` (2 preceding siblings ...)
  2012-12-06 14:56 ` [Qemu-devel] [PATCH 3/4] QAPI: Introduce memchar-read " Lei Li
@ 2012-12-06 14:56 ` Lei Li
  2013-01-18 10:50 ` [Qemu-devel] [PATCH 0/4 V8] char: Add CirMemCharDriver and provide QMP interface Lei Li
  4 siblings, 0 replies; 6+ messages in thread
From: Lei Li @ 2012-12-06 14:56 UTC (permalink / raw)
  To: aliguori; +Cc: qemu-devel, anthony, Lei Li

Signed-off-by: Lei Li <lilei@linux.vnet.ibm.com>
---
 hmp-commands.hx |   21 +++++++++++++++++++++
 hmp.c           |   52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 hmp.h           |    1 +
 monitor.c       |   15 +++++++++++++++
 monitor.h       |    3 +++
 5 files changed, 92 insertions(+), 0 deletions(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 3975e22..9ec5ed7 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -874,6 +874,27 @@ if the requested size is larger than it.
 ETEXI
 
     {
+        .name       = "console",
+        .args_type  = "chardev:s",
+        .params     = "chardev",
+        .mhandler.cmd = hmp_console,
+    },
+
+STEXI
+@item console @var{device}
+@findex console
+Connect to the serial console from within the monitor, allow to write data
+to memchardev @var{chardev}. Exit from the console and return back to
+monitor by 'ctrl-]' or enter.
+
+@example
+(qemu) console foo
+foo: data string...
+@end example
+
+ETEXI
+
+    {
         .name       = "migrate",
         .args_type  = "detach:-d,blk:-b,inc:-i,uri:s",
         .params     = "[-d] [-b] [-i] uri",
diff --git a/hmp.c b/hmp.c
index 413012f..a6c053c 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1365,3 +1365,55 @@ void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict)
     qmp_nbd_server_stop(&errp);
     hmp_handle_error(mon, &errp);
 }
+
+enum escape_char
+{
+    ESCAPE_CHAR_CTRL_GS = 0x1d  /* ctrl-] used for escape */
+};
+
+static void hmp_read_console(Monitor *mon, const char *data,
+                             void *opaque)
+{
+    CharDriverState *chr = opaque;
+    uint32_t size = strlen(data);
+    enum escape_char console_escape = ESCAPE_CHAR_CTRL_GS;
+
+    Error *err = NULL;
+
+    if (*data == console_escape) {
+        monitor_resume(mon);
+        return;
+    }
+
+    qmp_memchar_write(chr->label, size, data, 0, 0, &err);
+
+    if (err) {
+        monitor_printf(mon, "%s\n", error_get_pretty(err));
+        monitor_read_command(mon,1);
+        error_free(err);
+        return;
+    }
+
+    monitor_read_command(mon, 1);
+}
+
+void hmp_console(Monitor *mon, const QDict *qdict)
+{
+    const char *device = qdict_get_str(qdict, "chardev");
+    CharDriverState *chr;
+    Error *err = NULL;
+
+    chr = qemu_chr_find(device);
+
+    if (!chr) {
+        error_set(&err, QERR_DEVICE_NOT_FOUND, device);
+        goto out;
+    }
+
+    if (monitor_read_console(mon, device, hmp_read_console, chr) < 0) {
+        monitor_printf(mon, "Connect to console %s failed\n", device);
+    }
+
+out:
+    hmp_handle_error(mon, &err);
+}
diff --git a/hmp.h b/hmp.h
index 22a6646..9082324 100644
--- a/hmp.h
+++ b/hmp.h
@@ -82,5 +82,6 @@ void hmp_screen_dump(Monitor *mon, const QDict *qdict);
 void hmp_nbd_server_start(Monitor *mon, const QDict *qdict);
 void hmp_nbd_server_add(Monitor *mon, const QDict *qdict);
 void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict);
+void hmp_console(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/monitor.c b/monitor.c
index c0e32d6..695a19a 100644
--- a/monitor.c
+++ b/monitor.c
@@ -256,6 +256,21 @@ int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
     }
 }
 
+int monitor_read_console(Monitor *mon, const char *device,
+                         ReadLineFunc *readline_func, void *opaque)
+{
+    char prompt[60];
+
+    if (!mon->rs) {
+        return -1;
+    }
+
+    snprintf(prompt, sizeof(prompt), "%s: ", device);
+    readline_start(mon->rs, prompt, 0, readline_func, opaque);
+
+    return 0;
+}
+
 void monitor_flush(Monitor *mon)
 {
     if (mon && mon->outbuf_index != 0 && !mon->mux_out) {
diff --git a/monitor.h b/monitor.h
index b4ef955..5f584b9 100644
--- a/monitor.h
+++ b/monitor.h
@@ -87,6 +87,9 @@ ReadLineState *monitor_get_rs(Monitor *mon);
 int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
                           void *opaque);
 
+int monitor_read_console(Monitor *mon, const char *device,
+                         ReadLineFunc *readline_func, void *opaque);
+
 int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret);
 
 int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret);
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [Qemu-devel] [PATCH 0/4 V8] char: Add CirMemCharDriver and provide QMP interface
  2012-12-06 14:56 [Qemu-devel] [PATCH 0/4 V8] char: Add CirMemCharDriver and provide QMP interface Lei Li
                   ` (3 preceding siblings ...)
  2012-12-06 14:56 ` [Qemu-devel] [PATCH 4/4] HMP: Introduce console command Lei Li
@ 2013-01-18 10:50 ` Lei Li
  4 siblings, 0 replies; 6+ messages in thread
From: Lei Li @ 2013-01-18 10:50 UTC (permalink / raw)
  To: Lei Li; +Cc: aliguori, qemu-devel, anthony

Hi Anthony,

As 1.4 freeze is going to close, should this patch series be merged?
It has been on mailing list for a long time after last time
I rebased and fixed the comment from Eric.

On 12/06/2012 10:56 PM, Lei Li wrote:
> This patch series attempts to add new char backend CirMemCharDriver with
> a circular buffer and expose it to users by introducing QMP interface
> memchar-write and memchar-read and via the command line like the other
> CharDriverStates.
>
> Serial ports in qemu always use CharDriverStates as there backends,
> Right now, all of our backends always try to write the data from the
> guest to a socket or file. The concern from OpenStack is that this could
> lead to unbounded disk space usage since they log the serial output.
> For more detail of the background info:
> https://bugs.launchpad.net/nova/+bug/832507
>
> So we want to use a circular buffer in QEMU instead, and then OpenStack
> can periodically read the buffer in QEMU and log it.
>
> The QMP commands introduced like:
>
> { 'command': 'memchar-write',
>    'data': {'chardev': 'str', 'size': 'int', 'data': 'str',
>             'format': 'str' } }
>
> { 'command': 'memchar-read',
>    'data': {'chardev': 'str', 'size': 'int', 'format': 'str' },
>    'returns': 'str' }
>
> Expose CirMemCharDriver via the command line like:
>
> qemu -chardev memory,id=foo,maxcapacity=65536 -serial chardev:foo
>
> Introduce HMP command 'console' like:
>
> (qemu) console foo
> foo: Input data
>
> Note:
> Now all of the feature were implemented, and the pervious comments
> are fixed up too. Since this patch series have been for mailing list
> for some time and missed 1.3, rebase it with minor fix.
>
> Changes since v7:
>    - Rebase the code and fix the format error pointed by Eric.
>    - Modify the version info.
>
> Changes since v6:
>    - Improve the document based on Luiz's comments.
>    - Keep pointing to the right position in cbuf for the case producer
>      and consumer might overflow for long running VMs pointed by Luiz.
>    - Limit the size of read_data to the amount of bytes available in the
>      circular buffer.
>    - Other fixups from Luiz.
>
> Changes since v5:
>    - Avoid writing the IAC information to the queue.
>    - Grammar of the doc for command line options improved from Eric.
>
> Changes since v4:
>    - Get rid of all CongestionControl bits, and assume a dropping behavior
>      based on Luiz's suggestion for now. Will add it when we add async
>      support to QMP.
>    - Squashed the patches about CirMemCharDriver in one.
>    - Other fixups from Luiz.
>
> Changes since v3:
>    - Improve the algorithm of circular buffer based on Anthony's
>      suggestion.
>    - Some changes suggested by Luiz and Blue.
>    - And other fixups.
>
> Changes since v2:
>    - Add congestion mechanism. For the 'block' option as sync command,
>      will support it later when we gain the necessary infrastructure
>      enhancement.
>    - Add HMP 'console' command so that can interact with multiple
>      chardevs via a single monitor socket.
>    - Make the circular buffer backend and the current MemCharDriver
>      live in parallel, expose a new char backend with circular buffer
>      CirMemCharDriver suggested by Luiz.
>    - Other fixs from Eric and Markus.
>
> Changes since v1:
>    - Exposing the MemCharDriver via command line.
>    - Support base64 data format suggested by Anthony and Eric.
>    - Follow the new rule for the name of qmp command from Eric.
>
>
> Lei Li (4):
>    qemu-char: Add new char backend CirMemCharDriver
>    QAPI: Introduce memchar-write QMP command
>    QAPI: Introduce memchar-read QMP command
>    HMP: Introduce console command
>
>   hmp-commands.hx  |   72 +++++++++++++++++++
>   hmp.c            |   99 +++++++++++++++++++++++
>   hmp.h            |    3 +
>   monitor.c        |   15 ++++
>   monitor.h        |    3 +
>   qapi-schema.json |   96 +++++++++++++++++++++++++
>   qemu-char.c      |  217 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>   qemu-config.c    |    3 +
>   qemu-options.hx  |   10 +++
>   qmp-commands.hx  |   89 +++++++++++++++++++++
>   10 files changed, 607 insertions(+), 0 deletions(-)
>
>


-- 
Lei

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2013-01-18 10:50 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-12-06 14:56 [Qemu-devel] [PATCH 0/4 V8] char: Add CirMemCharDriver and provide QMP interface Lei Li
2012-12-06 14:56 ` [Qemu-devel] [PATCH 1/4] qemu-char: Add new char backend CirMemCharDriver Lei Li
2012-12-06 14:56 ` [Qemu-devel] [PATCH 2/4] QAPI: Introduce memchar-write QMP command Lei Li
2012-12-06 14:56 ` [Qemu-devel] [PATCH 3/4] QAPI: Introduce memchar-read " Lei Li
2012-12-06 14:56 ` [Qemu-devel] [PATCH 4/4] HMP: Introduce console command Lei Li
2013-01-18 10:50 ` [Qemu-devel] [PATCH 0/4 V8] char: Add CirMemCharDriver and provide QMP interface Lei Li

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).