Merge remote-tracking branch 'luiz/queue/qmp' into staging
authorAnthony Liguori <aliguori@us.ibm.com>
Mon, 28 Jan 2013 20:41:25 +0000 (14:41 -0600)
committerAnthony Liguori <aliguori@us.ibm.com>
Mon, 28 Jan 2013 20:41:25 +0000 (14:41 -0600)
# By Lei Li (3) and others
# Via Luiz Capitulino
* luiz/queue/qmp:
  QAPI: Introduce memchar-read QMP command
  QAPI: Introduce memchar-write QMP command
  qemu-char: Add new char backend CirMemCharDriver
  docs: document virtio-balloon stats
  balloon: re-enable balloon stats
  balloon: drop old stats code & API
  block: Monitor command commit neglects to report some errors

1  2 
qemu-char.c

diff --combined qemu-char.c
index da1db1d10450e1c3bbcc17ffe4323bf126496c0a,1d1c631c98cc0590e4e44b111afa0275459713b2..ac5d62dd9a323b9e1eab8111562259dd24ed3e89
@@@ -98,6 -98,7 +98,7 @@@
  #include "ui/qemu-spice.h"
  
  #define READ_BUF_LEN 4096
+ #define CBUFF_SIZE 65536
  
  /***********************************************************/
  /* character device */
@@@ -2643,6 -2644,199 +2644,199 @@@ size_t qemu_chr_mem_osize(const CharDri
      return d->outbuf_size;
  }
  
+ /*********************************************************/
+ /*CircularMemory chardev*/
+ typedef struct {
+     size_t size;
+     size_t prod;
+     size_t cons;
+     uint8_t *cbuf;
+ } CirMemCharDriver;
+ static bool cirmem_chr_is_empty(const CharDriverState *chr)
+ {
+     const CirMemCharDriver *d = chr->opaque;
+     return d->cons == d->prod;
+ }
+ static size_t qemu_chr_cirmem_count(const CharDriverState *chr)
+ {
+     const CirMemCharDriver *d = chr->opaque;
+     return (d->prod - d->cons);
+ }
+ static int cirmem_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+ {
+     CirMemCharDriver *d = chr->opaque;
+     int i;
+     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;
+         }
+         d->cbuf[d->prod++ % d->size] = buf[i];
+         if ((d->prod - d->cons) > d->size) {
+             d->cons = d->prod - d->size;
+         }
+     }
+     return 0;
+ }
+ static int cirmem_chr_read(CharDriverState *chr, uint8_t *buf, int len)
+ {
+     CirMemCharDriver *d = chr->opaque;
+     int i;
+     for (i = 0; i < len && !cirmem_chr_is_empty(chr); i++) {
+         buf[i] = d->cbuf[d->cons++ % d->size];
+     }
+     return i;
+ }
+ 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)) {
+         fprintf(stderr, "chardev: size of memory device must be power of 2\n");
+         goto fail;
+     }
+     d->prod = 0;
+     d->cons = 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;
+ }
+ static bool qemu_is_chr(const CharDriverState *chr, const char *filename)
+ {
+     return strcmp(chr->filename, filename);
+ }
+ void qmp_memchar_write(const char *device, 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(device);
+     if (!chr) {
+         error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+         return;
+     }
+     if (qemu_is_chr(chr, "memory")) {
+         error_setg(errp,"%s is not memory char device", device);
+         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", device);
+         return;
+     }
+ }
+ MemCharRead *qmp_memchar_read(const char *device, int64_t size,
+                               bool has_format, enum DataFormat format,
+                               Error **errp)
+ {
+     CharDriverState *chr;
+     guchar *read_data;
+     MemCharRead *meminfo;
+     size_t count;
+     chr = qemu_chr_find(device);
+     if (!chr) {
+         error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+         return NULL;
+     }
+     if (qemu_is_chr(chr, "memory")) {
+         error_setg(errp,"%s is not memory char device", device);
+         return NULL;
+     }
+     if (size <= 0) {
+         error_setg(errp, "size must be greater than zero");
+         return NULL;
+     }
+     meminfo = g_malloc0(sizeof(MemCharRead));
+     count = qemu_chr_cirmem_count(chr);
+     if (count == 0) {
+         meminfo->data = g_strdup("");
+         return meminfo;
+     }
+     size = size > count ? count : size;
+     read_data = g_malloc0(size + 1);
+     meminfo->count = cirmem_chr_read(chr, read_data, size);
+     if (has_format && (format == DATA_FORMAT_BASE64)) {
+         meminfo->data = g_base64_encode(read_data, (size_t)meminfo->count);
+     } else {
+         meminfo->data = (char *)read_data;
+     }
+     return meminfo;
+ }
  QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
  {
      char host[65], port[33], width[8], height[8];
          qemu_opt_set(opts, "path", filename);
          return opts;
      }
+     if (strstart(filename, "memory", &p)) {
+         qemu_opt_set(opts, "backend", "memory");
+         qemu_opt_set(opts, "maxcapacity", p);
+         return opts;
+     }
      if (strstart(filename, "file:", &p)) {
          qemu_opt_set(opts, "backend", "file");
          qemu_opt_set(opts, "path", p);
@@@ -2796,6 -2995,7 +2995,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 },
@@@ -3055,6 -3255,9 +3255,9 @@@ QemuOptsList qemu_chardev_opts = 
          },{
              .name = "debug",
              .type = QEMU_OPT_NUMBER,
+         },{
+             .name = "maxcapacity",
+             .type = QEMU_OPT_NUMBER,
          },
          { /* end of list */ }
      },
@@@ -3129,11 -3332,11 +3332,11 @@@ static CharDriverState *qmp_chardev_ope
  
  static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp)
  {
 -    int flags, fd;
 -
      switch (port->type) {
  #ifdef HAVE_CHARDEV_TTY
      case CHARDEV_PORT_KIND_SERIAL:
 +    {
 +        int flags, fd;
          flags = O_RDWR;
          fd = qmp_chardev_open_file_source(port->device, flags, errp);
          if (error_is_set(errp)) {
          }
          socket_set_nonblock(fd);
          return qemu_chr_open_tty_fd(fd);
 +    }
  #endif
  #ifdef HAVE_CHARDEV_PARPORT
      case CHARDEV_PORT_KIND_PARALLEL:
 +    {
 +        int flags, fd;
          flags = O_RDWR;
          fd = qmp_chardev_open_file_source(port->device, flags, errp);
          if (error_is_set(errp)) {
              return NULL;
          }
          return qemu_chr_open_pp_fd(fd);
 +    }
  #endif
      default:
          error_setg(errp, "unknown chardev port (%d)", port->type);