summary refs log tree commit diff stats
path: root/qemu-char.c
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@redhat.com>2016-10-21 23:44:44 +0300
committerPaolo Bonzini <pbonzini@redhat.com>2017-01-27 18:07:59 +0100
commit41ac54b253f41df924c350ef63564df8e1d8ad88 (patch)
treea6d8fdcb913b558c4f5ecc698bd82ae1a195705c /qemu-char.c
parent5ebd67030c4e4bc702d07a3e10c909be4520f170 (diff)
downloadfocaccia-qemu-41ac54b253f41df924c350ef63564df8e1d8ad88.tar.gz
focaccia-qemu-41ac54b253f41df924c350ef63564df8e1d8ad88.zip
char: allocate CharDriverState as a single object
Use a single allocation for CharDriverState, this avoids extra
allocations & pointers, and is a step towards more object-oriented
CharDriver.

Gtk console is a bit peculiar, gd_vc_chr_set_echo() used to have a
temporary VirtualConsole to save the echo bit. Instead now, we consider
whether vcd->console is set or not, and restore the echo bit saved in
VCDriverState when calling gd_vc_vte_init().

The casts added are temporary, they are replaced with QOM type-safe
macros in a later patch in this series.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'qemu-char.c')
-rw-r--r--qemu-char.c280
1 files changed, 144 insertions, 136 deletions
diff --git a/qemu-char.c b/qemu-char.c
index 5d04d829ab..dfd1b4c80f 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -165,12 +165,14 @@ static void qemu_chr_free_common(CharDriverState *chr);
 CharDriverState *qemu_chr_alloc(const CharDriver *driver,
                                 ChardevCommon *backend, Error **errp)
 {
-    CharDriverState *chr = g_malloc0(sizeof(CharDriverState));
-    qemu_mutex_init(&chr->chr_write_lock);
+    CharDriverState *chr;
 
     assert(driver);
     assert(driver->chr_write);
+    assert(driver->instance_size >= sizeof(CharDriverState));
 
+    chr = g_malloc0(driver->instance_size);
+    qemu_mutex_init(&chr->chr_write_lock);
     if (backend->has_logfile) {
         int flags = O_WRONLY | O_CREAT;
         if (backend->has_logappend &&
@@ -536,6 +538,7 @@ static CharDriverState *qemu_chr_open_null(const CharDriver *driver,
 }
 
 static const CharDriver null_driver = {
+    .instance_size = sizeof(CharDriverState),
     .kind = CHARDEV_BACKEND_KIND_NULL,
     .create = qemu_chr_open_null,
     .chr_write = null_chr_write,
@@ -546,6 +549,7 @@ static const CharDriver null_driver = {
 #define MUX_BUFFER_SIZE 32	/* Must be a power of 2.  */
 #define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1)
 struct MuxDriver {
+    CharDriverState parent;
     CharBackend *backends[MAX_MUX];
     CharBackend chr;
     int focus;
@@ -568,7 +572,7 @@ struct MuxDriver {
 /* Called with chr_write_lock held.  */
 static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
-    MuxDriver *d = chr->opaque;
+    MuxDriver *d = (MuxDriver *)chr;
     int ret;
     if (!d->timestamps) {
         ret = qemu_chr_fe_write(&d->chr, buf, len);
@@ -702,7 +706,7 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
 
 static void mux_chr_accept_input(CharDriverState *chr)
 {
-    MuxDriver *d = chr->opaque;
+    MuxDriver *d = (MuxDriver *)chr;
     int m = d->focus;
     CharBackend *be = d->backends[m];
 
@@ -715,8 +719,7 @@ static void mux_chr_accept_input(CharDriverState *chr)
 
 static int mux_chr_can_read(void *opaque)
 {
-    CharDriverState *chr = opaque;
-    MuxDriver *d = chr->opaque;
+    MuxDriver *d = opaque;
     int m = d->focus;
     CharBackend *be = d->backends[m];
 
@@ -734,7 +737,7 @@ static int mux_chr_can_read(void *opaque)
 static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
 {
     CharDriverState *chr = opaque;
-    MuxDriver *d = chr->opaque;
+    MuxDriver *d = opaque;
     int m = d->focus;
     CharBackend *be = d->backends[m];
     int i;
@@ -756,8 +759,7 @@ static bool muxes_realized;
 
 static void mux_chr_event(void *opaque, int event)
 {
-    CharDriverState *chr = opaque;
-    MuxDriver *d = chr->opaque;
+    MuxDriver *d = opaque;
     int i;
 
     if (!muxes_realized) {
@@ -787,7 +789,7 @@ static void muxes_realize_done(Notifier *notifier, void *unused)
 
     QTAILQ_FOREACH(chr, &chardevs, next) {
         if (qemu_chr_get_kind(chr) == CHARDEV_BACKEND_KIND_MUX) {
-            MuxDriver *d = chr->opaque;
+            MuxDriver *d = (MuxDriver *)chr;
             int i;
 
             /* send OPENED to all already-attached FEs */
@@ -809,7 +811,7 @@ static Notifier muxes_realize_notify = {
 
 static GSource *mux_chr_add_watch(CharDriverState *s, GIOCondition cond)
 {
-    MuxDriver *d = s->opaque;
+    MuxDriver *d = (MuxDriver *)s;
     CharDriverState *chr = qemu_chr_fe_get_driver(&d->chr);
 
     if (!chr->driver->chr_add_watch) {
@@ -821,7 +823,7 @@ static GSource *mux_chr_add_watch(CharDriverState *s, GIOCondition cond)
 
 static void mux_chr_free(struct CharDriverState *chr)
 {
-    MuxDriver *d = chr->opaque;
+    MuxDriver *d = (MuxDriver *)chr;
     int i;
 
     for (i = 0; i < d->mux_cnt; i++) {
@@ -831,12 +833,11 @@ static void mux_chr_free(struct CharDriverState *chr)
         }
     }
     qemu_chr_fe_deinit(&d->chr);
-    g_free(d);
 }
 
 static void mux_chr_set_handlers(CharDriverState *chr, GMainContext *context)
 {
-    MuxDriver *d = chr->opaque;
+    MuxDriver *d = (MuxDriver *)chr;
 
     /* Fix up the real driver with mux routines */
     qemu_chr_fe_set_handlers(&d->chr,
@@ -849,7 +850,7 @@ static void mux_chr_set_handlers(CharDriverState *chr, GMainContext *context)
 
 static void mux_set_focus(CharDriverState *chr, int focus)
 {
-    MuxDriver *d = chr->opaque;
+    MuxDriver *d = (MuxDriver *)chr;
 
     assert(focus >= 0);
     assert(focus < d->mux_cnt);
@@ -885,9 +886,7 @@ static CharDriverState *qemu_chr_open_mux(const CharDriver *driver,
     if (!chr) {
         return NULL;
     }
-    d = g_new0(MuxDriver, 1);
-
-    chr->opaque = d;
+    d = (MuxDriver *)chr;
     d->focus = -1;
     /* only default to opened state if we've realized the initial
      * set of muxes
@@ -911,7 +910,7 @@ bool qemu_chr_fe_init(CharBackend *b, CharDriverState *s, Error **errp)
     int tag = 0;
 
     if (qemu_chr_get_kind(s) == CHARDEV_BACKEND_KIND_MUX) {
-        MuxDriver *d = s->opaque;
+        MuxDriver *d = (MuxDriver *)s;
 
         if (d->mux_cnt >= MAX_MUX) {
             goto unavailable;
@@ -938,7 +937,7 @@ unavailable:
 static bool qemu_chr_is_busy(CharDriverState *s)
 {
     if (qemu_chr_get_kind(s) == CHARDEV_BACKEND_KIND_MUX) {
-        MuxDriver *d = s->opaque;
+        MuxDriver *d = (MuxDriver *)s;
         return d->mux_cnt >= 0;
     } else {
         return s->be != NULL;
@@ -955,7 +954,7 @@ void qemu_chr_fe_deinit(CharBackend *b)
             b->chr->be = NULL;
         }
         if (qemu_chr_get_kind(b->chr) == CHARDEV_BACKEND_KIND_MUX) {
-            MuxDriver *d = b->chr->opaque;
+            MuxDriver *d = (MuxDriver *)b->chr;
             d->backends[b->tag] = NULL;
         }
         b->chr = NULL;
@@ -1195,6 +1194,7 @@ static int io_channel_send(QIOChannel *ioc, const void *buf, size_t len)
 
 
 typedef struct FDCharDriver {
+    CharDriverState parent;
     CharDriverState *chr;
     QIOChannel *ioc_in, *ioc_out;
     int max_size;
@@ -1203,15 +1203,15 @@ typedef struct FDCharDriver {
 /* Called with chr_write_lock held.  */
 static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
-    FDCharDriver *s = chr->opaque;
-    
+    FDCharDriver *s = (FDCharDriver *)chr;
+
     return io_channel_send(s->ioc_out, buf, len);
 }
 
 static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 {
     CharDriverState *chr = opaque;
-    FDCharDriver *s = chr->opaque;
+    FDCharDriver *s = opaque;
     int len;
     uint8_t buf[READ_BUF_LEN];
     ssize_t ret;
@@ -1241,7 +1241,7 @@ static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 static int fd_chr_read_poll(void *opaque)
 {
     CharDriverState *chr = opaque;
-    FDCharDriver *s = chr->opaque;
+    FDCharDriver *s = opaque;
 
     s->max_size = qemu_chr_be_can_write(chr);
     return s->max_size;
@@ -1249,14 +1249,14 @@ static int fd_chr_read_poll(void *opaque)
 
 static GSource *fd_chr_add_watch(CharDriverState *chr, GIOCondition cond)
 {
-    FDCharDriver *s = chr->opaque;
+    FDCharDriver *s = (FDCharDriver *)chr;
     return qio_channel_create_watch(s->ioc_out, cond);
 }
 
 static void fd_chr_update_read_handler(CharDriverState *chr,
                                        GMainContext *context)
 {
-    FDCharDriver *s = chr->opaque;
+    FDCharDriver *s = (FDCharDriver *)chr;
 
     remove_fd_in_watch(chr);
     if (s->ioc_in) {
@@ -1269,7 +1269,7 @@ static void fd_chr_update_read_handler(CharDriverState *chr,
 
 static void fd_chr_free(struct CharDriverState *chr)
 {
-    FDCharDriver *s = chr->opaque;
+    FDCharDriver *s = (FDCharDriver *)chr;
 
     remove_fd_in_watch(chr);
     if (s->ioc_in) {
@@ -1279,7 +1279,6 @@ static void fd_chr_free(struct CharDriverState *chr)
         object_unref(OBJECT(s->ioc_out));
     }
 
-    g_free(s);
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
@@ -1296,7 +1295,7 @@ static CharDriverState *qemu_chr_open_fd(const CharDriver *driver,
     if (!chr) {
         return NULL;
     }
-    s = g_new0(FDCharDriver, 1);
+    s = (FDCharDriver *)chr;
     s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in));
     name = g_strdup_printf("chardev-file-in-%s", chr->label);
     qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name);
@@ -1307,7 +1306,6 @@ static CharDriverState *qemu_chr_open_fd(const CharDriver *driver,
     g_free(name);
     qemu_set_nonblock(fd_out);
     s->chr = chr;
-    chr->opaque = s;
 
     return chr;
 }
@@ -1448,6 +1446,7 @@ static CharDriverState *qemu_chr_open_stdio(const CharDriver *driver,
 #define HAVE_CHARDEV_PTY 1
 
 typedef struct {
+    CharDriverState parent;
     QIOChannel *ioc;
     int read_bytes;
 
@@ -1463,7 +1462,7 @@ static void pty_chr_state(CharDriverState *chr, int connected);
 static gboolean pty_chr_timer(gpointer opaque)
 {
     struct CharDriverState *chr = opaque;
-    PtyCharDriver *s = chr->opaque;
+    PtyCharDriver *s = opaque;
 
     qemu_mutex_lock(&chr->chr_write_lock);
     s->timer_tag = 0;
@@ -1479,7 +1478,7 @@ static gboolean pty_chr_timer(gpointer opaque)
 /* Called with chr_write_lock held.  */
 static void pty_chr_rearm_timer(CharDriverState *chr, int ms)
 {
-    PtyCharDriver *s = chr->opaque;
+    PtyCharDriver *s = (PtyCharDriver *)chr;
     char *name;
 
     if (s->timer_tag) {
@@ -1501,7 +1500,7 @@ static void pty_chr_rearm_timer(CharDriverState *chr, int ms)
 /* Called with chr_write_lock held.  */
 static void pty_chr_update_read_handler_locked(CharDriverState *chr)
 {
-    PtyCharDriver *s = chr->opaque;
+    PtyCharDriver *s = (PtyCharDriver *)chr;
     GPollFD pfd;
     int rc;
     QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc);
@@ -1532,7 +1531,7 @@ static void pty_chr_update_read_handler(CharDriverState *chr,
 /* Called with chr_write_lock held.  */
 static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
-    PtyCharDriver *s = chr->opaque;
+    PtyCharDriver *s = (PtyCharDriver *)chr;
 
     if (!s->connected) {
         /* guest sends data, check for (re-)connect */
@@ -1546,7 +1545,7 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 
 static GSource *pty_chr_add_watch(CharDriverState *chr, GIOCondition cond)
 {
-    PtyCharDriver *s = chr->opaque;
+    PtyCharDriver *s = (PtyCharDriver *)chr;
     if (!s->connected) {
         return NULL;
     }
@@ -1556,7 +1555,7 @@ static GSource *pty_chr_add_watch(CharDriverState *chr, GIOCondition cond)
 static int pty_chr_read_poll(void *opaque)
 {
     CharDriverState *chr = opaque;
-    PtyCharDriver *s = chr->opaque;
+    PtyCharDriver *s = opaque;
 
     s->read_bytes = qemu_chr_be_can_write(chr);
     return s->read_bytes;
@@ -1565,7 +1564,7 @@ static int pty_chr_read_poll(void *opaque)
 static gboolean pty_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 {
     CharDriverState *chr = opaque;
-    PtyCharDriver *s = chr->opaque;
+    PtyCharDriver *s = opaque;
     gsize len;
     uint8_t buf[READ_BUF_LEN];
     ssize_t ret;
@@ -1590,7 +1589,7 @@ static gboolean pty_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 static gboolean qemu_chr_be_generic_open_func(gpointer opaque)
 {
     CharDriverState *chr = opaque;
-    PtyCharDriver *s = chr->opaque;
+    PtyCharDriver *s = opaque;
 
     s->open_tag = 0;
     qemu_chr_be_generic_open(chr);
@@ -1600,7 +1599,7 @@ static gboolean qemu_chr_be_generic_open_func(gpointer opaque)
 /* Called with chr_write_lock held.  */
 static void pty_chr_state(CharDriverState *chr, int connected)
 {
-    PtyCharDriver *s = chr->opaque;
+    PtyCharDriver *s = (PtyCharDriver *)chr;
 
     if (!connected) {
         if (s->open_tag) {
@@ -1634,7 +1633,7 @@ static void pty_chr_state(CharDriverState *chr, int connected)
 
 static void pty_chr_free(struct CharDriverState *chr)
 {
-    PtyCharDriver *s = chr->opaque;
+    PtyCharDriver *s = (PtyCharDriver *)chr;
 
     qemu_mutex_lock(&chr->chr_write_lock);
     pty_chr_state(chr, 0);
@@ -1644,7 +1643,6 @@ static void pty_chr_free(struct CharDriverState *chr)
         s->timer_tag = 0;
     }
     qemu_mutex_unlock(&chr->chr_write_lock);
-    g_free(s);
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
@@ -1684,20 +1682,19 @@ static CharDriverState *qemu_chr_open_pty(const CharDriver *driver,
     fprintf(stderr, "char device redirected to %s (label %s)\n",
             pty_name, id);
 
-    s = g_new0(PtyCharDriver, 1);
-    chr->opaque = s;
-    *be_opened = false;
-
+    s = (PtyCharDriver *)chr;
     s->ioc = QIO_CHANNEL(qio_channel_file_new_fd(master_fd));
     name = g_strdup_printf("chardev-pty-%s", chr->label);
     qio_channel_set_name(QIO_CHANNEL(s->ioc), name);
     g_free(name);
     s->timer_tag = 0;
+    *be_opened = false;
 
     return chr;
 }
 
 static const CharDriver pty_driver = {
+    .instance_size = sizeof(PtyCharDriver),
     .kind = CHARDEV_BACKEND_KIND_PTY,
     .create = qemu_chr_open_pty,
     .chr_write = pty_chr_write,
@@ -1823,7 +1820,7 @@ static void tty_serial_init(int fd, int speed,
 
 static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
 {
-    FDCharDriver *s = chr->opaque;
+    FDCharDriver *s = (FDCharDriver *)chr;
     QIOChannelFile *fioc = QIO_CHANNEL_FILE(s->ioc_in);
 
     switch(cmd) {
@@ -1902,6 +1899,7 @@ static void qemu_chr_free_tty(CharDriverState *chr)
 #define HAVE_CHARDEV_PARPORT 1
 
 typedef struct {
+    CharDriverState parent;
     int fd;
     int mode;
 } ParallelCharDriver;
@@ -1919,7 +1917,7 @@ static int pp_hw_mode(ParallelCharDriver *s, uint16_t mode)
 
 static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
 {
-    ParallelCharDriver *drv = chr->opaque;
+    ParallelCharDriver *drv = (ParallelCharDriver *)chr;
     int fd = drv->fd;
     uint8_t b;
 
@@ -2000,13 +1998,12 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
 
 static void pp_free(CharDriverState *chr)
 {
-    ParallelCharDriver *drv = chr->opaque;
+    ParallelCharDriver *drv = (ParallelCharDriver *)chr;
     int fd = drv->fd;
 
     pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
     ioctl(fd, PPRELEASE);
     close(fd);
-    g_free(drv);
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
@@ -2030,9 +2027,7 @@ static CharDriverState *qemu_chr_open_pp_fd(const CharDriver *driver,
         return NULL;
     }
 
-    drv = g_new0(ParallelCharDriver, 1);
-    chr->opaque = drv;
-
+    drv = (ParallelCharDriver *)chr;
     drv->fd = fd;
     drv->mode = IEEE1284_MODE_COMPAT;
 
@@ -2044,35 +2039,45 @@ static CharDriverState *qemu_chr_open_pp_fd(const CharDriver *driver,
 
 #define HAVE_CHARDEV_PARPORT 1
 
+typedef struct {
+    CharDriverState parent;
+    int fd;
+} ParallelCharDriver;
+
 static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
 {
-    int fd = (int)(intptr_t)chr->opaque;
+    ParallelCharDriver *drv = (ParallelCharDriver *)chr;
     uint8_t b;
 
-    switch(cmd) {
+    switch (cmd) {
     case CHR_IOCTL_PP_READ_DATA:
-        if (ioctl(fd, PPIGDATA, &b) < 0)
+        if (ioctl(drv->fd, PPIGDATA, &b) < 0) {
             return -ENOTSUP;
+        }
         *(uint8_t *)arg = b;
         break;
     case CHR_IOCTL_PP_WRITE_DATA:
         b = *(uint8_t *)arg;
-        if (ioctl(fd, PPISDATA, &b) < 0)
+        if (ioctl(drv->fd, PPISDATA, &b) < 0) {
             return -ENOTSUP;
+        }
         break;
     case CHR_IOCTL_PP_READ_CONTROL:
-        if (ioctl(fd, PPIGCTRL, &b) < 0)
+        if (ioctl(drv->fd, PPIGCTRL, &b) < 0) {
             return -ENOTSUP;
+        }
         *(uint8_t *)arg = b;
         break;
     case CHR_IOCTL_PP_WRITE_CONTROL:
         b = *(uint8_t *)arg;
-        if (ioctl(fd, PPISCTRL, &b) < 0)
+        if (ioctl(drv->fd, PPISCTRL, &b) < 0) {
             return -ENOTSUP;
+        }
         break;
     case CHR_IOCTL_PP_READ_STATUS:
-        if (ioctl(fd, PPIGSTATUS, &b) < 0)
+        if (ioctl(drv->fd, PPIGSTATUS, &b) < 0) {
             return -ENOTSUP;
+        }
         *(uint8_t *)arg = b;
         break;
     default:
@@ -2088,12 +2093,14 @@ static CharDriverState *qemu_chr_open_pp_fd(const CharDriver *driver,
                                             Error **errp)
 {
     CharDriverState *chr;
+    ParallelCharDriver *drv;
 
     chr = qemu_chr_alloc(driver, backend, errp);
     if (!chr) {
         return NULL;
     }
-    chr->opaque = (void *)(intptr_t)fd;
+    drv = (ParallelCharDriver *)chr;
+    drv->fd = fd;
     *be_opened = false;
     return chr;
 }
@@ -2104,6 +2111,7 @@ static CharDriverState *qemu_chr_open_pp_fd(const CharDriver *driver,
 #define HAVE_CHARDEV_SERIAL 1
 
 typedef struct {
+    CharDriverState parent;
     int max_size;
     HANDLE hcom, hrecv, hsend;
     OVERLAPPED orecv;
@@ -2115,6 +2123,7 @@ typedef struct {
 } WinCharState;
 
 typedef struct {
+    CharDriverState parent;
     HANDLE  hStdIn;
     HANDLE  hInputReadyEvent;
     HANDLE  hInputDoneEvent;
@@ -2132,7 +2141,7 @@ static int win_chr_pipe_poll(void *opaque);
 
 static void win_chr_free(CharDriverState *chr)
 {
-    WinCharState *s = chr->opaque;
+    WinCharState *s = (WinCharState *)chr;
 
     if (s->hsend) {
         CloseHandle(s->hsend);
@@ -2156,7 +2165,7 @@ static void win_chr_free(CharDriverState *chr)
 
 static int win_chr_init(CharDriverState *chr, const char *filename, Error **errp)
 {
-    WinCharState *s = chr->opaque;
+    WinCharState *s = (WinCharState *)chr;
     COMMCONFIG comcfg;
     COMMTIMEOUTS cto = { 0, 0, 0, 0, 0};
     COMSTAT comstat;
@@ -2224,7 +2233,7 @@ static int win_chr_init(CharDriverState *chr, const char *filename, Error **errp
 /* Called with chr_write_lock held.  */
 static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1)
 {
-    WinCharState *s = chr->opaque;
+    WinCharState *s = (WinCharState *)chr;
     DWORD len, ret, size, err;
 
     len = len1;
@@ -2258,7 +2267,7 @@ static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1)
 
 static int win_chr_read_poll(CharDriverState *chr)
 {
-    WinCharState *s = chr->opaque;
+    WinCharState *s = (WinCharState *)chr;
 
     s->max_size = qemu_chr_be_can_write(chr);
     return s->max_size;
@@ -2266,7 +2275,7 @@ static int win_chr_read_poll(CharDriverState *chr)
 
 static void win_chr_readfile(CharDriverState *chr)
 {
-    WinCharState *s = chr->opaque;
+    WinCharState *s = (WinCharState *)chr;
     int ret, err;
     uint8_t buf[READ_BUF_LEN];
     DWORD size;
@@ -2288,7 +2297,7 @@ static void win_chr_readfile(CharDriverState *chr)
 
 static void win_chr_read(CharDriverState *chr)
 {
-    WinCharState *s = chr->opaque;
+    WinCharState *s = (WinCharState *)chr;
 
     if (s->len > s->max_size)
         s->len = s->max_size;
@@ -2301,7 +2310,7 @@ static void win_chr_read(CharDriverState *chr)
 static int win_chr_poll(void *opaque)
 {
     CharDriverState *chr = opaque;
-    WinCharState *s = chr->opaque;
+    WinCharState *s = opaque;
     COMSTAT status;
     DWORD comerr;
 
@@ -2318,7 +2327,7 @@ static int win_chr_poll(void *opaque)
 static int win_chr_pipe_poll(void *opaque)
 {
     CharDriverState *chr = opaque;
-    WinCharState *s = chr->opaque;
+    WinCharState *s = opaque;
     DWORD size;
 
     PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL);
@@ -2334,7 +2343,7 @@ static int win_chr_pipe_poll(void *opaque)
 static int win_chr_pipe_init(CharDriverState *chr, const char *filename,
                              Error **errp)
 {
-    WinCharState *s = chr->opaque;
+    WinCharState *s = (WinCharState *)chr;
     OVERLAPPED ov;
     int ret;
     DWORD size;
@@ -2406,18 +2415,14 @@ static CharDriverState *qemu_chr_open_pipe(const CharDriver *driver,
     ChardevHostdev *opts = backend->u.pipe.data;
     const char *filename = opts->device;
     CharDriverState *chr;
-    WinCharState *s;
     ChardevCommon *common = qapi_ChardevHostdev_base(opts);
 
     chr = qemu_chr_alloc(driver, common, errp);
     if (!chr) {
         return NULL;
     }
-    s = g_new0(WinCharState, 1);
-    chr->opaque = s;
 
     if (win_chr_pipe_init(chr, filename, errp) < 0) {
-        g_free(s);
         qemu_chr_free_common(chr);
         return NULL;
     }
@@ -2436,9 +2441,8 @@ static CharDriverState *qemu_chr_open_win_file(const CharDriver *driver,
     if (!chr) {
         return NULL;
     }
-    s = g_new0(WinCharState, 1);
+    s = (WinCharState *)chr;
     s->hcom = fd_out;
-    chr->opaque = s;
     return chr;
 }
 
@@ -2456,6 +2460,7 @@ static CharDriverState *qemu_chr_open_win_con(const CharDriver *driver,
 }
 
 static const CharDriver console_driver = {
+    .instance_size = sizeof(WinCharState),
     .kind = CHARDEV_BACKEND_KIND_CONSOLE,
     .create = qemu_chr_open_win_con,
     .chr_write = win_chr_write,
@@ -2483,7 +2488,7 @@ static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len)
 static void win_stdio_wait_func(void *opaque)
 {
     CharDriverState   *chr   = opaque;
-    WinStdioCharState *stdio = chr->opaque;
+    WinStdioCharState *stdio = opaque;
     INPUT_RECORD       buf[4];
     int                ret;
     DWORD              dwSize;
@@ -2516,8 +2521,7 @@ static void win_stdio_wait_func(void *opaque)
 
 static DWORD WINAPI win_stdio_thread(LPVOID param)
 {
-    CharDriverState   *chr   = param;
-    WinStdioCharState *stdio = chr->opaque;
+    WinStdioCharState *stdio = param;
     int                ret;
     DWORD              dwSize;
 
@@ -2556,7 +2560,7 @@ static DWORD WINAPI win_stdio_thread(LPVOID param)
 static void win_stdio_thread_wait_func(void *opaque)
 {
     CharDriverState   *chr   = opaque;
-    WinStdioCharState *stdio = chr->opaque;
+    WinStdioCharState *stdio = opaque;
 
     if (qemu_chr_be_can_write(chr)) {
         qemu_chr_be_write(chr, &stdio->win_stdio_buf, 1);
@@ -2567,7 +2571,7 @@ static void win_stdio_thread_wait_func(void *opaque)
 
 static void qemu_chr_set_echo_win_stdio(CharDriverState *chr, bool echo)
 {
-    WinStdioCharState *stdio  = chr->opaque;
+    WinStdioCharState *stdio  = (WinStdioCharState *)chr;
     DWORD              dwMode = 0;
 
     GetConsoleMode(stdio->hStdIn, &dwMode);
@@ -2581,7 +2585,7 @@ static void qemu_chr_set_echo_win_stdio(CharDriverState *chr, bool echo)
 
 static void win_stdio_free(CharDriverState *chr)
 {
-    WinStdioCharState *stdio = chr->opaque;
+    WinStdioCharState *stdio = (WinStdioCharState *)chr;
 
     if (stdio->hInputReadyEvent != INVALID_HANDLE_VALUE) {
         CloseHandle(stdio->hInputReadyEvent);
@@ -2592,8 +2596,6 @@ static void win_stdio_free(CharDriverState *chr)
     if (stdio->hInputThread != INVALID_HANDLE_VALUE) {
         TerminateThread(stdio->hInputThread, 0);
     }
-
-    g_free(chr->opaque);
 }
 
 static CharDriverState *qemu_chr_open_stdio(const CharDriver *driver,
@@ -2613,7 +2615,7 @@ static CharDriverState *qemu_chr_open_stdio(const CharDriver *driver,
     if (!chr) {
         return NULL;
     }
-    stdio = g_new0(WinStdioCharState, 1);
+    stdio = (WinStdioCharState *)chr;
 
     stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE);
     if (stdio->hStdIn == INVALID_HANDLE_VALUE) {
@@ -2623,8 +2625,6 @@ static CharDriverState *qemu_chr_open_stdio(const CharDriver *driver,
 
     is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0;
 
-    chr->opaque    = stdio;
-
     if (is_console) {
         if (qemu_add_wait_object(stdio->hStdIn,
                                  win_stdio_wait_func, chr)) {
@@ -2684,6 +2684,7 @@ err1:
 /* UDP Net console */
 
 typedef struct {
+    CharDriverState parent;
     QIOChannel *ioc;
     uint8_t buf[READ_BUF_LEN];
     int bufcnt;
@@ -2694,7 +2695,7 @@ typedef struct {
 /* Called with chr_write_lock held.  */
 static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
-    NetCharDriver *s = chr->opaque;
+    NetCharDriver *s = (NetCharDriver *)chr;
 
     return qio_channel_write(
         s->ioc, (const char *)buf, len, NULL);
@@ -2703,7 +2704,7 @@ static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 static int udp_chr_read_poll(void *opaque)
 {
     CharDriverState *chr = opaque;
-    NetCharDriver *s = chr->opaque;
+    NetCharDriver *s = opaque;
 
     s->max_size = qemu_chr_be_can_write(chr);
 
@@ -2721,7 +2722,7 @@ static int udp_chr_read_poll(void *opaque)
 static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 {
     CharDriverState *chr = opaque;
-    NetCharDriver *s = chr->opaque;
+    NetCharDriver *s = opaque;
     ssize_t ret;
 
     if (s->max_size == 0) {
@@ -2748,7 +2749,7 @@ static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 static void udp_chr_update_read_handler(CharDriverState *chr,
                                         GMainContext *context)
 {
-    NetCharDriver *s = chr->opaque;
+    NetCharDriver *s = (NetCharDriver *)chr;
 
     remove_fd_in_watch(chr);
     if (s->ioc) {
@@ -2761,13 +2762,12 @@ static void udp_chr_update_read_handler(CharDriverState *chr,
 
 static void udp_chr_free(CharDriverState *chr)
 {
-    NetCharDriver *s = chr->opaque;
+    NetCharDriver *s = (NetCharDriver *)chr;
 
     remove_fd_in_watch(chr);
     if (s->ioc) {
         object_unref(OBJECT(s->ioc));
     }
-    g_free(s);
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
@@ -2775,6 +2775,7 @@ static void udp_chr_free(CharDriverState *chr)
 /* TCP Net console */
 
 typedef struct {
+    CharDriverState parent;
     QIOChannel *ioc; /* Client I/O channel */
     QIOChannelSocket *sioc; /* Client master channel */
     QIOChannelSocket *listen_ioc;
@@ -2803,8 +2804,9 @@ static gboolean socket_reconnect_timeout(gpointer opaque);
 
 static void qemu_chr_socket_restart_timer(CharDriverState *chr)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
     char *name;
+
     assert(s->connected == 0);
     s->reconnect_timer = g_timeout_add_seconds(s->reconnect_time,
                                                socket_reconnect_timeout, chr);
@@ -2816,7 +2818,7 @@ static void qemu_chr_socket_restart_timer(CharDriverState *chr)
 static void check_report_connect_error(CharDriverState *chr,
                                        Error *err)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
 
     if (!s->connect_err_reported) {
         error_report("Unable to connect character device %s: %s",
@@ -2833,7 +2835,8 @@ static gboolean tcp_chr_accept(QIOChannel *chan,
 /* Called with chr_write_lock held.  */
 static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
+
     if (s->connected) {
         int ret =  io_channel_send_full(s->ioc, buf, len,
                                         s->write_msgfds,
@@ -2856,7 +2859,7 @@ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 static int tcp_chr_read_poll(void *opaque)
 {
     CharDriverState *chr = opaque;
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = opaque;
     if (!s->connected)
         return 0;
     s->max_size = qemu_chr_be_can_write(chr);
@@ -2915,7 +2918,8 @@ static void tcp_chr_process_IAC_bytes(CharDriverState *chr,
 
 static int tcp_get_msgfds(CharDriverState *chr, int *fds, int num)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
+
     int to_copy = (s->read_msgfds_num < num) ? s->read_msgfds_num : num;
 
     assert(num <= TCP_MAX_FDS);
@@ -2940,7 +2944,7 @@ static int tcp_get_msgfds(CharDriverState *chr, int *fds, int num)
 
 static int tcp_set_msgfds(CharDriverState *chr, int *fds, int num)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
 
     /* clear old pending fd array */
     g_free(s->write_msgfds);
@@ -2965,7 +2969,7 @@ static int tcp_set_msgfds(CharDriverState *chr, int *fds, int num)
 
 static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
     struct iovec iov = { .iov_base = buf, .iov_len = len };
     int ret;
     size_t i;
@@ -3022,13 +3026,13 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
 
 static GSource *tcp_chr_add_watch(CharDriverState *chr, GIOCondition cond)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
     return qio_channel_create_watch(s->ioc, cond);
 }
 
 static void tcp_chr_free_connection(CharDriverState *chr)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
     int i;
 
     if (!s->connected) {
@@ -3057,7 +3061,7 @@ static void tcp_chr_free_connection(CharDriverState *chr)
 
 static void tcp_chr_disconnect(CharDriverState *chr)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
 
     if (!s->connected) {
         return;
@@ -3080,7 +3084,7 @@ static void tcp_chr_disconnect(CharDriverState *chr)
 static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 {
     CharDriverState *chr = opaque;
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = opaque;
     uint8_t buf[READ_BUF_LEN];
     int len, size;
 
@@ -3106,7 +3110,7 @@ static gboolean tcp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 
 static int tcp_chr_sync_read(CharDriverState *chr, const uint8_t *buf, int len)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
     int size;
 
     if (!s->connected) {
@@ -3125,7 +3129,7 @@ static int tcp_chr_sync_read(CharDriverState *chr, const uint8_t *buf, int len)
 static void tcp_chr_connect(void *opaque)
 {
     CharDriverState *chr = opaque;
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = opaque;
 
     g_free(chr->filename);
     chr->filename = sockaddr_to_str(
@@ -3146,7 +3150,7 @@ static void tcp_chr_connect(void *opaque)
 static void tcp_chr_update_read_handler(CharDriverState *chr,
                                         GMainContext *context)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
 
     if (!s->connected) {
         return;
@@ -3197,7 +3201,7 @@ static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
 
 static void tcp_chr_telnet_init(CharDriverState *chr)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
     TCPCharDriverTelnetInit *init =
         g_new0(TCPCharDriverTelnetInit, 1);
     size_t n = 0;
@@ -3232,7 +3236,7 @@ static void tcp_chr_tls_handshake(QIOTask *task,
                                   gpointer user_data)
 {
     CharDriverState *chr = user_data;
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = user_data;
 
     if (qio_task_propagate_error(task, NULL)) {
         tcp_chr_disconnect(chr);
@@ -3248,7 +3252,7 @@ static void tcp_chr_tls_handshake(QIOTask *task,
 
 static void tcp_chr_tls_init(CharDriverState *chr)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
     QIOChannelTLS *tioc;
     Error *err = NULL;
     gchar *name;
@@ -3287,7 +3291,7 @@ static void tcp_chr_tls_init(CharDriverState *chr)
 static void tcp_chr_set_client_ioc_name(CharDriverState *chr,
                                         QIOChannelSocket *sioc)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
     char *name;
     name = g_strdup_printf("chardev-tcp-%s-%s",
                            s->is_listen ? "server" : "client",
@@ -3299,7 +3303,8 @@ static void tcp_chr_set_client_ioc_name(CharDriverState *chr,
 
 static int tcp_chr_new_client(CharDriverState *chr, QIOChannelSocket *sioc)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
+
     if (s->ioc != NULL) {
 	return -1;
     }
@@ -3370,7 +3375,7 @@ static gboolean tcp_chr_accept(QIOChannel *channel,
 
 static int tcp_chr_wait_connected(CharDriverState *chr, Error **errp)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
     QIOChannelSocket *sioc;
 
     /* It can't wait on s->connected, since it is set asynchronously
@@ -3418,7 +3423,7 @@ int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp)
 
 static void tcp_chr_free(CharDriverState *chr)
 {
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
 
     tcp_chr_free_connection(chr);
 
@@ -3437,7 +3442,7 @@ static void tcp_chr_free(CharDriverState *chr)
     if (s->tls_creds) {
         object_unref(OBJECT(s->tls_creds));
     }
-    g_free(s);
+
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
@@ -3446,7 +3451,7 @@ static void qemu_chr_socket_connected(QIOTask *task, void *opaque)
 {
     QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
     CharDriverState *chr = opaque;
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = (TCPCharDriver *)chr;
     Error *err = NULL;
 
     if (qio_task_propagate_error(task, &err)) {
@@ -3467,6 +3472,7 @@ static void qemu_chr_socket_connected(QIOTask *task, void *opaque)
 /* Ring buffer chardev */
 
 typedef struct {
+    CharDriverState parent;
     size_t size;
     size_t prod;
     size_t cons;
@@ -3475,7 +3481,7 @@ typedef struct {
 
 static size_t ringbuf_count(const CharDriverState *chr)
 {
-    const RingBufCharDriver *d = chr->opaque;
+    const RingBufCharDriver *d = (RingBufCharDriver *)chr;
 
     return d->prod - d->cons;
 }
@@ -3483,7 +3489,7 @@ static size_t ringbuf_count(const CharDriverState *chr)
 /* Called with chr_write_lock held.  */
 static int ringbuf_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
-    RingBufCharDriver *d = chr->opaque;
+    RingBufCharDriver *d = (RingBufCharDriver *)chr;
     int i;
 
     if (!buf || (len < 0)) {
@@ -3502,7 +3508,7 @@ static int ringbuf_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 
 static int ringbuf_chr_read(CharDriverState *chr, uint8_t *buf, int len)
 {
-    RingBufCharDriver *d = chr->opaque;
+    RingBufCharDriver *d = (RingBufCharDriver *)chr;
     int i;
 
     qemu_mutex_lock(&chr->chr_write_lock);
@@ -3516,11 +3522,9 @@ static int ringbuf_chr_read(CharDriverState *chr, uint8_t *buf, int len)
 
 static void ringbuf_chr_free(struct CharDriverState *chr)
 {
-    RingBufCharDriver *d = chr->opaque;
+    RingBufCharDriver *d = (RingBufCharDriver *)chr;
 
     g_free(d->cbuf);
-    g_free(d);
-    chr->opaque = NULL;
 }
 
 static CharDriverState *qemu_chr_open_ringbuf(const CharDriver *driver,
@@ -3539,7 +3543,7 @@ static CharDriverState *qemu_chr_open_ringbuf(const CharDriver *driver,
     if (!chr) {
         return NULL;
     }
-    d = g_malloc(sizeof(*d));
+    d = (RingBufCharDriver *)chr;
 
     d->size = opts->has_size ? opts->size : 65536;
 
@@ -3553,12 +3557,9 @@ static CharDriverState *qemu_chr_open_ringbuf(const CharDriver *driver,
     d->cons = 0;
     d->cbuf = g_malloc0(d->size);
 
-    chr->opaque = d;
-
     return chr;
 
 fail:
-    g_free(d);
     qemu_chr_free_common(chr);
     return NULL;
 }
@@ -3849,10 +3850,12 @@ static const CharDriver stdio_driver = {
     .parse = qemu_chr_parse_stdio,
     .create = qemu_chr_open_stdio,
 #ifdef _WIN32
+    sizeof(WinStdioCharState),
     .chr_write = win_stdio_write,
     .chr_set_echo = qemu_chr_set_echo_win_stdio,
     .chr_free = win_stdio_free,
 #else
+    sizeof(FDCharDriver),
     .chr_add_watch = fd_chr_add_watch,
     .chr_write = fd_chr_write,
     .chr_update_read_handler = fd_chr_update_read_handler,
@@ -3915,9 +3918,11 @@ static const CharDriver pipe_driver = {
     .parse = qemu_chr_parse_pipe,
     .create = qemu_chr_open_pipe,
 #ifdef _WIN32
+    sizeof(WinCharState),
     .chr_write = win_chr_write,
     .chr_free = win_chr_free,
 #else
+    sizeof(FDCharDriver),
     .chr_add_watch = fd_chr_add_watch,
     .chr_write = fd_chr_write,
     .chr_update_read_handler = fd_chr_update_read_handler,
@@ -3942,6 +3947,7 @@ static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
 }
 
 static const CharDriver ringbuf_driver = {
+    .instance_size = sizeof(RingBufCharDriver),
     .kind = CHARDEV_BACKEND_KIND_RINGBUF,
     .parse = qemu_chr_parse_ringbuf,
     .create = qemu_chr_open_ringbuf,
@@ -3951,6 +3957,7 @@ static const CharDriver ringbuf_driver = {
 
 /* Bug-compatibility: */
 static const CharDriver memory_driver = {
+    .instance_size = sizeof(RingBufCharDriver),
     .kind = CHARDEV_BACKEND_KIND_MEMORY,
     .parse = qemu_chr_parse_ringbuf,
     .create = qemu_chr_open_ringbuf,
@@ -3974,6 +3981,7 @@ static void qemu_chr_parse_mux(QemuOpts *opts, ChardevBackend *backend,
 }
 
 static const CharDriver mux_driver = {
+    .instance_size = sizeof(MuxDriver),
     .kind = CHARDEV_BACKEND_KIND_MUX,
     .parse = qemu_chr_parse_mux,
     .create = qemu_chr_open_mux,
@@ -4558,17 +4566,13 @@ static CharDriverState *qmp_chardev_open_serial(const CharDriver *driver,
     ChardevHostdev *serial = backend->u.serial.data;
     ChardevCommon *common = qapi_ChardevHostdev_base(serial);
     CharDriverState *chr;
-    WinCharState *s;
 
     chr = qemu_chr_alloc(driver, common, errp);
     if (!chr) {
         return NULL;
     }
 
-    s = g_new0(WinCharState, 1);
-    chr->opaque = s;
     if (win_chr_init(chr, serial->device, errp) < 0) {
-        g_free(s);
         qemu_chr_free_common(chr);
         return NULL;
     }
@@ -4668,6 +4672,7 @@ static CharDriverState *qmp_chardev_open_parallel(const CharDriver *driver,
 }
 
 static const CharDriver parallel_driver = {
+    .instance_size = sizeof(ParallelCharDriver),
     .kind = CHARDEV_BACKEND_KIND_PARALLEL,
     .alias = "parport",
     .parse = qemu_chr_parse_parallel,
@@ -4691,9 +4696,11 @@ static const CharDriver file_driver = {
     .parse = qemu_chr_parse_file_out,
     .create = qmp_chardev_open_file,
 #ifdef _WIN32
+    sizeof(WinCharState),
     .chr_write = win_chr_write,
     /* FIXME: no chr_free */
 #else
+    sizeof(FDCharDriver),
     .chr_add_watch = fd_chr_add_watch,
     .chr_write = fd_chr_write,
     .chr_update_read_handler = fd_chr_update_read_handler,
@@ -4708,9 +4715,11 @@ static const CharDriver serial_driver = {
     .parse = qemu_chr_parse_serial,
     .create = qmp_chardev_open_serial,
 #ifdef _WIN32
+    sizeof(WinCharState),
     .chr_write = win_chr_write,
     .chr_free = win_chr_free,
 #else
+    sizeof(FDCharDriver),
     .chr_add_watch = fd_chr_add_watch,
     .chr_write = fd_chr_write,
     .chr_update_read_handler = fd_chr_update_read_handler,
@@ -4723,7 +4732,7 @@ static const CharDriver serial_driver = {
 static gboolean socket_reconnect_timeout(gpointer opaque)
 {
     CharDriverState *chr = opaque;
-    TCPCharDriver *s = chr->opaque;
+    TCPCharDriver *s = opaque;
     QIOChannelSocket *sioc;
 
     s->reconnect_timer = 0;
@@ -4764,7 +4773,7 @@ static CharDriverState *qmp_chardev_open_socket(const CharDriver *driver,
     if (!chr) {
         return NULL;
     }
-    s = g_new0(TCPCharDriver, 1);
+    s = (TCPCharDriver *)chr;
 
     s->is_unix = addr->type == SOCKET_ADDRESS_KIND_UNIX;
     s->is_listen = is_listen;
@@ -4810,7 +4819,6 @@ static CharDriverState *qmp_chardev_open_socket(const CharDriver *driver,
         qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_FD_PASS);
     }
 
-    chr->opaque = s;
     /* be isn't opened until we get a connection */
     *be_opened = false;
 
@@ -4867,12 +4875,12 @@ static CharDriverState *qmp_chardev_open_socket(const CharDriver *driver,
     if (s->tls_creds) {
         object_unref(OBJECT(s->tls_creds));
     }
-    g_free(s);
     qemu_chr_free_common(chr);
     return NULL;
 }
 
 static const CharDriver socket_driver = {
+    .instance_size = sizeof(TCPCharDriver),
     .kind = CHARDEV_BACKEND_KIND_SOCKET,
     .parse = qemu_chr_parse_socket,
     .create = qmp_chardev_open_socket,
@@ -4918,9 +4926,8 @@ static CharDriverState *qmp_chardev_open_udp(const CharDriver *driver,
     qio_channel_set_name(QIO_CHANNEL(sioc), name);
     g_free(name);
 
-    s = g_new0(NetCharDriver, 1);
+    s = (NetCharDriver *)chr;
     s->ioc = QIO_CHANNEL(sioc);
-    chr->opaque = s;
     /* be isn't opened until we get a connection */
     *be_opened = false;
 
@@ -4928,6 +4935,7 @@ static CharDriverState *qmp_chardev_open_udp(const CharDriver *driver,
 }
 
 static const CharDriver udp_driver = {
+    .instance_size = sizeof(NetCharDriver),
     .kind = CHARDEV_BACKEND_KIND_UDP,
     .parse = qemu_chr_parse_udp,
     .create = qmp_chardev_open_udp,