All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24
@ 2016-10-24 13:46 Paolo Bonzini
  2016-10-24 13:46 ` [Qemu-devel] [PULL 01/50] kvm-all: don't use stale dbg_data->cpu Paolo Bonzini
                   ` (50 more replies)
  0 siblings, 51 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:46 UTC (permalink / raw)
  To: qemu-devel

The following changes since commit b49e452fe994f8fbcd22bf5a87b79a2355481318:

  Merge remote-tracking branch 'remotes/riku/tags/pull-linux-user-20160921' into staging (2016-10-21 13:49:58 +0100)

are available in the git repository at:


  git://github.com/bonzini/qemu.git tags/for-upstream

for you to fetch changes up to 8360668e6988736bf621d8f3a3bae5d9f1a30bc5:

  exec.c: workaround regression caused by alignment change in d2f39ad (2016-10-24 15:46:11 +0200)

----------------------------------------------------------------
* KVM run_on_cpu fix (Alex)
* atomic usage fixes (Emilio, me)
* hugetlbfs alignment fix (Haozhong)
* CharBackend refactoring (Marc-André)
* test-i386 fixes (me)
* MemoryListener optimizations (me)
* Miscellaneous bugfixes (me)
* iSER support (Roy)
* --version formatting (Thomas)

----------------------------------------------------------------
Alex Bennée (1):
      kvm-all: don't use stale dbg_data->cpu

Emilio G. Cota (1):
      qht-bench: relax test_start/stop atomic accesses

Haozhong Zhang (1):
      exec.c: workaround regression caused by alignment change in d2f39ad

Marc-André Lureau (30):
      char.h: misc doc fix
      rng: remove unused included header
      char: remove use-after-free on win-stdio
      ringbuf: fix chr_write return value
      sun4uv: fix serial initialization regression
      malta: replace chr init by CHR_EVENT_OPENED handler
      char: remove init callback
      mux: split mux_chr_update_read_handler()
      char: introduce CharBackend
      char: start converting mux driver to use CharBackend
      char: replace PROP_CHR with CharBackend
      char: remaining switch to CharBackend in frontend
      char: rename some frontend functions
      colo: claim in find_and_check_chardev
      char: use qemu_chr_fe* functions with CharBackend argument
      char: fold qemu_chr_set_handlers in qemu_chr_fe_set_handlers
      vhost-user: only initialize queue 0 CharBackend
      char: replace qemu_chr_claim/release with qemu_chr_fe_init/deinit
      char: make some qemu_chr_fe skip if no driver
      tests: start chardev unit tests
      char: move front end handlers in CharBackend
      char: rename chr_close/chr_free
      char: remove explicit_fe_open, use a set_handlers argument
      char: move fe_open in CharBackend
      char: remove unused CHR_EVENT_FOCUS
      char: use an enum for CHR_EVENT
      char: remove unused qemu_chr_fe_event
      char: replace avail_connections
      char: use common error path in qmp_chardev_add
      char: remove explicit_be_open from CharDriverState

Paolo Bonzini (13):
      rbd: shift byte count as a 64-bit value
      atomic: introduce smp_mb_acquire and smp_mb_release
      qemu-thread: use acquire/release to clarify semantics of QemuEvent
      rcu: simplify memory barriers
      atomic: base mb_read/mb_set on load-acquire and store-release
      test-i386: fix bitrot for 64-bit
      target-i386: fix 32-bit addresses in LEA
      tcg: try sti when moving a constant into a dead memory temp
      memory: eliminate global MemoryListeners
      memory: add a per-AddressSpace list of listeners
      memory: optimize memory_global_dirty_log_sync
      memory: optimize memory_region_sync_dirty_bitmap
      xilinx: fix buffer overflow on realize

Prasad J Pandit (1):
      char: serial: check divider value against baud base

Roy Shterman (2):
      block/iscsi: Introducing new zero-copy API
      block/iscsi: Adding new iSER transport layer option

Thomas Huth (1):
      Put the copyright information on a separate line

 backends/baum.c                   |   5 +-
 backends/msmouse.c                |   7 +-
 backends/rng-egd.c                |  29 +-
 backends/testdev.c                |   5 +-
 block/iscsi.c                     |  89 +++++-
 block/rbd.c                       |   4 +-
 bsd-user/main.c                   |   2 +-
 docs/atomics.txt                  |  84 +++---
 exec.c                            |   7 +-
 gdbstub.c                         |  31 +-
 hmp.c                             |   2 +-
 hw/alpha/dp264.c                  |   2 +-
 hw/arm/fsl-imx25.c                |   2 +-
 hw/arm/fsl-imx31.c                |   2 +-
 hw/arm/fsl-imx6.c                 |   2 +-
 hw/arm/omap2.c                    |  16 +-
 hw/arm/pxa2xx.c                   |  19 +-
 hw/arm/strongarm.c                |  22 +-
 hw/bt/hci-csr.c                   |  13 +-
 hw/char/bcm2835_aux.c             |  18 +-
 hw/char/cadence_uart.c            |  30 +-
 hw/char/debugcon.c                |   8 +-
 hw/char/digic-uart.c              |  13 +-
 hw/char/escc.c                    |  22 +-
 hw/char/etraxfs_ser.c             |  12 +-
 hw/char/exynos4210_uart.c         |  15 +-
 hw/char/grlib_apbuart.c           |  17 +-
 hw/char/imx_serial.c              |  29 +-
 hw/char/ipoctal232.c              |  23 +-
 hw/char/lm32_juart.c              |  15 +-
 hw/char/lm32_uart.c               |  17 +-
 hw/char/mcf_uart.c                |  20 +-
 hw/char/milkymist-uart.c          |  13 +-
 hw/char/omap_uart.c               |   4 +-
 hw/char/parallel.c                |  46 +--
 hw/char/pl011.c                   |  19 +-
 hw/char/sclpconsole-lm.c          |  13 +-
 hw/char/sclpconsole.c             |  12 +-
 hw/char/serial-isa.c              |   7 +-
 hw/char/serial.c                  |  39 +--
 hw/char/sh_serial.c               |  16 +-
 hw/char/spapr_vty.c               |  12 +-
 hw/char/stm32f2xx_usart.c         |  22 +-
 hw/char/virtio-console.c          |  29 +-
 hw/char/xen_console.c             |  43 ++-
 hw/char/xilinx_uartlite.c         |  16 +-
 hw/core/qdev-properties-system.c  |  80 ++---
 hw/i386/pc.c                      |   2 +-
 hw/ipmi/ipmi_bmc_extern.c         |   9 +-
 hw/isa/pc87312.c                  |   4 +-
 hw/mips/mips_fulong2e.c           |   2 +-
 hw/mips/mips_malta.c              |  44 ++-
 hw/mips/mips_r4k.c                |   2 +-
 hw/misc/ivshmem.c                 |  23 +-
 hw/sparc64/sun4u.c                |   2 +-
 hw/ssi/xilinx_spips.c             |   7 +-
 hw/usb/ccid-card-passthru.c       |  21 +-
 hw/usb/dev-serial.c               |  31 +-
 hw/usb/redirect.c                 |  22 +-
 hw/virtio/vhost-user.c            |   4 +-
 hw/xtensa/xtfpga.c                |   2 +-
 include/exec/memory.h             |   5 +-
 include/hw/char/bcm2835_aux.h     |   2 +-
 include/hw/char/cadence_uart.h    |   2 +-
 include/hw/char/digic-uart.h      |   3 +-
 include/hw/char/imx_serial.h      |   3 +-
 include/hw/char/serial.h          |   6 +-
 include/hw/char/stm32f2xx_usart.h |   2 +-
 include/hw/qdev-properties.h      |   2 +-
 include/qemu/atomic.h             | 141 ++++-----
 include/sysemu/char.h             | 230 +++++++-------
 kvm-all.c                         |   5 +-
 linux-user/main.c                 |   2 +-
 memory.c                          |  95 +++---
 monitor.c                         |  29 +-
 net/colo-compare.c                |  59 ++--
 net/filter-mirror.c               |  64 ++--
 net/slirp.c                       |  25 +-
 net/vhost-user.c                  |  49 ++-
 qemu-char.c                       | 616 +++++++++++++++++++++++---------------
 qemu-img.c                        |   2 +-
 qtest.c                           |  29 +-
 spice-qemu-char.c                 |  19 +-
 target-i386/translate.c           |  14 +-
 tcg/tcg.c                         |  56 ++--
 tests/Makefile.include            |   4 +
 tests/qht-bench.c                 |   6 +-
 tests/tcg/test-i386.c             |   4 +-
 tests/test-char.c                 | 253 ++++++++++++++++
 tests/vhost-user-test.c           |  27 +-
 ui/console.c                      |  17 +-
 ui/gtk.c                          |   6 -
 util/qemu-thread-posix.c          |  15 +-
 util/qemu-thread-win32.c          |  15 +-
 util/rcu.c                        |  11 +-
 vl.c                              |  15 +-
 96 files changed, 1735 insertions(+), 1226 deletions(-)
 create mode 100644 tests/test-char.c
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 01/50] kvm-all: don't use stale dbg_data->cpu
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
@ 2016-10-24 13:46 ` Paolo Bonzini
  2016-10-24 13:46 ` [Qemu-devel] [PULL 02/50] rbd: shift byte count as a 64-bit value Paolo Bonzini
                   ` (49 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alex Bennée

From: Alex Bennée <alex.bennee@linaro.org>

The changes to run_on_cpu and friends mean that all helpers are passed
the CPUState of vCPU they are running on. The conversion missed the
field in commit e0eeb4a21a3ca4b296220ce4449d8acef9de9049 which
introduced bugs.

Reported-by: Claudio Imbrenda <imbrenda@linux.vnet.ibm.com>
Tested-by: Claudio Imbrenda <imbrenda@linux.vnet.ibm.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20161010154625.14881-1-alex.bennee@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 kvm-all.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/kvm-all.c b/kvm-all.c
index efb5fe3..3dcce16 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -2215,15 +2215,14 @@ int kvm_sw_breakpoints_active(CPUState *cpu)
 
 struct kvm_set_guest_debug_data {
     struct kvm_guest_debug dbg;
-    CPUState *cpu;
     int err;
 };
 
-static void kvm_invoke_set_guest_debug(CPUState *unused_cpu, void *data)
+static void kvm_invoke_set_guest_debug(CPUState *cpu, void *data)
 {
     struct kvm_set_guest_debug_data *dbg_data = data;
 
-    dbg_data->err = kvm_vcpu_ioctl(dbg_data->cpu, KVM_SET_GUEST_DEBUG,
+    dbg_data->err = kvm_vcpu_ioctl(cpu, KVM_SET_GUEST_DEBUG,
                                    &dbg_data->dbg);
 }
 
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 02/50] rbd: shift byte count as a 64-bit value
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
  2016-10-24 13:46 ` [Qemu-devel] [PULL 01/50] kvm-all: don't use stale dbg_data->cpu Paolo Bonzini
@ 2016-10-24 13:46 ` Paolo Bonzini
  2016-10-24 13:46 ` [Qemu-devel] [PULL 03/50] block/iscsi: Introducing new zero-copy API Paolo Bonzini
                   ` (48 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, kwolf, eblake

Otherwise, reads of more than 2GB fail.  Until commit
7bbca9e290a9c7c217b5a24fc6094e91e54bd05d, reads of 2^41
bytes succeeded at least theoretically.

In fact, pdiscard ought to receive a 64-bit integer as the
count for the same reason.

Reported by Coverity.

Fixes: 7bbca9e290a9c7c217b5a24fc6094e91e54bd05d
Cc: qemu-stable@nongnu.org
Cc: kwolf@redhat.com
Cc: eblake@redhat.com
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 block/rbd.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index 6f9eb6f..f6e1d4b 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -733,7 +733,7 @@ static BlockAIOCB *qemu_rbd_aio_readv(BlockDriverState *bs,
                                       void *opaque)
 {
     return rbd_start_aio(bs, sector_num << BDRV_SECTOR_BITS, qiov,
-                         nb_sectors << BDRV_SECTOR_BITS, cb, opaque,
+                         (int64_t) nb_sectors << BDRV_SECTOR_BITS, cb, opaque,
                          RBD_AIO_READ);
 }
 
@@ -745,7 +745,7 @@ static BlockAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
                                        void *opaque)
 {
     return rbd_start_aio(bs, sector_num << BDRV_SECTOR_BITS, qiov,
-                         nb_sectors << BDRV_SECTOR_BITS, cb, opaque,
+                         (int64_t) nb_sectors << BDRV_SECTOR_BITS, cb, opaque,
                          RBD_AIO_WRITE);
 }
 
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 03/50] block/iscsi: Introducing new zero-copy API
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
  2016-10-24 13:46 ` [Qemu-devel] [PULL 01/50] kvm-all: don't use stale dbg_data->cpu Paolo Bonzini
  2016-10-24 13:46 ` [Qemu-devel] [PULL 02/50] rbd: shift byte count as a 64-bit value Paolo Bonzini
@ 2016-10-24 13:46 ` Paolo Bonzini
  2016-10-24 13:46 ` [Qemu-devel] [PULL 04/50] block/iscsi: Adding new iSER transport layer option Paolo Bonzini
                   ` (47 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Roy Shterman

From: Roy Shterman <roysh@mellanox.com>

A new API to deploy zero-copy command submission. The new API takes I/O
vectors list and number of I/O vectors to submit as input parameters
when initiating the command. New API must be used if working with
iSER transport option.

Signed-off-by: Roy Shterman <roysh@mellanox.com>
Message-Id: <1476000896-18632-2-git-send-email-roysh@mellanox.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 block/iscsi.c | 42 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 40 insertions(+), 2 deletions(-)

diff --git a/block/iscsi.c b/block/iscsi.c
index 46ddc35..e9bf5db 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -202,6 +202,10 @@ static inline unsigned exp_random(double mean)
 #define SCSI_SENSE_ASCQ_PARAMETER_LIST_LENGTH_ERROR        0x1a00
 #endif
 
+#ifndef LIBISCSI_API_VERSION
+#define LIBISCSI_API_VERSION 20130701
+#endif
+
 static int iscsi_translate_sense(struct scsi_sense *sense)
 {
     int ret;
@@ -592,6 +596,20 @@ iscsi_co_writev_flags(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
     iscsi_co_init_iscsitask(iscsilun, &iTask);
 retry:
     if (iscsilun->use_16_for_rw) {
+#if LIBISCSI_API_VERSION >= (20160603)
+        iTask.task = iscsi_write16_iov_task(iscsilun->iscsi, iscsilun->lun, lba,
+                                            NULL, num_sectors * iscsilun->block_size,
+                                            iscsilun->block_size, 0, 0, fua, 0, 0,
+                                            iscsi_co_generic_cb, &iTask,
+                                            (struct scsi_iovec *)iov->iov, iov->niov);
+    } else {
+        iTask.task = iscsi_write10_iov_task(iscsilun->iscsi, iscsilun->lun, lba,
+                                            NULL, num_sectors * iscsilun->block_size,
+                                            iscsilun->block_size, 0, 0, fua, 0, 0,
+                                            iscsi_co_generic_cb, &iTask,
+                                            (struct scsi_iovec *)iov->iov, iov->niov);
+    }
+#else
         iTask.task = iscsi_write16_task(iscsilun->iscsi, iscsilun->lun, lba,
                                         NULL, num_sectors * iscsilun->block_size,
                                         iscsilun->block_size, 0, 0, fua, 0, 0,
@@ -602,11 +620,14 @@ retry:
                                         iscsilun->block_size, 0, 0, fua, 0, 0,
                                         iscsi_co_generic_cb, &iTask);
     }
+#endif
     if (iTask.task == NULL) {
         return -ENOMEM;
     }
+#if LIBISCSI_API_VERSION < (20160603)
     scsi_task_set_iov_out(iTask.task, (struct scsi_iovec *) iov->iov,
                           iov->niov);
+#endif
     while (!iTask.complete) {
         iscsi_set_events(iscsilun);
         qemu_coroutine_yield();
@@ -789,6 +810,21 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
     iscsi_co_init_iscsitask(iscsilun, &iTask);
 retry:
     if (iscsilun->use_16_for_rw) {
+#if LIBISCSI_API_VERSION >= (20160603)
+        iTask.task = iscsi_read16_iov_task(iscsilun->iscsi, iscsilun->lun, lba,
+                                           num_sectors * iscsilun->block_size,
+                                           iscsilun->block_size, 0, 0, 0, 0, 0,
+                                           iscsi_co_generic_cb, &iTask,
+                                           (struct scsi_iovec *)iov->iov, iov->niov);
+    } else {
+        iTask.task = iscsi_read10_iov_task(iscsilun->iscsi, iscsilun->lun, lba,
+                                           num_sectors * iscsilun->block_size,
+                                           iscsilun->block_size,
+                                           0, 0, 0, 0, 0,
+                                           iscsi_co_generic_cb, &iTask,
+                                           (struct scsi_iovec *)iov->iov, iov->niov);
+    }
+#else
         iTask.task = iscsi_read16_task(iscsilun->iscsi, iscsilun->lun, lba,
                                        num_sectors * iscsilun->block_size,
                                        iscsilun->block_size, 0, 0, 0, 0, 0,
@@ -800,11 +836,13 @@ retry:
                                        0, 0, 0, 0, 0,
                                        iscsi_co_generic_cb, &iTask);
     }
+#endif
     if (iTask.task == NULL) {
         return -ENOMEM;
     }
+#if LIBISCSI_API_VERSION < (20160603)
     scsi_task_set_iov_in(iTask.task, (struct scsi_iovec *) iov->iov, iov->niov);
-
+#endif
     while (!iTask.complete) {
         iscsi_set_events(iscsilun);
         qemu_coroutine_yield();
@@ -1649,7 +1687,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
 
     /* timeout handling is broken in libiscsi before 1.15.0 */
     timeout = parse_timeout(iscsi_url->target);
-#if defined(LIBISCSI_API_VERSION) && LIBISCSI_API_VERSION >= 20150621
+#if LIBISCSI_API_VERSION >= 20150621
     iscsi_set_timeout(iscsi, timeout);
 #else
     if (timeout) {
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 04/50] block/iscsi: Adding new iSER transport layer option
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (2 preceding siblings ...)
  2016-10-24 13:46 ` [Qemu-devel] [PULL 03/50] block/iscsi: Introducing new zero-copy API Paolo Bonzini
@ 2016-10-24 13:46 ` Paolo Bonzini
  2016-10-24 13:46 ` [Qemu-devel] [PULL 05/50] Put the copyright information on a separate line Paolo Bonzini
                   ` (46 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Roy Shterman

From: Roy Shterman <roysh@mellanox.com>

iSER is a new transport layer supported in Libiscsi,
iSER provides a zero-copy RDMA capable interface that can
improve performance.

In order to use the new iSER transport one need to have RDMA supported HW
and to choose iser as the protocol name in Libiscsi URI.

For now iSER memory buffers are pre-allocated and pre-registered,
hence in order to work with iSER from QEMU, one need to enable
MEMLOCK attribute in the VM to be large enough for all iSER buffers and RDMA
resources.

Signed-off-by: Roy Shterman <roysh@mellanox.com>
Message-Id: <1476000896-18632-3-git-send-email-roysh@mellanox.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 block/iscsi.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 46 insertions(+), 1 deletion(-)

diff --git a/block/iscsi.c b/block/iscsi.c
index e9bf5db..71bd523 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -1644,7 +1644,13 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
         ret = -ENOMEM;
         goto out;
     }
-
+#if LIBISCSI_API_VERSION >= (20160603)
+    if (iscsi_init_transport(iscsi, iscsi_url->transport)) {
+        error_setg(errp, ("Error initializing transport."));
+        ret = -EINVAL;
+        goto out;
+    }
+#endif
     if (iscsi_set_targetname(iscsi, iscsi_url->target)) {
         error_setg(errp, "iSCSI: Failed to set target name.");
         ret = -EINVAL;
@@ -2048,9 +2054,48 @@ static BlockDriver bdrv_iscsi = {
     .bdrv_attach_aio_context = iscsi_attach_aio_context,
 };
 
+#if LIBISCSI_API_VERSION >= (20160603)
+static BlockDriver bdrv_iser = {
+    .format_name     = "iser",
+    .protocol_name   = "iser",
+
+    .instance_size   = sizeof(IscsiLun),
+    .bdrv_needs_filename = true,
+    .bdrv_file_open  = iscsi_open,
+    .bdrv_close      = iscsi_close,
+    .bdrv_create     = iscsi_create,
+    .create_opts     = &iscsi_create_opts,
+    .bdrv_reopen_prepare   = iscsi_reopen_prepare,
+    .bdrv_reopen_commit    = iscsi_reopen_commit,
+    .bdrv_invalidate_cache = iscsi_invalidate_cache,
+
+    .bdrv_getlength  = iscsi_getlength,
+    .bdrv_get_info   = iscsi_get_info,
+    .bdrv_truncate   = iscsi_truncate,
+    .bdrv_refresh_limits = iscsi_refresh_limits,
+
+    .bdrv_co_get_block_status = iscsi_co_get_block_status,
+    .bdrv_co_pdiscard      = iscsi_co_pdiscard,
+    .bdrv_co_pwrite_zeroes = iscsi_co_pwrite_zeroes,
+    .bdrv_co_readv         = iscsi_co_readv,
+    .bdrv_co_writev_flags  = iscsi_co_writev_flags,
+    .bdrv_co_flush_to_disk = iscsi_co_flush,
+
+#ifdef __linux__
+    .bdrv_aio_ioctl   = iscsi_aio_ioctl,
+#endif
+
+    .bdrv_detach_aio_context = iscsi_detach_aio_context,
+    .bdrv_attach_aio_context = iscsi_attach_aio_context,
+};
+#endif
+
 static void iscsi_block_init(void)
 {
     bdrv_register(&bdrv_iscsi);
+#if LIBISCSI_API_VERSION >= (20160603)
+    bdrv_register(&bdrv_iser);
+#endif
 }
 
 block_init(iscsi_block_init);
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 05/50] Put the copyright information on a separate line
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (3 preceding siblings ...)
  2016-10-24 13:46 ` [Qemu-devel] [PULL 04/50] block/iscsi: Adding new iSER transport layer option Paolo Bonzini
@ 2016-10-24 13:46 ` Paolo Bonzini
  2016-10-24 13:46 ` [Qemu-devel] [PULL 06/50] atomic: introduce smp_mb_acquire and smp_mb_release Paolo Bonzini
                   ` (45 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Thomas Huth

From: Thomas Huth <thuth@redhat.com>

The output string QEMU with "--version" is very long, it does
not fit into a normal line of a terminal window anymore. By
putting the copyright information on a separate line instead,
the output looks much nicer.

Signed-off-by: Thomas Huth <thuth@redhat.com>
Message-Id: <1475661284-30153-1-git-send-email-thuth@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 bsd-user/main.c   | 2 +-
 linux-user/main.c | 2 +-
 qemu-img.c        | 2 +-
 vl.c              | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/bsd-user/main.c b/bsd-user/main.c
index 4fd7b63..714a692 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -651,7 +651,7 @@ void cpu_loop(CPUSPARCState *env)
 static void usage(void)
 {
     printf("qemu-" TARGET_NAME " version " QEMU_VERSION QEMU_PKGVERSION
-           ", " QEMU_COPYRIGHT "\n"
+           "\n" QEMU_COPYRIGHT "\n"
            "usage: qemu-" TARGET_NAME " [options] program [arguments...]\n"
            "BSD CPU emulator (compiled for %s emulation)\n"
            "\n"
diff --git a/linux-user/main.c b/linux-user/main.c
index 18d5a62..c6f2e20 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -3956,7 +3956,7 @@ static void handle_arg_strace(const char *arg)
 static void handle_arg_version(const char *arg)
 {
     printf("qemu-" TARGET_NAME " version " QEMU_VERSION QEMU_PKGVERSION
-           ", " QEMU_COPYRIGHT "\n");
+           "\n" QEMU_COPYRIGHT "\n");
     exit(EXIT_SUCCESS);
 }
 
diff --git a/qemu-img.c b/qemu-img.c
index 02c07b9..67e8512 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -44,7 +44,7 @@
 #include <getopt.h>
 
 #define QEMU_IMG_VERSION "qemu-img version " QEMU_VERSION QEMU_PKGVERSION \
-                          ", " QEMU_COPYRIGHT "\n"
+                          "\n" QEMU_COPYRIGHT "\n"
 
 typedef struct img_cmd_t {
     const char *name;
diff --git a/vl.c b/vl.c
index ebd47af..2e152ac 100644
--- a/vl.c
+++ b/vl.c
@@ -1958,7 +1958,7 @@ static void main_loop(void)
 
 static void version(void)
 {
-    printf("QEMU emulator version " QEMU_VERSION QEMU_PKGVERSION ", "
+    printf("QEMU emulator version " QEMU_VERSION QEMU_PKGVERSION "\n"
            QEMU_COPYRIGHT "\n");
 }
 
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 06/50] atomic: introduce smp_mb_acquire and smp_mb_release
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (4 preceding siblings ...)
  2016-10-24 13:46 ` [Qemu-devel] [PULL 05/50] Put the copyright information on a separate line Paolo Bonzini
@ 2016-10-24 13:46 ` Paolo Bonzini
  2016-10-24 13:46 ` [Qemu-devel] [PULL 07/50] qemu-thread: use acquire/release to clarify semantics of QemuEvent Paolo Bonzini
                   ` (44 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:46 UTC (permalink / raw)
  To: qemu-devel

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 docs/atomics.txt      | 79 ++++++++++++++++++++++++++++++---------------------
 include/qemu/atomic.h | 50 +++++++++++++++++++-------------
 2 files changed, 77 insertions(+), 52 deletions(-)

diff --git a/docs/atomics.txt b/docs/atomics.txt
index c95950b..c8e4cbe 100644
--- a/docs/atomics.txt
+++ b/docs/atomics.txt
@@ -15,7 +15,8 @@ Macros defined by qemu/atomic.h fall in three camps:
 - compiler barriers: barrier();
 
 - weak atomic access and manual memory barriers: atomic_read(),
-  atomic_set(), smp_rmb(), smp_wmb(), smp_mb(), smp_read_barrier_depends();
+  atomic_set(), smp_rmb(), smp_wmb(), smp_mb(), smp_mb_acquire(),
+  smp_mb_release(), smp_read_barrier_depends();
 
 - sequentially consistent atomic access: everything else.
 
@@ -111,8 +112,8 @@ consistent primitives.
 
 When using this model, variables are accessed with atomic_read() and
 atomic_set(), and restrictions to the ordering of accesses is enforced
-using the smp_rmb(), smp_wmb(), smp_mb() and smp_read_barrier_depends()
-memory barriers.
+using the memory barrier macros: smp_rmb(), smp_wmb(), smp_mb(),
+smp_mb_acquire(), smp_mb_release(), smp_read_barrier_depends().
 
 atomic_read() and atomic_set() prevents the compiler from using
 optimizations that might otherwise optimize accesses out of existence
@@ -124,7 +125,7 @@ other threads, and which are local to the current thread or protected
 by other, more mundane means.
 
 Memory barriers control the order of references to shared memory.
-They come in four kinds:
+They come in six kinds:
 
 - smp_rmb() guarantees that all the LOAD operations specified before
   the barrier will appear to happen before all the LOAD operations
@@ -142,6 +143,16 @@ They come in four kinds:
   In other words, smp_wmb() puts a partial ordering on stores, but is not
   required to have any effect on loads.
 
+- smp_mb_acquire() guarantees that all the LOAD operations specified before
+  the barrier will appear to happen before all the LOAD or STORE operations
+  specified after the barrier with respect to the other components of
+  the system.
+
+- smp_mb_release() guarantees that all the STORE operations specified *after*
+  the barrier will appear to happen after all the LOAD or STORE operations
+  specified *before* the barrier with respect to the other components of
+  the system.
+
 - smp_mb() guarantees that all the LOAD and STORE operations specified
   before the barrier will appear to happen before all the LOAD and
   STORE operations specified after the barrier with respect to the other
@@ -149,8 +160,9 @@ They come in four kinds:
 
   smp_mb() puts a partial ordering on both loads and stores.  It is
   stronger than both a read and a write memory barrier; it implies both
-  smp_rmb() and smp_wmb(), but it also prevents STOREs coming before the
-  barrier from overtaking LOADs coming after the barrier and vice versa.
+  smp_mb_acquire() and smp_mb_release(), but it also prevents STOREs
+  coming before the barrier from overtaking LOADs coming after the
+  barrier and vice versa.
 
 - smp_read_barrier_depends() is a weaker kind of read barrier.  On
   most processors, whenever two loads are performed such that the
@@ -173,24 +185,21 @@ They come in four kinds:
 This is the set of barriers that is required *between* two atomic_read()
 and atomic_set() operations to achieve sequential consistency:
 
-                    |               2nd operation             |
-                    |-----------------------------------------|
-     1st operation  | (after last) | atomic_read | atomic_set |
-     ---------------+--------------+-------------+------------|
-     (before first) |              | none        | smp_wmb()  |
-     ---------------+--------------+-------------+------------|
-     atomic_read    | smp_rmb()    | smp_rmb()*  | **         |
-     ---------------+--------------+-------------+------------|
-     atomic_set     | none         | smp_mb()*** | smp_wmb()  |
-     ---------------+--------------+-------------+------------|
+                    |               2nd operation                   |
+                    |-----------------------------------------------|
+     1st operation  | (after last)   | atomic_read | atomic_set     |
+     ---------------+----------------+-------------+----------------|
+     (before first) |                | none        | smp_mb_release |
+     ---------------+----------------+-------------+----------------|
+     atomic_read    | smp_mb_acquire | smp_rmb     | **             |
+     ---------------+----------------+-------------+----------------|
+     atomic_set     | none           | smp_mb()*** | smp_wmb()      |
+     ---------------+----------------+-------------+----------------|
 
        * Or smp_read_barrier_depends().
 
-      ** This requires a load-store barrier.  How to achieve this varies
-         depending on the machine, but in practice smp_rmb()+smp_wmb()
-         should have the desired effect.  For example, on PowerPC the
-         lwsync instruction is a combined load-load, load-store and
-         store-store barrier.
+      ** This requires a load-store barrier.  This is achieved by
+         either smp_mb_acquire() or smp_mb_release().
 
      *** This requires a store-load barrier.  On most machines, the only
          way to achieve this is a full barrier.
@@ -199,11 +208,11 @@ and atomic_set() operations to achieve sequential consistency:
 You can see that the two possible definitions of atomic_mb_read()
 and atomic_mb_set() are the following:
 
-    1) atomic_mb_read(p)   = atomic_read(p); smp_rmb()
-       atomic_mb_set(p, v) = smp_wmb(); atomic_set(p, v); smp_mb()
+    1) atomic_mb_read(p)   = atomic_read(p); smp_mb_acquire()
+       atomic_mb_set(p, v) = smp_mb_release(); atomic_set(p, v); smp_mb()
 
-    2) atomic_mb_read(p)   = smp_mb() atomic_read(p); smp_rmb()
-       atomic_mb_set(p, v) = smp_wmb(); atomic_set(p, v);
+    2) atomic_mb_read(p)   = smp_mb() atomic_read(p); smp_mb_acquire()
+       atomic_mb_set(p, v) = smp_mb_release(); atomic_set(p, v);
 
 Usually the former is used, because smp_mb() is expensive and a program
 normally has more reads than writes.  Therefore it makes more sense to
@@ -222,7 +231,7 @@ place barriers instead:
      thread 1                                thread 1
      -------------------------               ------------------------
      (other writes)
-                                             smp_wmb()
+                                             smp_mb_release()
      atomic_mb_set(&a, x)                    atomic_set(&a, x)
                                              smp_wmb()
      atomic_mb_set(&b, y)                    atomic_set(&b, y)
@@ -233,7 +242,13 @@ place barriers instead:
      y = atomic_mb_read(&b)                  y = atomic_read(&b)
                                              smp_rmb()
      x = atomic_mb_read(&a)                  x = atomic_read(&a)
-                                             smp_rmb()
+                                             smp_mb_acquire()
+
+  Note that the barrier between the stores in thread 1, and between
+  the loads in thread 2, has been optimized here to a write or a
+  read memory barrier respectively.  On some architectures, notably
+  ARMv7, smp_mb_acquire and smp_mb_release are just as expensive as
+  smp_mb, but smp_rmb and/or smp_wmb are more efficient.
 
 - sometimes, a thread is accessing many variables that are otherwise
   unrelated to each other (for example because, apart from the current
@@ -246,12 +261,12 @@ place barriers instead:
      n = 0;                                  n = 0;
      for (i = 0; i < 10; i++)          =>    for (i = 0; i < 10; i++)
        n += atomic_mb_read(&a[i]);             n += atomic_read(&a[i]);
-                                             smp_rmb();
+                                             smp_mb_acquire();
 
   Similarly, atomic_mb_set() can be transformed as follows:
   smp_mb():
 
-                                             smp_wmb();
+                                             smp_mb_release();
      for (i = 0; i < 10; i++)          =>    for (i = 0; i < 10; i++)
        atomic_mb_set(&a[i], false);            atomic_set(&a[i], false);
                                              smp_mb();
@@ -261,7 +276,7 @@ The two tricks can be combined.  In this case, splitting a loop in
 two lets you hoist the barriers out of the loops _and_ eliminate the
 expensive smp_mb():
 
-                                             smp_wmb();
+                                             smp_mb_release();
      for (i = 0; i < 10; i++) {        =>    for (i = 0; i < 10; i++)
        atomic_mb_set(&a[i], false);            atomic_set(&a[i], false);
        atomic_mb_set(&b[i], false);          smb_wmb();
@@ -312,8 +327,8 @@ access and for data dependency barriers:
                              smp_read_barrier_depends();
                              z = b[y];
 
-smp_wmb() also pairs with atomic_mb_read(), and smp_rmb() also pairs
-with atomic_mb_set().
+smp_wmb() also pairs with atomic_mb_read() and smp_mb_acquire().
+and smp_rmb() also pairs with atomic_mb_set() and smp_mb_release().
 
 
 COMPARISON WITH LINUX KERNEL MEMORY BARRIERS
diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h
index c4f6950..b108df0 100644
--- a/include/qemu/atomic.h
+++ b/include/qemu/atomic.h
@@ -72,16 +72,16 @@
  * Add one here, and similarly in smp_rmb() and smp_read_barrier_depends().
  */
 
-#define smp_mb()    ({ barrier(); __atomic_thread_fence(__ATOMIC_SEQ_CST); })
-#define smp_wmb()   ({ barrier(); __atomic_thread_fence(__ATOMIC_RELEASE); })
-#define smp_rmb()   ({ barrier(); __atomic_thread_fence(__ATOMIC_ACQUIRE); })
+#define smp_mb()                     ({ barrier(); __atomic_thread_fence(__ATOMIC_SEQ_CST); })
+#define smp_mb_release()             ({ barrier(); __atomic_thread_fence(__ATOMIC_RELEASE); })
+#define smp_mb_acquire()             ({ barrier(); __atomic_thread_fence(__ATOMIC_ACQUIRE); })
 
 /* Most compilers currently treat consume and acquire the same, but really
  * no processors except Alpha need a barrier here.  Leave it in if
  * using Thread Sanitizer to avoid warnings, otherwise optimize it away.
  */
 #if defined(__SANITIZE_THREAD__)
-#define smp_read_barrier_depends() ({ barrier(); __atomic_thread_fence(__ATOMIC_CONSUME); })
+#define smp_read_barrier_depends()   ({ barrier(); __atomic_thread_fence(__ATOMIC_CONSUME); })
 #elif defined(__alpha__)
 #define smp_read_barrier_depends()   asm volatile("mb":::"memory")
 #else
@@ -149,13 +149,13 @@
     QEMU_BUILD_BUG_ON(sizeof(*ptr) > sizeof(void *));   \
     typeof_strip_qual(*ptr) _val;                       \
      __atomic_load(ptr, &_val, __ATOMIC_RELAXED);       \
-     smp_rmb();                                         \
+     smp_mb_acquire();                                  \
     _val;                                               \
     })
 
 #define atomic_mb_set(ptr, i)  do {                     \
     QEMU_BUILD_BUG_ON(sizeof(*ptr) > sizeof(void *));   \
-    smp_wmb();                                          \
+    smp_mb_release();                                   \
     __atomic_store_n(ptr, i, __ATOMIC_RELAXED);         \
     smp_mb();                                           \
 } while(0)
@@ -238,8 +238,8 @@
  * here (a compiler barrier only).  QEMU doesn't do accesses to write-combining
  * qemu memory or non-temporal load/stores from C code.
  */
-#define smp_wmb()   barrier()
-#define smp_rmb()   barrier()
+#define smp_mb_release()   barrier()
+#define smp_mb_acquire()   barrier()
 
 /*
  * __sync_lock_test_and_set() is documented to be an acquire barrier only,
@@ -263,13 +263,15 @@
  * smp_mb has the same problem as on x86 for not-very-new GCC
  * (http://patchwork.ozlabs.org/patch/126184/, Nov 2011).
  */
-#define smp_wmb()   ({ asm volatile("eieio" ::: "memory"); (void)0; })
+#define smp_wmb()          ({ asm volatile("eieio" ::: "memory"); (void)0; })
 #if defined(__powerpc64__)
-#define smp_rmb()   ({ asm volatile("lwsync" ::: "memory"); (void)0; })
+#define smp_mb_release()   ({ asm volatile("lwsync" ::: "memory"); (void)0; })
+#define smp_mb_acquire()   ({ asm volatile("lwsync" ::: "memory"); (void)0; })
 #else
-#define smp_rmb()   ({ asm volatile("sync" ::: "memory"); (void)0; })
+#define smp_mb_release()   ({ asm volatile("sync" ::: "memory"); (void)0; })
+#define smp_mb_acquire()   ({ asm volatile("sync" ::: "memory"); (void)0; })
 #endif
-#define smp_mb()    ({ asm volatile("sync" ::: "memory"); (void)0; })
+#define smp_mb()           ({ asm volatile("sync" ::: "memory"); (void)0; })
 
 #endif /* _ARCH_PPC */
 
@@ -277,18 +279,18 @@
  * For (host) platforms we don't have explicit barrier definitions
  * for, we use the gcc __sync_synchronize() primitive to generate a
  * full barrier.  This should be safe on all platforms, though it may
- * be overkill for smp_wmb() and smp_rmb().
+ * be overkill for smp_mb_acquire() and smp_mb_release().
  */
 #ifndef smp_mb
-#define smp_mb()    __sync_synchronize()
+#define smp_mb()           __sync_synchronize()
 #endif
 
-#ifndef smp_wmb
-#define smp_wmb()   __sync_synchronize()
+#ifndef smp_mb_acquire
+#define smp_mb_acquire()   __sync_synchronize()
 #endif
 
-#ifndef smp_rmb
-#define smp_rmb()   __sync_synchronize()
+#ifndef smp_mb_release
+#define smp_mb_release()   __sync_synchronize()
 #endif
 
 #ifndef smp_read_barrier_depends
@@ -365,13 +367,13 @@
  */
 #define atomic_mb_read(ptr)    ({           \
     typeof(*ptr) _val = atomic_read(ptr);   \
-    smp_rmb();                              \
+    smp_mb_acquire();                       \
     _val;                                   \
 })
 
 #ifndef atomic_mb_set
 #define atomic_mb_set(ptr, i)  do {         \
-    smp_wmb();                              \
+    smp_mb_release();                       \
     atomic_set(ptr, i);                     \
     smp_mb();                               \
 } while (0)
@@ -404,4 +406,12 @@
 #define atomic_or(ptr, n)      ((void) __sync_fetch_and_or(ptr, n))
 
 #endif /* __ATOMIC_RELAXED */
+
+#ifndef smp_wmb
+#define smp_wmb()   smp_mb_release()
+#endif
+#ifndef smp_rmb
+#define smp_rmb()   smp_mb_acquire()
+#endif
+
 #endif /* QEMU_ATOMIC_H */
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 07/50] qemu-thread: use acquire/release to clarify semantics of QemuEvent
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (5 preceding siblings ...)
  2016-10-24 13:46 ` [Qemu-devel] [PULL 06/50] atomic: introduce smp_mb_acquire and smp_mb_release Paolo Bonzini
@ 2016-10-24 13:46 ` Paolo Bonzini
  2016-10-24 13:46 ` [Qemu-devel] [PULL 08/50] rcu: simplify memory barriers Paolo Bonzini
                   ` (43 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:46 UTC (permalink / raw)
  To: qemu-devel

Do not use the somewhat mysterious atomic_mb_read/atomic_mb_set,
instead make sure that the operations on QemuEvent are annotated
with the desired acquire and release semantics.

In particular, qemu_event_set wakes up the waiting thread, so it must
be a release from the POV of the waker (compare with qemu_mutex_unlock).
And it actually needs a full barrier, because that's the only thing that
provides something like a "load-release".

Use smp_mb_acquire until we have atomic_load_acquire and
atomic_store_release in atomic.h.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 util/qemu-thread-posix.c | 15 ++++++++++++---
 util/qemu-thread-win32.c | 15 ++++++++++++---
 2 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c
index 74a3023..ce51b37 100644
--- a/util/qemu-thread-posix.c
+++ b/util/qemu-thread-posix.c
@@ -360,7 +360,11 @@ void qemu_event_destroy(QemuEvent *ev)
 
 void qemu_event_set(QemuEvent *ev)
 {
-    if (atomic_mb_read(&ev->value) != EV_SET) {
+    /* qemu_event_set has release semantics, but because it *loads*
+     * ev->value we need a full memory barrier here.
+     */
+    smp_mb();
+    if (atomic_read(&ev->value) != EV_SET) {
         if (atomic_xchg(&ev->value, EV_SET) == EV_BUSY) {
             /* There were waiters, wake them up.  */
             futex_wake(ev, INT_MAX);
@@ -370,7 +374,11 @@ void qemu_event_set(QemuEvent *ev)
 
 void qemu_event_reset(QemuEvent *ev)
 {
-    if (atomic_mb_read(&ev->value) == EV_SET) {
+    unsigned value;
+
+    value = atomic_read(&ev->value);
+    smp_mb_acquire();
+    if (value == EV_SET) {
         /*
          * If there was a concurrent reset (or even reset+wait),
          * do nothing.  Otherwise change EV_SET->EV_FREE.
@@ -383,7 +391,8 @@ void qemu_event_wait(QemuEvent *ev)
 {
     unsigned value;
 
-    value = atomic_mb_read(&ev->value);
+    value = atomic_read(&ev->value);
+    smp_mb_acquire();
     if (value != EV_SET) {
         if (value == EV_FREE) {
             /*
diff --git a/util/qemu-thread-win32.c b/util/qemu-thread-win32.c
index 98a5ddf..072806f 100644
--- a/util/qemu-thread-win32.c
+++ b/util/qemu-thread-win32.c
@@ -274,7 +274,11 @@ void qemu_event_destroy(QemuEvent *ev)
 
 void qemu_event_set(QemuEvent *ev)
 {
-    if (atomic_mb_read(&ev->value) != EV_SET) {
+    /* qemu_event_set has release semantics, but because it *loads*
+     * ev->value we need a full memory barrier here.
+     */
+    smp_mb();
+    if (atomic_read(&ev->value) != EV_SET) {
         if (atomic_xchg(&ev->value, EV_SET) == EV_BUSY) {
             /* There were waiters, wake them up.  */
             SetEvent(ev->event);
@@ -284,7 +288,11 @@ void qemu_event_set(QemuEvent *ev)
 
 void qemu_event_reset(QemuEvent *ev)
 {
-    if (atomic_mb_read(&ev->value) == EV_SET) {
+    unsigned value;
+
+    value = atomic_read(&ev->value);
+    smp_mb_acquire();
+    if (value == EV_SET) {
         /* If there was a concurrent reset (or even reset+wait),
          * do nothing.  Otherwise change EV_SET->EV_FREE.
          */
@@ -296,7 +304,8 @@ void qemu_event_wait(QemuEvent *ev)
 {
     unsigned value;
 
-    value = atomic_mb_read(&ev->value);
+    value = atomic_read(&ev->value);
+    smp_mb_acquire();
     if (value != EV_SET) {
         if (value == EV_FREE) {
             /* qemu_event_set is not yet going to call SetEvent, but we are
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 08/50] rcu: simplify memory barriers
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (6 preceding siblings ...)
  2016-10-24 13:46 ` [Qemu-devel] [PULL 07/50] qemu-thread: use acquire/release to clarify semantics of QemuEvent Paolo Bonzini
@ 2016-10-24 13:46 ` Paolo Bonzini
  2016-10-24 13:46 ` [Qemu-devel] [PULL 09/50] atomic: base mb_read/mb_set on load-acquire and store-release Paolo Bonzini
                   ` (42 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:46 UTC (permalink / raw)
  To: qemu-devel

Thanks to the acquire semantics of qemu_event_reset and qemu_event_wait,
some memory barriers can be removed.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 util/rcu.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/util/rcu.c b/util/rcu.c
index bceb3e4..9adc5e4 100644
--- a/util/rcu.c
+++ b/util/rcu.c
@@ -82,14 +82,16 @@ static void wait_for_readers(void)
         /* Instead of using atomic_mb_set for index->waiting, and
          * atomic_mb_read for index->ctr, memory barriers are placed
          * manually since writes to different threads are independent.
-         * atomic_mb_set has a smp_wmb before...
+         * qemu_event_reset has acquire semantics, so no memory barrier
+         * is needed here.
          */
-        smp_wmb();
         QLIST_FOREACH(index, &registry, node) {
             atomic_set(&index->waiting, true);
         }
 
-        /* ... and a smp_mb after.  */
+        /* Here, order the stores to index->waiting before the
+         * loads of index->ctr.
+         */
         smp_mb();
 
         QLIST_FOREACH_SAFE(index, &registry, node, tmp) {
@@ -104,9 +106,6 @@ static void wait_for_readers(void)
             }
         }
 
-        /* atomic_mb_read has smp_rmb after.  */
-        smp_rmb();
-
         if (QLIST_EMPTY(&registry)) {
             break;
         }
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 09/50] atomic: base mb_read/mb_set on load-acquire and store-release
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (7 preceding siblings ...)
  2016-10-24 13:46 ` [Qemu-devel] [PULL 08/50] rcu: simplify memory barriers Paolo Bonzini
@ 2016-10-24 13:46 ` Paolo Bonzini
  2016-10-24 13:46 ` [Qemu-devel] [PULL 10/50] qht-bench: relax test_start/stop atomic accesses Paolo Bonzini
                   ` (41 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:46 UTC (permalink / raw)
  To: qemu-devel

This introduces load-acquire and store-release operations in QEMU.
For now, just use them as an implementation detail of atomic_mb_read
and atomic_mb_set.

Since docs/atomics.txt documents that atomic_mb_read only synchronizes
with an atomic_mb_set of the same variable, we can use the new implementation
everywhere instead of seq-cst loads and stores.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 docs/atomics.txt      |  5 +--
 include/qemu/atomic.h | 95 ++++++++++++++++++---------------------------------
 2 files changed, 36 insertions(+), 64 deletions(-)

diff --git a/docs/atomics.txt b/docs/atomics.txt
index c8e4cbe..3ef5d85 100644
--- a/docs/atomics.txt
+++ b/docs/atomics.txt
@@ -374,8 +374,9 @@ and memory barriers, and the equivalents in QEMU:
   note that smp_store_mb() is a little weaker than atomic_mb_set().
   atomic_mb_read() compiles to the same instructions as Linux's
   smp_load_acquire(), but this should be treated as an implementation
-  detail.  If required, QEMU might later add atomic_load_acquire() and
-  atomic_store_release() macros.
+  detail.  QEMU does have atomic_load_acquire() and atomic_store_release()
+  macros, but for now they are only used within atomic.h.  This may
+  change in the future.
 
 
 SOURCES
diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h
index b108df0..c09fce7 100644
--- a/include/qemu/atomic.h
+++ b/include/qemu/atomic.h
@@ -135,44 +135,18 @@
     __atomic_store_n(ptr, i, __ATOMIC_RELEASE);       \
 } while(0)
 
-/* atomic_mb_read/set semantics map Java volatile variables. They are
- * less expensive on some platforms (notably POWER & ARMv7) than fully
- * sequentially consistent operations.
- *
- * As long as they are used as paired operations they are safe to
- * use. See docs/atomic.txt for more discussion.
- */
-
-#if defined(_ARCH_PPC)
-#define atomic_mb_read(ptr)                             \
+#define atomic_load_acquire(ptr)                        \
     ({                                                  \
     QEMU_BUILD_BUG_ON(sizeof(*ptr) > sizeof(void *));   \
     typeof_strip_qual(*ptr) _val;                       \
-     __atomic_load(ptr, &_val, __ATOMIC_RELAXED);       \
-     smp_mb_acquire();                                  \
+    __atomic_load(ptr, &_val, __ATOMIC_ACQUIRE);        \
     _val;                                               \
     })
 
-#define atomic_mb_set(ptr, i)  do {                     \
+#define atomic_store_release(ptr, i)  do {              \
     QEMU_BUILD_BUG_ON(sizeof(*ptr) > sizeof(void *));   \
-    smp_mb_release();                                   \
-    __atomic_store_n(ptr, i, __ATOMIC_RELAXED);         \
-    smp_mb();                                           \
+    __atomic_store_n(ptr, i, __ATOMIC_RELEASE);         \
 } while(0)
-#else
-#define atomic_mb_read(ptr)                             \
-    ({                                                  \
-    QEMU_BUILD_BUG_ON(sizeof(*ptr) > sizeof(void *));   \
-    typeof_strip_qual(*ptr) _val;                       \
-    __atomic_load(ptr, &_val, __ATOMIC_SEQ_CST);        \
-    _val;                                               \
-    })
-
-#define atomic_mb_set(ptr, i)  do {                     \
-    QEMU_BUILD_BUG_ON(sizeof(*ptr) > sizeof(void *));   \
-    __atomic_store_n(ptr, i, __ATOMIC_SEQ_CST);         \
-} while(0)
-#endif
 
 
 /* All the remaining operations are fully sequentially consistent */
@@ -248,11 +222,6 @@
  */
 #define atomic_xchg(ptr, i)    (barrier(), __sync_lock_test_and_set(ptr, i))
 
-/*
- * Load/store with Java volatile semantics.
- */
-#define atomic_mb_set(ptr, i)  ((void)atomic_xchg(ptr, i))
-
 #elif defined(_ARCH_PPC)
 
 /*
@@ -343,41 +312,16 @@
     atomic_set(ptr, i);                           \
 } while (0)
 
-/* These have the same semantics as Java volatile variables.
- * See http://gee.cs.oswego.edu/dl/jmm/cookbook.html:
- * "1. Issue a StoreStore barrier (wmb) before each volatile store."
- *  2. Issue a StoreLoad barrier after each volatile store.
- *     Note that you could instead issue one before each volatile load, but
- *     this would be slower for typical programs using volatiles in which
- *     reads greatly outnumber writes. Alternatively, if available, you
- *     can implement volatile store as an atomic instruction (for example
- *     XCHG on x86) and omit the barrier. This may be more efficient if
- *     atomic instructions are cheaper than StoreLoad barriers.
- *  3. Issue LoadLoad and LoadStore barriers after each volatile load."
- *
- * If you prefer to think in terms of "pairing" of memory barriers,
- * an atomic_mb_read pairs with an atomic_mb_set.
- *
- * And for the few ia64 lovers that exist, an atomic_mb_read is a ld.acq,
- * while an atomic_mb_set is a st.rel followed by a memory barrier.
- *
- * These are a bit weaker than __atomic_load/store with __ATOMIC_SEQ_CST
- * (see docs/atomics.txt), and I'm not sure that __ATOMIC_ACQ_REL is enough.
- * Just always use the barriers manually by the rules above.
- */
-#define atomic_mb_read(ptr)    ({           \
+#define atomic_load_acquire(ptr)    ({      \
     typeof(*ptr) _val = atomic_read(ptr);   \
     smp_mb_acquire();                       \
     _val;                                   \
 })
 
-#ifndef atomic_mb_set
-#define atomic_mb_set(ptr, i)  do {         \
+#define atomic_store_release(ptr, i)  do {  \
     smp_mb_release();                       \
     atomic_set(ptr, i);                     \
-    smp_mb();                               \
 } while (0)
-#endif
 
 #ifndef atomic_xchg
 #if defined(__clang__)
@@ -414,4 +358,31 @@
 #define smp_rmb()   smp_mb_acquire()
 #endif
 
+/* This is more efficient than a store plus a fence.  */
+#if !defined(__SANITIZE_THREAD__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__s390x__)
+#define atomic_mb_set(ptr, i)  ((void)atomic_xchg(ptr, i))
+#endif
+#endif
+
+/* atomic_mb_read/set semantics map Java volatile variables. They are
+ * less expensive on some platforms (notably POWER) than fully
+ * sequentially consistent operations.
+ *
+ * As long as they are used as paired operations they are safe to
+ * use. See docs/atomic.txt for more discussion.
+ */
+
+#ifndef atomic_mb_read
+#define atomic_mb_read(ptr)                             \
+    atomic_load_acquire(ptr)
+#endif
+
+#ifndef atomic_mb_set
+#define atomic_mb_set(ptr, i)  do {                     \
+    atomic_store_release(ptr, i);                       \
+    smp_mb();                                           \
+} while(0)
+#endif
+
 #endif /* QEMU_ATOMIC_H */
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 10/50] qht-bench: relax test_start/stop atomic accesses
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (8 preceding siblings ...)
  2016-10-24 13:46 ` [Qemu-devel] [PULL 09/50] atomic: base mb_read/mb_set on load-acquire and store-release Paolo Bonzini
@ 2016-10-24 13:46 ` Paolo Bonzini
  2016-10-24 13:46 ` [Qemu-devel] [PULL 11/50] test-i386: fix bitrot for 64-bit Paolo Bonzini
                   ` (40 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: Emilio G. Cota

From: "Emilio G. Cota" <cota@braap.org>

test_start/stop are used only as flags to loop on. Barriers are unnecessary,
since no dependent data is transferred among threads apart from the flags
themselves.

This commit relaxes the three accesses to test_start/stop that were
not yet relaxed.

Signed-off-by: Emilio G. Cota <cota@braap.org>
---
 tests/qht-bench.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/tests/qht-bench.c b/tests/qht-bench.c
index 76360a0..2afa09d 100644
--- a/tests/qht-bench.c
+++ b/tests/qht-bench.c
@@ -193,7 +193,7 @@ static void *thread_func(void *p)
     rcu_register_thread();
 
     atomic_inc(&n_ready_threads);
-    while (!atomic_mb_read(&test_start)) {
+    while (!atomic_read(&test_start)) {
         cpu_relax();
     }
 
@@ -393,11 +393,11 @@ static void run_test(void)
     while (atomic_read(&n_ready_threads) != n_rw_threads + n_rz_threads) {
         cpu_relax();
     }
-    atomic_mb_set(&test_start, true);
+    atomic_set(&test_start, true);
     do {
         remaining = sleep(duration);
     } while (remaining);
-    atomic_mb_set(&test_stop, true);
+    atomic_set(&test_stop, true);
 
     for (i = 0; i < n_rw_threads; i++) {
         qemu_thread_join(&rw_threads[i]);
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 11/50] test-i386: fix bitrot for 64-bit
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (9 preceding siblings ...)
  2016-10-24 13:46 ` [Qemu-devel] [PULL 10/50] qht-bench: relax test_start/stop atomic accesses Paolo Bonzini
@ 2016-10-24 13:46 ` Paolo Bonzini
  2016-10-24 13:46 ` [Qemu-devel] [PULL 12/50] target-i386: fix 32-bit addresses in LEA Paolo Bonzini
                   ` (39 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:46 UTC (permalink / raw)
  To: qemu-devel

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/tcg/test-i386.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tests/tcg/test-i386.c b/tests/tcg/test-i386.c
index b05572b..0f7b943 100644
--- a/tests/tcg/test-i386.c
+++ b/tests/tcg/test-i386.c
@@ -2250,14 +2250,14 @@ SSE_OP(a ## sd);
 
 #define SSE_COMI(op, field)\
 {\
-    unsigned int eflags;\
+    unsigned long eflags;\
     XMMReg a, b;\
     a.field[0] = a1;\
     b.field[0] = b1;\
     asm volatile (#op " %2, %1\n"\
         "pushf\n"\
         "pop %0\n"\
-        : "=m" (eflags)\
+        : "=rm" (eflags)\
         : "x" (a.dq), "x" (b.dq));\
     printf("%-9s: a=%f b=%f cc=%04x\n",\
            #op, a1, b1,\
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 12/50] target-i386: fix 32-bit addresses in LEA
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (10 preceding siblings ...)
  2016-10-24 13:46 ` [Qemu-devel] [PULL 11/50] test-i386: fix bitrot for 64-bit Paolo Bonzini
@ 2016-10-24 13:46 ` Paolo Bonzini
  2016-10-24 13:46 ` [Qemu-devel] [PULL 13/50] tcg: try sti when moving a constant into a dead memory temp Paolo Bonzini
                   ` (38 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:46 UTC (permalink / raw)
  To: qemu-devel

This was found with test-i386.  The issue is that instructions
such as

    addr32 lea (%eax), %rax

did not perform a 32-bit extension, because the LEA translation
skipped the gen_lea_v_seg step.  That step does not just add
segments, it also takes care of extending from address size to
pointer size.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 target-i386/translate.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/target-i386/translate.c b/target-i386/translate.c
index 9447557..23fde58 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -457,13 +457,12 @@ static void gen_lea_v_seg(DisasContext *s, TCGMemOp aflag, TCGv a0,
 #endif
     case MO_32:
         /* 32 bit address */
+        if (ovr_seg < 0 && s->addseg) {
+            ovr_seg = def_seg;
+        }
         if (ovr_seg < 0) {
-            if (s->addseg) {
-                ovr_seg = def_seg;
-            } else {
-                tcg_gen_ext32u_tl(cpu_A0, a0);
-                return;
-            }
+            tcg_gen_ext32u_tl(cpu_A0, a0);
+            return;
         }
         break;
     case MO_16:
@@ -5372,7 +5371,8 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
         {
             AddressParts a = gen_lea_modrm_0(env, s, modrm);
             TCGv ea = gen_lea_modrm_1(a);
-            gen_op_mov_reg_v(dflag, reg, ea);
+            gen_lea_v_seg(s, s->aflag, ea, -1, -1);
+            gen_op_mov_reg_v(dflag, reg, cpu_A0);
         }
         break;
 
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 13/50] tcg: try sti when moving a constant into a dead memory temp
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (11 preceding siblings ...)
  2016-10-24 13:46 ` [Qemu-devel] [PULL 12/50] target-i386: fix 32-bit addresses in LEA Paolo Bonzini
@ 2016-10-24 13:46 ` Paolo Bonzini
  2016-10-24 13:46 ` [Qemu-devel] [PULL 14/50] memory: eliminate global MemoryListeners Paolo Bonzini
                   ` (37 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:46 UTC (permalink / raw)
  To: qemu-devel

This comes from free from unifying tcg_reg_alloc_mov and
tcg_reg_alloc_movi's handling of TEMP_VAL_CONST.  It triggers
often on moves to cc_dst, such as the following translation
of "sub $0x3c,%esp":

  before:                          after:
  subl   $0x3c,%ebp                subl   $0x3c,%ebp
  movl   %ebp,0x10(%r14)           movl   %ebp,0x10(%r14)
  movl   $0x3c,%ebx                movl   $0x3c,0x2c(%r14)
  movl   %ebx,0x2c(%r14)

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <1473945360-13663-1-git-send-email-pbonzini@redhat.com>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tcg/tcg.c | 56 +++++++++++++++++++++++++++-----------------------------
 1 file changed, 27 insertions(+), 29 deletions(-)

diff --git a/tcg/tcg.c b/tcg/tcg.c
index c450c62..2d3e498 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -2097,15 +2097,9 @@ static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
     save_globals(s, allocated_regs);
 }
 
-static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args,
-                               TCGLifeData arg_life)
+static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
+                                  tcg_target_ulong val, TCGLifeData arg_life)
 {
-    TCGTemp *ots;
-    tcg_target_ulong val;
-
-    ots = &s->temps[args[0]];
-    val = args[1];
-
     if (ots->fixed_reg) {
         /* For fixed registers, we do not do any constant propagation.  */
         tcg_out_movi(s, ots->type, ots->reg, val);
@@ -2126,6 +2120,15 @@ static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args,
     }
 }
 
+static void tcg_reg_alloc_movi(TCGContext *s, const TCGArg *args,
+                               TCGLifeData arg_life)
+{
+    TCGTemp *ots = &s->temps[args[0]];
+    tcg_target_ulong val = args[1];
+
+    tcg_reg_alloc_do_movi(s, ots, val, arg_life);
+}
+
 static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
                               const TCGArg *args, TCGLifeData arg_life)
 {
@@ -2141,21 +2144,29 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
     otype = ots->type;
     itype = ts->type;
 
-    /* If the source value is not in a register, and we're going to be
-       forced to have it in a register in order to perform the copy,
-       then copy the SOURCE value into its own register first.  That way
-       we don't have to reload SOURCE the next time it is used. */
-    if (((NEED_SYNC_ARG(0) || ots->fixed_reg) && ts->val_type != TEMP_VAL_REG)
-        || ts->val_type == TEMP_VAL_MEM) {
+    if (ts->val_type == TEMP_VAL_CONST) {
+        /* propagate constant or generate sti */
+        tcg_target_ulong val = ts->val;
+        if (IS_DEAD_ARG(1)) {
+            temp_dead(s, ts);
+        }
+        tcg_reg_alloc_do_movi(s, ots, val, arg_life);
+        return;
+    }
+
+    /* If the source value is in memory we're going to be forced
+       to have it in a register in order to perform the copy.  Copy
+       the SOURCE value into its own register first, that way we
+       don't have to reload SOURCE the next time it is used. */
+    if (ts->val_type == TEMP_VAL_MEM) {
         temp_load(s, ts, tcg_target_available_regs[itype], allocated_regs);
     }
 
+    tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
     if (IS_DEAD_ARG(0) && !ots->fixed_reg) {
         /* mov to a non-saved dead register makes no sense (even with
            liveness analysis disabled). */
         tcg_debug_assert(NEED_SYNC_ARG(0));
-        /* The code above should have moved the temp to a register. */
-        tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
         if (!ots->mem_allocated) {
             temp_allocate_frame(s, args[0]);
         }
@@ -2164,20 +2175,7 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
             temp_dead(s, ts);
         }
         temp_dead(s, ots);
-    } else if (ts->val_type == TEMP_VAL_CONST) {
-        /* propagate constant */
-        if (ots->val_type == TEMP_VAL_REG) {
-            s->reg_to_temp[ots->reg] = NULL;
-        }
-        ots->val_type = TEMP_VAL_CONST;
-        ots->val = ts->val;
-        if (IS_DEAD_ARG(1)) {
-            temp_dead(s, ts);
-        }
     } else {
-        /* The code in the first if block should have moved the
-           temp to a register. */
-        tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
         if (IS_DEAD_ARG(1) && !ts->fixed_reg && !ots->fixed_reg) {
             /* the mov can be suppressed */
             if (ots->val_type == TEMP_VAL_REG) {
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 14/50] memory: eliminate global MemoryListeners
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (12 preceding siblings ...)
  2016-10-24 13:46 ` [Qemu-devel] [PULL 13/50] tcg: try sti when moving a constant into a dead memory temp Paolo Bonzini
@ 2016-10-24 13:46 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 15/50] memory: add a per-AddressSpace list of listeners Paolo Bonzini
                   ` (36 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:46 UTC (permalink / raw)
  To: qemu-devel

There is none, so just drop the code.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/exec/memory.h |  2 +-
 memory.c              | 23 ++++++-----------------
 2 files changed, 7 insertions(+), 18 deletions(-)

diff --git a/include/exec/memory.h b/include/exec/memory.h
index 10d7eac..39f3410 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -255,7 +255,7 @@ struct MemoryListener {
                                hwaddr addr, hwaddr len);
     /* Lower = earlier (during add), later (during del) */
     unsigned priority;
-    AddressSpace *address_space_filter;
+    AddressSpace *address_space;
     QTAILQ_ENTRY(MemoryListener) link;
 };
 
diff --git a/memory.c b/memory.c
index 58f9269..1886b44 100644
--- a/memory.c
+++ b/memory.c
@@ -100,8 +100,7 @@ enum ListenerDirection { Forward, Reverse };
 static bool memory_listener_match(MemoryListener *listener,
                                   MemoryRegionSection *section)
 {
-    return !listener->address_space_filter
-        || listener->address_space_filter == section->address_space;
+    return listener->address_space == section->address_space;
 }
 
 #define MEMORY_LISTENER_CALL_GLOBAL(_callback, _direction, _args...)    \
@@ -2176,9 +2175,7 @@ void memory_global_dirty_log_sync(void)
         if (!listener->log_sync) {
             continue;
         }
-        /* Global listeners are being phased out.  */
-        assert(listener->address_space_filter);
-        as = listener->address_space_filter;
+        as = listener->address_space;
         view = address_space_get_flatview(as);
         FOR_EACH_FLAT_RANGE(fr, view) {
             MemoryRegionSection mrs = section_from_flat_range(fr, as);
@@ -2218,11 +2215,6 @@ static void listener_add_address_space(MemoryListener *listener,
     FlatView *view;
     FlatRange *fr;
 
-    if (listener->address_space_filter
-        && listener->address_space_filter != as) {
-        return;
-    }
-
     if (listener->begin) {
         listener->begin(listener);
     }
@@ -2255,12 +2247,11 @@ static void listener_add_address_space(MemoryListener *listener,
     flatview_unref(view);
 }
 
-void memory_listener_register(MemoryListener *listener, AddressSpace *filter)
+void memory_listener_register(MemoryListener *listener, AddressSpace *as)
 {
     MemoryListener *other = NULL;
-    AddressSpace *as;
 
-    listener->address_space_filter = filter;
+    listener->address_space = as;
     if (QTAILQ_EMPTY(&memory_listeners)
         || listener->priority >= QTAILQ_LAST(&memory_listeners,
                                              memory_listeners)->priority) {
@@ -2274,9 +2265,7 @@ void memory_listener_register(MemoryListener *listener, AddressSpace *filter)
         QTAILQ_INSERT_BEFORE(other, listener, link);
     }
 
-    QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
-        listener_add_address_space(listener, as);
-    }
+    listener_add_address_space(listener, as);
 }
 
 void memory_listener_unregister(MemoryListener *listener)
@@ -2310,7 +2299,7 @@ static void do_address_space_destroy(AddressSpace *as)
     address_space_destroy_dispatch(as);
 
     QTAILQ_FOREACH(listener, &memory_listeners, link) {
-        assert(listener->address_space_filter != as);
+        assert(listener->address_space != as);
     }
 
     flatview_unref(as->current_map);
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 15/50] memory: add a per-AddressSpace list of listeners
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (13 preceding siblings ...)
  2016-10-24 13:46 ` [Qemu-devel] [PULL 14/50] memory: eliminate global MemoryListeners Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 16/50] memory: optimize memory_global_dirty_log_sync Paolo Bonzini
                   ` (35 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel

This speeds up MEMORY_LISTENER_CALL noticeably.  Right now,
with many PCI devices you have N regions added to M AddressSpaces
(M = # PCI devices with bus-master enabled) and each call looks
up the whole listener list, with at least M listeners in it.
Because most of the regions in N are BARs, which are also roughly
proportional to M, the whole thing is O(M^3).  This changes it
to O(M^2), which is the best we can do without rewriting the
whole thing.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/exec/memory.h |  3 ++-
 memory.c              | 52 +++++++++++++++++++++++++++------------------------
 2 files changed, 30 insertions(+), 25 deletions(-)

diff --git a/include/exec/memory.h b/include/exec/memory.h
index 39f3410..79ccaab 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -257,6 +257,7 @@ struct MemoryListener {
     unsigned priority;
     AddressSpace *address_space;
     QTAILQ_ENTRY(MemoryListener) link;
+    QTAILQ_ENTRY(MemoryListener) link_as;
 };
 
 /**
@@ -278,7 +279,7 @@ struct AddressSpace {
     struct AddressSpaceDispatch *dispatch;
     struct AddressSpaceDispatch *next_dispatch;
     MemoryListener dispatch_listener;
-
+    QTAILQ_HEAD(memory_listeners_as, MemoryListener) listeners;
     QTAILQ_ENTRY(AddressSpace) address_spaces_link;
 };
 
diff --git a/memory.c b/memory.c
index 1886b44..1507878 100644
--- a/memory.c
+++ b/memory.c
@@ -97,12 +97,6 @@ static AddrRange addrrange_intersection(AddrRange r1, AddrRange r2)
 
 enum ListenerDirection { Forward, Reverse };
 
-static bool memory_listener_match(MemoryListener *listener,
-                                  MemoryRegionSection *section)
-{
-    return listener->address_space == section->address_space;
-}
-
 #define MEMORY_LISTENER_CALL_GLOBAL(_callback, _direction, _args...)    \
     do {                                                                \
         MemoryListener *_listener;                                      \
@@ -128,24 +122,23 @@ static bool memory_listener_match(MemoryListener *listener,
         }                                                               \
     } while (0)
 
-#define MEMORY_LISTENER_CALL(_callback, _direction, _section, _args...) \
+#define MEMORY_LISTENER_CALL(_as, _callback, _direction, _section, _args...) \
     do {                                                                \
         MemoryListener *_listener;                                      \
+        struct memory_listeners_as *list = &(_as)->listeners;           \
                                                                         \
         switch (_direction) {                                           \
         case Forward:                                                   \
-            QTAILQ_FOREACH(_listener, &memory_listeners, link) {        \
-                if (_listener->_callback                                \
-                    && memory_listener_match(_listener, _section)) {    \
+            QTAILQ_FOREACH(_listener, list, link_as) {                  \
+                if (_listener->_callback) {                             \
                     _listener->_callback(_listener, _section, ##_args); \
                 }                                                       \
             }                                                           \
             break;                                                      \
         case Reverse:                                                   \
-            QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners,        \
-                                   memory_listeners, link) {            \
-                if (_listener->_callback                                \
-                    && memory_listener_match(_listener, _section)) {    \
+            QTAILQ_FOREACH_REVERSE(_listener, list, memory_listeners_as, \
+                                   link_as) {                           \
+                if (_listener->_callback) {                             \
                     _listener->_callback(_listener, _section, ##_args); \
                 }                                                       \
             }                                                           \
@@ -159,7 +152,7 @@ static bool memory_listener_match(MemoryListener *listener,
 #define MEMORY_LISTENER_UPDATE_REGION(fr, as, dir, callback, _args...)  \
     do {                                                                \
         MemoryRegionSection mrs = section_from_flat_range(fr, as);      \
-        MEMORY_LISTENER_CALL(callback, dir, &mrs, ##_args);             \
+        MEMORY_LISTENER_CALL(as, callback, dir, &mrs, ##_args);         \
     } while(0)
 
 struct CoalescedMemoryRange {
@@ -748,7 +741,7 @@ static void address_space_add_del_ioeventfds(AddressSpace *as,
                 .offset_within_address_space = int128_get64(fd->addr.start),
                 .size = fd->addr.size,
             };
-            MEMORY_LISTENER_CALL(eventfd_del, Forward, &section,
+            MEMORY_LISTENER_CALL(as, eventfd_del, Forward, &section,
                                  fd->match_data, fd->data, fd->e);
             ++iold;
         } else if (inew < fds_new_nb
@@ -761,7 +754,7 @@ static void address_space_add_del_ioeventfds(AddressSpace *as,
                 .offset_within_address_space = int128_get64(fd->addr.start),
                 .size = fd->addr.size,
             };
-            MEMORY_LISTENER_CALL(eventfd_add, Reverse, &section,
+            MEMORY_LISTENER_CALL(as, eventfd_add, Reverse, &section,
                                  fd->match_data, fd->data, fd->e);
             ++inew;
         } else {
@@ -1773,7 +1766,7 @@ static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpa
                 .size = fr->addr.size,
             };
 
-            MEMORY_LISTENER_CALL(coalesced_mmio_del, Reverse, &section,
+            MEMORY_LISTENER_CALL(as, coalesced_mmio_del, Reverse, &section,
                                  int128_get64(fr->addr.start),
                                  int128_get64(fr->addr.size));
             QTAILQ_FOREACH(cmr, &mr->coalesced, link) {
@@ -1784,7 +1777,7 @@ static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpa
                     continue;
                 }
                 tmp = addrrange_intersection(tmp, fr->addr);
-                MEMORY_LISTENER_CALL(coalesced_mmio_add, Forward, &section,
+                MEMORY_LISTENER_CALL(as, coalesced_mmio_add, Forward, &section,
                                      int128_get64(tmp.start),
                                      int128_get64(tmp.size));
             }
@@ -2265,12 +2258,26 @@ void memory_listener_register(MemoryListener *listener, AddressSpace *as)
         QTAILQ_INSERT_BEFORE(other, listener, link);
     }
 
+    if (QTAILQ_EMPTY(&as->listeners)
+        || listener->priority >= QTAILQ_LAST(&as->listeners,
+                                             memory_listeners)->priority) {
+        QTAILQ_INSERT_TAIL(&as->listeners, listener, link_as);
+    } else {
+        QTAILQ_FOREACH(other, &as->listeners, link_as) {
+            if (listener->priority < other->priority) {
+                break;
+            }
+        }
+        QTAILQ_INSERT_BEFORE(other, listener, link_as);
+    }
+
     listener_add_address_space(listener, as);
 }
 
 void memory_listener_unregister(MemoryListener *listener)
 {
     QTAILQ_REMOVE(&memory_listeners, listener, link);
+    QTAILQ_REMOVE(&listener->address_space->listeners, listener, link_as);
 }
 
 void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name)
@@ -2284,6 +2291,7 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name)
     flatview_init(as->current_map);
     as->ioeventfd_nb = 0;
     as->ioeventfds = NULL;
+    QTAILQ_INIT(&as->listeners);
     QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link);
     as->name = g_strdup(name ? name : "anonymous");
     address_space_init_dispatch(as);
@@ -2293,14 +2301,10 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name)
 
 static void do_address_space_destroy(AddressSpace *as)
 {
-    MemoryListener *listener;
     bool do_free = as->malloced;
 
     address_space_destroy_dispatch(as);
-
-    QTAILQ_FOREACH(listener, &memory_listeners, link) {
-        assert(listener->address_space != as);
-    }
+    assert(QTAILQ_EMPTY(&as->listeners));
 
     flatview_unref(as->current_map);
     g_free(as->name);
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 16/50] memory: optimize memory_global_dirty_log_sync
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (14 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 15/50] memory: add a per-AddressSpace list of listeners Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 17/50] memory: optimize memory_region_sync_dirty_bitmap Paolo Bonzini
                   ` (34 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel

Only return a nonzero dirty_log_mask for RAM/ROM memory regions.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 memory.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/memory.c b/memory.c
index 1507878..c857722 100644
--- a/memory.c
+++ b/memory.c
@@ -1499,7 +1499,7 @@ bool memory_region_is_skip_dump(MemoryRegion *mr)
 uint8_t memory_region_get_dirty_log_mask(MemoryRegion *mr)
 {
     uint8_t mask = mr->dirty_log_mask;
-    if (global_dirty_log) {
+    if (global_dirty_log && mr->ram_block) {
         mask |= (1 << DIRTY_MEMORY_MIGRATION);
     }
     return mask;
@@ -2171,8 +2171,10 @@ void memory_global_dirty_log_sync(void)
         as = listener->address_space;
         view = address_space_get_flatview(as);
         FOR_EACH_FLAT_RANGE(fr, view) {
-            MemoryRegionSection mrs = section_from_flat_range(fr, as);
-            listener->log_sync(listener, &mrs);
+            if (fr->dirty_log_mask) {
+                MemoryRegionSection mrs = section_from_flat_range(fr, as);
+                listener->log_sync(listener, &mrs);
+            }
         }
         flatview_unref(view);
     }
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 17/50] memory: optimize memory_region_sync_dirty_bitmap
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (15 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 16/50] memory: optimize memory_global_dirty_log_sync Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 18/50] char: serial: check divider value against baud base Paolo Bonzini
                   ` (33 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel

Avoid walking the FlatView of all address spaces.  Most of the
address spaces will have no log_sync callback on their listeners.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 memory.c | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/memory.c b/memory.c
index c857722..edbc701 100644
--- a/memory.c
+++ b/memory.c
@@ -1642,14 +1642,26 @@ bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr,
 
 void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
 {
+    MemoryListener *listener;
     AddressSpace *as;
+    FlatView *view;
     FlatRange *fr;
 
-    QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
-        FlatView *view = address_space_get_flatview(as);
+    /* If the same address space has multiple log_sync listeners, we
+     * visit that address space's FlatView multiple times.  But because
+     * log_sync listeners are rare, it's still cheaper than walking each
+     * address space once.
+     */
+    QTAILQ_FOREACH(listener, &memory_listeners, link) {
+        if (!listener->log_sync) {
+            continue;
+        }
+        as = listener->address_space;
+        view = address_space_get_flatview(as);
         FOR_EACH_FLAT_RANGE(fr, view) {
             if (fr->mr == mr) {
-                MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync);
+                MemoryRegionSection mrs = section_from_flat_range(fr, as);
+                listener->log_sync(listener, &mrs);
             }
         }
         flatview_unref(view);
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 18/50] char: serial: check divider value against baud base
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (16 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 17/50] memory: optimize memory_region_sync_dirty_bitmap Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 19/50] char.h: misc doc fix Paolo Bonzini
                   ` (32 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Prasad J Pandit

From: Prasad J Pandit <pjp@fedoraproject.org>

16550A UART device uses an oscillator to generate frequencies
(baud base), which decide communication speed. This speed could
be changed by dividing it by a divider. If the divider is
greater than the baud base, speed is set to zero, leading to a
divide by zero error. Add check to avoid it.

Reported-by: Huawei PSIRT <psirt@huawei.com>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
Message-Id: <1476251888-20238-1-git-send-email-ppandit@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/char/serial.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/hw/char/serial.c b/hw/char/serial.c
index 3442f47..eec72b7 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -153,8 +153,9 @@ static void serial_update_parameters(SerialState *s)
     int speed, parity, data_bits, stop_bits, frame_size;
     QEMUSerialSetParams ssp;
 
-    if (s->divider == 0)
+    if (s->divider == 0 || s->divider > s->baudbase) {
         return;
+    }
 
     /* Start bit. */
     frame_size = 1;
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 19/50] char.h: misc doc fix
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (17 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 18/50] char: serial: check divider value against baud base Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 20/50] rng: remove unused included header Paolo Bonzini
                   ` (31 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161011152012.3228-1-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/sysemu/char.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 19dad3f..d0ffdbd 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -380,7 +380,7 @@ int qemu_chr_fe_claim(CharDriverState *s);
 void qemu_chr_fe_claim_no_fail(CharDriverState *s);
 
 /**
- * @qemu_chr_fe_claim:
+ * @qemu_chr_fe_release:
  *
  * Release a backend for use by another frontend.
  *
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 20/50] rng: remove unused included header
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (18 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 19/50] char.h: misc doc fix Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 21/50] char: remove use-after-free on win-stdio Paolo Bonzini
                   ` (30 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

DEFINE_PROP_CHR is not used (rng is not of TYPE_DEVICE)

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-2-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 backends/rng-egd.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/backends/rng-egd.c b/backends/rng-egd.c
index ba17c07..0f6d0af 100644
--- a/backends/rng-egd.c
+++ b/backends/rng-egd.c
@@ -15,7 +15,6 @@
 #include "sysemu/char.h"
 #include "qapi/error.h"
 #include "qapi/qmp/qerror.h"
-#include "hw/qdev.h" /* just for DEFINE_PROP_CHR */
 
 #define TYPE_RNG_EGD "rng-egd"
 #define RNG_EGD(obj) OBJECT_CHECK(RngEgd, (obj), TYPE_RNG_EGD)
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 21/50] char: remove use-after-free on win-stdio
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (19 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 20/50] rng: remove unused included header Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 22/50] ringbuf: fix chr_write return value Paolo Bonzini
                   ` (29 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Found by reviewing the code, win_stdio_close() is called by
qemu_chr_free() which then call qemu_chr_free_common() taking care of
freeing CharDriverState*.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-3-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 qemu-char.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/qemu-char.c b/qemu-char.c
index d83a896..9165051 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2435,7 +2435,6 @@ static void win_stdio_close(CharDriverState *chr)
     }
 
     g_free(chr->opaque);
-    g_free(chr);
 }
 
 static CharDriverState *qemu_chr_open_stdio(const char *id,
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 22/50] ringbuf: fix chr_write return value
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (20 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 21/50] char: remove use-after-free on win-stdio Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 23/50] sun4uv: fix serial initialization regression Paolo Bonzini
                   ` (28 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

It should return the number of written bytes.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-4-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 qemu-char.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/qemu-char.c b/qemu-char.c
index 9165051..650943d 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -3328,7 +3328,7 @@ static int ringbuf_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
         }
     }
 
-    return 0;
+    return len;
 }
 
 static int ringbuf_chr_read(CharDriverState *chr, uint8_t *buf, int len)
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 23/50] sun4uv: fix serial initialization regression
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (21 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 22/50] ringbuf: fix chr_write return value Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 24/50] malta: replace chr init by CHR_EVENT_OPENED handler Paolo Bonzini
                   ` (27 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Since commit b6607a1a204d, serial_hds_isa_init() was introduced to
factor out serial_isa_init() loops. However, sun4uv shouldn't start from
0 when there is a mm serial on 0 already. Add a "from" argument to
serial_hds_isa_init().

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-5-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/alpha/dp264.c         | 2 +-
 hw/char/serial-isa.c     | 7 ++++---
 hw/i386/pc.c             | 2 +-
 hw/mips/mips_fulong2e.c  | 2 +-
 hw/mips/mips_malta.c     | 2 +-
 hw/mips/mips_r4k.c       | 2 +-
 hw/sparc64/sun4u.c       | 2 +-
 include/hw/char/serial.h | 2 +-
 8 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c
index f1267b5..d6431fd 100644
--- a/hw/alpha/dp264.c
+++ b/hw/alpha/dp264.c
@@ -88,7 +88,7 @@ static void clipper_init(MachineState *machine)
     pci_vga_init(pci_bus);
 
     /* Serial code setup.  */
-    serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS);
+    serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS);
 
     /* Network setup.  e1000 is good enough, failing Tulip support.  */
     for (i = 0; i < nb_nics; i++) {
diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c
index 1594ec4..54d3a12 100644
--- a/hw/char/serial-isa.c
+++ b/hw/char/serial-isa.c
@@ -133,13 +133,14 @@ static void serial_isa_init(ISABus *bus, int index, CharDriverState *chr)
     qdev_init_nofail(dev);
 }
 
-void serial_hds_isa_init(ISABus *bus, int n)
+void serial_hds_isa_init(ISABus *bus, int from, int to)
 {
     int i;
 
-    assert(n <= MAX_SERIAL_PORTS);
+    assert(from >= 0);
+    assert(to <= MAX_SERIAL_PORTS);
 
-    for (i = 0; i < n; ++i) {
+    for (i = from; i < to; ++i) {
         if (serial_hds[i]) {
             serial_isa_init(bus, i, serial_hds[i]);
         }
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index f4b0cda..fb8f29c 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1589,7 +1589,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
         pcspk_init(isa_bus, pit);
     }
 
-    serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS);
+    serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS);
     parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS);
 
     a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2);
diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c
index 889cdc7..9a4dae4 100644
--- a/hw/mips/mips_fulong2e.c
+++ b/hw/mips/mips_fulong2e.c
@@ -374,7 +374,7 @@ static void mips_fulong2e_init(MachineState *machine)
 
     rtc_init(isa_bus, 2000, NULL);
 
-    serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS);
+    serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS);
     parallel_hds_isa_init(isa_bus, 1);
 
     /* Sound card */
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index e90857e..bae60be 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -1215,7 +1215,7 @@ void mips_malta_init(MachineState *machine)
     isa_create_simple(isa_bus, "i8042");
 
     rtc_init(isa_bus, 2000, NULL);
-    serial_hds_isa_init(isa_bus, 2);
+    serial_hds_isa_init(isa_bus, 0, 2);
     parallel_hds_isa_init(isa_bus, 1);
 
     for(i = 0; i < MAX_FD; i++) {
diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c
index 16a59c7..27548c4 100644
--- a/hw/mips/mips_r4k.c
+++ b/hw/mips/mips_r4k.c
@@ -286,7 +286,7 @@ void mips_r4k_init(MachineState *machine)
 
     pit = pit_init(isa_bus, 0x40, 0, NULL);
 
-    serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS);
+    serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS);
 
     isa_vga_init(isa_bus);
 
diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
index 3165e18..7b8134e 100644
--- a/hw/sparc64/sun4u.c
+++ b/hw/sparc64/sun4u.c
@@ -824,7 +824,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
         i++;
     }
 
-    serial_hds_isa_init(isa_bus, MAX_SERIAL_PORTS);
+    serial_hds_isa_init(isa_bus, i, MAX_SERIAL_PORTS);
     parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS);
 
     for(i = 0; i < nb_nics; i++)
diff --git a/include/hw/char/serial.h b/include/hw/char/serial.h
index a4fd3d5..4f3b73c 100644
--- a/include/hw/char/serial.h
+++ b/include/hw/char/serial.h
@@ -94,6 +94,6 @@ SerialState *serial_mm_init(MemoryRegion *address_space,
 
 /* serial-isa.c */
 #define TYPE_ISA_SERIAL "isa-serial"
-void serial_hds_isa_init(ISABus *bus, int n);
+void serial_hds_isa_init(ISABus *bus, int from, int to);
 
 #endif
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 24/50] malta: replace chr init by CHR_EVENT_OPENED handler
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (22 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 23/50] sun4uv: fix serial initialization regression Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 25/50] char: remove init callback Paolo Bonzini
                   ` (26 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

The CharDriverState.init() callback was introduced in commit
ceecf1d158. It is only called from text_console_do_init(), but it is no
longer set since commit a61ae7f88 (init assignment has been removed by
accident).

It seems correct to use an event callback instead and print the console
text on CHR_EVENT_OPENED. That way we can remove the single user of
CharDriverState init().

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-6-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/mips/mips_malta.c | 30 +++++++++++++++++++-----------
 1 file changed, 19 insertions(+), 11 deletions(-)

diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index bae60be..3aec6d8 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -88,6 +88,7 @@ typedef struct {
     CharDriverState *display;
     char display_text[9];
     SerialState *uart;
+    bool display_inited;
 } MaltaFPGAState;
 
 #define TYPE_MIPS_MALTA "mips-malta"
@@ -530,17 +531,22 @@ static void malta_fpga_reset(void *opaque)
     snprintf(s->display_text, 9, "        ");
 }
 
-static void malta_fpga_led_init(CharDriverState *chr)
+static void malta_fgpa_display_event(void *opaque, int event)
 {
-    qemu_chr_fe_printf(chr, "\e[HMalta LEDBAR\r\n");
-    qemu_chr_fe_printf(chr, "+--------+\r\n");
-    qemu_chr_fe_printf(chr, "+        +\r\n");
-    qemu_chr_fe_printf(chr, "+--------+\r\n");
-    qemu_chr_fe_printf(chr, "\n");
-    qemu_chr_fe_printf(chr, "Malta ASCII\r\n");
-    qemu_chr_fe_printf(chr, "+--------+\r\n");
-    qemu_chr_fe_printf(chr, "+        +\r\n");
-    qemu_chr_fe_printf(chr, "+--------+\r\n");
+    MaltaFPGAState *s = opaque;
+
+    if (event == CHR_EVENT_OPENED && !s->display_inited) {
+        qemu_chr_fe_printf(s->display, "\e[HMalta LEDBAR\r\n");
+        qemu_chr_fe_printf(s->display, "+--------+\r\n");
+        qemu_chr_fe_printf(s->display, "+        +\r\n");
+        qemu_chr_fe_printf(s->display, "+--------+\r\n");
+        qemu_chr_fe_printf(s->display, "\n");
+        qemu_chr_fe_printf(s->display, "Malta ASCII\r\n");
+        qemu_chr_fe_printf(s->display, "+--------+\r\n");
+        qemu_chr_fe_printf(s->display, "+        +\r\n");
+        qemu_chr_fe_printf(s->display, "+--------+\r\n");
+        s->display_inited = true;
+    }
 }
 
 static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
@@ -560,7 +566,9 @@ static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
     memory_region_add_subregion(address_space, base, &s->iomem_lo);
     memory_region_add_subregion(address_space, base + 0xa00, &s->iomem_hi);
 
-    s->display = qemu_chr_new("fpga", "vc:320x200", malta_fpga_led_init);
+    s->display = qemu_chr_new("fpga", "vc:320x200", NULL);
+    qemu_chr_add_handlers(s->display, NULL, NULL,
+                          malta_fgpa_display_event, s);
 
     s->uart = serial_mm_init(address_space, base + 0x900, 3, uart_irq,
                              230400, uart_chr, DEVICE_NATIVE_ENDIAN);
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 25/50] char: remove init callback
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (23 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 24/50] malta: replace chr init by CHR_EVENT_OPENED handler Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 26/50] xilinx: fix buffer overflow on realize Paolo Bonzini
                   ` (25 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

The CharDriverState.init() callback is no longer set since commit
a61ae7f88ce and thus unused. The only user, the malta FGPA display has
been converted to use an event "opened" callback instead.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-7-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 gdbstub.c                 |  2 +-
 hmp.c                     |  2 +-
 hw/arm/fsl-imx25.c        |  2 +-
 hw/arm/fsl-imx31.c        |  2 +-
 hw/arm/fsl-imx6.c         |  2 +-
 hw/arm/omap2.c            |  2 +-
 hw/char/exynos4210_uart.c |  2 +-
 hw/char/omap_uart.c       |  4 ++--
 hw/char/xen_console.c     |  2 +-
 hw/isa/pc87312.c          |  4 ++--
 hw/mips/mips_malta.c      |  4 ++--
 hw/usb/dev-serial.c       |  4 ++--
 hw/xtensa/xtfpga.c        |  2 +-
 include/sysemu/char.h     | 13 +++----------
 net/slirp.c               |  2 +-
 qemu-char.c               | 12 +++++-------
 qtest.c                   |  2 +-
 tests/vhost-user-test.c   |  2 +-
 ui/console.c              |  2 --
 ui/gtk.c                  |  3 ---
 vl.c                      | 12 ++++++------
 21 files changed, 34 insertions(+), 48 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index ecea8c4..2fe71ca 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1745,7 +1745,7 @@ int gdbserver_start(const char *device)
             sigaction(SIGINT, &act, NULL);
         }
 #endif
-        chr = qemu_chr_new_noreplay("gdb", device, NULL);
+        chr = qemu_chr_new_noreplay("gdb", device);
         if (!chr)
             return -1;
 
diff --git a/hmp.c b/hmp.c
index 80f7f1f..3d60259 100644
--- a/hmp.c
+++ b/hmp.c
@@ -2002,7 +2002,7 @@ void hmp_chardev_add(Monitor *mon, const QDict *qdict)
     if (opts == NULL) {
         error_setg(&err, "Parsing chardev args failed");
     } else {
-        qemu_chr_new_from_opts(opts, NULL, &err);
+        qemu_chr_new_from_opts(opts, &err);
         qemu_opts_del(opts);
     }
     hmp_handle_error(mon, &err);
diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c
index b4e358d..7bb7be7 100644
--- a/hw/arm/fsl-imx25.c
+++ b/hw/arm/fsl-imx25.c
@@ -125,7 +125,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
             if (!chr) {
                 char label[20];
                 snprintf(label, sizeof(label), "imx31.uart%d", i);
-                chr = qemu_chr_new(label, "null", NULL);
+                chr = qemu_chr_new(label, "null");
             }
 
             qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr);
diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c
index fe204ac..f23672b 100644
--- a/hw/arm/fsl-imx31.c
+++ b/hw/arm/fsl-imx31.c
@@ -114,7 +114,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp)
             if (!chr) {
                 char label[20];
                 snprintf(label, sizeof(label), "imx31.uart%d", i);
-                chr = qemu_chr_new(label, "null", NULL);
+                chr = qemu_chr_new(label, "null");
             }
 
             qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr);
diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c
index 6a1bf26..e93532f 100644
--- a/hw/arm/fsl-imx6.c
+++ b/hw/arm/fsl-imx6.c
@@ -193,7 +193,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
 
             if (!chr) {
                 char *label = g_strdup_printf("imx6.uart%d", i + 1);
-                chr = qemu_chr_new(label, "null", NULL);
+                chr = qemu_chr_new(label, "null");
                 g_free(label);
                 serial_hds[i] = chr;
             }
diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c
index 7e11c65..0b2a355 100644
--- a/hw/arm/omap2.c
+++ b/hw/arm/omap2.c
@@ -798,7 +798,7 @@ static struct omap_sti_s *omap_sti_init(struct omap_target_agent_s *ta,
     s->irq = irq;
     omap_sti_reset(s);
 
-    s->chr = chr ?: qemu_chr_new("null", "null", NULL);
+    s->chr = chr ?: qemu_chr_new("null", "null");
 
     memory_region_init_io(&s->iomem, NULL, &omap_sti_ops, s, "omap.sti",
                           omap_l4_region_size(ta, 0));
diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
index 1107578..66e6304 100644
--- a/hw/char/exynos4210_uart.c
+++ b/hw/char/exynos4210_uart.c
@@ -606,7 +606,7 @@ DeviceState *exynos4210_uart_create(hwaddr addr,
         chr = serial_hds[channel];
         if (!chr) {
             snprintf(label, ARRAY_SIZE(label), "%s%d", chr_name, channel);
-            chr = qemu_chr_new(label, "null", NULL);
+            chr = qemu_chr_new(label, "null");
             if (!(chr)) {
                 error_report("Can't assign serial port to UART%d", channel);
                 exit(1);
diff --git a/hw/char/omap_uart.c b/hw/char/omap_uart.c
index 415bec5..893ab10 100644
--- a/hw/char/omap_uart.c
+++ b/hw/char/omap_uart.c
@@ -63,7 +63,7 @@ struct omap_uart_s *omap_uart_init(hwaddr base,
     s->irq = irq;
     s->serial = serial_mm_init(get_system_memory(), base, 2, irq,
                                omap_clk_getrate(fclk)/16,
-                               chr ?: qemu_chr_new(label, "null", NULL),
+                               chr ?: qemu_chr_new(label, "null"),
                                DEVICE_NATIVE_ENDIAN);
     return s;
 }
@@ -183,6 +183,6 @@ void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr)
     /* TODO: Should reuse or destroy current s->serial */
     s->serial = serial_mm_init(get_system_memory(), s->base, 2, s->irq,
                                omap_clk_getrate(s->fclk) / 16,
-                               chr ?: qemu_chr_new("null", "null", NULL),
+                               chr ?: qemu_chr_new("null", "null"),
                                DEVICE_NATIVE_ENDIAN);
 }
diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c
index 83108b0..11bf6a4 100644
--- a/hw/char/xen_console.c
+++ b/hw/char/xen_console.c
@@ -199,7 +199,7 @@ static int con_init(struct XenDevice *xendev)
         con->chr = serial_hds[con->xendev.dev];
     } else {
         snprintf(label, sizeof(label), "xencons%d", con->xendev.dev);
-        con->chr = qemu_chr_new(label, output, NULL);
+        con->chr = qemu_chr_new(label, output);
     }
 
     xenstore_store_pv_console_info(con->xendev.dev, con->chr);
diff --git a/hw/isa/pc87312.c b/hw/isa/pc87312.c
index c3ebf3e..b1c1a0a 100644
--- a/hw/isa/pc87312.c
+++ b/hw/isa/pc87312.c
@@ -283,7 +283,7 @@ static void pc87312_realize(DeviceState *dev, Error **errp)
         /* FIXME use a qdev chardev prop instead of parallel_hds[] */
         chr = parallel_hds[0];
         if (chr == NULL) {
-            chr = qemu_chr_new("par0", "null", NULL);
+            chr = qemu_chr_new("par0", "null");
         }
         isa = isa_create(bus, "isa-parallel");
         d = DEVICE(isa);
@@ -303,7 +303,7 @@ static void pc87312_realize(DeviceState *dev, Error **errp)
             chr = serial_hds[i];
             if (chr == NULL) {
                 snprintf(name, sizeof(name), "ser%d", i);
-                chr = qemu_chr_new(name, "null", NULL);
+                chr = qemu_chr_new(name, "null");
             }
             isa = isa_create(bus, "isa-serial");
             d = DEVICE(isa);
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index 3aec6d8..ed0850c 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -566,7 +566,7 @@ static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
     memory_region_add_subregion(address_space, base, &s->iomem_lo);
     memory_region_add_subregion(address_space, base + 0xa00, &s->iomem_hi);
 
-    s->display = qemu_chr_new("fpga", "vc:320x200", NULL);
+    s->display = qemu_chr_new("fpga", "vc:320x200");
     qemu_chr_add_handlers(s->display, NULL, NULL,
                           malta_fgpa_display_event, s);
 
@@ -1033,7 +1033,7 @@ void mips_malta_init(MachineState *machine)
         if (!serial_hds[i]) {
             char label[32];
             snprintf(label, sizeof(label), "serial%d", i);
-            serial_hds[i] = qemu_chr_new(label, "null", NULL);
+            serial_hds[i] = qemu_chr_new(label, "null");
         }
     }
 
diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c
index 966ad84..61452b5 100644
--- a/hw/usb/dev-serial.c
+++ b/hw/usb/dev-serial.c
@@ -547,7 +547,7 @@ static USBDevice *usb_serial_init(USBBus *bus, const char *filename)
     filename++;
 
     snprintf(label, sizeof(label), "usbserial%d", index++);
-    cdrv = qemu_chr_new(label, filename, NULL);
+    cdrv = qemu_chr_new(label, filename);
     if (!cdrv)
         return NULL;
 
@@ -565,7 +565,7 @@ static USBDevice *usb_braille_init(USBBus *bus, const char *unused)
     USBDevice *dev;
     CharDriverState *cdrv;
 
-    cdrv = qemu_chr_new("braille", "braille", NULL);
+    cdrv = qemu_chr_new("braille", "braille");
     if (!cdrv)
         return NULL;
 
diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c
index ac75949..dc6fdcc 100644
--- a/hw/xtensa/xtfpga.c
+++ b/hw/xtensa/xtfpga.c
@@ -265,7 +265,7 @@ static void lx_init(const LxBoardDesc *board, MachineState *machine)
     }
 
     if (!serial_hds[0]) {
-        serial_hds[0] = qemu_chr_new("serial0", "null", NULL);
+        serial_hds[0] = qemu_chr_new("serial0", "null");
     }
 
     serial_mm_init(system_io, 0x0d050020, 2, xtensa_get_extint(env, 0),
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index d0ffdbd..eba77e0 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -75,7 +75,6 @@ typedef enum {
 
 struct CharDriverState {
     QemuMutex chr_write_lock;
-    void (*init)(struct CharDriverState *s);
     int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len);
     int (*chr_sync_read)(struct CharDriverState *s,
                          const uint8_t *buf, int len);
@@ -130,13 +129,11 @@ CharDriverState *qemu_chr_alloc(ChardevCommon *backend, Error **errp);
  * Create a new character backend from a QemuOpts list.
  *
  * @opts see qemu-config.c for a list of valid options
- * @init not sure..
  *
  * Returns: a new character backend
  */
 CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
-                                    void (*init)(struct CharDriverState *s),
-                                    Error **errp);
+                                        Error **errp);
 
 /**
  * @qemu_chr_parse_common:
@@ -155,12 +152,10 @@ void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend);
  *
  * @label the name of the backend
  * @filename the URI
- * @init not sure..
  *
  * Returns: a new character backend
  */
-CharDriverState *qemu_chr_new(const char *label, const char *filename,
-                              void (*init)(struct CharDriverState *s));
+CharDriverState *qemu_chr_new(const char *label, const char *filename);
 /**
  * @qemu_chr_disconnect:
  *
@@ -191,12 +186,10 @@ int qemu_chr_wait_connected(CharDriverState *chr, Error **errp);
  *
  * @label the name of the backend
  * @filename the URI
- * @init not sure..
  *
  * Returns: a new character backend
  */
-CharDriverState *qemu_chr_new_noreplay(const char *label, const char *filename,
-                                       void (*init)(struct CharDriverState *s));
+CharDriverState *qemu_chr_new_noreplay(const char *label, const char *filename);
 
 /**
  * @qemu_chr_delete:
diff --git a/net/slirp.c b/net/slirp.c
index b60893f..f9fdff5 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -747,7 +747,7 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str,
         }
     } else {
         fwd = g_new(struct GuestFwd, 1);
-        fwd->hd = qemu_chr_new(buf, p, NULL);
+        fwd->hd = qemu_chr_new(buf, p);
         if (!fwd->hd) {
             error_report("could not open guest forwarding device '%s'", buf);
             g_free(fwd);
diff --git a/qemu-char.c b/qemu-char.c
index 650943d..22504cc 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -3909,8 +3909,7 @@ void register_char_driver(const char *name, ChardevBackendKind kind,
 }
 
 CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
-                                    void (*init)(struct CharDriverState *s),
-                                    Error **errp)
+                                        Error **errp)
 {
     Error *local_err = NULL;
     CharDriver *cd;
@@ -4007,8 +4006,7 @@ err:
     return NULL;
 }
 
-CharDriverState *qemu_chr_new_noreplay(const char *label, const char *filename,
-                                       void (*init)(struct CharDriverState *s))
+CharDriverState *qemu_chr_new_noreplay(const char *label, const char *filename)
 {
     const char *p;
     CharDriverState *chr;
@@ -4023,7 +4021,7 @@ CharDriverState *qemu_chr_new_noreplay(const char *label, const char *filename,
     if (!opts)
         return NULL;
 
-    chr = qemu_chr_new_from_opts(opts, init, &err);
+    chr = qemu_chr_new_from_opts(opts, &err);
     if (err) {
         error_report_err(err);
     }
@@ -4035,10 +4033,10 @@ CharDriverState *qemu_chr_new_noreplay(const char *label, const char *filename,
     return chr;
 }
 
-CharDriverState *qemu_chr_new(const char *label, const char *filename, void (*init)(struct CharDriverState *s))
+CharDriverState *qemu_chr_new(const char *label, const char *filename)
 {
     CharDriverState *chr;
-    chr = qemu_chr_new_noreplay(label, filename, init);
+    chr = qemu_chr_new_noreplay(label, filename);
     if (chr) {
         chr->replay = replay_mode != REPLAY_MODE_NONE;
         if (chr->replay && chr->chr_ioctl) {
diff --git a/qtest.c b/qtest.c
index b53b39c..2d9a021 100644
--- a/qtest.c
+++ b/qtest.c
@@ -670,7 +670,7 @@ void qtest_init(const char *qtest_chrdev, const char *qtest_log, Error **errp)
 {
     CharDriverState *chr;
 
-    chr = qemu_chr_new("qtest", qtest_chrdev, NULL);
+    chr = qemu_chr_new("qtest", qtest_chrdev);
 
     if (chr == NULL) {
         error_setg(errp, "Failed to initialize device for qtest: \"%s\"",
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index d7c48c5..edf30ac 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -455,7 +455,7 @@ static void test_server_create_chr(TestServer *server, const gchar *opt)
     gchar *chr_path;
 
     chr_path = g_strdup_printf("unix:%s%s", server->socket_path, opt);
-    server->chr = qemu_chr_new(server->chr_name, chr_path, NULL);
+    server->chr = qemu_chr_new(server->chr_name, chr_path);
     g_free(chr_path);
 
     qemu_chr_add_handlers(server->chr, chr_can_read, chr_read,
diff --git a/ui/console.c b/ui/console.c
index fa3e658..19adac7 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -2033,8 +2033,6 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
     }
 
     qemu_chr_be_generic_open(chr);
-    if (chr->init)
-        chr->init(chr);
 }
 
 static CharDriverState *text_console_init(ChardevVC *vc, Error **errp)
diff --git a/ui/gtk.c b/ui/gtk.c
index 58d20ee..83984f6 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1789,9 +1789,6 @@ static GSList *gd_vc_vte_init(GtkDisplayState *s, VirtualConsole *vc,
                              gtk_label_new(vc->label));
 
     qemu_chr_be_generic_open(vc->vte.chr);
-    if (vc->vte.chr->init) {
-        vc->vte.chr->init(vc->vte.chr);
-    }
 
     return group;
 }
diff --git a/vl.c b/vl.c
index 2e152ac..e4c534c 100644
--- a/vl.c
+++ b/vl.c
@@ -2369,7 +2369,7 @@ static int chardev_init_func(void *opaque, QemuOpts *opts, Error **errp)
 {
     Error *local_err = NULL;
 
-    qemu_chr_new_from_opts(opts, NULL, &local_err);
+    qemu_chr_new_from_opts(opts, &local_err);
     if (local_err) {
         error_report_err(local_err);
         return -1;
@@ -2514,7 +2514,7 @@ static int serial_parse(const char *devname)
         exit(1);
     }
     snprintf(label, sizeof(label), "serial%d", index);
-    serial_hds[index] = qemu_chr_new(label, devname, NULL);
+    serial_hds[index] = qemu_chr_new(label, devname);
     if (!serial_hds[index]) {
         error_report("could not connect serial device"
                      " to character backend '%s'", devname);
@@ -2536,7 +2536,7 @@ static int parallel_parse(const char *devname)
         exit(1);
     }
     snprintf(label, sizeof(label), "parallel%d", index);
-    parallel_hds[index] = qemu_chr_new(label, devname, NULL);
+    parallel_hds[index] = qemu_chr_new(label, devname);
     if (!parallel_hds[index]) {
         error_report("could not connect parallel device"
                      " to character backend '%s'", devname);
@@ -2567,7 +2567,7 @@ static int virtcon_parse(const char *devname)
     qemu_opt_set(dev_opts, "driver", "virtconsole", &error_abort);
 
     snprintf(label, sizeof(label), "virtcon%d", index);
-    virtcon_hds[index] = qemu_chr_new(label, devname, NULL);
+    virtcon_hds[index] = qemu_chr_new(label, devname);
     if (!virtcon_hds[index]) {
         error_report("could not connect virtio console"
                      " to character backend '%s'", devname);
@@ -2600,7 +2600,7 @@ static int sclp_parse(const char *devname)
     qemu_opt_set(dev_opts, "driver", "sclpconsole", &error_abort);
 
     snprintf(label, sizeof(label), "sclpcon%d", index);
-    sclp_hds[index] = qemu_chr_new(label, devname, NULL);
+    sclp_hds[index] = qemu_chr_new(label, devname);
     if (!sclp_hds[index]) {
         error_report("could not connect sclp console"
                      " to character backend '%s'", devname);
@@ -2616,7 +2616,7 @@ static int debugcon_parse(const char *devname)
 {
     QemuOpts *opts;
 
-    if (!qemu_chr_new("debugcon", devname, NULL)) {
+    if (!qemu_chr_new("debugcon", devname)) {
         exit(1);
     }
     opts = qemu_opts_create(qemu_find_opts("device"), "debugcon", 1, NULL);
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 26/50] xilinx: fix buffer overflow on realize
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (24 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 25/50] char: remove init callback Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 27/50] mux: split mux_chr_update_read_handler() Paolo Bonzini
                   ` (24 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel

ASAN complains about buffer overflow when running:
aarch64-softmmu/qemu-system-aarch64 -machine xilinx-zynq-a9

==476==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000035e38 at pc 0x000000f75253 bp 0x7ffc597e0ec0 sp 0x7ffc597e0eb0
READ of size 8 at 0x602000035e38 thread T0
    #0 0xf75252 in xilinx_spips_realize hw/ssi/xilinx_spips.c:623
    #1 0xb9ef6c in device_set_realized hw/core/qdev.c:918
    #2 0x129ae01 in property_set_bool qom/object.c:1854
    #3 0x1296e70 in object_property_set qom/object.c:1088
    #4 0x129dd1b in object_property_set_qobject qom/qom-qobject.c:27
    #5 0x1297168 in object_property_set_bool qom/object.c:1157
    #6 0xb9aeac in qdev_init_nofail hw/core/qdev.c:358
    #7 0x78a5bf in zynq_init_spi_flashes /home/elmarco/src/qemu/hw/arm/xilinx_zynq.c:125
    #8 0x78af60 in zynq_init /home/elmarco/src/qemu/hw/arm/xilinx_zynq.c:238
    #9 0x998eac in main /home/elmarco/src/qemu/vl.c:4534
    #10 0x7f96ed692730 in __libc_start_main (/lib64/libc.so.6+0x20730)
    #11 0x41d0a8 in _start (/home/elmarco/src/qemu/aarch64-softmmu/qemu-system-aarch64+0x41d0a8)

0x602000035e38 is located 0 bytes to the right of 8-byte region [0x602000035e30,0x602000035e38)
allocated by thread T0 here:
    #0 0x7f970b014e60 in malloc (/lib64/libasan.so.3+0xc6e60)
    #1 0x7f96f15b0e18 in g_malloc (/lib64/libglib-2.0.so.0+0x4ee18)
    #2 0xb9ef6c in device_set_realized hw/core/qdev.c:918
    #3 0x129ae01 in property_set_bool qom/object.c:1854
    #4 0x1296e70 in object_property_set qom/object.c:1088
    #5 0x129dd1b in object_property_set_qobject qom/qom-qobject.c:27
    #6 0x1297168 in object_property_set_bool qom/object.c:1157
    #7 0xb9aeac in qdev_init_nofail hw/core/qdev.c:358
    #8 0x78a5bf in zynq_init_spi_flashes /home/elmarco/src/qemu/hw/arm/xilinx_zynq.c:125
    #9 0x78af60 in zynq_init /home/elmarco/src/qemu/hw/arm/xilinx_zynq.c:238
    #10 0x998eac in main /home/elmarco/src/qemu/vl.c:4534
    #11 0x7f96ed692730 in __libc_start_main (/lib64/libc.so.6+0x20730)

s->spi is allocated with the size of num_busses which may be 1 (by
default).  Change to use a loop up to s->num_busses also for the
call to ssi_auto_connect_slaves().

Reported-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/ssi/xilinx_spips.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index e2b77dc..da8adfa 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -607,6 +607,7 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp)
     XilinxSPIPS *s = XILINX_SPIPS(dev);
     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
     XilinxSPIPSClass *xsc = XILINX_SPIPS_GET_CLASS(s);
+    qemu_irq *cs;
     int i;
 
     DB_PRINT_L(0, "realized spips\n");
@@ -619,8 +620,10 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp)
     }
 
     s->cs_lines = g_new0(qemu_irq, s->num_cs * s->num_busses);
-    ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[0]);
-    ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[1]);
+    for (i = 0, cs = s->cs_lines; i < s->num_busses; ++i, cs += s->num_cs) {
+        ssi_auto_connect_slaves(DEVICE(s), cs, s->spi[i]);
+    }
+
     sysbus_init_irq(sbd, &s->irq);
     for (i = 0; i < s->num_cs * s->num_busses; ++i) {
         sysbus_init_irq(sbd, &s->cs_lines[i]);
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 27/50] mux: split mux_chr_update_read_handler()
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (25 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 26/50] xilinx: fix buffer overflow on realize Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 28/50] char: introduce CharBackend Paolo Bonzini
                   ` (23 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Make qemu_chr_add_handlers_full() aware of mux handling. This allows
introduction of a tag associated with the fe handlers and a
qemu_chr_set_handlers() function to set the handler for a particular
tag. That will allow to get rid of qemu_chr_add_handlers*() in later
changes, in favor of qemu_chr_fe_set_handler().

To this end, chr_update_read_handler callback is enhanced with a tag
argument, and mux_chr_update_read_handler() is splitted in new
functions: mux_chr_new_handler_tag(), mux_chr_set_handlers(),
mux_set_focus().

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-9-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/sysemu/char.h |   2 +-
 qemu-char.c           | 139 +++++++++++++++++++++++++++++++++++---------------
 2 files changed, 99 insertions(+), 42 deletions(-)

diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index eba77e0..36b5d30 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -80,7 +80,7 @@ struct CharDriverState {
                          const uint8_t *buf, int len);
     GSource *(*chr_add_watch)(struct CharDriverState *s, GIOCondition cond);
     void (*chr_update_read_handler)(struct CharDriverState *s,
-                                    GMainContext *context);
+                                    GMainContext *context, int tag);
     int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg);
     int (*get_msgfds)(struct CharDriverState *s, int* fds, int num);
     int (*set_msgfds)(struct CharDriverState *s, int *fds, int num);
diff --git a/qemu-char.c b/qemu-char.c
index 22504cc..29b339f 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -89,6 +89,8 @@
 #define READ_RETRIES 10
 #define TCP_MAX_FDS 16
 
+typedef struct MuxDriver MuxDriver;
+
 /***********************************************************/
 /* Socket address helpers */
 
@@ -449,12 +451,14 @@ void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...)
 
 static void remove_fd_in_watch(CharDriverState *chr);
 
-void qemu_chr_add_handlers_full(CharDriverState *s,
-                                IOCanReadHandler *fd_can_read,
-                                IOReadHandler *fd_read,
-                                IOEventHandler *fd_event,
-                                void *opaque,
-                                GMainContext *context)
+static void
+qemu_chr_set_handlers(CharDriverState *s,
+                      IOCanReadHandler *fd_can_read,
+                      IOReadHandler *fd_read,
+                      IOEventHandler *fd_event,
+                      void *opaque,
+                      GMainContext *context,
+                      int tag)
 {
     int fe_open;
 
@@ -469,7 +473,7 @@ void qemu_chr_add_handlers_full(CharDriverState *s,
     s->chr_event = fd_event;
     s->handler_opaque = opaque;
     if (s->chr_update_read_handler) {
-        s->chr_update_read_handler(s, context);
+        s->chr_update_read_handler(s, context, tag);
     }
 
     if (!s->explicit_fe_open) {
@@ -483,6 +487,34 @@ void qemu_chr_add_handlers_full(CharDriverState *s,
     }
 }
 
+static int mux_chr_new_handler_tag(CharDriverState *chr, Error **errp);
+static void mux_chr_set_handlers(CharDriverState *chr, GMainContext *context);
+static void mux_set_focus(MuxDriver *d, int focus);
+
+void qemu_chr_add_handlers_full(CharDriverState *s,
+                                IOCanReadHandler *fd_can_read,
+                                IOReadHandler *fd_read,
+                                IOEventHandler *fd_event,
+                                void *opaque,
+                                GMainContext *context)
+{
+    int tag = 0;
+
+    if (s->is_mux) {
+        tag = mux_chr_new_handler_tag(s, &error_abort);
+        if (tag == 0) {
+            mux_chr_set_handlers(s, context);
+        }
+    }
+
+    qemu_chr_set_handlers(s, fd_can_read, fd_read,
+                          fd_event, opaque, context, tag);
+
+    if (s->is_mux) {
+        mux_set_focus(s->opaque, tag);
+    }
+}
+
 void qemu_chr_add_handlers(CharDriverState *s,
                            IOCanReadHandler *fd_can_read,
                            IOReadHandler *fd_read,
@@ -519,7 +551,7 @@ static CharDriverState *qemu_chr_open_null(const char *id,
 #define MAX_MUX 4
 #define MUX_BUFFER_SIZE 32	/* Must be a power of 2.  */
 #define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1)
-typedef struct {
+struct MuxDriver {
     IOCanReadHandler *chr_can_read[MAX_MUX];
     IOReadHandler *chr_read[MAX_MUX];
     IOEventHandler *chr_event[MAX_MUX];
@@ -540,8 +572,7 @@ typedef struct {
     /* Protected by the CharDriverState chr_write_lock.  */
     int linestart;
     int64_t timestamps_start;
-} MuxDriver;
-
+};
 
 /* Called with chr_write_lock held.  */
 static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
@@ -655,12 +686,9 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
             qemu_chr_be_event(chr, CHR_EVENT_BREAK);
             break;
         case 'c':
+            assert(d->mux_cnt > 0); /* handler registered with first fe */
             /* Switch to the next registered device */
-            mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);
-            d->focus++;
-            if (d->focus >= d->mux_cnt)
-                d->focus = 0;
-            mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
+            mux_set_focus(d, (d->focus + 1) % d->mux_cnt);
             break;
         case 't':
             d->timestamps = !d->timestamps;
@@ -735,31 +763,18 @@ static void mux_chr_event(void *opaque, int event)
 }
 
 static void mux_chr_update_read_handler(CharDriverState *chr,
-                                        GMainContext *context)
+                                        GMainContext *context,
+                                        int tag)
 {
     MuxDriver *d = chr->opaque;
 
-    if (d->mux_cnt >= MAX_MUX) {
-        fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n");
-        return;
-    }
-    d->ext_opaque[d->mux_cnt] = chr->handler_opaque;
-    d->chr_can_read[d->mux_cnt] = chr->chr_can_read;
-    d->chr_read[d->mux_cnt] = chr->chr_read;
-    d->chr_event[d->mux_cnt] = chr->chr_event;
-    /* Fix up the real driver with mux routines */
-    if (d->mux_cnt == 0) {
-        qemu_chr_add_handlers_full(d->drv, mux_chr_can_read,
-                                   mux_chr_read,
-                                   mux_chr_event,
-                                   chr, context);
-    }
-    if (d->focus != -1) {
-        mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);
-    }
-    d->focus = d->mux_cnt;
-    d->mux_cnt++;
-    mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
+    assert(tag >= 0);
+    assert(tag < d->mux_cnt);
+
+    d->ext_opaque[tag] = chr->handler_opaque;
+    d->chr_can_read[tag] = chr->chr_can_read;
+    d->chr_read[tag] = chr->chr_read;
+    d->chr_event[tag] = chr->chr_event;
 }
 
 static bool muxes_realized;
@@ -815,6 +830,44 @@ static void mux_chr_close(struct CharDriverState *chr)
     g_free(d);
 }
 
+static int mux_chr_new_handler_tag(CharDriverState *chr, Error **errp)
+{
+    MuxDriver *d = chr->opaque;
+
+    if (d->mux_cnt >= MAX_MUX) {
+        fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n");
+        return -1;
+    }
+
+    return d->mux_cnt++;
+}
+
+static void mux_chr_set_handlers(CharDriverState *chr, GMainContext *context)
+{
+    MuxDriver *d = chr->opaque;
+
+    /* Fix up the real driver with mux routines */
+    qemu_chr_add_handlers_full(d->drv,
+                               mux_chr_can_read,
+                               mux_chr_read,
+                               mux_chr_event,
+                               chr,
+                               context);
+}
+
+static void mux_set_focus(MuxDriver *d, int focus)
+{
+    assert(focus >= 0);
+    assert(focus < d->mux_cnt);
+
+    if (d->focus != -1) {
+        mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);
+    }
+
+    d->focus = focus;
+    mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
+}
+
 static CharDriverState *qemu_chr_open_mux(const char *id,
                                           ChardevBackend *backend,
                                           ChardevReturn *ret, Error **errp)
@@ -1085,7 +1138,8 @@ static GSource *fd_chr_add_watch(CharDriverState *chr, GIOCondition cond)
 }
 
 static void fd_chr_update_read_handler(CharDriverState *chr,
-                                       GMainContext *context)
+                                       GMainContext *context,
+                                       int tag)
 {
     FDCharDriver *s = chr->opaque;
 
@@ -1342,7 +1396,8 @@ static void pty_chr_update_read_handler_locked(CharDriverState *chr)
 }
 
 static void pty_chr_update_read_handler(CharDriverState *chr,
-                                        GMainContext *context)
+                                        GMainContext *context,
+                                        int tag)
 {
     qemu_mutex_lock(&chr->chr_write_lock);
     pty_chr_update_read_handler_locked(chr);
@@ -2589,7 +2644,8 @@ static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 }
 
 static void udp_chr_update_read_handler(CharDriverState *chr,
-                                        GMainContext *context)
+                                        GMainContext *context,
+                                        int tag)
 {
     NetCharDriver *s = chr->opaque;
 
@@ -3008,7 +3064,8 @@ static void tcp_chr_connect(void *opaque)
 }
 
 static void tcp_chr_update_read_handler(CharDriverState *chr,
-                                        GMainContext *context)
+                                        GMainContext *context,
+                                        int tag)
 {
     TCPCharDriver *s = chr->opaque;
 
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 28/50] char: introduce CharBackend
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (26 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 27/50] mux: split mux_chr_update_read_handler() Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 29/50] char: start converting mux driver to use CharBackend Paolo Bonzini
                   ` (22 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

This new structure is meant to keep the details associated with a char
driver usage. On initialization, it gets a tag from the mux backend.
It can change its handlers thanks to qemu_chr_fe_set_handlers().

This structure is introduced so that all frontend will be moved to hold
and use a CharBackend. This will allow to better track char usage and
allocation, and help prevent some memory leaks or corruption.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-10-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/sysemu/char.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 qemu-char.c           | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 100 insertions(+)

diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 36b5d30..c518c2f 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -72,6 +72,12 @@ typedef enum {
     QEMU_CHAR_FEATURE_LAST,
 } CharDriverFeature;
 
+/* This is the backend as seen by frontend, the actual backend is
+ * CharDriverState */
+typedef struct CharBackend {
+    CharDriverState *chr;
+    int tag;
+} CharBackend;
 
 struct CharDriverState {
     QemuMutex chr_write_lock;
@@ -156,6 +162,8 @@ void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend);
  * Returns: a new character backend
  */
 CharDriverState *qemu_chr_new(const char *label, const char *filename);
+
+
 /**
  * @qemu_chr_disconnect:
  *
@@ -425,6 +433,48 @@ void qemu_chr_be_write_impl(CharDriverState *s, uint8_t *buf, int len);
  */
 void qemu_chr_be_event(CharDriverState *s, int event);
 
+/**
+ * @qemu_chr_fe_init:
+ *
+ * Initializes a front end for the given CharBackend and CharDriver.
+ *
+ * Returns: false on error.
+ */
+bool qemu_chr_fe_init(CharBackend *b, CharDriverState *s, Error **errp);
+
+/**
+ * @qemu_chr_fe_get_driver:
+ *
+ * Returns the driver associated with a CharBackend or NULL.
+ */
+CharDriverState *qemu_chr_fe_get_driver(CharBackend *be);
+
+/**
+ * @qemu_chr_fe_set_handlers:
+ * @b: a CharBackend
+ * @fd_can_read: callback to get the amount of data the frontend may
+ *               receive
+ * @fd_read: callback to receive data from char
+ * @fd_event: event callback
+ * @opaque: an opaque pointer for the callbacks
+ * @context: a main loop context or NULL for the default
+ *
+ * Set the front end char handlers.
+ */
+void qemu_chr_fe_set_handlers(CharBackend *b,
+                              IOCanReadHandler *fd_can_read,
+                              IOReadHandler *fd_read,
+                              IOEventHandler *fd_event,
+                              void *opaque,
+                              GMainContext *context);
+
+/**
+ * @qemu_chr_fe_take_focus:
+ *
+ * Take the focus (if the front end is muxed)
+ */
+void qemu_chr_fe_take_focus(CharBackend *b);
+
 void qemu_chr_add_handlers(CharDriverState *s,
                            IOCanReadHandler *fd_can_read,
                            IOReadHandler *fd_read,
diff --git a/qemu-char.c b/qemu-char.c
index 29b339f..9c27371 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -910,6 +910,53 @@ static CharDriverState *qemu_chr_open_mux(const char *id,
     return chr;
 }
 
+CharDriverState *qemu_chr_fe_get_driver(CharBackend *be)
+{
+    return be->chr;
+}
+
+bool qemu_chr_fe_init(CharBackend *b, CharDriverState *s, Error **errp)
+{
+    int tag = 0;
+
+    if (s->is_mux) {
+        tag = mux_chr_new_handler_tag(s, errp);
+        if (tag < 0) {
+            return false;
+        }
+    }
+
+    b->tag = tag;
+    b->chr = s;
+
+    return true;
+}
+
+void qemu_chr_fe_set_handlers(CharBackend *b,
+                              IOCanReadHandler *fd_can_read,
+                              IOReadHandler *fd_read,
+                              IOEventHandler *fd_event,
+                              void *opaque,
+                              GMainContext *context)
+{
+    if (!b->chr) {
+        return;
+    }
+
+    qemu_chr_set_handlers(b->chr, fd_can_read, fd_read,
+                          fd_event, opaque, context, b->tag);
+
+    if (b->chr->is_mux) {
+        mux_chr_set_handlers(b->chr, context);
+    }
+}
+
+void qemu_chr_fe_take_focus(CharBackend *b)
+{
+    if (b->chr->is_mux) {
+        mux_set_focus(b->chr->opaque, b->tag);
+    }
+}
 
 typedef struct IOWatchPoll
 {
@@ -4184,6 +4231,9 @@ void qemu_chr_disconnect(CharDriverState *chr)
 
 static void qemu_chr_free_common(CharDriverState *chr)
 {
+    if (chr->be) {
+        chr->be->chr = NULL;
+    }
     g_free(chr->filename);
     g_free(chr->label);
     if (chr->logfd != -1) {
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 29/50] char: start converting mux driver to use CharBackend
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (27 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 28/50] char: introduce CharBackend Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 30/50] char: replace PROP_CHR with CharBackend Paolo Bonzini
                   ` (21 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Start using qemu_chr_fe* CharBackend functions:
initialize a CharBackend and use qemu_chr_fe_set_handlers().

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-11-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 qemu-char.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index 9c27371..9eefa7f 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -502,9 +502,7 @@ void qemu_chr_add_handlers_full(CharDriverState *s,
 
     if (s->is_mux) {
         tag = mux_chr_new_handler_tag(s, &error_abort);
-        if (tag == 0) {
-            mux_chr_set_handlers(s, context);
-        }
+        mux_chr_set_handlers(s, context);
     }
 
     qemu_chr_set_handlers(s, fd_can_read, fd_read,
@@ -557,6 +555,7 @@ struct MuxDriver {
     IOEventHandler *chr_event[MAX_MUX];
     void *ext_opaque[MAX_MUX];
     CharDriverState *drv;
+    CharBackend chr;
     int focus;
     int mux_cnt;
     int term_got_escape;
@@ -847,12 +846,12 @@ static void mux_chr_set_handlers(CharDriverState *chr, GMainContext *context)
     MuxDriver *d = chr->opaque;
 
     /* Fix up the real driver with mux routines */
-    qemu_chr_add_handlers_full(d->drv,
-                               mux_chr_can_read,
-                               mux_chr_read,
-                               mux_chr_event,
-                               chr,
-                               context);
+    qemu_chr_fe_set_handlers(&d->chr,
+                             mux_chr_can_read,
+                             mux_chr_read,
+                             mux_chr_event,
+                             chr,
+                             context);
 }
 
 static void mux_set_focus(MuxDriver *d, int focus)
@@ -906,6 +905,10 @@ static CharDriverState *qemu_chr_open_mux(const char *id,
      */
     chr->explicit_be_open = muxes_realized ? 0 : 1;
     chr->is_mux = 1;
+    if (!qemu_chr_fe_init(&d->chr, d->drv, errp)) {
+        qemu_chr_free(chr);
+        return NULL;
+    }
 
     return chr;
 }
@@ -4231,9 +4234,6 @@ void qemu_chr_disconnect(CharDriverState *chr)
 
 static void qemu_chr_free_common(CharDriverState *chr)
 {
-    if (chr->be) {
-        chr->be->chr = NULL;
-    }
     g_free(chr->filename);
     g_free(chr->label);
     if (chr->logfd != -1) {
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 30/50] char: replace PROP_CHR with CharBackend
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (28 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 29/50] char: start converting mux driver to use CharBackend Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 31/50] char: remaining switch to CharBackend in frontend Paolo Bonzini
                   ` (20 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Store the property in a CharBackend instead of CharDriverState*.  This
also replace systematically chr by chr.chr to access the
CharDriverState*. The following patches will replace it with calls to
qemu_chr_fe CharBackend functions.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-12-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/arm/pxa2xx.c                   | 18 +++++----
 hw/arm/strongarm.c                | 14 +++----
 hw/char/bcm2835_aux.c             | 12 +++---
 hw/char/cadence_uart.c            | 26 ++++++------
 hw/char/debugcon.c                |  8 ++--
 hw/char/digic-uart.c              |  8 ++--
 hw/char/escc.c                    | 21 +++++-----
 hw/char/etraxfs_ser.c             |  8 ++--
 hw/char/exynos4210_uart.c         | 10 ++---
 hw/char/grlib_apbuart.c           |  8 ++--
 hw/char/imx_serial.c              | 19 ++++-----
 hw/char/ipoctal232.c              | 14 +++----
 hw/char/lm32_juart.c              | 11 ++---
 hw/char/lm32_uart.c               | 12 +++---
 hw/char/milkymist-uart.c          | 12 +++---
 hw/char/parallel.c                | 46 +++++++++++----------
 hw/char/pl011.c                   | 15 +++----
 hw/char/sclpconsole-lm.c          | 13 +++---
 hw/char/sclpconsole.c             | 10 ++---
 hw/char/serial.c                  | 34 +++++++++-------
 hw/char/spapr_vty.c               | 10 ++---
 hw/char/stm32f2xx_usart.c         | 16 ++++----
 hw/char/virtio-console.c          | 28 ++++++-------
 hw/char/xilinx_uartlite.c         | 15 +++----
 hw/core/qdev-properties-system.c  | 84 +++++++++++++++++++++++----------------
 hw/ipmi/ipmi_bmc_extern.c         |  8 ++--
 hw/misc/ivshmem.c                 | 18 ++++-----
 hw/usb/ccid-card-passthru.c       | 14 +++----
 hw/usb/dev-serial.c               | 22 +++++-----
 hw/usb/redirect.c                 | 16 ++++----
 include/hw/char/bcm2835_aux.h     |  2 +-
 include/hw/char/cadence_uart.h    |  2 +-
 include/hw/char/digic-uart.h      |  3 +-
 include/hw/char/imx_serial.h      |  3 +-
 include/hw/char/serial.h          |  3 +-
 include/hw/char/stm32f2xx_usart.h |  2 +-
 include/hw/qdev-properties.h      |  2 +-
 37 files changed, 302 insertions(+), 265 deletions(-)

diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index 9898287..27f112c 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -1764,7 +1764,7 @@ struct PXA2xxFIrState {
     qemu_irq rx_dma;
     qemu_irq tx_dma;
     uint32_t enable;
-    CharDriverState *chr;
+    CharBackend chr;
 
     uint8_t control[3];
     uint8_t status[2];
@@ -1898,14 +1898,16 @@ static void pxa2xx_fir_write(void *opaque, hwaddr addr,
         pxa2xx_fir_update(s);
         break;
     case ICDR:
-        if (s->control[2] & (1 << 2))			/* TXP */
+        if (s->control[2] & (1 << 2)) { /* TXP */
             ch = value;
-        else
+        } else {
             ch = ~value;
-        if (s->chr && s->enable && (s->control[0] & (1 << 3)))	/* TXE */
+        }
+        if (s->chr.chr && s->enable && (s->control[0] & (1 << 3))) { /* TXE */
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(s->chr, &ch, 1);
+            qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
+        }
         break;
     case ICSR0:
         s->status[0] &= ~(value & 0x66);
@@ -1973,9 +1975,9 @@ static void pxa2xx_fir_realize(DeviceState *dev, Error **errp)
 {
     PXA2xxFIrState *s = PXA2XX_FIR(dev);
 
-    if (s->chr) {
-        qemu_chr_fe_claim_no_fail(s->chr);
-        qemu_chr_add_handlers(s->chr, pxa2xx_fir_is_empty,
+    if (s->chr.chr) {
+        qemu_chr_fe_claim_no_fail(s->chr.chr);
+        qemu_chr_add_handlers(s->chr.chr, pxa2xx_fir_is_empty,
                         pxa2xx_fir_rx, pxa2xx_fir_event, s);
     }
 }
diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c
index 021cbf9..d3e8aff 100644
--- a/hw/arm/strongarm.c
+++ b/hw/arm/strongarm.c
@@ -912,7 +912,7 @@ typedef struct StrongARMUARTState {
     SysBusDevice parent_obj;
 
     MemoryRegion iomem;
-    CharDriverState *chr;
+    CharBackend chr;
     qemu_irq irq;
 
     uint8_t utcr0;
@@ -1020,8 +1020,8 @@ static void strongarm_uart_update_parameters(StrongARMUARTState *s)
     ssp.data_bits = data_bits;
     ssp.stop_bits = stop_bits;
     s->char_transmit_time =  (NANOSECONDS_PER_SECOND / speed) * frame_size;
-    if (s->chr) {
-        qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+    if (s->chr.chr) {
+        qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
     }
 
     DPRINTF(stderr, "%s speed=%d parity=%c data=%d stop=%d\n", s->chr->label,
@@ -1107,10 +1107,10 @@ static void strongarm_uart_tx(void *opaque)
 
     if (s->utcr3 & UTCR3_LBM) /* loopback */ {
         strongarm_uart_receive(s, &s->tx_fifo[s->tx_start], 1);
-    } else if (s->chr) {
+    } else if (s->chr.chr) {
         /* XXX this blocks entire thread. Rewrite to use
          * qemu_chr_fe_write and background I/O callbacks */
-        qemu_chr_fe_write_all(s->chr, &s->tx_fifo[s->tx_start], 1);
+        qemu_chr_fe_write_all(s->chr.chr, &s->tx_fifo[s->tx_start], 1);
     }
 
     s->tx_start = (s->tx_start + 1) % 8;
@@ -1239,8 +1239,8 @@ static void strongarm_uart_init(Object *obj)
     s->rx_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_rx_to, s);
     s->tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_tx, s);
 
-    if (s->chr) {
-        qemu_chr_add_handlers(s->chr,
+    if (s->chr.chr) {
+        qemu_chr_add_handlers(s->chr.chr,
                         strongarm_uart_can_receive,
                         strongarm_uart_receive,
                         strongarm_uart_event,
diff --git a/hw/char/bcm2835_aux.c b/hw/char/bcm2835_aux.c
index f7a845d..4bc5d02 100644
--- a/hw/char/bcm2835_aux.c
+++ b/hw/char/bcm2835_aux.c
@@ -79,8 +79,8 @@ static uint64_t bcm2835_aux_read(void *opaque, hwaddr offset, unsigned size)
                 s->read_pos = 0;
             }
         }
-        if (s->chr) {
-            qemu_chr_accept_input(s->chr);
+        if (s->chr.chr) {
+            qemu_chr_accept_input(s->chr.chr);
         }
         bcm2835_aux_update(s);
         return c;
@@ -168,10 +168,10 @@ static void bcm2835_aux_write(void *opaque, hwaddr offset, uint64_t value,
     case AUX_MU_IO_REG:
         /* "DLAB bit set means access baudrate register" is NYI */
         ch = value;
-        if (s->chr) {
+        if (s->chr.chr) {
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(s->chr, &ch, 1);
+            qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
         }
         break;
 
@@ -282,8 +282,8 @@ static void bcm2835_aux_realize(DeviceState *dev, Error **errp)
 {
     BCM2835AuxState *s = BCM2835_AUX(dev);
 
-    if (s->chr) {
-        qemu_chr_add_handlers(s->chr, bcm2835_aux_can_receive,
+    if (s->chr.chr) {
+        qemu_chr_add_handlers(s->chr.chr, bcm2835_aux_can_receive,
                               bcm2835_aux_receive, NULL, s);
     }
 }
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
index e3bc52f..d5687dd 100644
--- a/hw/char/cadence_uart.c
+++ b/hw/char/cadence_uart.c
@@ -142,8 +142,8 @@ static void uart_rx_reset(CadenceUARTState *s)
 {
     s->rx_wpos = 0;
     s->rx_count = 0;
-    if (s->chr) {
-        qemu_chr_accept_input(s->chr);
+    if (s->chr.chr) {
+        qemu_chr_accept_input(s->chr.chr);
     }
 }
 
@@ -156,8 +156,8 @@ static void uart_send_breaks(CadenceUARTState *s)
 {
     int break_enabled = 1;
 
-    if (s->chr) {
-        qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
+    if (s->chr.chr) {
+        qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_SERIAL_SET_BREAK,
                                    &break_enabled);
     }
 }
@@ -210,8 +210,8 @@ static void uart_parameters_setup(CadenceUARTState *s)
 
     packet_size += ssp.data_bits + ssp.stop_bits;
     s->char_tx_time = (NANOSECONDS_PER_SECOND / ssp.speed) * packet_size;
-    if (s->chr) {
-        qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+    if (s->chr.chr) {
+        qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
     }
 }
 
@@ -278,7 +278,7 @@ static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond,
     int ret;
 
     /* instant drain the fifo when there's no back-end */
-    if (!s->chr) {
+    if (!s->chr.chr) {
         s->tx_count = 0;
         return FALSE;
     }
@@ -287,7 +287,7 @@ static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond,
         return FALSE;
     }
 
-    ret = qemu_chr_fe_write(s->chr, s->tx_fifo, s->tx_count);
+    ret = qemu_chr_fe_write(s->chr.chr, s->tx_fifo, s->tx_count);
 
     if (ret >= 0) {
         s->tx_count -= ret;
@@ -295,7 +295,7 @@ static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond,
     }
 
     if (s->tx_count) {
-        guint r = qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP,
+        guint r = qemu_chr_fe_add_watch(s->chr.chr, G_IO_OUT | G_IO_HUP,
                                         cadence_uart_xmit, s);
         if (!r) {
             s->tx_count = 0;
@@ -368,8 +368,8 @@ static void uart_read_rx_fifo(CadenceUARTState *s, uint32_t *c)
         *c = s->rx_fifo[rx_rpos];
         s->rx_count--;
 
-        if (s->chr) {
-            qemu_chr_accept_input(s->chr);
+        if (s->chr.chr) {
+            qemu_chr_accept_input(s->chr.chr);
         }
     } else {
         *c = 0;
@@ -474,8 +474,8 @@ static void cadence_uart_realize(DeviceState *dev, Error **errp)
     s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
                                           fifo_trigger_update, s);
 
-    if (s->chr) {
-        qemu_chr_add_handlers(s->chr, uart_can_receive, uart_receive,
+    if (s->chr.chr) {
+        qemu_chr_add_handlers(s->chr.chr, uart_can_receive, uart_receive,
                               uart_event, s);
     }
 }
diff --git a/hw/char/debugcon.c b/hw/char/debugcon.c
index 4402033..b405109 100644
--- a/hw/char/debugcon.c
+++ b/hw/char/debugcon.c
@@ -39,7 +39,7 @@
 
 typedef struct DebugconState {
     MemoryRegion io;
-    CharDriverState *chr;
+    CharBackend chr;
     uint32_t readback;
 } DebugconState;
 
@@ -62,7 +62,7 @@ static void debugcon_ioport_write(void *opaque, hwaddr addr, uint64_t val,
 
     /* XXX this blocks entire thread. Rewrite to use
      * qemu_chr_fe_write and background I/O callbacks */
-    qemu_chr_fe_write_all(s->chr, &ch, 1);
+    qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
 }
 
 
@@ -87,12 +87,12 @@ static const MemoryRegionOps debugcon_ops = {
 
 static void debugcon_realize_core(DebugconState *s, Error **errp)
 {
-    if (!s->chr) {
+    if (!s->chr.chr) {
         error_setg(errp, "Can't create debugcon device, empty char device");
         return;
     }
 
-    qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, s);
+    qemu_chr_add_handlers(s->chr.chr, NULL, NULL, NULL, s);
 }
 
 static void debugcon_isa_realizefn(DeviceState *dev, Error **errp)
diff --git a/hw/char/digic-uart.c b/hw/char/digic-uart.c
index e96a9b2..fb4969f 100644
--- a/hw/char/digic-uart.c
+++ b/hw/char/digic-uart.c
@@ -76,10 +76,10 @@ static void digic_uart_write(void *opaque, hwaddr addr, uint64_t value,
 
     switch (addr) {
     case R_TX:
-        if (s->chr) {
+        if (s->chr.chr) {
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(s->chr, &ch, 1);
+            qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
         }
         break;
 
@@ -147,8 +147,8 @@ static void digic_uart_realize(DeviceState *dev, Error **errp)
 {
     DigicUartState *s = DIGIC_UART(dev);
 
-    if (s->chr) {
-        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+    if (s->chr.chr) {
+        qemu_chr_add_handlers(s->chr.chr, uart_can_rx, uart_rx, uart_event, s);
     }
 }
 
diff --git a/hw/char/escc.c b/hw/char/escc.c
index aa17397..ae69b39 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -88,7 +88,7 @@ typedef struct ChannelState {
     uint32_t reg;
     uint8_t wregs[SERIAL_REGS], rregs[SERIAL_REGS];
     SERIOQueue queue;
-    CharDriverState *chr;
+    CharBackend chr;
     int e0_mode, led_mode, caps_lock_mode, num_lock_mode;
     int disabled;
     int clock;
@@ -416,7 +416,7 @@ static void escc_update_parameters(ChannelState *s)
     int speed, parity, data_bits, stop_bits;
     QEMUSerialSetParams ssp;
 
-    if (!s->chr || s->type != ser)
+    if (!s->chr.chr || s->type != ser)
         return;
 
     if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREN) {
@@ -466,7 +466,7 @@ static void escc_update_parameters(ChannelState *s)
     ssp.data_bits = data_bits;
     ssp.stop_bits = stop_bits;
     trace_escc_update_parameters(CHN_C(s), speed, parity, data_bits, stop_bits);
-    qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+    qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
 }
 
 static void escc_mem_write(void *opaque, hwaddr addr,
@@ -556,11 +556,11 @@ static void escc_mem_write(void *opaque, hwaddr addr,
         trace_escc_mem_writeb_data(CHN_C(s), val);
         s->tx = val;
         if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled
-            if (s->chr)
+            if (s->chr.chr) {
                 /* XXX this blocks entire thread. Rewrite to use
                  * qemu_chr_fe_write and background I/O callbacks */
-                qemu_chr_fe_write_all(s->chr, &s->tx, 1);
-            else if (s->type == kbd && !s->disabled) {
+                qemu_chr_fe_write_all(s->chr.chr, &s->tx, 1);
+            } else if (s->type == kbd && !s->disabled) {
                 handle_kbd_command(s, val);
             }
         }
@@ -599,8 +599,9 @@ static uint64_t escc_mem_read(void *opaque, hwaddr addr,
         else
             ret = s->rx;
         trace_escc_mem_readb_data(CHN_C(s), ret);
-        if (s->chr)
-            qemu_chr_accept_input(s->chr);
+        if (s->chr.chr) {
+            qemu_chr_accept_input(s->chr.chr);
+        }
         return ret;
     default:
         break;
@@ -1013,9 +1014,9 @@ static void escc_realize(DeviceState *dev, Error **errp)
                           ESCC_SIZE << s->it_shift);
 
     for (i = 0; i < 2; i++) {
-        if (s->chn[i].chr) {
+        if (s->chn[i].chr.chr) {
             s->chn[i].clock = s->frequency / 2;
-            qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive,
+            qemu_chr_add_handlers(s->chn[i].chr.chr, serial_can_receive,
                                   serial_receive1, serial_event, &s->chn[i]);
         }
     }
diff --git a/hw/char/etraxfs_ser.c b/hw/char/etraxfs_ser.c
index c99cc5d..99c4801 100644
--- a/hw/char/etraxfs_ser.c
+++ b/hw/char/etraxfs_ser.c
@@ -53,7 +53,7 @@ typedef struct ETRAXSerial {
     SysBusDevice parent_obj;
 
     MemoryRegion mmio;
-    CharDriverState *chr;
+    CharBackend chr;
     qemu_irq irq;
 
     int pending_tx;
@@ -128,7 +128,7 @@ ser_write(void *opaque, hwaddr addr,
         case RW_DOUT:
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(s->chr, &ch, 1);
+            qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
             s->regs[R_INTR] |= 3;
             s->pending_tx = 1;
             s->regs[addr] = value;
@@ -231,8 +231,8 @@ static void etraxfs_ser_realize(DeviceState *dev, Error **errp)
 {
     ETRAXSerial *s = ETRAX_SERIAL(dev);
 
-    if (s->chr) {
-        qemu_chr_add_handlers(s->chr,
+    if (s->chr.chr) {
+        qemu_chr_add_handlers(s->chr.chr,
                               serial_can_receive, serial_receive,
                               serial_event, s);
     }
diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
index 66e6304..3f71059 100644
--- a/hw/char/exynos4210_uart.c
+++ b/hw/char/exynos4210_uart.c
@@ -181,7 +181,7 @@ typedef struct Exynos4210UartState {
     Exynos4210UartFIFO   rx;
     Exynos4210UartFIFO   tx;
 
-    CharDriverState  *chr;
+    CharBackend       chr;
     qemu_irq          irq;
 
     uint32_t channel;
@@ -346,7 +346,7 @@ static void exynos4210_uart_update_parameters(Exynos4210UartState *s)
     ssp.data_bits = data_bits;
     ssp.stop_bits = stop_bits;
 
-    qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+    qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
 
     PRINT_DEBUG("UART%d: speed: %d, parity: %c, data: %d, stop: %d\n",
                 s->channel, speed, parity, data_bits, stop_bits);
@@ -383,13 +383,13 @@ static void exynos4210_uart_write(void *opaque, hwaddr offset,
         break;
 
     case UTXH:
-        if (s->chr) {
+        if (s->chr.chr) {
             s->reg[I_(UTRSTAT)] &= ~(UTRSTAT_TRANSMITTER_EMPTY |
                     UTRSTAT_Tx_BUFFER_EMPTY);
             ch = (uint8_t)val;
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(s->chr, &ch, 1);
+            qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
 #if DEBUG_Tx_DATA
             fprintf(stderr, "%c", ch);
 #endif
@@ -640,7 +640,7 @@ static int exynos4210_uart_init(SysBusDevice *dev)
 
     sysbus_init_irq(dev, &s->irq);
 
-    qemu_chr_add_handlers(s->chr, exynos4210_uart_can_receive,
+    qemu_chr_add_handlers(s->chr.chr, exynos4210_uart_can_receive,
                           exynos4210_uart_receive, exynos4210_uart_event, s);
 
     return 0;
diff --git a/hw/char/grlib_apbuart.c b/hw/char/grlib_apbuart.c
index 778148a..13c9455 100644
--- a/hw/char/grlib_apbuart.c
+++ b/hw/char/grlib_apbuart.c
@@ -78,7 +78,7 @@ typedef struct UART {
     MemoryRegion iomem;
     qemu_irq irq;
 
-    CharDriverState *chr;
+    CharBackend chr;
 
     /* registers */
     uint32_t status;
@@ -201,11 +201,11 @@ static void grlib_apbuart_write(void *opaque, hwaddr addr,
     case DATA_OFFSET:
     case DATA_OFFSET + 3:       /* When only one byte write */
         /* Transmit when character device available and transmitter enabled */
-        if ((uart->chr) && (uart->control & UART_TRANSMIT_ENABLE)) {
+        if (uart->chr.chr && (uart->control & UART_TRANSMIT_ENABLE)) {
             c = value & 0xFF;
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(uart->chr, &c, 1);
+            qemu_chr_fe_write_all(uart->chr.chr, &c, 1);
             /* Generate interrupt */
             if (uart->control & UART_TRANSMIT_INTERRUPT) {
                 qemu_irq_pulse(uart->irq);
@@ -242,7 +242,7 @@ static int grlib_apbuart_init(SysBusDevice *dev)
 {
     UART *uart = GRLIB_APB_UART(dev);
 
-    qemu_chr_add_handlers(uart->chr,
+    qemu_chr_add_handlers(uart->chr.chr,
                           grlib_apbuart_can_receive,
                           grlib_apbuart_receive,
                           grlib_apbuart_event,
diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c
index 5c3fa61..5c11de2 100644
--- a/hw/char/imx_serial.c
+++ b/hw/char/imx_serial.c
@@ -121,8 +121,8 @@ static uint64_t imx_serial_read(void *opaque, hwaddr offset,
             s->usr2 &= ~USR2_RDR;
             s->uts1 |= UTS1_RXEMPTY;
             imx_update(s);
-            if (s->chr) {
-                qemu_chr_accept_input(s->chr);
+            if (s->chr.chr) {
+                qemu_chr_accept_input(s->chr.chr);
             }
         }
         return c;
@@ -175,16 +175,17 @@ static void imx_serial_write(void *opaque, hwaddr offset,
     unsigned char ch;
 
     DPRINTF("write(offset=0x%" HWADDR_PRIx ", value = 0x%x) to %s\n",
-            offset, (unsigned int)value, s->chr ? s->chr->label : "NODEV");
+            offset, (unsigned int)value,
+            s->chr.chr ? s->chr.chr->label : "NODEV");
 
     switch (offset >> 2) {
     case 0x10: /* UTXD */
         ch = value;
         if (s->ucr2 & UCR2_TXEN) {
-            if (s->chr) {
+            if (s->chr.chr) {
                 /* XXX this blocks entire thread. Rewrite to use
                  * qemu_chr_fe_write and background I/O callbacks */
-                qemu_chr_fe_write_all(s->chr, &ch, 1);
+                qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
             }
             s->usr1 &= ~USR1_TRDY;
             imx_update(s);
@@ -214,8 +215,8 @@ static void imx_serial_write(void *opaque, hwaddr offset,
         }
         if (value & UCR2_RXEN) {
             if (!(s->ucr2 & UCR2_RXEN)) {
-                if (s->chr) {
-                    qemu_chr_accept_input(s->chr);
+                if (s->chr.chr) {
+                    qemu_chr_accept_input(s->chr.chr);
                 }
             }
         }
@@ -318,8 +319,8 @@ static void imx_serial_realize(DeviceState *dev, Error **errp)
 {
     IMXSerialState *s = IMX_SERIAL(dev);
 
-    if (s->chr) {
-        qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive,
+    if (s->chr.chr) {
+        qemu_chr_add_handlers(s->chr.chr, imx_can_receive, imx_receive,
                               imx_event, s);
     } else {
         DPRINTF("No char dev for uart\n");
diff --git a/hw/char/ipoctal232.c b/hw/char/ipoctal232.c
index 2859fdd..0c9dea3 100644
--- a/hw/char/ipoctal232.c
+++ b/hw/char/ipoctal232.c
@@ -93,7 +93,7 @@ typedef struct SCC2698Block SCC2698Block;
 
 struct SCC2698Channel {
     IPOctalState *ipoctal;
-    CharDriverState *dev;
+    CharBackend dev;
     bool rx_enabled;
     uint8_t mr[2];
     uint8_t mr_idx;
@@ -288,8 +288,8 @@ static uint16_t io_read(IPackDevice *ip, uint8_t addr)
             if (ch->rx_pending == 0) {
                 ch->sr &= ~SR_RXRDY;
                 blk->isr &= ~ISR_RXRDY(channel);
-                if (ch->dev) {
-                    qemu_chr_accept_input(ch->dev);
+                if (ch->dev.chr) {
+                    qemu_chr_accept_input(ch->dev.chr);
                 }
             } else {
                 ch->rhr_idx = (ch->rhr_idx + 1) % RX_FIFO_SIZE;
@@ -358,11 +358,11 @@ static void io_write(IPackDevice *ip, uint8_t addr, uint16_t val)
     case REG_THRb:
         if (ch->sr & SR_TXRDY) {
             DPRINTF("Write THR%c (0x%x)\n", channel + 'a', reg);
-            if (ch->dev) {
+            if (ch->dev.chr) {
                 uint8_t thr = reg;
                 /* XXX this blocks entire thread. Rewrite to use
                  * qemu_chr_fe_write and background I/O callbacks */
-                qemu_chr_fe_write_all(ch->dev, &thr, 1);
+                qemu_chr_fe_write_all(ch->dev.chr, &thr, 1);
             }
         } else {
             DPRINTF("Write THR%c (0x%x), Tx disabled\n", channel + 'a', reg);
@@ -546,8 +546,8 @@ static void ipoctal_realize(DeviceState *dev, Error **errp)
         ch->ipoctal = s;
 
         /* Redirect IP-Octal channels to host character devices */
-        if (ch->dev) {
-            qemu_chr_add_handlers(ch->dev, hostdev_can_receive,
+        if (ch->dev.chr) {
+            qemu_chr_add_handlers(ch->dev.chr, hostdev_can_receive,
                                   hostdev_receive, hostdev_event, ch);
             DPRINTF("Redirecting channel %u to %s\n", i, ch->dev->label);
         } else {
diff --git a/hw/char/lm32_juart.c b/hw/char/lm32_juart.c
index cb1ac76..a0eb312 100644
--- a/hw/char/lm32_juart.c
+++ b/hw/char/lm32_juart.c
@@ -44,7 +44,7 @@ enum {
 struct LM32JuartState {
     SysBusDevice parent_obj;
 
-    CharDriverState *chr;
+    CharBackend chr;
 
     uint32_t jtx;
     uint32_t jrx;
@@ -75,10 +75,10 @@ void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx)
     trace_lm32_juart_set_jtx(s->jtx);
 
     s->jtx = jtx;
-    if (s->chr) {
+    if (s->chr.chr) {
         /* XXX this blocks entire thread. Rewrite to use
          * qemu_chr_fe_write and background I/O callbacks */
-        qemu_chr_fe_write_all(s->chr, &ch, 1);
+        qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
     }
 }
 
@@ -120,8 +120,9 @@ static void lm32_juart_realize(DeviceState *dev, Error **errp)
 {
     LM32JuartState *s = LM32_JUART(dev);
 
-    if (s->chr) {
-        qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s);
+    if (s->chr.chr) {
+        qemu_chr_add_handlers(s->chr.chr, juart_can_rx,
+                              juart_rx, juart_event, s);
     }
 }
 
diff --git a/hw/char/lm32_uart.c b/hw/char/lm32_uart.c
index be93697..72fc41c 100644
--- a/hw/char/lm32_uart.c
+++ b/hw/char/lm32_uart.c
@@ -97,7 +97,7 @@ struct LM32UartState {
     SysBusDevice parent_obj;
 
     MemoryRegion iomem;
-    CharDriverState *chr;
+    CharBackend chr;
     qemu_irq irq;
 
     uint32_t regs[R_MAX];
@@ -142,7 +142,7 @@ static uint64_t uart_read(void *opaque, hwaddr addr,
         r = s->regs[R_RXTX];
         s->regs[R_LSR] &= ~LSR_DR;
         uart_update_irq(s);
-        qemu_chr_accept_input(s->chr);
+        qemu_chr_accept_input(s->chr.chr);
         break;
     case R_IIR:
     case R_LSR:
@@ -177,10 +177,10 @@ static void uart_write(void *opaque, hwaddr addr,
     addr >>= 2;
     switch (addr) {
     case R_RXTX:
-        if (s->chr) {
+        if (s->chr.chr) {
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(s->chr, &ch, 1);
+            qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
         }
         break;
     case R_IER:
@@ -267,8 +267,8 @@ static void lm32_uart_realize(DeviceState *dev, Error **errp)
 {
     LM32UartState *s = LM32_UART(dev);
 
-    if (s->chr) {
-        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+    if (s->chr.chr) {
+        qemu_chr_add_handlers(s->chr.chr, uart_can_rx, uart_rx, uart_event, s);
     }
 }
 
diff --git a/hw/char/milkymist-uart.c b/hw/char/milkymist-uart.c
index baddb37..a6518e6 100644
--- a/hw/char/milkymist-uart.c
+++ b/hw/char/milkymist-uart.c
@@ -61,7 +61,7 @@ struct MilkymistUartState {
     SysBusDevice parent_obj;
 
     MemoryRegion regs_region;
-    CharDriverState *chr;
+    CharBackend chr;
     qemu_irq irq;
 
     uint32_t regs[R_MAX];
@@ -124,8 +124,8 @@ static void uart_write(void *opaque, hwaddr addr, uint64_t value,
     addr >>= 2;
     switch (addr) {
     case R_RXTX:
-        if (s->chr) {
-            qemu_chr_fe_write_all(s->chr, &ch, 1);
+        if (s->chr.chr) {
+            qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
         }
         s->regs[R_STAT] |= STAT_TX_EVT;
         break;
@@ -138,7 +138,7 @@ static void uart_write(void *opaque, hwaddr addr, uint64_t value,
     case R_STAT:
         /* write one to clear bits */
         s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT));
-        qemu_chr_accept_input(s->chr);
+        qemu_chr_accept_input(s->chr.chr);
         break;
 
     default:
@@ -200,8 +200,8 @@ static void milkymist_uart_realize(DeviceState *dev, Error **errp)
 {
     MilkymistUartState *s = MILKYMIST_UART(dev);
 
-    if (s->chr) {
-        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+    if (s->chr.chr) {
+        qemu_chr_add_handlers(s->chr.chr, uart_can_rx, uart_rx, uart_event, s);
     }
 }
 
diff --git a/hw/char/parallel.c b/hw/char/parallel.c
index da22e36..80576af 100644
--- a/hw/char/parallel.c
+++ b/hw/char/parallel.c
@@ -74,7 +74,7 @@ typedef struct ParallelState {
     uint8_t control;
     qemu_irq irq;
     int irq_pending;
-    CharDriverState *chr;
+    CharBackend chr;
     int hw_driver;
     int epp_timeout;
     uint32_t last_read_offset; /* For debugging */
@@ -131,7 +131,7 @@ parallel_ioport_write_sw(void *opaque, uint32_t addr, uint32_t val)
                 if ((s->control & PARA_CTR_STROBE) == 0)
                     /* XXX this blocks entire thread. Rewrite to use
                      * qemu_chr_fe_write and background I/O callbacks */
-                    qemu_chr_fe_write_all(s->chr, &s->dataw, 1);
+                    qemu_chr_fe_write_all(s->chr.chr, &s->dataw, 1);
             } else {
                 if (s->control & PARA_CTR_INTEN) {
                     s->irq_pending = 1;
@@ -161,7 +161,7 @@ static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
         if (s->dataw == val)
             return;
         pdebug("wd%02x\n", val);
-        qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &parm);
+        qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_WRITE_DATA, &parm);
         s->dataw = val;
         break;
     case PARA_REG_STS:
@@ -181,11 +181,11 @@ static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
             } else {
                 dir = 0;
             }
-            qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_DATA_DIR, &dir);
+            qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_DATA_DIR, &dir);
             parm &= ~PARA_CTR_DIR;
         }
 
-        qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm);
+        qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm);
         s->control = val;
         break;
     case PARA_REG_EPP_ADDR:
@@ -194,7 +194,8 @@ static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
             pdebug("wa%02x s\n", val);
         else {
             struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
-            if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE_ADDR, &ioarg)) {
+            if (qemu_chr_fe_ioctl(s->chr.chr,
+                                  CHR_IOCTL_PP_EPP_WRITE_ADDR, &ioarg)) {
                 s->epp_timeout = 1;
                 pdebug("wa%02x t\n", val);
             }
@@ -208,7 +209,7 @@ static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
             pdebug("we%02x s\n", val);
         else {
             struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
-            if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg)) {
+            if (qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg)) {
                 s->epp_timeout = 1;
                 pdebug("we%02x t\n", val);
             }
@@ -233,7 +234,7 @@ parallel_ioport_eppdata_write_hw2(void *opaque, uint32_t addr, uint32_t val)
         pdebug("we%04x s\n", val);
         return;
     }
-    err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
+    err = qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
     if (err) {
         s->epp_timeout = 1;
         pdebug("we%04x t\n", val);
@@ -256,7 +257,7 @@ parallel_ioport_eppdata_write_hw4(void *opaque, uint32_t addr, uint32_t val)
         pdebug("we%08x s\n", val);
         return;
     }
-    err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
+    err = qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
     if (err) {
         s->epp_timeout = 1;
         pdebug("we%08x t\n", val);
@@ -308,13 +309,13 @@ static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
     addr &= 7;
     switch(addr) {
     case PARA_REG_DATA:
-        qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &ret);
+        qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_READ_DATA, &ret);
         if (s->last_read_offset != addr || s->datar != ret)
             pdebug("rd%02x\n", ret);
         s->datar = ret;
         break;
     case PARA_REG_STS:
-        qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &ret);
+        qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_READ_STATUS, &ret);
         ret &= ~PARA_STS_TMOUT;
         if (s->epp_timeout)
             ret |= PARA_STS_TMOUT;
@@ -326,7 +327,7 @@ static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
         /* s->control has some bits fixed to 1. It is zero only when
            it has not been yet written to.  */
         if (s->control == 0) {
-            qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &ret);
+            qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_READ_CONTROL, &ret);
             if (s->last_read_offset != addr)
                 pdebug("rc%02x\n", ret);
             s->control = ret;
@@ -338,12 +339,14 @@ static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
         }
         break;
     case PARA_REG_EPP_ADDR:
-        if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT))
+        if ((s->control & (PARA_CTR_DIR | PARA_CTR_SIGNAL)) !=
+            (PARA_CTR_DIR | PARA_CTR_INIT))
             /* Controls not correct for EPP addr cycle, so do nothing */
             pdebug("ra%02x s\n", ret);
         else {
             struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
-            if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ_ADDR, &ioarg)) {
+            if (qemu_chr_fe_ioctl(s->chr.chr,
+                                  CHR_IOCTL_PP_EPP_READ_ADDR, &ioarg)) {
                 s->epp_timeout = 1;
                 pdebug("ra%02x t\n", ret);
             }
@@ -352,12 +355,13 @@ static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
         }
         break;
     case PARA_REG_EPP_DATA:
-        if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT))
+        if ((s->control & (PARA_CTR_DIR | PARA_CTR_SIGNAL)) !=
+            (PARA_CTR_DIR | PARA_CTR_INIT))
             /* Controls not correct for EPP data cycle, so do nothing */
             pdebug("re%02x s\n", ret);
         else {
             struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
-            if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg)) {
+            if (qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_EPP_READ, &ioarg)) {
                 s->epp_timeout = 1;
                 pdebug("re%02x t\n", ret);
             }
@@ -385,7 +389,7 @@ parallel_ioport_eppdata_read_hw2(void *opaque, uint32_t addr)
         pdebug("re%04x s\n", eppdata);
         return eppdata;
     }
-    err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
+    err = qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
     ret = le16_to_cpu(eppdata);
 
     if (err) {
@@ -412,7 +416,7 @@ parallel_ioport_eppdata_read_hw4(void *opaque, uint32_t addr)
         pdebug("re%08x s\n", eppdata);
         return eppdata;
     }
-    err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
+    err = qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
     ret = le32_to_cpu(eppdata);
 
     if (err) {
@@ -508,7 +512,7 @@ static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
     int base;
     uint8_t dummy;
 
-    if (!s->chr) {
+    if (!s->chr.chr) {
         error_setg(errp, "Can't create parallel device, empty char device");
         return;
     }
@@ -530,7 +534,7 @@ static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
     isa_init_irq(isadev, &s->irq, isa->isairq);
     qemu_register_reset(parallel_reset, s);
 
-    if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) {
+    if (qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) {
         s->hw_driver = 1;
         s->status = dummy;
     }
@@ -605,7 +609,7 @@ bool parallel_mm_init(MemoryRegion *address_space,
 
     s = g_malloc0(sizeof(ParallelState));
     s->irq = irq;
-    s->chr = chr;
+    qemu_chr_fe_init(&s->chr, chr, &error_abort);
     s->it_shift = it_shift;
     qemu_register_reset(parallel_reset, s);
 
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
index 1a7911f..9645195 100644
--- a/hw/char/pl011.c
+++ b/hw/char/pl011.c
@@ -36,7 +36,7 @@ typedef struct PL011State {
     int read_pos;
     int read_count;
     int read_trigger;
-    CharDriverState *chr;
+    CharBackend chr;
     qemu_irq irq;
     const unsigned char *id;
 } PL011State;
@@ -87,8 +87,8 @@ static uint64_t pl011_read(void *opaque, hwaddr offset,
         trace_pl011_read_fifo(s->read_count);
         s->rsr = c >> 8;
         pl011_update(s);
-        if (s->chr) {
-            qemu_chr_accept_input(s->chr);
+        if (s->chr.chr) {
+            qemu_chr_accept_input(s->chr.chr);
         }
         r = c;
         break;
@@ -168,10 +168,11 @@ static void pl011_write(void *opaque, hwaddr offset,
     case 0: /* UARTDR */
         /* ??? Check if transmitter is enabled.  */
         ch = value;
-        if (s->chr)
+        if (s->chr.chr) {
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(s->chr, &ch, 1);
+            qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
+        }
         s->int_level |= PL011_INT_TX;
         pl011_update(s);
         break;
@@ -331,8 +332,8 @@ static void pl011_realize(DeviceState *dev, Error **errp)
 {
     PL011State *s = PL011(dev);
 
-    if (s->chr) {
-        qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive,
+    if (s->chr.chr) {
+        qemu_chr_add_handlers(s->chr.chr, pl011_can_receive, pl011_receive,
                               pl011_event, s);
     }
 }
diff --git a/hw/char/sclpconsole-lm.c b/hw/char/sclpconsole-lm.c
index 9a56326..3ef1517 100644
--- a/hw/char/sclpconsole-lm.c
+++ b/hw/char/sclpconsole-lm.c
@@ -37,7 +37,7 @@ typedef struct OprtnsCommand {
 
 typedef struct SCLPConsoleLM {
     SCLPEvent event;
-    CharDriverState *chr;
+    CharBackend chr;
     bool echo;                  /* immediate echo of input if true        */
     uint32_t write_errors;      /* errors writing to char layer           */
     uint32_t length;            /* length of byte stream in buffer        */
@@ -91,7 +91,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
     if (scon->echo) {
         /* XXX this blocks entire thread. Rewrite to use
          * qemu_chr_fe_write and background I/O callbacks */
-        qemu_chr_fe_write_all(scon->chr, buf, size);
+        qemu_chr_fe_write_all(scon->chr.chr, buf, size);
     }
 }
 
@@ -195,14 +195,14 @@ static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len)
 {
     SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
 
-    if (!scon->chr) {
+    if (!scon->chr.chr) {
         /* If there's no backend, we can just say we consumed all data. */
         return len;
     }
 
     /* XXX this blocks entire thread. Rewrite to use
      * qemu_chr_fe_write and background I/O callbacks */
-    return qemu_chr_fe_write_all(scon->chr, buf, len);
+    return qemu_chr_fe_write_all(scon->chr.chr, buf, len);
 }
 
 static int process_mdb(SCLPEvent *event, MDBO *mdbo)
@@ -312,8 +312,9 @@ static int console_init(SCLPEvent *event)
     }
     console_available = true;
 
-    if (scon->chr) {
-        qemu_chr_add_handlers(scon->chr, chr_can_read, chr_read, NULL, scon);
+    if (scon->chr.chr) {
+        qemu_chr_add_handlers(scon->chr.chr, chr_can_read,
+                              chr_read, NULL, scon);
     }
 
     return 0;
diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c
index a75ad4f..bb51a2c 100644
--- a/hw/char/sclpconsole.c
+++ b/hw/char/sclpconsole.c
@@ -31,7 +31,7 @@ typedef struct ASCIIConsoleData {
 
 typedef struct SCLPConsole {
     SCLPEvent event;
-    CharDriverState *chr;
+    CharBackend chr;
     uint8_t iov[SIZE_BUFFER_VT220];
     uint32_t iov_sclp;      /* offset in buf for SCLP read operation       */
     uint32_t iov_bs;        /* offset in buf for char layer read operation */
@@ -163,14 +163,14 @@ static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf,
 {
     SCLPConsole *scon = SCLP_CONSOLE(event);
 
-    if (!scon->chr) {
+    if (!scon->chr.chr) {
         /* If there's no backend, we can just say we consumed all data. */
         return len;
     }
 
     /* XXX this blocks entire thread. Rewrite to use
      * qemu_chr_fe_write and background I/O callbacks */
-    return qemu_chr_fe_write_all(scon->chr, buf, len);
+    return qemu_chr_fe_write_all(scon->chr.chr, buf, len);
 }
 
 static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr)
@@ -227,8 +227,8 @@ static int console_init(SCLPEvent *event)
         return -1;
     }
     console_available = true;
-    if (scon->chr) {
-        qemu_chr_add_handlers(scon->chr, chr_can_read,
+    if (scon->chr.chr) {
+        qemu_chr_add_handlers(scon->chr.chr, chr_can_read,
                               chr_read, NULL, scon);
     }
 
diff --git a/hw/char/serial.c b/hw/char/serial.c
index eec72b7..18c7482 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -182,7 +182,7 @@ static void serial_update_parameters(SerialState *s)
     ssp.data_bits = data_bits;
     ssp.stop_bits = stop_bits;
     s->char_transmit_time =  (NANOSECONDS_PER_SECOND / speed) * frame_size;
-    qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+    qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
 
     DPRINTF("speed=%d parity=%c data=%d stop=%d\n",
            speed, parity, data_bits, stop_bits);
@@ -195,7 +195,8 @@ static void serial_update_msl(SerialState *s)
 
     timer_del(s->modem_status_poll);
 
-    if (qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) {
+    if (qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_SERIAL_GET_TIOCM,
+                          &flags) == -ENOTSUP) {
         s->poll_msl = -1;
         return;
     }
@@ -260,11 +261,12 @@ static void serial_xmit(SerialState *s)
         if (s->mcr & UART_MCR_LOOP) {
             /* in loopback mode, say that we just received a char */
             serial_receive1(s, &s->tsr, 1);
-        } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1 &&
+        } else if (qemu_chr_fe_write(s->chr.chr, &s->tsr, 1) != 1 &&
                    s->tsr_retry < MAX_XMIT_RETRY) {
             assert(s->watch_tag == 0);
-            s->watch_tag = qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP,
-                                                 serial_watch_cb, s);
+            s->watch_tag =
+                qemu_chr_fe_add_watch(s->chr.chr, G_IO_OUT | G_IO_HUP,
+                                      serial_watch_cb, s);
             if (s->watch_tag > 0) {
                 s->tsr_retry++;
                 return;
@@ -417,7 +419,7 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
             break_enable = (val >> 6) & 1;
             if (break_enable != s->last_break_enable) {
                 s->last_break_enable = break_enable;
-                qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
+                qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_SERIAL_SET_BREAK,
                                &break_enable);
             }
         }
@@ -432,7 +434,8 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
 
             if (s->poll_msl >= 0 && old_mcr != s->mcr) {
 
-                qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
+                qemu_chr_fe_ioctl(s->chr.chr,
+                                  CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
 
                 flags &= ~(CHR_TIOCM_RTS | CHR_TIOCM_DTR);
 
@@ -441,7 +444,8 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
                 if (val & UART_MCR_DTR)
                     flags |= CHR_TIOCM_DTR;
 
-                qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
+                qemu_chr_fe_ioctl(s->chr.chr,
+                                  CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
                 /* Update the modem status after a one-character-send wait-time, since there may be a response
                    from the device/computer at the other end of the serial line */
                 timer_mod(s->modem_status_poll, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time);
@@ -486,7 +490,7 @@ static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size)
             serial_update_irq(s);
             if (!(s->mcr & UART_MCR_LOOP)) {
                 /* in loopback mode, don't receive any data */
-                qemu_chr_accept_input(s->chr);
+                qemu_chr_accept_input(s->chr.chr);
             }
         }
         break;
@@ -659,7 +663,7 @@ static int serial_post_load(void *opaque, int version_id)
         }
 
         assert(s->watch_tag == 0);
-        s->watch_tag = qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP,
+        s->watch_tag = qemu_chr_fe_add_watch(s->chr.chr, G_IO_OUT | G_IO_HUP,
                                              serial_watch_cb, s);
     } else {
         /* tsr_retry == 0 implies LSR.TEMT = 1 (transmitter empty).  */
@@ -884,7 +888,7 @@ static void serial_reset(void *opaque)
 
 void serial_realize_core(SerialState *s, Error **errp)
 {
-    if (!s->chr) {
+    if (!s->chr.chr) {
         error_setg(errp, "Can't create serial device, empty char device");
         return;
     }
@@ -894,7 +898,7 @@ void serial_realize_core(SerialState *s, Error **errp)
     s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) fifo_timeout_int, s);
     qemu_register_reset(serial_reset, s);
 
-    qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1,
+    qemu_chr_add_handlers(s->chr.chr, serial_can_receive1, serial_receive1,
                           serial_event, s);
     fifo8_create(&s->recv_fifo, UART_FIFO_LENGTH);
     fifo8_create(&s->xmit_fifo, UART_FIFO_LENGTH);
@@ -903,7 +907,7 @@ void serial_realize_core(SerialState *s, Error **errp)
 
 void serial_exit_core(SerialState *s)
 {
-    qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL);
+    qemu_chr_add_handlers(s->chr.chr, NULL, NULL, NULL, NULL);
     qemu_unregister_reset(serial_reset, s);
 }
 
@@ -933,7 +937,7 @@ SerialState *serial_init(int base, qemu_irq irq, int baudbase,
 
     s->irq = irq;
     s->baudbase = baudbase;
-    s->chr = chr;
+    qemu_chr_fe_init(&s->chr, chr, &error_abort);
     serial_realize_core(s, &error_fatal);
 
     vmstate_register(NULL, base, &vmstate_serial, s);
@@ -990,7 +994,7 @@ SerialState *serial_mm_init(MemoryRegion *address_space,
     s->it_shift = it_shift;
     s->irq = irq;
     s->baudbase = baudbase;
-    s->chr = chr;
+    qemu_chr_fe_init(&s->chr, chr, &error_abort);
 
     serial_realize_core(s, &error_fatal);
     vmstate_register(NULL, base, &vmstate_serial, s);
diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c
index 9aeafc0..dcb4a85 100644
--- a/hw/char/spapr_vty.c
+++ b/hw/char/spapr_vty.c
@@ -11,7 +11,7 @@
 
 typedef struct VIOsPAPRVTYDevice {
     VIOsPAPRDevice sdev;
-    CharDriverState *chardev;
+    CharBackend chardev;
     uint32_t in, out;
     uint8_t buf[VTERM_BUFSIZE];
 } VIOsPAPRVTYDevice;
@@ -51,7 +51,7 @@ static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
         buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
     }
 
-    qemu_chr_accept_input(dev->chardev);
+    qemu_chr_accept_input(dev->chardev.chr);
 
     return n;
 }
@@ -62,19 +62,19 @@ void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len)
 
     /* XXX this blocks entire thread. Rewrite to use
      * qemu_chr_fe_write and background I/O callbacks */
-    qemu_chr_fe_write_all(dev->chardev, buf, len);
+    qemu_chr_fe_write_all(dev->chardev.chr, buf, len);
 }
 
 static void spapr_vty_realize(VIOsPAPRDevice *sdev, Error **errp)
 {
     VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev);
 
-    if (!dev->chardev) {
+    if (!dev->chardev.chr) {
         error_setg(errp, "chardev property not set");
         return;
     }
 
-    qemu_chr_add_handlers(dev->chardev, vty_can_receive,
+    qemu_chr_add_handlers(dev->chardev.chr, vty_can_receive,
                           vty_receive, NULL, dev);
 }
 
diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c
index 4c6640d..8cc2737 100644
--- a/hw/char/stm32f2xx_usart.c
+++ b/hw/char/stm32f2xx_usart.c
@@ -97,16 +97,16 @@ static uint64_t stm32f2xx_usart_read(void *opaque, hwaddr addr,
     case USART_SR:
         retvalue = s->usart_sr;
         s->usart_sr &= ~USART_SR_TC;
-        if (s->chr) {
-            qemu_chr_accept_input(s->chr);
+        if (s->chr.chr) {
+            qemu_chr_accept_input(s->chr.chr);
         }
         return retvalue;
     case USART_DR:
         DB_PRINT("Value: 0x%" PRIx32 ", %c\n", s->usart_dr, (char) s->usart_dr);
         s->usart_sr |= USART_SR_TXE;
         s->usart_sr &= ~USART_SR_RXNE;
-        if (s->chr) {
-            qemu_chr_accept_input(s->chr);
+        if (s->chr.chr) {
+            qemu_chr_accept_input(s->chr.chr);
         }
         qemu_set_irq(s->irq, 0);
         return s->usart_dr & 0x3FF;
@@ -152,10 +152,10 @@ static void stm32f2xx_usart_write(void *opaque, hwaddr addr,
     case USART_DR:
         if (value < 0xF000) {
             ch = value;
-            if (s->chr) {
+            if (s->chr.chr) {
                 /* XXX this blocks entire thread. Rewrite to use
                  * qemu_chr_fe_write and background I/O callbacks */
-                qemu_chr_fe_write_all(s->chr, &ch, 1);
+                qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
             }
             s->usart_sr |= USART_SR_TC;
             s->usart_sr &= ~USART_SR_TXE;
@@ -212,8 +212,8 @@ static void stm32f2xx_usart_realize(DeviceState *dev, Error **errp)
 {
     STM32F2XXUsartState *s = STM32F2XX_USART(dev);
 
-    if (s->chr) {
-        qemu_chr_add_handlers(s->chr, stm32f2xx_usart_can_receive,
+    if (s->chr.chr) {
+        qemu_chr_add_handlers(s->chr.chr, stm32f2xx_usart_can_receive,
                               stm32f2xx_usart_receive, NULL, s);
     }
 }
diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c
index d44c18c..a4730ba 100644
--- a/hw/char/virtio-console.c
+++ b/hw/char/virtio-console.c
@@ -24,7 +24,7 @@
 typedef struct VirtConsole {
     VirtIOSerialPort parent_obj;
 
-    CharDriverState *chr;
+    CharBackend chr;
     guint watch;
 } VirtConsole;
 
@@ -49,12 +49,12 @@ static ssize_t flush_buf(VirtIOSerialPort *port,
     VirtConsole *vcon = VIRTIO_CONSOLE(port);
     ssize_t ret;
 
-    if (!vcon->chr) {
+    if (!vcon->chr.chr) {
         /* If there's no backend, we can just say we consumed all data. */
         return len;
     }
 
-    ret = qemu_chr_fe_write(vcon->chr, buf, len);
+    ret = qemu_chr_fe_write(vcon->chr.chr, buf, len);
     trace_virtio_console_flush_buf(port->id, len, ret);
 
     if (ret < len) {
@@ -92,8 +92,8 @@ static ssize_t flush_buf(VirtIOSerialPort *port,
         if (!k->is_console) {
             virtio_serial_throttle_port(port, true);
             if (!vcon->watch) {
-                vcon->watch = qemu_chr_fe_add_watch(vcon->chr,
-                                                    G_IO_OUT|G_IO_HUP,
+                vcon->watch = qemu_chr_fe_add_watch(vcon->chr.chr,
+                                                    G_IO_OUT | G_IO_HUP,
                                                     chr_write_unblocked, vcon);
             }
         }
@@ -108,8 +108,8 @@ static void set_guest_connected(VirtIOSerialPort *port, int guest_connected)
     DeviceState *dev = DEVICE(port);
     VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
 
-    if (vcon->chr && !k->is_console) {
-        qemu_chr_fe_set_open(vcon->chr, guest_connected);
+    if (vcon->chr.chr && !k->is_console) {
+        qemu_chr_fe_set_open(vcon->chr.chr, guest_connected);
     }
 
     if (dev->id) {
@@ -122,8 +122,8 @@ static void guest_writable(VirtIOSerialPort *port)
 {
     VirtConsole *vcon = VIRTIO_CONSOLE(port);
 
-    if (vcon->chr) {
-        qemu_chr_accept_input(vcon->chr);
+    if (vcon->chr.chr) {
+        qemu_chr_accept_input(vcon->chr.chr);
     }
 }
 
@@ -177,7 +177,7 @@ static void virtconsole_realize(DeviceState *dev, Error **errp)
         return;
     }
 
-    if (vcon->chr) {
+    if (vcon->chr.chr) {
         /*
          * For consoles we don't block guest data transfer just
          * because nothing is connected - we'll just let it go
@@ -188,13 +188,13 @@ static void virtconsole_realize(DeviceState *dev, Error **errp)
          * trigger open/close of the device
          */
         if (k->is_console) {
-            vcon->chr->explicit_fe_open = 0;
-            qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read,
+            vcon->chr.chr->explicit_fe_open = 0;
+            qemu_chr_add_handlers(vcon->chr.chr, chr_can_read, chr_read,
                                   NULL, vcon);
             virtio_serial_open(port);
         } else {
-            vcon->chr->explicit_fe_open = 1;
-            qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read,
+            vcon->chr.chr->explicit_fe_open = 1;
+            qemu_chr_add_handlers(vcon->chr.chr, chr_can_read, chr_read,
                                   chr_event, vcon);
         }
     }
diff --git a/hw/char/xilinx_uartlite.c b/hw/char/xilinx_uartlite.c
index 3766dc2..0e809d5 100644
--- a/hw/char/xilinx_uartlite.c
+++ b/hw/char/xilinx_uartlite.c
@@ -55,7 +55,7 @@ typedef struct XilinxUARTLite {
     SysBusDevice parent_obj;
 
     MemoryRegion mmio;
-    CharDriverState *chr;
+    CharBackend chr;
     qemu_irq irq;
 
     uint8_t rx_fifo[8];
@@ -107,7 +107,7 @@ uart_read(void *opaque, hwaddr addr, unsigned int size)
                 s->rx_fifo_len--;
             uart_update_status(s);
             uart_update_irq(s);
-            qemu_chr_accept_input(s->chr);
+            qemu_chr_accept_input(s->chr.chr);
             break;
 
         default:
@@ -143,11 +143,11 @@ uart_write(void *opaque, hwaddr addr,
             break;
 
         case R_TX:
-            if (s->chr)
+            if (s->chr.chr) {
                 /* XXX this blocks entire thread. Rewrite to use
                  * qemu_chr_fe_write and background I/O callbacks */
-                qemu_chr_fe_write_all(s->chr, &ch, 1);
-
+                qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
+            }
             s->regs[addr] = value;
 
             /* hax.  */
@@ -213,8 +213,9 @@ static void xilinx_uartlite_realize(DeviceState *dev, Error **errp)
 {
     XilinxUARTLite *s = XILINX_UARTLITE(dev);
 
-    if (s->chr)
-        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+    if (s->chr.chr) {
+        qemu_chr_add_handlers(s->chr.chr, uart_can_rx, uart_rx, uart_event, s);
+    }
 }
 
 static void xilinx_uartlite_init(Object *obj)
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index e55afe6..6d45d32 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -160,55 +160,71 @@ PropertyInfo qdev_prop_drive = {
 
 /* --- character device --- */
 
-static void parse_chr(DeviceState *dev, const char *str, void **ptr,
-                      const char *propname, Error **errp)
+static void get_chr(Object *obj, Visitor *v, const char *name, void *opaque,
+                    Error **errp)
 {
-    CharDriverState *chr = qemu_chr_find(str);
-    if (chr == NULL) {
-        error_setg(errp, "Property '%s.%s' can't find value '%s'",
-                   object_get_typename(OBJECT(dev)), propname, str);
-        return;
-    }
-    if (qemu_chr_fe_claim(chr) != 0) {
-        error_setg(errp, "Property '%s.%s' can't take value '%s', it's in use",
-                  object_get_typename(OBJECT(dev)), propname, str);
-        return;
-    }
-    *ptr = chr;
+    DeviceState *dev = DEVICE(obj);
+    CharBackend *be = qdev_get_prop_ptr(dev, opaque);
+    char *p;
+
+    p = g_strdup(be->chr && be->chr->label ? be->chr->label : "");
+    visit_type_str(v, name, &p, errp);
+    g_free(p);
 }
 
-static void release_chr(Object *obj, const char *name, void *opaque)
+static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
+                    Error **errp)
 {
     DeviceState *dev = DEVICE(obj);
+    Error *local_err = NULL;
     Property *prop = opaque;
-    CharDriverState **ptr = qdev_get_prop_ptr(dev, prop);
-    CharDriverState *chr = *ptr;
+    CharBackend *be = qdev_get_prop_ptr(dev, prop);
+    CharDriverState *s;
+    char *str;
 
-    if (chr) {
-        qemu_chr_add_handlers(chr, NULL, NULL, NULL, NULL);
-        qemu_chr_fe_release(chr);
+    if (dev->realized) {
+        qdev_prop_set_after_realize(dev, name, errp);
+        return;
     }
-}
 
+    visit_type_str(v, name, &str, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
 
-static char *print_chr(void *ptr)
-{
-    CharDriverState *chr = ptr;
-    const char *val = chr->label ? chr->label : "";
+    if (!*str) {
+        g_free(str);
+        be->chr = NULL;
+        return;
+    }
 
-    return g_strdup(val);
-}
+    s = qemu_chr_find(str);
+    g_free(str);
+    if (s == NULL) {
+        error_setg(errp, "Property '%s.%s' can't find value '%s'",
+                   object_get_typename(obj), prop->name, str);
+        return;
+    }
+    if (qemu_chr_fe_claim(s) != 0) {
+        error_setg(errp, "Property '%s.%s' can't take value '%s', it's in use",
+                  object_get_typename(obj), prop->name, str);
+        return;
+    }
 
-static void get_chr(Object *obj, Visitor *v, const char *name, void *opaque,
-                    Error **errp)
-{
-    get_pointer(obj, v, opaque, print_chr, name, errp);
+    qemu_chr_fe_init(be, s, errp);
 }
 
-static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
-                    Error **errp)
+static void release_chr(Object *obj, const char *name, void *opaque)
 {
-    set_pointer(obj, v, opaque, parse_chr, name, errp);
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    CharBackend *be = qdev_get_prop_ptr(dev, prop);
+
+    if (be->chr) {
+        qemu_chr_fe_set_handlers(be, NULL, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_release(be->chr);
+    }
 }
 
 PropertyInfo qdev_prop_chr = {
diff --git a/hw/ipmi/ipmi_bmc_extern.c b/hw/ipmi/ipmi_bmc_extern.c
index d93e3f3..af9b6f3 100644
--- a/hw/ipmi/ipmi_bmc_extern.c
+++ b/hw/ipmi/ipmi_bmc_extern.c
@@ -62,7 +62,7 @@
 typedef struct IPMIBmcExtern {
     IPMIBmc parent;
 
-    CharDriverState *chr;
+    CharBackend chr;
 
     bool connected;
 
@@ -105,7 +105,7 @@ static void continue_send(IPMIBmcExtern *ibe)
         goto check_reset;
     }
  send:
-    ret = qemu_chr_fe_write(ibe->chr, ibe->outbuf + ibe->outpos,
+    ret = qemu_chr_fe_write(ibe->chr.chr, ibe->outbuf + ibe->outpos,
                             ibe->outlen - ibe->outpos);
     if (ret > 0) {
         ibe->outpos += ret;
@@ -442,12 +442,12 @@ static void ipmi_bmc_extern_realize(DeviceState *dev, Error **errp)
 {
     IPMIBmcExtern *ibe = IPMI_BMC_EXTERN(dev);
 
-    if (!ibe->chr) {
+    if (!ibe->chr.chr) {
         error_setg(errp, "IPMI external bmc requires chardev attribute");
         return;
     }
 
-    qemu_chr_add_handlers(ibe->chr, can_receive, receive, chr_event, ibe);
+    qemu_chr_add_handlers(ibe->chr.chr, can_receive, receive, chr_event, ibe);
 }
 
 static int ipmi_bmc_extern_post_migrate(void *opaque, int version_id)
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index f803dfd..efca8b0 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -88,7 +88,7 @@ typedef struct IVShmemState {
 
     /* exactly one of these two may be set */
     HostMemoryBackend *hostmem; /* with interrupts */
-    CharDriverState *server_chr; /* without interrupts */
+    CharBackend server_chr; /* without interrupts */
 
     /* registers */
     uint32_t intrmask;
@@ -627,7 +627,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
     msg = le64_to_cpu(s->msg_buf);
     s->msg_buffered_bytes = 0;
 
-    fd = qemu_chr_fe_get_msgfd(s->server_chr);
+    fd = qemu_chr_fe_get_msgfd(s->server_chr.chr);
 
     process_msg(s, msg, fd, &err);
     if (err) {
@@ -642,7 +642,7 @@ static int64_t ivshmem_recv_msg(IVShmemState *s, int *pfd, Error **errp)
 
     n = 0;
     do {
-        ret = qemu_chr_fe_read_all(s->server_chr, (uint8_t *)&msg + n,
+        ret = qemu_chr_fe_read_all(s->server_chr.chr, (uint8_t *)&msg + n,
                                  sizeof(msg) - n);
         if (ret < 0 && ret != -EINTR) {
             error_setg_errno(errp, -ret, "read from server failed");
@@ -651,7 +651,7 @@ static int64_t ivshmem_recv_msg(IVShmemState *s, int *pfd, Error **errp)
         n += ret;
     } while (n < sizeof(msg));
 
-    *pfd = qemu_chr_fe_get_msgfd(s->server_chr);
+    *pfd = qemu_chr_fe_get_msgfd(s->server_chr.chr);
     return msg;
 }
 
@@ -868,10 +868,10 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
         s->ivshmem_bar2 = host_memory_backend_get_memory(s->hostmem,
                                                          &error_abort);
     } else {
-        assert(s->server_chr);
+        assert(s->server_chr.chr);
 
         IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
-                        s->server_chr->filename);
+                        s->server_chr.chr->filename);
 
         /* we allocate enough space for 16 peers and grow as needed */
         resize_peers(s, 16);
@@ -893,7 +893,7 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
             return;
         }
 
-        qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive,
+        qemu_chr_add_handlers(s->server_chr.chr, ivshmem_can_receive,
                               ivshmem_read, NULL, s);
 
         if (ivshmem_setup_interrupts(s) < 0) {
@@ -1121,7 +1121,7 @@ static void ivshmem_doorbell_realize(PCIDevice *dev, Error **errp)
 {
     IVShmemState *s = IVSHMEM_COMMON(dev);
 
-    if (!s->server_chr) {
+    if (!s->server_chr.chr) {
         error_setg(errp, "You must specify a 'chardev'");
         return;
     }
@@ -1250,7 +1250,7 @@ static void ivshmem_realize(PCIDevice *dev, Error **errp)
                      " or ivshmem-doorbell instead");
     }
 
-    if (!!s->server_chr + !!s->shmobj != 1) {
+    if (!!s->server_chr.chr + !!s->shmobj != 1) {
         error_setg(errp, "You must specify either 'shm' or 'chardev'");
         return;
     }
diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c
index 2eacea7..ebe3942 100644
--- a/hw/usb/ccid-card-passthru.c
+++ b/hw/usb/ccid-card-passthru.c
@@ -48,7 +48,7 @@ typedef struct PassthruState PassthruState;
 
 struct PassthruState {
     CCIDCardState base;
-    CharDriverState *cs;
+    CharBackend cs;
     uint8_t  vscard_in_data[VSCARD_IN_SIZE];
     uint32_t vscard_in_pos;
     uint32_t vscard_in_hdr;
@@ -77,9 +77,9 @@ static void ccid_card_vscard_send_msg(PassthruState *s,
     scr_msg_header.length = htonl(length);
     /* XXX this blocks entire thread. Rewrite to use
      * qemu_chr_fe_write and background I/O callbacks */
-    qemu_chr_fe_write_all(s->cs, (uint8_t *)&scr_msg_header,
+    qemu_chr_fe_write_all(s->cs.chr, (uint8_t *)&scr_msg_header,
                           sizeof(VSCMsgHeader));
-    qemu_chr_fe_write_all(s->cs, payload, length);
+    qemu_chr_fe_write_all(s->cs.chr, payload, length);
 }
 
 static void ccid_card_vscard_send_apdu(PassthruState *s,
@@ -264,7 +264,7 @@ static void ccid_card_vscard_handle_message(PassthruState *card,
 
 static void ccid_card_vscard_drop_connection(PassthruState *card)
 {
-    qemu_chr_delete(card->cs);
+    qemu_chr_delete(card->cs.chr);
     card->vscard_in_pos = card->vscard_in_hdr = 0;
 }
 
@@ -324,7 +324,7 @@ static void passthru_apdu_from_guest(
 {
     PassthruState *card = PASSTHRU_CCID_CARD(base);
 
-    if (!card->cs) {
+    if (!card->cs.chr) {
         printf("ccid-passthru: no chardev, discarding apdu length %d\n", len);
         return;
     }
@@ -345,9 +345,9 @@ static int passthru_initfn(CCIDCardState *base)
 
     card->vscard_in_pos = 0;
     card->vscard_in_hdr = 0;
-    if (card->cs) {
+    if (card->cs.chr) {
         DPRINTF(card, D_INFO, "initing chardev\n");
-        qemu_chr_add_handlers(card->cs,
+        qemu_chr_add_handlers(card->cs.chr,
             ccid_card_vscard_can_read,
             ccid_card_vscard_read,
             ccid_card_vscard_event, card);
diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c
index 61452b5..b8774b4 100644
--- a/hw/usb/dev-serial.c
+++ b/hw/usb/dev-serial.c
@@ -103,7 +103,7 @@ typedef struct {
     uint8_t event_trigger;
     QEMUSerialSetParams params;
     int latency;        /* ms */
-    CharDriverState *cs;
+    CharBackend cs;
 } USBSerialState;
 
 #define TYPE_USB_SERIAL "usb-serial-dev"
@@ -209,8 +209,10 @@ static uint8_t usb_get_modem_lines(USBSerialState *s)
     int flags;
     uint8_t ret;
 
-    if (qemu_chr_fe_ioctl(s->cs, CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP)
+    if (qemu_chr_fe_ioctl(s->cs.chr,
+                          CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) {
         return FTDI_CTS|FTDI_DSR|FTDI_RLSD;
+    }
 
     ret = 0;
     if (flags & CHR_TIOCM_CTS)
@@ -260,7 +262,7 @@ static void usb_serial_handle_control(USBDevice *dev, USBPacket *p,
     case DeviceOutVendor | FTDI_SET_MDM_CTRL:
     {
         static int flags;
-        qemu_chr_fe_ioctl(s->cs,CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
+        qemu_chr_fe_ioctl(s->cs.chr, CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
         if (value & FTDI_SET_RTS) {
             if (value & FTDI_RTS)
                 flags |= CHR_TIOCM_RTS;
@@ -273,7 +275,7 @@ static void usb_serial_handle_control(USBDevice *dev, USBPacket *p,
             else
                 flags &= ~CHR_TIOCM_DTR;
         }
-        qemu_chr_fe_ioctl(s->cs,CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
+        qemu_chr_fe_ioctl(s->cs.chr, CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
         break;
     }
     case DeviceOutVendor | FTDI_SET_FLOW_CTRL:
@@ -292,7 +294,7 @@ static void usb_serial_handle_control(USBDevice *dev, USBPacket *p,
             divisor = 1;
 
         s->params.speed = (48000000 / 2) / (8 * divisor + subdivisor8);
-        qemu_chr_fe_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
+        qemu_chr_fe_ioctl(s->cs.chr, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
         break;
     }
     case DeviceOutVendor | FTDI_SET_DATA:
@@ -321,7 +323,7 @@ static void usb_serial_handle_control(USBDevice *dev, USBPacket *p,
                 DPRINTF("unsupported stop bits %d\n", value & FTDI_STOP);
                 goto fail;
         }
-        qemu_chr_fe_ioctl(s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
+        qemu_chr_fe_ioctl(s->cs.chr, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
         /* TODO: TX ON/OFF */
         break;
     case DeviceInVendor | FTDI_GET_MDM_ST:
@@ -368,7 +370,7 @@ static void usb_serial_handle_data(USBDevice *dev, USBPacket *p)
             iov = p->iov.iov + i;
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(s->cs, iov->iov_base, iov->iov_len);
+            qemu_chr_fe_write_all(s->cs.chr, iov->iov_base, iov->iov_len);
         }
         p->actual_length = p->iov.size;
         break;
@@ -488,7 +490,7 @@ static void usb_serial_realize(USBDevice *dev, Error **errp)
     usb_desc_init(dev);
     dev->auto_attach = 0;
 
-    if (!s->cs) {
+    if (!s->cs.chr) {
         error_setg(errp, "Property chardev is required");
         return;
     }
@@ -499,11 +501,11 @@ static void usb_serial_realize(USBDevice *dev, Error **errp)
         return;
     }
 
-    qemu_chr_add_handlers(s->cs, usb_serial_can_read, usb_serial_read,
+    qemu_chr_add_handlers(s->cs.chr, usb_serial_can_read, usb_serial_read,
                           usb_serial_event, s);
     usb_serial_handle_reset(dev);
 
-    if (s->cs->be_open && !dev->attached) {
+    if (s->cs.chr->be_open && !dev->attached) {
         usb_device_attach(dev, &error_abort);
     }
 }
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index d4ca026..0b21804 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -105,7 +105,7 @@ struct PacketIdQueue {
 struct USBRedirDevice {
     USBDevice dev;
     /* Properties */
-    CharDriverState *cs;
+    CharBackend cs;
     uint8_t debug;
     char *filter_str;
     int32_t bootindex;
@@ -285,7 +285,7 @@ static int usbredir_write(void *priv, uint8_t *data, int count)
     USBRedirDevice *dev = priv;
     int r;
 
-    if (!dev->cs->be_open) {
+    if (!dev->cs.chr->be_open) {
         return 0;
     }
 
@@ -294,10 +294,10 @@ static int usbredir_write(void *priv, uint8_t *data, int count)
         return 0;
     }
 
-    r = qemu_chr_fe_write(dev->cs, data, count);
+    r = qemu_chr_fe_write(dev->cs.chr, data, count);
     if (r < count) {
         if (!dev->watch) {
-            dev->watch = qemu_chr_fe_add_watch(dev->cs, G_IO_OUT|G_IO_HUP,
+            dev->watch = qemu_chr_fe_add_watch(dev->cs.chr, G_IO_OUT | G_IO_HUP,
                                                usbredir_write_unblocked, dev);
         }
         if (r < 0) {
@@ -1375,7 +1375,7 @@ static void usbredir_realize(USBDevice *udev, Error **errp)
     USBRedirDevice *dev = USB_REDIRECT(udev);
     int i;
 
-    if (dev->cs == NULL) {
+    if (dev->cs.chr == NULL) {
         error_setg(errp, QERR_MISSING_PARAMETER, "chardev");
         return;
     }
@@ -1406,7 +1406,7 @@ static void usbredir_realize(USBDevice *udev, Error **errp)
     dev->compatible_speedmask = USB_SPEED_MASK_FULL | USB_SPEED_MASK_HIGH;
 
     /* Let the backend know we are ready */
-    qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read,
+    qemu_chr_add_handlers(dev->cs.chr, usbredir_chardev_can_read,
                           usbredir_chardev_read, usbredir_chardev_event, dev);
 
     qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev);
@@ -1427,8 +1427,8 @@ static void usbredir_handle_destroy(USBDevice *udev)
 {
     USBRedirDevice *dev = USB_REDIRECT(udev);
 
-    qemu_chr_delete(dev->cs);
-    dev->cs = NULL;
+    qemu_chr_delete(dev->cs.chr);
+    dev->cs.chr = NULL;
     /* Note must be done after qemu_chr_close, as that causes a close event */
     qemu_bh_delete(dev->chardev_close_bh);
     qemu_bh_delete(dev->device_reject_bh);
diff --git a/include/hw/char/bcm2835_aux.h b/include/hw/char/bcm2835_aux.h
index 42f0ee7..6865f15 100644
--- a/include/hw/char/bcm2835_aux.h
+++ b/include/hw/char/bcm2835_aux.h
@@ -22,7 +22,7 @@ typedef struct {
     /*< public >*/
 
     MemoryRegion iomem;
-    CharDriverState *chr;
+    CharBackend chr;
     qemu_irq irq;
 
     uint8_t read_fifo[BCM2835_AUX_RX_FIFO_LEN];
diff --git a/include/hw/char/cadence_uart.h b/include/hw/char/cadence_uart.h
index a12773c..ca75eb5 100644
--- a/include/hw/char/cadence_uart.h
+++ b/include/hw/char/cadence_uart.h
@@ -44,7 +44,7 @@ typedef struct {
     uint32_t rx_count;
     uint32_t tx_count;
     uint64_t char_tx_time;
-    CharDriverState *chr;
+    CharBackend chr;
     qemu_irq irq;
     QEMUTimer *fifo_trigger_handle;
 } CadenceUARTState;
diff --git a/include/hw/char/digic-uart.h b/include/hw/char/digic-uart.h
index 7b3f145..340c8e1 100644
--- a/include/hw/char/digic-uart.h
+++ b/include/hw/char/digic-uart.h
@@ -19,6 +19,7 @@
 #define HW_CHAR_DIGIC_UART_H
 
 #include "hw/sysbus.h"
+#include "sysemu/char.h"
 
 #define TYPE_DIGIC_UART "digic-uart"
 #define DIGIC_UART(obj) \
@@ -37,7 +38,7 @@ typedef struct DigicUartState {
     /*< public >*/
 
     MemoryRegion regs_region;
-    CharDriverState *chr;
+    CharBackend chr;
 
     uint32_t reg_rx;
     uint32_t reg_st;
diff --git a/include/hw/char/imx_serial.h b/include/hw/char/imx_serial.h
index 6cd75c0..4cc3fbc 100644
--- a/include/hw/char/imx_serial.h
+++ b/include/hw/char/imx_serial.h
@@ -19,6 +19,7 @@
 #define IMX_SERIAL_H
 
 #include "hw/sysbus.h"
+#include "sysemu/char.h"
 
 #define TYPE_IMX_SERIAL "imx.serial"
 #define IMX_SERIAL(obj) OBJECT_CHECK(IMXSerialState, (obj), TYPE_IMX_SERIAL)
@@ -96,7 +97,7 @@ typedef struct IMXSerialState {
     uint32_t ucr3;
 
     qemu_irq irq;
-    CharDriverState *chr;
+    CharBackend chr;
 } IMXSerialState;
 
 #endif
diff --git a/include/hw/char/serial.h b/include/hw/char/serial.h
index 4f3b73c..c3312fb 100644
--- a/include/hw/char/serial.h
+++ b/include/hw/char/serial.h
@@ -30,6 +30,7 @@
 #include "sysemu/sysemu.h"
 #include "exec/memory.h"
 #include "qemu/fifo8.h"
+#include "sysemu/char.h"
 
 #define UART_FIFO_LENGTH    16      /* 16550A Fifo Length */
 
@@ -52,7 +53,7 @@ struct SerialState {
        it can be reset while reading iir */
     int thr_ipending;
     qemu_irq irq;
-    CharDriverState *chr;
+    CharBackend chr;
     int last_break_enable;
     int it_shift;
     int baudbase;
diff --git a/include/hw/char/stm32f2xx_usart.h b/include/hw/char/stm32f2xx_usart.h
index b97f192..3267523 100644
--- a/include/hw/char/stm32f2xx_usart.h
+++ b/include/hw/char/stm32f2xx_usart.h
@@ -67,7 +67,7 @@ typedef struct {
     uint32_t usart_cr3;
     uint32_t usart_gtpr;
 
-    CharDriverState *chr;
+    CharBackend chr;
     qemu_irq irq;
 } STM32F2XXUsartState;
 #endif /* HW_STM32F2XX_USART_H */
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index 2a9d2f9..306bbab 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -146,7 +146,7 @@ extern PropertyInfo qdev_prop_arraylen;
     DEFINE_PROP(_n, _s, _f, qdev_prop_ptr, void*)
 
 #define DEFINE_PROP_CHR(_n, _s, _f)             \
-    DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharDriverState*)
+    DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharBackend)
 #define DEFINE_PROP_STRING(_n, _s, _f)             \
     DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*)
 #define DEFINE_PROP_NETDEV(_n, _s, _f)             \
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 31/50] char: remaining switch to CharBackend in frontend
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (29 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 30/50] char: replace PROP_CHR with CharBackend Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 32/50] char: rename some frontend functions Paolo Bonzini
                   ` (19 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Similar to previous change, for the remaining CharDriverState front ends
users.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-13-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 backends/rng-egd.c      | 29 ++++++++++++++-----------
 gdbstub.c               | 22 +++++++++++--------
 hw/arm/omap2.c          | 11 +++++-----
 hw/char/mcf_uart.c      | 12 +++++-----
 hw/char/sh_serial.c     | 10 ++++-----
 hw/char/xen_console.c   | 39 +++++++++++++++++++--------------
 hw/mips/mips_malta.c    | 32 +++++++++++++++------------
 monitor.c               | 19 ++++++++--------
 net/colo-compare.c      | 46 +++++++++++++++++++--------------------
 net/filter-mirror.c     | 58 +++++++++++++++++++++++++++++--------------------
 net/slirp.c             | 23 ++++++++++++++------
 net/vhost-user.c        | 27 +++++++++++++----------
 qtest.c                 |  8 +++----
 tests/vhost-user-test.c | 39 ++++++++++++++++++---------------
 14 files changed, 211 insertions(+), 164 deletions(-)

diff --git a/backends/rng-egd.c b/backends/rng-egd.c
index 0f6d0af..e2f8189 100644
--- a/backends/rng-egd.c
+++ b/backends/rng-egd.c
@@ -23,7 +23,7 @@ typedef struct RngEgd
 {
     RngBackend parent;
 
-    CharDriverState *chr;
+    CharBackend chr;
     char *chr_name;
 } RngEgd;
 
@@ -42,7 +42,7 @@ static void rng_egd_request_entropy(RngBackend *b, RngRequest *req)
 
         /* XXX this blocks entire thread. Rewrite to use
          * qemu_chr_fe_write and background I/O callbacks */
-        qemu_chr_fe_write_all(s->chr, header, sizeof(header));
+        qemu_chr_fe_write_all(s->chr.chr, header, sizeof(header));
 
         size -= len;
     }
@@ -86,6 +86,7 @@ static void rng_egd_chr_read(void *opaque, const uint8_t *buf, int size)
 static void rng_egd_opened(RngBackend *b, Error **errp)
 {
     RngEgd *s = RNG_EGD(b);
+    CharDriverState *chr;
 
     if (s->chr_name == NULL) {
         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
@@ -93,21 +94,23 @@ static void rng_egd_opened(RngBackend *b, Error **errp)
         return;
     }
 
-    s->chr = qemu_chr_find(s->chr_name);
-    if (s->chr == NULL) {
+    chr = qemu_chr_find(s->chr_name);
+    if (chr == NULL) {
         error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
                   "Device '%s' not found", s->chr_name);
         return;
     }
-
-    if (qemu_chr_fe_claim(s->chr) != 0) {
+    if (qemu_chr_fe_claim(chr) != 0) {
         error_setg(errp, QERR_DEVICE_IN_USE, s->chr_name);
         return;
     }
+    if (!qemu_chr_fe_init(&s->chr, chr, errp)) {
+        return;
+    }
 
     /* FIXME we should resubmit pending requests when the CDS reconnects. */
-    qemu_chr_add_handlers(s->chr, rng_egd_chr_can_read, rng_egd_chr_read,
-                          NULL, s);
+    qemu_chr_add_handlers(s->chr.chr, rng_egd_chr_can_read,
+                          rng_egd_chr_read, NULL, s);
 }
 
 static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)
@@ -127,8 +130,8 @@ static char *rng_egd_get_chardev(Object *obj, Error **errp)
 {
     RngEgd *s = RNG_EGD(obj);
 
-    if (s->chr && s->chr->label) {
-        return g_strdup(s->chr->label);
+    if (s->chr.chr && s->chr.chr->label) {
+        return g_strdup(s->chr.chr->label);
     }
 
     return NULL;
@@ -145,9 +148,9 @@ static void rng_egd_finalize(Object *obj)
 {
     RngEgd *s = RNG_EGD(obj);
 
-    if (s->chr) {
-        qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL);
-        qemu_chr_fe_release(s->chr);
+    if (s->chr.chr) {
+        qemu_chr_add_handlers(s->chr.chr, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_release(s->chr.chr);
     }
 
     g_free(s->chr_name);
diff --git a/gdbstub.c b/gdbstub.c
index 2fe71ca..347bd4d 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -303,7 +303,7 @@ typedef struct GDBState {
     int fd;
     int running_state;
 #else
-    CharDriverState *chr;
+    CharBackend chr;
     CharDriverState *mon_chr;
 #endif
     char syscall_buf[256];
@@ -404,7 +404,7 @@ static void put_buffer(GDBState *s, const uint8_t *buf, int len)
 #else
     /* XXX this blocks entire thread. Rewrite to use
      * qemu_chr_fe_write and background I/O callbacks */
-    qemu_chr_fe_write_all(s->chr, buf, len);
+    qemu_chr_fe_write_all(s->chr.chr, buf, len);
 #endif
 }
 
@@ -1481,7 +1481,7 @@ void gdb_exit(CPUArchState *env, int code)
       return;
   }
 #else
-  if (!s->chr) {
+  if (!s->chr.chr) {
       return;
   }
 #endif
@@ -1490,7 +1490,7 @@ void gdb_exit(CPUArchState *env, int code)
   put_packet(s, buf);
 
 #ifndef CONFIG_USER_ONLY
-  qemu_chr_delete(s->chr);
+  qemu_chr_delete(s->chr.chr);
 #endif
 }
 
@@ -1750,8 +1750,6 @@ int gdbserver_start(const char *device)
             return -1;
 
         qemu_chr_fe_claim_no_fail(chr);
-        qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive,
-                              gdb_chr_event, NULL);
     }
 
     s = gdbserver_state;
@@ -1766,14 +1764,20 @@ int gdbserver_start(const char *device)
         mon_chr->chr_write = gdb_monitor_write;
         monitor_init(mon_chr, 0);
     } else {
-        if (s->chr)
-            qemu_chr_delete(s->chr);
+        if (s->chr.chr) {
+            qemu_chr_delete(s->chr.chr);
+        }
         mon_chr = s->mon_chr;
         memset(s, 0, sizeof(GDBState));
+        s->mon_chr = mon_chr;
     }
     s->c_cpu = first_cpu;
     s->g_cpu = first_cpu;
-    s->chr = chr;
+    if (chr) {
+        qemu_chr_fe_init(&s->chr, chr, &error_abort);
+        qemu_chr_add_handlers(s->chr.chr, gdb_chr_can_receive, gdb_chr_receive,
+                              gdb_chr_event, NULL);
+    }
     s->state = chr ? RS_IDLE : RS_INACTIVE;
     s->mon_chr = mon_chr;
     s->current_syscall_cb = NULL;
diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c
index 0b2a355..43d9c4b 100644
--- a/hw/arm/omap2.c
+++ b/hw/arm/omap2.c
@@ -621,7 +621,7 @@ struct omap_sti_s {
     qemu_irq irq;
     MemoryRegion iomem;
     MemoryRegion iomem_fifo;
-    CharDriverState *chr;
+    CharBackend chr;
 
     uint32_t sysconfig;
     uint32_t systest;
@@ -771,14 +771,14 @@ static void omap_sti_fifo_write(void *opaque, hwaddr addr,
         /* Flush channel <i>value</i>.  */
         /* XXX this blocks entire thread. Rewrite to use
          * qemu_chr_fe_write and background I/O callbacks */
-        qemu_chr_fe_write_all(s->chr, (const uint8_t *) "\r", 1);
+        qemu_chr_fe_write_all(s->chr.chr, (const uint8_t *) "\r", 1);
     } else if (ch == STI_TRACE_CONSOLE_CHANNEL || 1) {
         if (value == 0xc0 || value == 0xc3) {
             /* Open channel <i>ch</i>.  */
         } else if (value == 0x00)
-            qemu_chr_fe_write_all(s->chr, (const uint8_t *) "\n", 1);
+            qemu_chr_fe_write_all(s->chr.chr, (const uint8_t *) "\n", 1);
         else
-            qemu_chr_fe_write_all(s->chr, &byte, 1);
+            qemu_chr_fe_write_all(s->chr.chr, &byte, 1);
     }
 }
 
@@ -798,7 +798,8 @@ static struct omap_sti_s *omap_sti_init(struct omap_target_agent_s *ta,
     s->irq = irq;
     omap_sti_reset(s);
 
-    s->chr = chr ?: qemu_chr_new("null", "null");
+    qemu_chr_fe_init(&s->chr, chr ?: qemu_chr_new("null", "null"),
+                     &error_abort);
 
     memory_region_init_io(&s->iomem, NULL, &omap_sti_ops, s, "omap.sti",
                           omap_l4_region_size(ta, 0));
diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c
index c184859..436e1b0 100644
--- a/hw/char/mcf_uart.c
+++ b/hw/char/mcf_uart.c
@@ -10,6 +10,7 @@
 #include "hw/m68k/mcf.h"
 #include "sysemu/char.h"
 #include "exec/address-spaces.h"
+#include "qapi/error.h"
 
 typedef struct {
     MemoryRegion iomem;
@@ -26,7 +27,7 @@ typedef struct {
     int tx_enabled;
     int rx_enabled;
     qemu_irq irq;
-    CharDriverState *chr;
+    CharBackend chr;
 } mcf_uart_state;
 
 /* UART Status Register bits.  */
@@ -92,7 +93,7 @@ uint64_t mcf_uart_read(void *opaque, hwaddr addr,
             if (s->fifo_len == 0)
                 s->sr &= ~MCF_UART_RxRDY;
             mcf_uart_update(s);
-            qemu_chr_accept_input(s->chr);
+            qemu_chr_accept_input(s->chr.chr);
             return val;
         }
     case 0x10:
@@ -113,10 +114,11 @@ uint64_t mcf_uart_read(void *opaque, hwaddr addr,
 static void mcf_uart_do_tx(mcf_uart_state *s)
 {
     if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
-        if (s->chr)
+        if (s->chr.chr) {
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(s->chr, (unsigned char *)&s->tb, 1);
+            qemu_chr_fe_write_all(s->chr.chr, (unsigned char *)&s->tb, 1);
+        }
         s->sr |= MCF_UART_TxEMP;
     }
     if (s->tx_enabled) {
@@ -280,9 +282,9 @@ void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
     mcf_uart_state *s;
 
     s = g_malloc0(sizeof(mcf_uart_state));
-    s->chr = chr;
     s->irq = irq;
     if (chr) {
+        qemu_chr_fe_init(&s->chr, chr, &error_abort);
         qemu_chr_fe_claim_no_fail(chr);
         qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive,
                               mcf_uart_event, s);
diff --git a/hw/char/sh_serial.c b/hw/char/sh_serial.c
index 97ce562..c8b91bb 100644
--- a/hw/char/sh_serial.c
+++ b/hw/char/sh_serial.c
@@ -29,6 +29,7 @@
 #include "hw/sh4/sh.h"
 #include "sysemu/char.h"
 #include "exec/address-spaces.h"
+#include "qapi/error.h"
 
 //#define DEBUG_SERIAL
 
@@ -62,7 +63,7 @@ typedef struct {
     int flags;
     int rtrg;
 
-    CharDriverState *chr;
+    CharBackend chr;
 
     qemu_irq eri;
     qemu_irq rxi;
@@ -109,11 +110,11 @@ static void sh_serial_write(void *opaque, hwaddr offs,
         }
         return;
     case 0x0c: /* FTDR / TDR */
-        if (s->chr) {
+        if (s->chr.chr) {
             ch = val;
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(s->chr, &ch, 1);
+            qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
 	}
 	s->dr = val;
 	s->flags &= ~SH_SERIAL_FLAG_TDE;
@@ -395,10 +396,9 @@ void sh_serial_init(MemoryRegion *sysmem,
                              0, 0x28);
     memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7);
 
-    s->chr = chr;
-
     if (chr) {
         qemu_chr_fe_claim_no_fail(chr);
+        qemu_chr_fe_init(&s->chr, chr, &error_abort);
         qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
 			      sh_serial_event, s);
     }
diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c
index 11bf6a4..c1d36dc 100644
--- a/hw/char/xen_console.c
+++ b/hw/char/xen_console.c
@@ -26,6 +26,7 @@
 #include "hw/hw.h"
 #include "sysemu/char.h"
 #include "hw/xen/xen_backend.h"
+#include "qapi/error.h"
 
 #include <xen/io/console.h>
 
@@ -43,7 +44,7 @@ struct XenConsole {
     char              console[XEN_BUFSIZE];
     int               ring_ref;
     void              *sring;
-    CharDriverState   *chr;
+    CharBackend       chr;
     int               backlog;
 };
 
@@ -148,11 +149,13 @@ static void xencons_send(struct XenConsole *con)
     ssize_t len, size;
 
     size = con->buffer.size - con->buffer.consumed;
-    if (con->chr)
-        len = qemu_chr_fe_write(con->chr, con->buffer.data + con->buffer.consumed,
-                             size);
-    else
+    if (con->chr.chr) {
+        len = qemu_chr_fe_write(con->chr.chr,
+                                con->buffer.data + con->buffer.consumed,
+                                size);
+    } else {
         len = size;
+    }
     if (len < 1) {
 	if (!con->backlog) {
 	    con->backlog = 1;
@@ -196,13 +199,17 @@ static int con_init(struct XenDevice *xendev)
 
     /* no Xen override, use qemu output device */
     if (output == NULL) {
-        con->chr = serial_hds[con->xendev.dev];
+        if (con->xendev.dev) {
+            qemu_chr_fe_init(&con->chr, serial_hds[con->xendev.dev],
+                             &error_abort);
+        }
     } else {
         snprintf(label, sizeof(label), "xencons%d", con->xendev.dev);
-        con->chr = qemu_chr_new(label, output);
+        qemu_chr_fe_init(&con->chr,
+                         qemu_chr_new(label, output), &error_abort);
     }
 
-    xenstore_store_pv_console_info(con->xendev.dev, con->chr);
+    xenstore_store_pv_console_info(con->xendev.dev, con->chr.chr);
 
 out:
     g_free(type);
@@ -235,15 +242,15 @@ static int con_initialise(struct XenDevice *xendev)
 	return -1;
 
     xen_be_bind_evtchn(&con->xendev);
-    if (con->chr) {
-        if (qemu_chr_fe_claim(con->chr) == 0) {
-            qemu_chr_add_handlers(con->chr, xencons_can_receive,
+    if (con->chr.chr) {
+        if (qemu_chr_fe_claim(con->chr.chr) == 0) {
+            qemu_chr_add_handlers(con->chr.chr, xencons_can_receive,
                                   xencons_receive, NULL, con);
         } else {
             xen_be_printf(xendev, 0,
                           "xen_console_init error chardev %s already used\n",
-                          con->chr->label);
-            con->chr = NULL;
+                          con->chr.chr->label);
+            con->chr.chr = NULL;
         }
     }
 
@@ -259,9 +266,9 @@ static void con_disconnect(struct XenDevice *xendev)
 {
     struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
 
-    if (con->chr) {
-        qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL);
-        qemu_chr_fe_release(con->chr);
+    if (con->chr.chr) {
+        qemu_chr_add_handlers(con->chr.chr, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_release(con->chr.chr);
     }
     xen_be_unbind_evtchn(&con->xendev);
 
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index ed0850c..d5601b1 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -85,7 +85,7 @@ typedef struct {
     uint32_t i2coe;
     uint32_t i2cout;
     uint32_t i2csel;
-    CharDriverState *display;
+    CharBackend display;
     char display_text[9];
     SerialState *uart;
     bool display_inited;
@@ -125,8 +125,10 @@ static void malta_fpga_update_display(void *opaque)
     }
     leds_text[8] = '\0';
 
-    qemu_chr_fe_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text);
-    qemu_chr_fe_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text);
+    qemu_chr_fe_printf(s->display.chr, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n",
+                       leds_text);
+    qemu_chr_fe_printf(s->display.chr, "\n\n\n\n|\e[31m%-8.8s\e[00m|",
+                       s->display_text);
 }
 
 /*
@@ -536,15 +538,15 @@ static void malta_fgpa_display_event(void *opaque, int event)
     MaltaFPGAState *s = opaque;
 
     if (event == CHR_EVENT_OPENED && !s->display_inited) {
-        qemu_chr_fe_printf(s->display, "\e[HMalta LEDBAR\r\n");
-        qemu_chr_fe_printf(s->display, "+--------+\r\n");
-        qemu_chr_fe_printf(s->display, "+        +\r\n");
-        qemu_chr_fe_printf(s->display, "+--------+\r\n");
-        qemu_chr_fe_printf(s->display, "\n");
-        qemu_chr_fe_printf(s->display, "Malta ASCII\r\n");
-        qemu_chr_fe_printf(s->display, "+--------+\r\n");
-        qemu_chr_fe_printf(s->display, "+        +\r\n");
-        qemu_chr_fe_printf(s->display, "+--------+\r\n");
+        qemu_chr_fe_printf(s->display.chr, "\e[HMalta LEDBAR\r\n");
+        qemu_chr_fe_printf(s->display.chr, "+--------+\r\n");
+        qemu_chr_fe_printf(s->display.chr, "+        +\r\n");
+        qemu_chr_fe_printf(s->display.chr, "+--------+\r\n");
+        qemu_chr_fe_printf(s->display.chr, "\n");
+        qemu_chr_fe_printf(s->display.chr, "Malta ASCII\r\n");
+        qemu_chr_fe_printf(s->display.chr, "+--------+\r\n");
+        qemu_chr_fe_printf(s->display.chr, "+        +\r\n");
+        qemu_chr_fe_printf(s->display.chr, "+--------+\r\n");
         s->display_inited = true;
     }
 }
@@ -553,6 +555,7 @@ static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
          hwaddr base, qemu_irq uart_irq, CharDriverState *uart_chr)
 {
     MaltaFPGAState *s;
+    CharDriverState *chr;
 
     s = (MaltaFPGAState *)g_malloc0(sizeof(MaltaFPGAState));
 
@@ -566,8 +569,9 @@ static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
     memory_region_add_subregion(address_space, base, &s->iomem_lo);
     memory_region_add_subregion(address_space, base + 0xa00, &s->iomem_hi);
 
-    s->display = qemu_chr_new("fpga", "vc:320x200");
-    qemu_chr_add_handlers(s->display, NULL, NULL,
+    chr = qemu_chr_new("fpga", "vc:320x200");
+    qemu_chr_fe_init(&s->display, chr, &error_abort);
+    qemu_chr_add_handlers(s->display.chr, NULL, NULL,
                           malta_fgpa_display_event, s);
 
     s->uart = serial_mm_init(address_space, base + 0x900, 3, uart_irq,
diff --git a/monitor.c b/monitor.c
index 8728dd9..40712f7 100644
--- a/monitor.c
+++ b/monitor.c
@@ -186,7 +186,7 @@ typedef struct {
 } MonitorQAPIEventConf;
 
 struct Monitor {
-    CharDriverState *chr;
+    CharBackend chr;
     int reset_seen;
     int flags;
     int suspend_cnt;
@@ -297,7 +297,7 @@ static void monitor_flush_locked(Monitor *mon)
     len = qstring_get_length(mon->outbuf);
 
     if (len && !mon->mux_out) {
-        rc = qemu_chr_fe_write(mon->chr, (const uint8_t *) buf, len);
+        rc = qemu_chr_fe_write(mon->chr.chr, (const uint8_t *) buf, len);
         if ((rc < 0 && errno != EAGAIN) || (rc == len)) {
             /* all flushed or error */
             QDECREF(mon->outbuf);
@@ -311,8 +311,9 @@ static void monitor_flush_locked(Monitor *mon)
             mon->outbuf = tmp;
         }
         if (mon->out_watch == 0) {
-            mon->out_watch = qemu_chr_fe_add_watch(mon->chr, G_IO_OUT|G_IO_HUP,
-                                                   monitor_unblocked, mon);
+            mon->out_watch =
+                qemu_chr_fe_add_watch(mon->chr.chr, G_IO_OUT | G_IO_HUP,
+                                      monitor_unblocked, mon);
         }
     }
 }
@@ -581,8 +582,8 @@ static void monitor_data_init(Monitor *mon)
 
 static void monitor_data_destroy(Monitor *mon)
 {
-    if (mon->chr) {
-        qemu_chr_add_handlers(mon->chr, NULL, NULL, NULL, NULL);
+    if (mon->chr.chr) {
+        qemu_chr_add_handlers(mon->chr.chr, NULL, NULL, NULL, NULL);
     }
     if (monitor_is_qmp(mon)) {
         json_message_parser_destroy(&mon->qmp.parser);
@@ -1745,7 +1746,7 @@ void qmp_getfd(const char *fdname, Error **errp)
     mon_fd_t *monfd;
     int fd;
 
-    fd = qemu_chr_fe_get_msgfd(cur_mon->chr);
+    fd = qemu_chr_fe_get_msgfd(cur_mon->chr.chr);
     if (fd == -1) {
         error_setg(errp, QERR_FD_NOT_SUPPLIED);
         return;
@@ -1870,7 +1871,7 @@ AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id, bool has_opaque,
     Monitor *mon = cur_mon;
     AddfdInfo *fdinfo;
 
-    fd = qemu_chr_fe_get_msgfd(mon->chr);
+    fd = qemu_chr_fe_get_msgfd(mon->chr.chr);
     if (fd == -1) {
         error_setg(errp, QERR_FD_NOT_SUPPLIED);
         goto error;
@@ -3977,7 +3978,7 @@ void monitor_init(CharDriverState *chr, int flags)
     mon = g_malloc(sizeof(*mon));
     monitor_data_init(mon);
 
-    mon->chr = chr;
+    qemu_chr_fe_init(&mon->chr, chr, &error_abort);
     mon->flags = flags;
     if (flags & MONITOR_USE_READLINE) {
         mon->rs = readline_init(monitor_readline_printf,
diff --git a/net/colo-compare.c b/net/colo-compare.c
index 47703c5..efcd15e 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -68,9 +68,9 @@ typedef struct CompareState {
     char *pri_indev;
     char *sec_indev;
     char *outdev;
-    CharDriverState *chr_pri_in;
-    CharDriverState *chr_sec_in;
-    CharDriverState *chr_out;
+    CharBackend chr_pri_in;
+    CharBackend chr_sec_in;
+    CharBackend chr_out;
     SocketReadState pri_rs;
     SocketReadState sec_rs;
 
@@ -385,7 +385,7 @@ static void colo_compare_connection(void *opaque, void *user_data)
         }
 
         if (result) {
-            ret = compare_chr_send(s->chr_out, pkt->data, pkt->size);
+            ret = compare_chr_send(s->chr_out.chr, pkt->data, pkt->size);
             if (ret < 0) {
                 error_report("colo_send_primary_packet failed");
             }
@@ -451,7 +451,7 @@ static void compare_pri_chr_in(void *opaque, const uint8_t *buf, int size)
 
     ret = net_fill_rstate(&s->pri_rs, buf, size);
     if (ret == -1) {
-        qemu_chr_add_handlers(s->chr_pri_in, NULL, NULL, NULL, NULL);
+        qemu_chr_add_handlers(s->chr_pri_in.chr, NULL, NULL, NULL, NULL);
         error_report("colo-compare primary_in error");
     }
 }
@@ -467,7 +467,7 @@ static void compare_sec_chr_in(void *opaque, const uint8_t *buf, int size)
 
     ret = net_fill_rstate(&s->sec_rs, buf, size);
     if (ret == -1) {
-        qemu_chr_add_handlers(s->chr_sec_in, NULL, NULL, NULL, NULL);
+        qemu_chr_add_handlers(s->chr_sec_in.chr, NULL, NULL, NULL, NULL);
         error_report("colo-compare secondary_in error");
     }
 }
@@ -480,9 +480,9 @@ static void *colo_compare_thread(void *opaque)
 
     worker_context = g_main_context_new();
 
-    qemu_chr_add_handlers_full(s->chr_pri_in, compare_chr_can_read,
+    qemu_chr_add_handlers_full(s->chr_pri_in.chr, compare_chr_can_read,
                           compare_pri_chr_in, NULL, s, worker_context);
-    qemu_chr_add_handlers_full(s->chr_sec_in, compare_chr_can_read,
+    qemu_chr_add_handlers_full(s->chr_sec_in.chr, compare_chr_can_read,
                           compare_sec_chr_in, NULL, s, worker_context);
 
     compare_loop = g_main_loop_new(worker_context, FALSE);
@@ -545,7 +545,7 @@ static void compare_pri_rs_finalize(SocketReadState *pri_rs)
 
     if (packet_enqueue(s, PRIMARY_IN)) {
         trace_colo_compare_main("primary: unsupported packet in");
-        compare_chr_send(s->chr_out, pri_rs->buf, pri_rs->packet_len);
+        compare_chr_send(s->chr_out.chr, pri_rs->buf, pri_rs->packet_len);
     } else {
         /* compare connection */
         g_queue_foreach(&s->conn_list, colo_compare_connection, s);
@@ -634,23 +634,23 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
         return;
     }
 
-    if (find_and_check_chardev(&s->chr_pri_in, s->pri_indev, errp)) {
+    if (find_and_check_chardev(&s->chr_pri_in.chr, s->pri_indev, errp)) {
         return;
     }
 
-    if (find_and_check_chardev(&s->chr_sec_in, s->sec_indev, errp)) {
+    if (find_and_check_chardev(&s->chr_sec_in.chr, s->sec_indev, errp)) {
         return;
     }
 
-    if (find_and_check_chardev(&s->chr_out, s->outdev, errp)) {
+    if (find_and_check_chardev(&s->chr_out.chr, s->outdev, errp)) {
         return;
     }
 
-    qemu_chr_fe_claim_no_fail(s->chr_pri_in);
+    qemu_chr_fe_claim_no_fail(s->chr_pri_in.chr);
 
-    qemu_chr_fe_claim_no_fail(s->chr_sec_in);
+    qemu_chr_fe_claim_no_fail(s->chr_sec_in.chr);
 
-    qemu_chr_fe_claim_no_fail(s->chr_out);
+    qemu_chr_fe_claim_no_fail(s->chr_out.chr);
 
     net_socket_rs_init(&s->pri_rs, compare_pri_rs_finalize);
     net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize);
@@ -702,16 +702,16 @@ static void colo_compare_finalize(Object *obj)
 {
     CompareState *s = COLO_COMPARE(obj);
 
-    if (s->chr_pri_in) {
-        qemu_chr_add_handlers(s->chr_pri_in, NULL, NULL, NULL, NULL);
-        qemu_chr_fe_release(s->chr_pri_in);
+    if (s->chr_pri_in.chr) {
+        qemu_chr_add_handlers(s->chr_pri_in.chr, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_release(s->chr_pri_in.chr);
     }
-    if (s->chr_sec_in) {
-        qemu_chr_add_handlers(s->chr_sec_in, NULL, NULL, NULL, NULL);
-        qemu_chr_fe_release(s->chr_sec_in);
+    if (s->chr_sec_in.chr) {
+        qemu_chr_add_handlers(s->chr_sec_in.chr, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_release(s->chr_sec_in.chr);
     }
-    if (s->chr_out) {
-        qemu_chr_fe_release(s->chr_out);
+    if (s->chr_out.chr) {
+        qemu_chr_fe_release(s->chr_out.chr);
     }
 
     g_queue_free(&s->conn_list);
diff --git a/net/filter-mirror.c b/net/filter-mirror.c
index 0ee58d9..425e146 100644
--- a/net/filter-mirror.c
+++ b/net/filter-mirror.c
@@ -38,8 +38,8 @@ typedef struct MirrorState {
     NetFilterState parent_obj;
     char *indev;
     char *outdev;
-    CharDriverState *chr_in;
-    CharDriverState *chr_out;
+    CharBackend chr_in;
+    CharBackend chr_out;
     SocketReadState rs;
 } MirrorState;
 
@@ -110,7 +110,7 @@ static void redirector_chr_read(void *opaque, const uint8_t *buf, int size)
     ret = net_fill_rstate(&s->rs, buf, size);
 
     if (ret == -1) {
-        qemu_chr_add_handlers(s->chr_in, NULL, NULL, NULL, NULL);
+        qemu_chr_add_handlers(s->chr_in.chr, NULL, NULL, NULL, NULL);
     }
 }
 
@@ -121,7 +121,7 @@ static void redirector_chr_event(void *opaque, int event)
 
     switch (event) {
     case CHR_EVENT_CLOSED:
-        qemu_chr_add_handlers(s->chr_in, NULL, NULL, NULL, NULL);
+        qemu_chr_add_handlers(s->chr_in.chr, NULL, NULL, NULL, NULL);
         break;
     default:
         break;
@@ -138,7 +138,7 @@ static ssize_t filter_mirror_receive_iov(NetFilterState *nf,
     MirrorState *s = FILTER_MIRROR(nf);
     int ret;
 
-    ret = filter_mirror_send(s->chr_out, iov, iovcnt);
+    ret = filter_mirror_send(s->chr_out.chr, iov, iovcnt);
     if (ret) {
         error_report("filter_mirror_send failed(%s)", strerror(-ret));
     }
@@ -160,8 +160,8 @@ static ssize_t filter_redirector_receive_iov(NetFilterState *nf,
     MirrorState *s = FILTER_REDIRECTOR(nf);
     int ret;
 
-    if (s->chr_out) {
-        ret = filter_mirror_send(s->chr_out, iov, iovcnt);
+    if (s->chr_out.chr) {
+        ret = filter_mirror_send(s->chr_out.chr, iov, iovcnt);
         if (ret) {
             error_report("filter_mirror_send failed(%s)", strerror(-ret));
         }
@@ -175,8 +175,8 @@ static void filter_mirror_cleanup(NetFilterState *nf)
 {
     MirrorState *s = FILTER_MIRROR(nf);
 
-    if (s->chr_out) {
-        qemu_chr_fe_release(s->chr_out);
+    if (s->chr_out.chr) {
+        qemu_chr_fe_release(s->chr_out.chr);
     }
 }
 
@@ -184,18 +184,19 @@ static void filter_redirector_cleanup(NetFilterState *nf)
 {
     MirrorState *s = FILTER_REDIRECTOR(nf);
 
-    if (s->chr_in) {
-        qemu_chr_add_handlers(s->chr_in, NULL, NULL, NULL, NULL);
-        qemu_chr_fe_release(s->chr_in);
+    if (s->chr_in.chr) {
+        qemu_chr_add_handlers(s->chr_in.chr, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_release(s->chr_in.chr);
     }
-    if (s->chr_out) {
-        qemu_chr_fe_release(s->chr_out);
+    if (s->chr_out.chr) {
+        qemu_chr_fe_release(s->chr_out.chr);
     }
 }
 
 static void filter_mirror_setup(NetFilterState *nf, Error **errp)
 {
     MirrorState *s = FILTER_MIRROR(nf);
+    CharDriverState *chr;
 
     if (!s->outdev) {
         error_setg(errp, "filter mirror needs 'outdev' "
@@ -203,17 +204,19 @@ static void filter_mirror_setup(NetFilterState *nf, Error **errp)
         return;
     }
 
-    s->chr_out = qemu_chr_find(s->outdev);
-    if (s->chr_out == NULL) {
+    chr = qemu_chr_find(s->outdev);
+    if (chr == NULL) {
         error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
                   "Device '%s' not found", s->outdev);
         return;
     }
 
-    if (qemu_chr_fe_claim(s->chr_out) != 0) {
+    if (qemu_chr_fe_claim(chr) != 0) {
         error_setg(errp, QERR_DEVICE_IN_USE, s->outdev);
         return;
     }
+
+    qemu_chr_fe_init(&s->chr_out, chr, errp);
 }
 
 static void redirector_rs_finalize(SocketReadState *rs)
@@ -227,6 +230,7 @@ static void redirector_rs_finalize(SocketReadState *rs)
 static void filter_redirector_setup(NetFilterState *nf, Error **errp)
 {
     MirrorState *s = FILTER_REDIRECTOR(nf);
+    CharDriverState *chr;
 
     if (!s->indev && !s->outdev) {
         error_setg(errp, "filter redirector needs 'indev' or "
@@ -243,26 +247,32 @@ static void filter_redirector_setup(NetFilterState *nf, Error **errp)
     net_socket_rs_init(&s->rs, redirector_rs_finalize);
 
     if (s->indev) {
-        s->chr_in = qemu_chr_find(s->indev);
-        if (s->chr_in == NULL) {
+        chr = qemu_chr_find(s->indev);
+        if (chr == NULL) {
             error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
                       "IN Device '%s' not found", s->indev);
             return;
         }
 
-        qemu_chr_fe_claim_no_fail(s->chr_in);
-        qemu_chr_add_handlers(s->chr_in, redirector_chr_can_read,
+        qemu_chr_fe_claim_no_fail(chr);
+        if (!qemu_chr_fe_init(&s->chr_in, chr, errp)) {
+            return;
+        }
+        qemu_chr_add_handlers(s->chr_in.chr, redirector_chr_can_read,
                               redirector_chr_read, redirector_chr_event, nf);
     }
 
     if (s->outdev) {
-        s->chr_out = qemu_chr_find(s->outdev);
-        if (s->chr_out == NULL) {
+        chr = qemu_chr_find(s->outdev);
+        if (chr == NULL) {
             error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
                       "OUT Device '%s' not found", s->outdev);
             return;
         }
-        qemu_chr_fe_claim_no_fail(s->chr_out);
+        qemu_chr_fe_claim_no_fail(chr);
+        if (!qemu_chr_fe_init(&s->chr_out, chr, errp)) {
+            return;
+        }
     }
 }
 
diff --git a/net/slirp.c b/net/slirp.c
index f9fdff5..407e8aa 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -40,6 +40,7 @@
 #include "sysemu/char.h"
 #include "sysemu/sysemu.h"
 #include "qemu/cutils.h"
+#include "qapi/error.h"
 
 static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
 {
@@ -682,7 +683,7 @@ int net_slirp_smb(const char *exported_dir)
 #endif /* !defined(_WIN32) */
 
 struct GuestFwd {
-    CharDriverState *hd;
+    CharBackend hd;
     struct in_addr server;
     int port;
     Slirp *slirp;
@@ -746,15 +747,23 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str,
             return -1;
         }
     } else {
-        fwd = g_new(struct GuestFwd, 1);
-        fwd->hd = qemu_chr_new(buf, p);
-        if (!fwd->hd) {
+        Error *err = NULL;
+        CharDriverState *chr = qemu_chr_new(buf, p);
+
+        if (!chr) {
             error_report("could not open guest forwarding device '%s'", buf);
+            return -1;
+        }
+
+        fwd = g_new(struct GuestFwd, 1);
+        qemu_chr_fe_init(&fwd->hd, chr, &err);
+        if (err) {
+            error_report_err(err);
             g_free(fwd);
             return -1;
         }
 
-        if (slirp_add_exec(s->slirp, 3, fwd->hd, &server, port) < 0) {
+        if (slirp_add_exec(s->slirp, 3, fwd->hd.chr, &server, port) < 0) {
             error_report("conflicting/invalid host:port in guest forwarding "
                          "rule '%s'", config_str);
             g_free(fwd);
@@ -764,8 +773,8 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str,
         fwd->port = port;
         fwd->slirp = s->slirp;
 
-        qemu_chr_fe_claim_no_fail(fwd->hd);
-        qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read,
+        qemu_chr_fe_claim_no_fail(fwd->hd.chr);
+        qemu_chr_add_handlers(fwd->hd.chr, guestfwd_can_read, guestfwd_read,
                               NULL, fwd);
     }
     return 0;
diff --git a/net/vhost-user.c b/net/vhost-user.c
index 5b94c84..957459f 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -20,7 +20,7 @@
 
 typedef struct VhostUserState {
     NetClientState nc;
-    CharDriverState *chr;
+    CharBackend chr;
     VHostNetState *vhost_net;
     guint watch;
     uint64_t acked_features;
@@ -78,7 +78,7 @@ static int vhost_user_start(int queues, NetClientState *ncs[])
         s = DO_UPCAST(VhostUserState, nc, ncs[i]);
 
         options.net_backend = ncs[i];
-        options.opaque      = s->chr;
+        options.opaque      = s->chr.chr;
         options.busyloop_timeout = 0;
         net = vhost_net_init(&options);
         if (!net) {
@@ -150,10 +150,10 @@ static void vhost_user_cleanup(NetClientState *nc)
         g_free(s->vhost_net);
         s->vhost_net = NULL;
     }
-    if (s->chr) {
-        qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL);
-        qemu_chr_fe_release(s->chr);
-        s->chr = NULL;
+    if (s->chr.chr) {
+        qemu_chr_add_handlers(s->chr.chr, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_release(s->chr.chr);
+        s->chr.chr = NULL;
     }
 
     qemu_purge_queued_packets(nc);
@@ -187,7 +187,7 @@ static gboolean net_vhost_user_watch(GIOChannel *chan, GIOCondition cond,
 {
     VhostUserState *s = opaque;
 
-    qemu_chr_disconnect(s->chr);
+    qemu_chr_disconnect(s->chr.chr);
 
     return FALSE;
 }
@@ -206,13 +206,13 @@ static void net_vhost_user_event(void *opaque, int event)
     assert(queues < MAX_QUEUE_NUM);
 
     s = DO_UPCAST(VhostUserState, nc, ncs[0]);
-    trace_vhost_user_event(s->chr->label, event);
+    trace_vhost_user_event(s->chr.chr->label, event);
     switch (event) {
     case CHR_EVENT_OPENED:
-        s->watch = qemu_chr_fe_add_watch(s->chr, G_IO_HUP,
+        s->watch = qemu_chr_fe_add_watch(s->chr.chr, G_IO_HUP,
                                          net_vhost_user_watch, s);
         if (vhost_user_start(queues, ncs) < 0) {
-            qemu_chr_disconnect(s->chr);
+            qemu_chr_disconnect(s->chr.chr);
             return;
         }
         qmp_set_link(name, true, &err);
@@ -235,6 +235,7 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
                                const char *name, CharDriverState *chr,
                                int queues)
 {
+    Error *err = NULL;
     NetClientState *nc, *nc0 = NULL;
     VhostUserState *s;
     int i;
@@ -254,12 +255,14 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
         nc->queue_index = i;
 
         s = DO_UPCAST(VhostUserState, nc, nc);
-        s->chr = chr;
+        if (!qemu_chr_fe_init(&s->chr, chr, &err)) {
+            error_report_err(err);
+            return -1;
+        }
     }
 
     s = DO_UPCAST(VhostUserState, nc, nc0);
     do {
-        Error *err = NULL;
         if (qemu_chr_wait_connected(chr, &err) < 0) {
             error_report_err(err);
             return -1;
diff --git a/qtest.c b/qtest.c
index 2d9a021..3fb3c11 100644
--- a/qtest.c
+++ b/qtest.c
@@ -38,7 +38,7 @@ bool qtest_allowed;
 
 static DeviceState *irq_intercept_dev;
 static FILE *qtest_log_fp;
-static CharDriverState *qtest_chr;
+static CharBackend qtest_chr;
 static GString *inbuf;
 static int irq_levels[MAX_IRQ];
 static qemu_timeval start_time;
@@ -249,7 +249,7 @@ static void qtest_irq_handler(void *opaque, int n, int level)
     qemu_set_irq(old_irq, level);
 
     if (irq_levels[n] != level) {
-        CharDriverState *chr = qtest_chr;
+        CharDriverState *chr = qtest_chr.chr;
         irq_levels[n] = level;
         qtest_send_prefix(chr);
         qtest_sendf(chr, "IRQ %s %d\n",
@@ -690,12 +690,12 @@ void qtest_init(const char *qtest_chrdev, const char *qtest_log, Error **errp)
     qemu_chr_fe_set_echo(chr, true);
 
     inbuf = g_string_new("");
-    qtest_chr = chr;
+    qemu_chr_fe_init(&qtest_chr, chr, errp);
 }
 
 bool qtest_driver(void)
 {
-    return qtest_chr;
+    return qtest_chr.chr != NULL;
 }
 
 static void qtest_accel_class_init(ObjectClass *oc, void *data)
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index edf30ac..52fbc03 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -19,6 +19,7 @@
 #include "libqos/libqos.h"
 #include "libqos/pci-pc.h"
 #include "libqos/virtio-pci.h"
+#include "qapi/error.h"
 
 #include "libqos/pci-pc.h"
 #include "libqos/virtio-pci.h"
@@ -141,7 +142,7 @@ typedef struct TestServer {
     gchar *socket_path;
     gchar *mig_path;
     gchar *chr_name;
-    CharDriverState *chr;
+    CharBackend chr;
     int fds_num;
     int fds[VHOST_MEMORY_MAX_NREGIONS];
     VhostUserMemory memory;
@@ -261,13 +262,13 @@ static int chr_can_read(void *opaque)
 static void chr_read(void *opaque, const uint8_t *buf, int size)
 {
     TestServer *s = opaque;
-    CharDriverState *chr = s->chr;
+    CharBackend *chr = &s->chr;
     VhostUserMsg msg;
     uint8_t *p = (uint8_t *) &msg;
     int fd;
 
     if (s->test_fail) {
-        qemu_chr_disconnect(chr);
+        qemu_chr_disconnect(chr->chr);
         /* now switch to non-failure */
         s->test_fail = false;
     }
@@ -282,7 +283,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
 
     if (msg.size) {
         p += VHOST_USER_HDR_SIZE;
-        size = qemu_chr_fe_read_all(chr, p, msg.size);
+        size = qemu_chr_fe_read_all(chr->chr, p, msg.size);
         if (size != msg.size) {
             g_test_message("Wrong message size received %d != %d\n",
                            size, msg.size);
@@ -305,14 +306,14 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
             s->test_flags = TEST_FLAGS_END;
         }
         p = (uint8_t *) &msg;
-        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
+        qemu_chr_fe_write_all(chr->chr, p, VHOST_USER_HDR_SIZE + msg.size);
         break;
 
     case VHOST_USER_SET_FEATURES:
 	g_assert_cmpint(msg.payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES),
 			!=, 0ULL);
         if (s->test_flags == TEST_FLAGS_DISCONNECT) {
-            qemu_chr_disconnect(chr);
+            qemu_chr_disconnect(chr->chr);
             s->test_flags = TEST_FLAGS_BAD;
         }
         break;
@@ -326,7 +327,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
             msg.payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_MQ;
         }
         p = (uint8_t *) &msg;
-        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
+        qemu_chr_fe_write_all(chr->chr, p, VHOST_USER_HDR_SIZE + msg.size);
         break;
 
     case VHOST_USER_GET_VRING_BASE:
@@ -335,7 +336,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
         msg.size = sizeof(m.payload.state);
         msg.payload.state.num = 0;
         p = (uint8_t *) &msg;
-        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
+        qemu_chr_fe_write_all(chr->chr, p, VHOST_USER_HDR_SIZE + msg.size);
 
         assert(msg.payload.state.index < s->queues * 2);
         s->rings &= ~(0x1ULL << msg.payload.state.index);
@@ -344,7 +345,8 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
     case VHOST_USER_SET_MEM_TABLE:
         /* received the mem table */
         memcpy(&s->memory, &msg.payload.memory, sizeof(msg.payload.memory));
-        s->fds_num = qemu_chr_fe_get_msgfds(chr, s->fds, G_N_ELEMENTS(s->fds));
+        s->fds_num = qemu_chr_fe_get_msgfds(chr->chr, s->fds,
+                                            G_N_ELEMENTS(s->fds));
 
         /* signal the test that it can continue */
         g_cond_signal(&s->data_cond);
@@ -353,7 +355,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
     case VHOST_USER_SET_VRING_KICK:
     case VHOST_USER_SET_VRING_CALL:
         /* consume the fd */
-        qemu_chr_fe_get_msgfds(chr, &fd, 1);
+        qemu_chr_fe_get_msgfds(chr->chr, &fd, 1);
         /*
          * This is a non-blocking eventfd.
          * The receive function forces it to be blocking,
@@ -367,11 +369,11 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
             close(s->log_fd);
             s->log_fd = -1;
         }
-        qemu_chr_fe_get_msgfds(chr, &s->log_fd, 1);
+        qemu_chr_fe_get_msgfds(chr->chr, &s->log_fd, 1);
         msg.flags |= VHOST_USER_REPLY_MASK;
         msg.size = 0;
         p = (uint8_t *) &msg;
-        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE);
+        qemu_chr_fe_write_all(chr->chr, p, VHOST_USER_HDR_SIZE);
 
         g_cond_signal(&s->data_cond);
         break;
@@ -386,7 +388,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
         msg.size = sizeof(m.payload.u64);
         msg.payload.u64 = s->queues;
         p = (uint8_t *) &msg;
-        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
+        qemu_chr_fe_write_all(chr->chr, p, VHOST_USER_HDR_SIZE + msg.size);
         break;
 
     default:
@@ -453,12 +455,13 @@ static void chr_event(void *opaque, int event)
 static void test_server_create_chr(TestServer *server, const gchar *opt)
 {
     gchar *chr_path;
-
+    CharDriverState *chr;
     chr_path = g_strdup_printf("unix:%s%s", server->socket_path, opt);
-    server->chr = qemu_chr_new(server->chr_name, chr_path);
+    chr = qemu_chr_new(server->chr_name, chr_path);
+    qemu_chr_fe_init(&server->chr, chr, &error_abort);
     g_free(chr_path);
 
-    qemu_chr_add_handlers(server->chr, chr_can_read, chr_read,
+    qemu_chr_add_handlers(server->chr.chr, chr_can_read, chr_read,
                           chr_event, server);
 }
 
@@ -484,7 +487,7 @@ static gboolean _test_server_free(TestServer *server)
 {
     int i;
 
-    qemu_chr_delete(server->chr);
+    qemu_chr_delete(server->chr.chr);
 
     for (i = 0; i < server->fds_num; i++) {
         close(server->fds[i]);
@@ -721,7 +724,7 @@ reconnect_cb(gpointer user_data)
 {
     TestServer *s = user_data;
 
-    qemu_chr_disconnect(s->chr);
+    qemu_chr_disconnect(s->chr.chr);
 
     return FALSE;
 }
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 32/50] char: rename some frontend functions
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (30 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 31/50] char: remaining switch to CharBackend in frontend Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 33/50] colo: claim in find_and_check_chardev Paolo Bonzini
                   ` (18 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

qemu_chr_accept_input() and qemu_chr_disconnect() are only used by
frontend, so use qemu_chr_fe prefix.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-14-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/char/bcm2835_aux.c     | 2 +-
 hw/char/cadence_uart.c    | 4 ++--
 hw/char/escc.c            | 2 +-
 hw/char/imx_serial.c      | 4 ++--
 hw/char/ipoctal232.c      | 2 +-
 hw/char/lm32_uart.c       | 2 +-
 hw/char/mcf_uart.c        | 2 +-
 hw/char/milkymist-uart.c  | 2 +-
 hw/char/pl011.c           | 2 +-
 hw/char/serial.c          | 2 +-
 hw/char/spapr_vty.c       | 2 +-
 hw/char/stm32f2xx_usart.c | 4 ++--
 hw/char/virtio-console.c  | 2 +-
 hw/char/xilinx_uartlite.c | 2 +-
 include/sysemu/char.h     | 6 +++---
 net/vhost-user.c          | 4 ++--
 qemu-char.c               | 4 ++--
 tests/vhost-user-test.c   | 6 +++---
 18 files changed, 27 insertions(+), 27 deletions(-)

diff --git a/hw/char/bcm2835_aux.c b/hw/char/bcm2835_aux.c
index 4bc5d02..30f4ea5 100644
--- a/hw/char/bcm2835_aux.c
+++ b/hw/char/bcm2835_aux.c
@@ -80,7 +80,7 @@ static uint64_t bcm2835_aux_read(void *opaque, hwaddr offset, unsigned size)
             }
         }
         if (s->chr.chr) {
-            qemu_chr_accept_input(s->chr.chr);
+            qemu_chr_fe_accept_input(s->chr.chr);
         }
         bcm2835_aux_update(s);
         return c;
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
index d5687dd..c027235 100644
--- a/hw/char/cadence_uart.c
+++ b/hw/char/cadence_uart.c
@@ -143,7 +143,7 @@ static void uart_rx_reset(CadenceUARTState *s)
     s->rx_wpos = 0;
     s->rx_count = 0;
     if (s->chr.chr) {
-        qemu_chr_accept_input(s->chr.chr);
+        qemu_chr_fe_accept_input(s->chr.chr);
     }
 }
 
@@ -369,7 +369,7 @@ static void uart_read_rx_fifo(CadenceUARTState *s, uint32_t *c)
         s->rx_count--;
 
         if (s->chr.chr) {
-            qemu_chr_accept_input(s->chr.chr);
+            qemu_chr_fe_accept_input(s->chr.chr);
         }
     } else {
         *c = 0;
diff --git a/hw/char/escc.c b/hw/char/escc.c
index ae69b39..f1e8fac 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -600,7 +600,7 @@ static uint64_t escc_mem_read(void *opaque, hwaddr addr,
             ret = s->rx;
         trace_escc_mem_readb_data(CHN_C(s), ret);
         if (s->chr.chr) {
-            qemu_chr_accept_input(s->chr.chr);
+            qemu_chr_fe_accept_input(s->chr.chr);
         }
         return ret;
     default:
diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c
index 5c11de2..2e39d31 100644
--- a/hw/char/imx_serial.c
+++ b/hw/char/imx_serial.c
@@ -122,7 +122,7 @@ static uint64_t imx_serial_read(void *opaque, hwaddr offset,
             s->uts1 |= UTS1_RXEMPTY;
             imx_update(s);
             if (s->chr.chr) {
-                qemu_chr_accept_input(s->chr.chr);
+                qemu_chr_fe_accept_input(s->chr.chr);
             }
         }
         return c;
@@ -216,7 +216,7 @@ static void imx_serial_write(void *opaque, hwaddr offset,
         if (value & UCR2_RXEN) {
             if (!(s->ucr2 & UCR2_RXEN)) {
                 if (s->chr.chr) {
-                    qemu_chr_accept_input(s->chr.chr);
+                    qemu_chr_fe_accept_input(s->chr.chr);
                 }
             }
         }
diff --git a/hw/char/ipoctal232.c b/hw/char/ipoctal232.c
index 0c9dea3..875fe3b 100644
--- a/hw/char/ipoctal232.c
+++ b/hw/char/ipoctal232.c
@@ -289,7 +289,7 @@ static uint16_t io_read(IPackDevice *ip, uint8_t addr)
                 ch->sr &= ~SR_RXRDY;
                 blk->isr &= ~ISR_RXRDY(channel);
                 if (ch->dev.chr) {
-                    qemu_chr_accept_input(ch->dev.chr);
+                    qemu_chr_fe_accept_input(ch->dev.chr);
                 }
             } else {
                 ch->rhr_idx = (ch->rhr_idx + 1) % RX_FIFO_SIZE;
diff --git a/hw/char/lm32_uart.c b/hw/char/lm32_uart.c
index 72fc41c..a8d4a2d 100644
--- a/hw/char/lm32_uart.c
+++ b/hw/char/lm32_uart.c
@@ -142,7 +142,7 @@ static uint64_t uart_read(void *opaque, hwaddr addr,
         r = s->regs[R_RXTX];
         s->regs[R_LSR] &= ~LSR_DR;
         uart_update_irq(s);
-        qemu_chr_accept_input(s->chr.chr);
+        qemu_chr_fe_accept_input(s->chr.chr);
         break;
     case R_IIR:
     case R_LSR:
diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c
index 436e1b0..57b47c6 100644
--- a/hw/char/mcf_uart.c
+++ b/hw/char/mcf_uart.c
@@ -93,7 +93,7 @@ uint64_t mcf_uart_read(void *opaque, hwaddr addr,
             if (s->fifo_len == 0)
                 s->sr &= ~MCF_UART_RxRDY;
             mcf_uart_update(s);
-            qemu_chr_accept_input(s->chr.chr);
+            qemu_chr_fe_accept_input(s->chr.chr);
             return val;
         }
     case 0x10:
diff --git a/hw/char/milkymist-uart.c b/hw/char/milkymist-uart.c
index a6518e6..c75bcb5 100644
--- a/hw/char/milkymist-uart.c
+++ b/hw/char/milkymist-uart.c
@@ -138,7 +138,7 @@ static void uart_write(void *opaque, hwaddr addr, uint64_t value,
     case R_STAT:
         /* write one to clear bits */
         s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT));
-        qemu_chr_accept_input(s->chr.chr);
+        qemu_chr_fe_accept_input(s->chr.chr);
         break;
 
     default:
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
index 9645195..29fb725 100644
--- a/hw/char/pl011.c
+++ b/hw/char/pl011.c
@@ -88,7 +88,7 @@ static uint64_t pl011_read(void *opaque, hwaddr offset,
         s->rsr = c >> 8;
         pl011_update(s);
         if (s->chr.chr) {
-            qemu_chr_accept_input(s->chr.chr);
+            qemu_chr_fe_accept_input(s->chr.chr);
         }
         r = c;
         break;
diff --git a/hw/char/serial.c b/hw/char/serial.c
index 18c7482..4489bf1 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -490,7 +490,7 @@ static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size)
             serial_update_irq(s);
             if (!(s->mcr & UART_MCR_LOOP)) {
                 /* in loopback mode, don't receive any data */
-                qemu_chr_accept_input(s->chr.chr);
+                qemu_chr_fe_accept_input(s->chr.chr);
             }
         }
         break;
diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c
index dcb4a85..7afc6a5 100644
--- a/hw/char/spapr_vty.c
+++ b/hw/char/spapr_vty.c
@@ -51,7 +51,7 @@ static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
         buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
     }
 
-    qemu_chr_accept_input(dev->chardev.chr);
+    qemu_chr_fe_accept_input(dev->chardev.chr);
 
     return n;
 }
diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c
index 8cc2737..8619d10 100644
--- a/hw/char/stm32f2xx_usart.c
+++ b/hw/char/stm32f2xx_usart.c
@@ -98,7 +98,7 @@ static uint64_t stm32f2xx_usart_read(void *opaque, hwaddr addr,
         retvalue = s->usart_sr;
         s->usart_sr &= ~USART_SR_TC;
         if (s->chr.chr) {
-            qemu_chr_accept_input(s->chr.chr);
+            qemu_chr_fe_accept_input(s->chr.chr);
         }
         return retvalue;
     case USART_DR:
@@ -106,7 +106,7 @@ static uint64_t stm32f2xx_usart_read(void *opaque, hwaddr addr,
         s->usart_sr |= USART_SR_TXE;
         s->usart_sr &= ~USART_SR_RXNE;
         if (s->chr.chr) {
-            qemu_chr_accept_input(s->chr.chr);
+            qemu_chr_fe_accept_input(s->chr.chr);
         }
         qemu_set_irq(s->irq, 0);
         return s->usart_dr & 0x3FF;
diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c
index a4730ba..93acbec 100644
--- a/hw/char/virtio-console.c
+++ b/hw/char/virtio-console.c
@@ -123,7 +123,7 @@ static void guest_writable(VirtIOSerialPort *port)
     VirtConsole *vcon = VIRTIO_CONSOLE(port);
 
     if (vcon->chr.chr) {
-        qemu_chr_accept_input(vcon->chr.chr);
+        qemu_chr_fe_accept_input(vcon->chr.chr);
     }
 }
 
diff --git a/hw/char/xilinx_uartlite.c b/hw/char/xilinx_uartlite.c
index 0e809d5..185c63b 100644
--- a/hw/char/xilinx_uartlite.c
+++ b/hw/char/xilinx_uartlite.c
@@ -107,7 +107,7 @@ uart_read(void *opaque, hwaddr addr, unsigned int size)
                 s->rx_fifo_len--;
             uart_update_status(s);
             uart_update_irq(s);
-            qemu_chr_accept_input(s->chr.chr);
+            qemu_chr_fe_accept_input(s->chr.chr);
             break;
 
         default:
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index c518c2f..5881094 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -165,11 +165,11 @@ CharDriverState *qemu_chr_new(const char *label, const char *filename);
 
 
 /**
- * @qemu_chr_disconnect:
+ * @qemu_chr_fe_disconnect:
  *
  * Close a fd accpeted by character backend.
  */
-void qemu_chr_disconnect(CharDriverState *chr);
+void qemu_chr_fe_disconnect(CharDriverState *chr);
 
 /**
  * @qemu_chr_cleanup:
@@ -490,7 +490,7 @@ void qemu_chr_add_handlers_full(CharDriverState *s,
                                 GMainContext *context);
 
 void qemu_chr_be_generic_open(CharDriverState *s);
-void qemu_chr_accept_input(CharDriverState *s);
+void qemu_chr_fe_accept_input(CharDriverState *s);
 int qemu_chr_add_client(CharDriverState *s, int fd);
 CharDriverState *qemu_chr_find(const char *name);
 bool chr_is_ringbuf(const CharDriverState *chr);
diff --git a/net/vhost-user.c b/net/vhost-user.c
index 957459f..4578247 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -187,7 +187,7 @@ static gboolean net_vhost_user_watch(GIOChannel *chan, GIOCondition cond,
 {
     VhostUserState *s = opaque;
 
-    qemu_chr_disconnect(s->chr.chr);
+    qemu_chr_fe_disconnect(s->chr.chr);
 
     return FALSE;
 }
@@ -212,7 +212,7 @@ static void net_vhost_user_event(void *opaque, int event)
         s->watch = qemu_chr_fe_add_watch(s->chr.chr, G_IO_HUP,
                                          net_vhost_user_watch, s);
         if (vhost_user_start(queues, ncs) < 0) {
-            qemu_chr_disconnect(s->chr.chr);
+            qemu_chr_fe_disconnect(s->chr.chr);
             return;
         }
         qmp_set_link(name, true, &err);
diff --git a/qemu-char.c b/qemu-char.c
index 9eefa7f..2c26839 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -430,7 +430,7 @@ int qemu_chr_add_client(CharDriverState *s, int fd)
     return s->chr_add_client ? s->chr_add_client(s, fd) : -1;
 }
 
-void qemu_chr_accept_input(CharDriverState *s)
+void qemu_chr_fe_accept_input(CharDriverState *s)
 {
     if (s->chr_accept_input)
         s->chr_accept_input(s);
@@ -4225,7 +4225,7 @@ void qemu_chr_fe_release(CharDriverState *s)
     s->avail_connections++;
 }
 
-void qemu_chr_disconnect(CharDriverState *chr)
+void qemu_chr_fe_disconnect(CharDriverState *chr)
 {
     if (chr->chr_disconnect) {
         chr->chr_disconnect(chr);
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index 52fbc03..6e5383d 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -268,7 +268,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
     int fd;
 
     if (s->test_fail) {
-        qemu_chr_disconnect(chr->chr);
+        qemu_chr_fe_disconnect(chr->chr);
         /* now switch to non-failure */
         s->test_fail = false;
     }
@@ -313,7 +313,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
 	g_assert_cmpint(msg.payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES),
 			!=, 0ULL);
         if (s->test_flags == TEST_FLAGS_DISCONNECT) {
-            qemu_chr_disconnect(chr->chr);
+            qemu_chr_fe_disconnect(chr->chr);
             s->test_flags = TEST_FLAGS_BAD;
         }
         break;
@@ -724,7 +724,7 @@ reconnect_cb(gpointer user_data)
 {
     TestServer *s = user_data;
 
-    qemu_chr_disconnect(s->chr.chr);
+    qemu_chr_fe_disconnect(s->chr.chr);
 
     return FALSE;
 }
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 33/50] colo: claim in find_and_check_chardev
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (31 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 32/50] char: rename some frontend functions Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 34/50] char: use qemu_chr_fe* functions with CharBackend argument Paolo Bonzini
                   ` (17 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

This factors out claiming of chardev, and changes the call to
non-fatal to return an error like the rest of the chardev checks.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-15-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 net/colo-compare.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/net/colo-compare.c b/net/colo-compare.c
index efcd15e..b115465 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -589,6 +589,13 @@ static int find_and_check_chardev(CharDriverState **chr,
                    chr_name);
         return 1;
     }
+
+    if (qemu_chr_fe_claim(*chr) < 0) {
+        error_setg(errp, "chardev \"%s\" cannot be claimed",
+                   chr_name);
+        return 1;
+    }
+
     return 0;
 }
 
@@ -646,12 +653,6 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
         return;
     }
 
-    qemu_chr_fe_claim_no_fail(s->chr_pri_in.chr);
-
-    qemu_chr_fe_claim_no_fail(s->chr_sec_in.chr);
-
-    qemu_chr_fe_claim_no_fail(s->chr_out.chr);
-
     net_socket_rs_init(&s->pri_rs, compare_pri_rs_finalize);
     net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize);
 
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 34/50] char: use qemu_chr_fe* functions with CharBackend argument
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (32 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 33/50] colo: claim in find_and_check_chardev Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 35/50] char: fold qemu_chr_set_handlers in qemu_chr_fe_set_handlers Paolo Bonzini
                   ` (16 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

This also switches from qemu_chr_add_handlers() to
qemu_chr_fe_set_handlers(). Note that qemu_chr_fe_set_handlers() now
takes the focus when fe_open (qemu_chr_add_handlers() did take the
focus)

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-16-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 backends/rng-egd.c          |  13 ++--
 gdbstub.c                   |  18 +++---
 hw/arm/omap2.c              |  11 ++--
 hw/arm/pxa2xx.c             |   6 +-
 hw/arm/strongarm.c          |  16 ++---
 hw/char/bcm2835_aux.c       |   8 +--
 hw/char/cadence_uart.c      |  20 +++---
 hw/char/debugcon.c          |   6 +-
 hw/char/digic-uart.c        |   5 +-
 hw/char/escc.c              |  17 +++---
 hw/char/etraxfs_ser.c       |   8 +--
 hw/char/exynos4210_uart.c   |  11 ++--
 hw/char/grlib_apbuart.c     |  15 ++---
 hw/char/imx_serial.c        |  14 ++---
 hw/char/ipoctal232.c        |  10 +--
 hw/char/lm32_juart.c        |   6 +-
 hw/char/lm32_uart.c         |   7 ++-
 hw/char/mcf_uart.c          |   8 +--
 hw/char/milkymist-uart.c    |   7 ++-
 hw/char/parallel.c          |  34 +++++------
 hw/char/pl011.c             |   8 +--
 hw/char/sclpconsole-lm.c    |  10 +--
 hw/char/sclpconsole.c       |   8 +--
 hw/char/serial.c            |  30 +++++----
 hw/char/sh_serial.c         |   9 +--
 hw/char/spapr_vty.c         |  10 +--
 hw/char/stm32f2xx_usart.c   |  10 +--
 hw/char/virtio-console.c    |  27 ++++----
 hw/char/xen_console.c       |  14 +++--
 hw/char/xilinx_uartlite.c   |   7 ++-
 hw/ipmi/ipmi_bmc_extern.c   |   7 ++-
 hw/mips/mips_malta.c        |  28 ++++-----
 hw/misc/ivshmem.c           |  21 ++++---
 hw/usb/ccid-card-passthru.c |  16 ++---
 hw/usb/dev-serial.c         |  21 ++++---
 hw/usb/redirect.c           |  18 +++---
 hw/virtio/vhost-user.c      |   4 +-
 include/hw/char/serial.h    |   1 +
 include/sysemu/char.h       |  51 ++++++----------
 monitor.c                   |  20 +++---
 net/colo-compare.c          |  34 ++++++-----
 net/filter-mirror.c         |  20 +++---
 net/slirp.c                 |   7 ++-
 net/vhost-user.c            |  21 ++++---
 qemu-char.c                 | 146 ++++++++++++++++++++++----------------------
 qtest.c                     |  23 +++----
 tests/vhost-user-test.c     |  35 ++++++-----
 47 files changed, 437 insertions(+), 409 deletions(-)

diff --git a/backends/rng-egd.c b/backends/rng-egd.c
index e2f8189..d9e50bb 100644
--- a/backends/rng-egd.c
+++ b/backends/rng-egd.c
@@ -42,7 +42,7 @@ static void rng_egd_request_entropy(RngBackend *b, RngRequest *req)
 
         /* XXX this blocks entire thread. Rewrite to use
          * qemu_chr_fe_write and background I/O callbacks */
-        qemu_chr_fe_write_all(s->chr.chr, header, sizeof(header));
+        qemu_chr_fe_write_all(&s->chr, header, sizeof(header));
 
         size -= len;
     }
@@ -109,8 +109,8 @@ static void rng_egd_opened(RngBackend *b, Error **errp)
     }
 
     /* FIXME we should resubmit pending requests when the CDS reconnects. */
-    qemu_chr_add_handlers(s->chr.chr, rng_egd_chr_can_read,
-                          rng_egd_chr_read, NULL, s);
+    qemu_chr_fe_set_handlers(&s->chr, rng_egd_chr_can_read,
+                             rng_egd_chr_read, NULL, s, NULL);
 }
 
 static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)
@@ -129,9 +129,10 @@ static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)
 static char *rng_egd_get_chardev(Object *obj, Error **errp)
 {
     RngEgd *s = RNG_EGD(obj);
+    CharDriverState *chr = qemu_chr_fe_get_driver(&s->chr);
 
-    if (s->chr.chr && s->chr.chr->label) {
-        return g_strdup(s->chr.chr->label);
+    if (chr && chr->label) {
+        return g_strdup(chr->label);
     }
 
     return NULL;
@@ -149,7 +150,7 @@ static void rng_egd_finalize(Object *obj)
     RngEgd *s = RNG_EGD(obj);
 
     if (s->chr.chr) {
-        qemu_chr_add_handlers(s->chr.chr, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, NULL, NULL);
         qemu_chr_fe_release(s->chr.chr);
     }
 
diff --git a/gdbstub.c b/gdbstub.c
index 347bd4d..33b056e 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -404,7 +404,7 @@ static void put_buffer(GDBState *s, const uint8_t *buf, int len)
 #else
     /* XXX this blocks entire thread. Rewrite to use
      * qemu_chr_fe_write and background I/O callbacks */
-    qemu_chr_fe_write_all(s->chr.chr, buf, len);
+    qemu_chr_fe_write_all(&s->chr, buf, len);
 #endif
 }
 
@@ -1471,6 +1471,9 @@ void gdb_exit(CPUArchState *env, int code)
 {
   GDBState *s;
   char buf[4];
+#ifndef CONFIG_USER_ONLY
+  CharDriverState *chr;
+#endif
 
   s = gdbserver_state;
   if (!s) {
@@ -1481,7 +1484,8 @@ void gdb_exit(CPUArchState *env, int code)
       return;
   }
 #else
-  if (!s->chr.chr) {
+  chr = qemu_chr_fe_get_driver(&s->chr);
+  if (!chr) {
       return;
   }
 #endif
@@ -1490,7 +1494,7 @@ void gdb_exit(CPUArchState *env, int code)
   put_packet(s, buf);
 
 #ifndef CONFIG_USER_ONLY
-  qemu_chr_delete(s->chr.chr);
+  qemu_chr_delete(chr);
 #endif
 }
 
@@ -1764,8 +1768,8 @@ int gdbserver_start(const char *device)
         mon_chr->chr_write = gdb_monitor_write;
         monitor_init(mon_chr, 0);
     } else {
-        if (s->chr.chr) {
-            qemu_chr_delete(s->chr.chr);
+        if (qemu_chr_fe_get_driver(&s->chr)) {
+            qemu_chr_delete(qemu_chr_fe_get_driver(&s->chr));
         }
         mon_chr = s->mon_chr;
         memset(s, 0, sizeof(GDBState));
@@ -1775,8 +1779,8 @@ int gdbserver_start(const char *device)
     s->g_cpu = first_cpu;
     if (chr) {
         qemu_chr_fe_init(&s->chr, chr, &error_abort);
-        qemu_chr_add_handlers(s->chr.chr, gdb_chr_can_receive, gdb_chr_receive,
-                              gdb_chr_event, NULL);
+        qemu_chr_fe_set_handlers(&s->chr, gdb_chr_can_receive, gdb_chr_receive,
+                                 gdb_chr_event, NULL, NULL);
     }
     s->state = chr ? RS_IDLE : RS_INACTIVE;
     s->mon_chr = mon_chr;
diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c
index 43d9c4b..6f05c98 100644
--- a/hw/arm/omap2.c
+++ b/hw/arm/omap2.c
@@ -771,14 +771,15 @@ static void omap_sti_fifo_write(void *opaque, hwaddr addr,
         /* Flush channel <i>value</i>.  */
         /* XXX this blocks entire thread. Rewrite to use
          * qemu_chr_fe_write and background I/O callbacks */
-        qemu_chr_fe_write_all(s->chr.chr, (const uint8_t *) "\r", 1);
+        qemu_chr_fe_write_all(&s->chr, (const uint8_t *) "\r", 1);
     } else if (ch == STI_TRACE_CONSOLE_CHANNEL || 1) {
         if (value == 0xc0 || value == 0xc3) {
             /* Open channel <i>ch</i>.  */
-        } else if (value == 0x00)
-            qemu_chr_fe_write_all(s->chr.chr, (const uint8_t *) "\n", 1);
-        else
-            qemu_chr_fe_write_all(s->chr.chr, &byte, 1);
+        } else if (value == 0x00) {
+            qemu_chr_fe_write_all(&s->chr, (const uint8_t *) "\n", 1);
+        } else {
+            qemu_chr_fe_write_all(&s->chr, &byte, 1);
+        }
     }
 }
 
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index 27f112c..798c05b 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -1906,7 +1906,7 @@ static void pxa2xx_fir_write(void *opaque, hwaddr addr,
         if (s->chr.chr && s->enable && (s->control[0] & (1 << 3))) { /* TXE */
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
+            qemu_chr_fe_write_all(&s->chr, &ch, 1);
         }
         break;
     case ICSR0:
@@ -1977,8 +1977,8 @@ static void pxa2xx_fir_realize(DeviceState *dev, Error **errp)
 
     if (s->chr.chr) {
         qemu_chr_fe_claim_no_fail(s->chr.chr);
-        qemu_chr_add_handlers(s->chr.chr, pxa2xx_fir_is_empty,
-                        pxa2xx_fir_rx, pxa2xx_fir_event, s);
+        qemu_chr_fe_set_handlers(&s->chr, pxa2xx_fir_is_empty,
+                                 pxa2xx_fir_rx, pxa2xx_fir_event, s, NULL);
     }
 }
 
diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c
index d3e8aff..fd13a39 100644
--- a/hw/arm/strongarm.c
+++ b/hw/arm/strongarm.c
@@ -1021,7 +1021,7 @@ static void strongarm_uart_update_parameters(StrongARMUARTState *s)
     ssp.stop_bits = stop_bits;
     s->char_transmit_time =  (NANOSECONDS_PER_SECOND / speed) * frame_size;
     if (s->chr.chr) {
-        qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+        qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
     }
 
     DPRINTF(stderr, "%s speed=%d parity=%c data=%d stop=%d\n", s->chr->label,
@@ -1107,10 +1107,10 @@ static void strongarm_uart_tx(void *opaque)
 
     if (s->utcr3 & UTCR3_LBM) /* loopback */ {
         strongarm_uart_receive(s, &s->tx_fifo[s->tx_start], 1);
-    } else if (s->chr.chr) {
+    } else if (qemu_chr_fe_get_driver(&s->chr)) {
         /* XXX this blocks entire thread. Rewrite to use
          * qemu_chr_fe_write and background I/O callbacks */
-        qemu_chr_fe_write_all(s->chr.chr, &s->tx_fifo[s->tx_start], 1);
+        qemu_chr_fe_write_all(&s->chr, &s->tx_fifo[s->tx_start], 1);
     }
 
     s->tx_start = (s->tx_start + 1) % 8;
@@ -1240,11 +1240,11 @@ static void strongarm_uart_init(Object *obj)
     s->tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_tx, s);
 
     if (s->chr.chr) {
-        qemu_chr_add_handlers(s->chr.chr,
-                        strongarm_uart_can_receive,
-                        strongarm_uart_receive,
-                        strongarm_uart_event,
-                        s);
+        qemu_chr_fe_set_handlers(&s->chr,
+                                 strongarm_uart_can_receive,
+                                 strongarm_uart_receive,
+                                 strongarm_uart_event,
+                                 s, NULL);
     }
 }
 
diff --git a/hw/char/bcm2835_aux.c b/hw/char/bcm2835_aux.c
index 30f4ea5..c49ec8c 100644
--- a/hw/char/bcm2835_aux.c
+++ b/hw/char/bcm2835_aux.c
@@ -80,7 +80,7 @@ static uint64_t bcm2835_aux_read(void *opaque, hwaddr offset, unsigned size)
             }
         }
         if (s->chr.chr) {
-            qemu_chr_fe_accept_input(s->chr.chr);
+            qemu_chr_fe_accept_input(&s->chr);
         }
         bcm2835_aux_update(s);
         return c;
@@ -171,7 +171,7 @@ static void bcm2835_aux_write(void *opaque, hwaddr offset, uint64_t value,
         if (s->chr.chr) {
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
+            qemu_chr_fe_write_all(&s->chr, &ch, 1);
         }
         break;
 
@@ -283,8 +283,8 @@ static void bcm2835_aux_realize(DeviceState *dev, Error **errp)
     BCM2835AuxState *s = BCM2835_AUX(dev);
 
     if (s->chr.chr) {
-        qemu_chr_add_handlers(s->chr.chr, bcm2835_aux_can_receive,
-                              bcm2835_aux_receive, NULL, s);
+        qemu_chr_fe_set_handlers(&s->chr, bcm2835_aux_can_receive,
+                                 bcm2835_aux_receive, NULL, s, NULL);
     }
 }
 
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
index c027235..4459b2d 100644
--- a/hw/char/cadence_uart.c
+++ b/hw/char/cadence_uart.c
@@ -143,7 +143,7 @@ static void uart_rx_reset(CadenceUARTState *s)
     s->rx_wpos = 0;
     s->rx_count = 0;
     if (s->chr.chr) {
-        qemu_chr_fe_accept_input(s->chr.chr);
+        qemu_chr_fe_accept_input(&s->chr);
     }
 }
 
@@ -157,8 +157,8 @@ static void uart_send_breaks(CadenceUARTState *s)
     int break_enabled = 1;
 
     if (s->chr.chr) {
-        qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_SERIAL_SET_BREAK,
-                                   &break_enabled);
+        qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
+                          &break_enabled);
     }
 }
 
@@ -211,7 +211,7 @@ static void uart_parameters_setup(CadenceUARTState *s)
     packet_size += ssp.data_bits + ssp.stop_bits;
     s->char_tx_time = (NANOSECONDS_PER_SECOND / ssp.speed) * packet_size;
     if (s->chr.chr) {
-        qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+        qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
     }
 }
 
@@ -278,7 +278,7 @@ static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond,
     int ret;
 
     /* instant drain the fifo when there's no back-end */
-    if (!s->chr.chr) {
+    if (!qemu_chr_fe_get_driver(&s->chr)) {
         s->tx_count = 0;
         return FALSE;
     }
@@ -287,7 +287,7 @@ static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond,
         return FALSE;
     }
 
-    ret = qemu_chr_fe_write(s->chr.chr, s->tx_fifo, s->tx_count);
+    ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_count);
 
     if (ret >= 0) {
         s->tx_count -= ret;
@@ -295,7 +295,7 @@ static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond,
     }
 
     if (s->tx_count) {
-        guint r = qemu_chr_fe_add_watch(s->chr.chr, G_IO_OUT | G_IO_HUP,
+        guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
                                         cadence_uart_xmit, s);
         if (!r) {
             s->tx_count = 0;
@@ -369,7 +369,7 @@ static void uart_read_rx_fifo(CadenceUARTState *s, uint32_t *c)
         s->rx_count--;
 
         if (s->chr.chr) {
-            qemu_chr_fe_accept_input(s->chr.chr);
+            qemu_chr_fe_accept_input(&s->chr);
         }
     } else {
         *c = 0;
@@ -475,8 +475,8 @@ static void cadence_uart_realize(DeviceState *dev, Error **errp)
                                           fifo_trigger_update, s);
 
     if (s->chr.chr) {
-        qemu_chr_add_handlers(s->chr.chr, uart_can_receive, uart_receive,
-                              uart_event, s);
+        qemu_chr_fe_set_handlers(&s->chr, uart_can_receive, uart_receive,
+                                 uart_event, s, NULL);
     }
 }
 
diff --git a/hw/char/debugcon.c b/hw/char/debugcon.c
index b405109..2009c3e 100644
--- a/hw/char/debugcon.c
+++ b/hw/char/debugcon.c
@@ -62,7 +62,7 @@ static void debugcon_ioport_write(void *opaque, hwaddr addr, uint64_t val,
 
     /* XXX this blocks entire thread. Rewrite to use
      * qemu_chr_fe_write and background I/O callbacks */
-    qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
+    qemu_chr_fe_write_all(&s->chr, &ch, 1);
 }
 
 
@@ -87,12 +87,12 @@ static const MemoryRegionOps debugcon_ops = {
 
 static void debugcon_realize_core(DebugconState *s, Error **errp)
 {
-    if (!s->chr.chr) {
+    if (!qemu_chr_fe_get_driver(&s->chr)) {
         error_setg(errp, "Can't create debugcon device, empty char device");
         return;
     }
 
-    qemu_chr_add_handlers(s->chr.chr, NULL, NULL, NULL, s);
+    qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, s, NULL);
 }
 
 static void debugcon_isa_realizefn(DeviceState *dev, Error **errp)
diff --git a/hw/char/digic-uart.c b/hw/char/digic-uart.c
index fb4969f..c7b3db6 100644
--- a/hw/char/digic-uart.c
+++ b/hw/char/digic-uart.c
@@ -79,7 +79,7 @@ static void digic_uart_write(void *opaque, hwaddr addr, uint64_t value,
         if (s->chr.chr) {
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
+            qemu_chr_fe_write_all(&s->chr, &ch, 1);
         }
         break;
 
@@ -148,7 +148,8 @@ static void digic_uart_realize(DeviceState *dev, Error **errp)
     DigicUartState *s = DIGIC_UART(dev);
 
     if (s->chr.chr) {
-        qemu_chr_add_handlers(s->chr.chr, uart_can_rx, uart_rx, uart_event, s);
+        qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
+                                 uart_event, s, NULL);
     }
 }
 
diff --git a/hw/char/escc.c b/hw/char/escc.c
index f1e8fac..4578a46 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -416,7 +416,7 @@ static void escc_update_parameters(ChannelState *s)
     int speed, parity, data_bits, stop_bits;
     QEMUSerialSetParams ssp;
 
-    if (!s->chr.chr || s->type != ser)
+    if (!qemu_chr_fe_get_driver(&s->chr) || s->type != ser)
         return;
 
     if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREN) {
@@ -466,7 +466,7 @@ static void escc_update_parameters(ChannelState *s)
     ssp.data_bits = data_bits;
     ssp.stop_bits = stop_bits;
     trace_escc_update_parameters(CHN_C(s), speed, parity, data_bits, stop_bits);
-    qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+    qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
 }
 
 static void escc_mem_write(void *opaque, hwaddr addr,
@@ -556,10 +556,10 @@ static void escc_mem_write(void *opaque, hwaddr addr,
         trace_escc_mem_writeb_data(CHN_C(s), val);
         s->tx = val;
         if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled
-            if (s->chr.chr) {
+            if (qemu_chr_fe_get_driver(&s->chr)) {
                 /* XXX this blocks entire thread. Rewrite to use
                  * qemu_chr_fe_write and background I/O callbacks */
-                qemu_chr_fe_write_all(s->chr.chr, &s->tx, 1);
+                qemu_chr_fe_write_all(&s->chr, &s->tx, 1);
             } else if (s->type == kbd && !s->disabled) {
                 handle_kbd_command(s, val);
             }
@@ -600,7 +600,7 @@ static uint64_t escc_mem_read(void *opaque, hwaddr addr,
             ret = s->rx;
         trace_escc_mem_readb_data(CHN_C(s), ret);
         if (s->chr.chr) {
-            qemu_chr_fe_accept_input(s->chr.chr);
+            qemu_chr_fe_accept_input(&s->chr);
         }
         return ret;
     default:
@@ -1014,10 +1014,11 @@ static void escc_realize(DeviceState *dev, Error **errp)
                           ESCC_SIZE << s->it_shift);
 
     for (i = 0; i < 2; i++) {
-        if (s->chn[i].chr.chr) {
+        if (qemu_chr_fe_get_driver(&s->chn[i].chr)) {
             s->chn[i].clock = s->frequency / 2;
-            qemu_chr_add_handlers(s->chn[i].chr.chr, serial_can_receive,
-                                  serial_receive1, serial_event, &s->chn[i]);
+            qemu_chr_fe_set_handlers(&s->chn[i].chr, serial_can_receive,
+                                     serial_receive1, serial_event,
+                                     &s->chn[i], NULL);
         }
     }
 
diff --git a/hw/char/etraxfs_ser.c b/hw/char/etraxfs_ser.c
index 99c4801..d812954 100644
--- a/hw/char/etraxfs_ser.c
+++ b/hw/char/etraxfs_ser.c
@@ -128,7 +128,7 @@ ser_write(void *opaque, hwaddr addr,
         case RW_DOUT:
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
+            qemu_chr_fe_write_all(&s->chr, &ch, 1);
             s->regs[R_INTR] |= 3;
             s->pending_tx = 1;
             s->regs[addr] = value;
@@ -232,9 +232,9 @@ static void etraxfs_ser_realize(DeviceState *dev, Error **errp)
     ETRAXSerial *s = ETRAX_SERIAL(dev);
 
     if (s->chr.chr) {
-        qemu_chr_add_handlers(s->chr.chr,
-                              serial_can_receive, serial_receive,
-                              serial_event, s);
+        qemu_chr_fe_set_handlers(&s->chr,
+                                 serial_can_receive, serial_receive,
+                                 serial_event, s, NULL);
     }
 }
 
diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
index 3f71059..48216b1 100644
--- a/hw/char/exynos4210_uart.c
+++ b/hw/char/exynos4210_uart.c
@@ -346,7 +346,7 @@ static void exynos4210_uart_update_parameters(Exynos4210UartState *s)
     ssp.data_bits = data_bits;
     ssp.stop_bits = stop_bits;
 
-    qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+    qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
 
     PRINT_DEBUG("UART%d: speed: %d, parity: %c, data: %d, stop: %d\n",
                 s->channel, speed, parity, data_bits, stop_bits);
@@ -383,13 +383,13 @@ static void exynos4210_uart_write(void *opaque, hwaddr offset,
         break;
 
     case UTXH:
-        if (s->chr.chr) {
+        if (qemu_chr_fe_get_driver(&s->chr)) {
             s->reg[I_(UTRSTAT)] &= ~(UTRSTAT_TRANSMITTER_EMPTY |
                     UTRSTAT_Tx_BUFFER_EMPTY);
             ch = (uint8_t)val;
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
+            qemu_chr_fe_write_all(&s->chr, &ch, 1);
 #if DEBUG_Tx_DATA
             fprintf(stderr, "%c", ch);
 #endif
@@ -640,8 +640,9 @@ static int exynos4210_uart_init(SysBusDevice *dev)
 
     sysbus_init_irq(dev, &s->irq);
 
-    qemu_chr_add_handlers(s->chr.chr, exynos4210_uart_can_receive,
-                          exynos4210_uart_receive, exynos4210_uart_event, s);
+    qemu_chr_fe_set_handlers(&s->chr, exynos4210_uart_can_receive,
+                             exynos4210_uart_receive, exynos4210_uart_event,
+                             s, NULL);
 
     return 0;
 }
diff --git a/hw/char/grlib_apbuart.c b/hw/char/grlib_apbuart.c
index 13c9455..e50d65b 100644
--- a/hw/char/grlib_apbuart.c
+++ b/hw/char/grlib_apbuart.c
@@ -201,11 +201,12 @@ static void grlib_apbuart_write(void *opaque, hwaddr addr,
     case DATA_OFFSET:
     case DATA_OFFSET + 3:       /* When only one byte write */
         /* Transmit when character device available and transmitter enabled */
-        if (uart->chr.chr && (uart->control & UART_TRANSMIT_ENABLE)) {
+        if (qemu_chr_fe_get_driver(&uart->chr) &&
+            (uart->control & UART_TRANSMIT_ENABLE)) {
             c = value & 0xFF;
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(uart->chr.chr, &c, 1);
+            qemu_chr_fe_write_all(&uart->chr, &c, 1);
             /* Generate interrupt */
             if (uart->control & UART_TRANSMIT_INTERRUPT) {
                 qemu_irq_pulse(uart->irq);
@@ -242,11 +243,11 @@ static int grlib_apbuart_init(SysBusDevice *dev)
 {
     UART *uart = GRLIB_APB_UART(dev);
 
-    qemu_chr_add_handlers(uart->chr.chr,
-                          grlib_apbuart_can_receive,
-                          grlib_apbuart_receive,
-                          grlib_apbuart_event,
-                          uart);
+    qemu_chr_fe_set_handlers(&uart->chr,
+                             grlib_apbuart_can_receive,
+                             grlib_apbuart_receive,
+                             grlib_apbuart_event,
+                             uart, NULL);
 
     sysbus_init_irq(dev, &uart->irq);
 
diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c
index 2e39d31..d9a0a25 100644
--- a/hw/char/imx_serial.c
+++ b/hw/char/imx_serial.c
@@ -122,7 +122,7 @@ static uint64_t imx_serial_read(void *opaque, hwaddr offset,
             s->uts1 |= UTS1_RXEMPTY;
             imx_update(s);
             if (s->chr.chr) {
-                qemu_chr_fe_accept_input(s->chr.chr);
+                qemu_chr_fe_accept_input(&s->chr);
             }
         }
         return c;
@@ -172,11 +172,11 @@ static void imx_serial_write(void *opaque, hwaddr offset,
                              uint64_t value, unsigned size)
 {
     IMXSerialState *s = (IMXSerialState *)opaque;
+    CharDriverState *chr = qemu_chr_fe_get_driver(&s->chr);
     unsigned char ch;
 
     DPRINTF("write(offset=0x%" HWADDR_PRIx ", value = 0x%x) to %s\n",
-            offset, (unsigned int)value,
-            s->chr.chr ? s->chr.chr->label : "NODEV");
+            offset, (unsigned int)value, chr ? chr->label : "NODEV");
 
     switch (offset >> 2) {
     case 0x10: /* UTXD */
@@ -185,7 +185,7 @@ static void imx_serial_write(void *opaque, hwaddr offset,
             if (s->chr.chr) {
                 /* XXX this blocks entire thread. Rewrite to use
                  * qemu_chr_fe_write and background I/O callbacks */
-                qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
+                qemu_chr_fe_write_all(&s->chr, &ch, 1);
             }
             s->usr1 &= ~USR1_TRDY;
             imx_update(s);
@@ -216,7 +216,7 @@ static void imx_serial_write(void *opaque, hwaddr offset,
         if (value & UCR2_RXEN) {
             if (!(s->ucr2 & UCR2_RXEN)) {
                 if (s->chr.chr) {
-                    qemu_chr_fe_accept_input(s->chr.chr);
+                    qemu_chr_fe_accept_input(&s->chr);
                 }
             }
         }
@@ -320,8 +320,8 @@ static void imx_serial_realize(DeviceState *dev, Error **errp)
     IMXSerialState *s = IMX_SERIAL(dev);
 
     if (s->chr.chr) {
-        qemu_chr_add_handlers(s->chr.chr, imx_can_receive, imx_receive,
-                              imx_event, s);
+        qemu_chr_fe_set_handlers(&s->chr, imx_can_receive, imx_receive,
+                                 imx_event, s, NULL);
     } else {
         DPRINTF("No char dev for uart\n");
     }
diff --git a/hw/char/ipoctal232.c b/hw/char/ipoctal232.c
index 875fe3b..d504721 100644
--- a/hw/char/ipoctal232.c
+++ b/hw/char/ipoctal232.c
@@ -289,7 +289,7 @@ static uint16_t io_read(IPackDevice *ip, uint8_t addr)
                 ch->sr &= ~SR_RXRDY;
                 blk->isr &= ~ISR_RXRDY(channel);
                 if (ch->dev.chr) {
-                    qemu_chr_fe_accept_input(ch->dev.chr);
+                    qemu_chr_fe_accept_input(&ch->dev);
                 }
             } else {
                 ch->rhr_idx = (ch->rhr_idx + 1) % RX_FIFO_SIZE;
@@ -362,7 +362,7 @@ static void io_write(IPackDevice *ip, uint8_t addr, uint16_t val)
                 uint8_t thr = reg;
                 /* XXX this blocks entire thread. Rewrite to use
                  * qemu_chr_fe_write and background I/O callbacks */
-                qemu_chr_fe_write_all(ch->dev.chr, &thr, 1);
+                qemu_chr_fe_write_all(&ch->dev, &thr, 1);
             }
         } else {
             DPRINTF("Write THR%c (0x%x), Tx disabled\n", channel + 'a', reg);
@@ -546,9 +546,9 @@ static void ipoctal_realize(DeviceState *dev, Error **errp)
         ch->ipoctal = s;
 
         /* Redirect IP-Octal channels to host character devices */
-        if (ch->dev.chr) {
-            qemu_chr_add_handlers(ch->dev.chr, hostdev_can_receive,
-                                  hostdev_receive, hostdev_event, ch);
+        if (qemu_chr_fe_get_driver(&ch->dev)) {
+            qemu_chr_fe_set_handlers(&ch->dev, hostdev_can_receive,
+                                     hostdev_receive, hostdev_event, ch, NULL);
             DPRINTF("Redirecting channel %u to %s\n", i, ch->dev->label);
         } else {
             DPRINTF("Could not redirect channel %u, no chardev set\n", i);
diff --git a/hw/char/lm32_juart.c b/hw/char/lm32_juart.c
index a0eb312..9629e9e 100644
--- a/hw/char/lm32_juart.c
+++ b/hw/char/lm32_juart.c
@@ -78,7 +78,7 @@ void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx)
     if (s->chr.chr) {
         /* XXX this blocks entire thread. Rewrite to use
          * qemu_chr_fe_write and background I/O callbacks */
-        qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
+        qemu_chr_fe_write_all(&s->chr, &ch, 1);
     }
 }
 
@@ -121,8 +121,8 @@ static void lm32_juart_realize(DeviceState *dev, Error **errp)
     LM32JuartState *s = LM32_JUART(dev);
 
     if (s->chr.chr) {
-        qemu_chr_add_handlers(s->chr.chr, juart_can_rx,
-                              juart_rx, juart_event, s);
+        qemu_chr_fe_set_handlers(&s->chr, juart_can_rx, juart_rx,
+                                 juart_event, s, NULL);
     }
 }
 
diff --git a/hw/char/lm32_uart.c b/hw/char/lm32_uart.c
index a8d4a2d..e325b91 100644
--- a/hw/char/lm32_uart.c
+++ b/hw/char/lm32_uart.c
@@ -142,7 +142,7 @@ static uint64_t uart_read(void *opaque, hwaddr addr,
         r = s->regs[R_RXTX];
         s->regs[R_LSR] &= ~LSR_DR;
         uart_update_irq(s);
-        qemu_chr_fe_accept_input(s->chr.chr);
+        qemu_chr_fe_accept_input(&s->chr);
         break;
     case R_IIR:
     case R_LSR:
@@ -180,7 +180,7 @@ static void uart_write(void *opaque, hwaddr addr,
         if (s->chr.chr) {
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
+            qemu_chr_fe_write_all(&s->chr, &ch, 1);
         }
         break;
     case R_IER:
@@ -268,7 +268,8 @@ static void lm32_uart_realize(DeviceState *dev, Error **errp)
     LM32UartState *s = LM32_UART(dev);
 
     if (s->chr.chr) {
-        qemu_chr_add_handlers(s->chr.chr, uart_can_rx, uart_rx, uart_event, s);
+        qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
+                                 uart_event, s, NULL);
     }
 }
 
diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c
index 57b47c6..cc3db13 100644
--- a/hw/char/mcf_uart.c
+++ b/hw/char/mcf_uart.c
@@ -93,7 +93,7 @@ uint64_t mcf_uart_read(void *opaque, hwaddr addr,
             if (s->fifo_len == 0)
                 s->sr &= ~MCF_UART_RxRDY;
             mcf_uart_update(s);
-            qemu_chr_fe_accept_input(s->chr.chr);
+            qemu_chr_fe_accept_input(&s->chr);
             return val;
         }
     case 0x10:
@@ -117,7 +117,7 @@ static void mcf_uart_do_tx(mcf_uart_state *s)
         if (s->chr.chr) {
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(s->chr.chr, (unsigned char *)&s->tb, 1);
+            qemu_chr_fe_write_all(&s->chr, (unsigned char *)&s->tb, 1);
         }
         s->sr |= MCF_UART_TxEMP;
     }
@@ -286,8 +286,8 @@ void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
     if (chr) {
         qemu_chr_fe_init(&s->chr, chr, &error_abort);
         qemu_chr_fe_claim_no_fail(chr);
-        qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive,
-                              mcf_uart_event, s);
+        qemu_chr_fe_set_handlers(&s->chr, mcf_uart_can_receive,
+                                 mcf_uart_receive, mcf_uart_event, s, NULL);
     }
     mcf_uart_reset(s);
     return s;
diff --git a/hw/char/milkymist-uart.c b/hw/char/milkymist-uart.c
index c75bcb5..0a4c617 100644
--- a/hw/char/milkymist-uart.c
+++ b/hw/char/milkymist-uart.c
@@ -125,7 +125,7 @@ static void uart_write(void *opaque, hwaddr addr, uint64_t value,
     switch (addr) {
     case R_RXTX:
         if (s->chr.chr) {
-            qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
+            qemu_chr_fe_write_all(&s->chr, &ch, 1);
         }
         s->regs[R_STAT] |= STAT_TX_EVT;
         break;
@@ -138,7 +138,7 @@ static void uart_write(void *opaque, hwaddr addr, uint64_t value,
     case R_STAT:
         /* write one to clear bits */
         s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT));
-        qemu_chr_fe_accept_input(s->chr.chr);
+        qemu_chr_fe_accept_input(&s->chr);
         break;
 
     default:
@@ -201,7 +201,8 @@ static void milkymist_uart_realize(DeviceState *dev, Error **errp)
     MilkymistUartState *s = MILKYMIST_UART(dev);
 
     if (s->chr.chr) {
-        qemu_chr_add_handlers(s->chr.chr, uart_can_rx, uart_rx, uart_event, s);
+        qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
+                                 uart_event, s, NULL);
     }
 }
 
diff --git a/hw/char/parallel.c b/hw/char/parallel.c
index 80576af..f2d5666 100644
--- a/hw/char/parallel.c
+++ b/hw/char/parallel.c
@@ -131,7 +131,7 @@ parallel_ioport_write_sw(void *opaque, uint32_t addr, uint32_t val)
                 if ((s->control & PARA_CTR_STROBE) == 0)
                     /* XXX this blocks entire thread. Rewrite to use
                      * qemu_chr_fe_write and background I/O callbacks */
-                    qemu_chr_fe_write_all(s->chr.chr, &s->dataw, 1);
+                    qemu_chr_fe_write_all(&s->chr, &s->dataw, 1);
             } else {
                 if (s->control & PARA_CTR_INTEN) {
                     s->irq_pending = 1;
@@ -161,7 +161,7 @@ static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
         if (s->dataw == val)
             return;
         pdebug("wd%02x\n", val);
-        qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_WRITE_DATA, &parm);
+        qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_WRITE_DATA, &parm);
         s->dataw = val;
         break;
     case PARA_REG_STS:
@@ -181,11 +181,11 @@ static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
             } else {
                 dir = 0;
             }
-            qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_DATA_DIR, &dir);
+            qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_DATA_DIR, &dir);
             parm &= ~PARA_CTR_DIR;
         }
 
-        qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm);
+        qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm);
         s->control = val;
         break;
     case PARA_REG_EPP_ADDR:
@@ -194,7 +194,7 @@ static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
             pdebug("wa%02x s\n", val);
         else {
             struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
-            if (qemu_chr_fe_ioctl(s->chr.chr,
+            if (qemu_chr_fe_ioctl(&s->chr,
                                   CHR_IOCTL_PP_EPP_WRITE_ADDR, &ioarg)) {
                 s->epp_timeout = 1;
                 pdebug("wa%02x t\n", val);
@@ -209,7 +209,7 @@ static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
             pdebug("we%02x s\n", val);
         else {
             struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
-            if (qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg)) {
+            if (qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg)) {
                 s->epp_timeout = 1;
                 pdebug("we%02x t\n", val);
             }
@@ -234,7 +234,7 @@ parallel_ioport_eppdata_write_hw2(void *opaque, uint32_t addr, uint32_t val)
         pdebug("we%04x s\n", val);
         return;
     }
-    err = qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
+    err = qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
     if (err) {
         s->epp_timeout = 1;
         pdebug("we%04x t\n", val);
@@ -257,7 +257,7 @@ parallel_ioport_eppdata_write_hw4(void *opaque, uint32_t addr, uint32_t val)
         pdebug("we%08x s\n", val);
         return;
     }
-    err = qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
+    err = qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
     if (err) {
         s->epp_timeout = 1;
         pdebug("we%08x t\n", val);
@@ -309,13 +309,13 @@ static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
     addr &= 7;
     switch(addr) {
     case PARA_REG_DATA:
-        qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_READ_DATA, &ret);
+        qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_READ_DATA, &ret);
         if (s->last_read_offset != addr || s->datar != ret)
             pdebug("rd%02x\n", ret);
         s->datar = ret;
         break;
     case PARA_REG_STS:
-        qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_READ_STATUS, &ret);
+        qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_READ_STATUS, &ret);
         ret &= ~PARA_STS_TMOUT;
         if (s->epp_timeout)
             ret |= PARA_STS_TMOUT;
@@ -327,7 +327,7 @@ static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
         /* s->control has some bits fixed to 1. It is zero only when
            it has not been yet written to.  */
         if (s->control == 0) {
-            qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_READ_CONTROL, &ret);
+            qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_READ_CONTROL, &ret);
             if (s->last_read_offset != addr)
                 pdebug("rc%02x\n", ret);
             s->control = ret;
@@ -345,7 +345,7 @@ static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
             pdebug("ra%02x s\n", ret);
         else {
             struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
-            if (qemu_chr_fe_ioctl(s->chr.chr,
+            if (qemu_chr_fe_ioctl(&s->chr,
                                   CHR_IOCTL_PP_EPP_READ_ADDR, &ioarg)) {
                 s->epp_timeout = 1;
                 pdebug("ra%02x t\n", ret);
@@ -361,7 +361,7 @@ static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
             pdebug("re%02x s\n", ret);
         else {
             struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
-            if (qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_EPP_READ, &ioarg)) {
+            if (qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg)) {
                 s->epp_timeout = 1;
                 pdebug("re%02x t\n", ret);
             }
@@ -389,7 +389,7 @@ parallel_ioport_eppdata_read_hw2(void *opaque, uint32_t addr)
         pdebug("re%04x s\n", eppdata);
         return eppdata;
     }
-    err = qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
+    err = qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
     ret = le16_to_cpu(eppdata);
 
     if (err) {
@@ -416,7 +416,7 @@ parallel_ioport_eppdata_read_hw4(void *opaque, uint32_t addr)
         pdebug("re%08x s\n", eppdata);
         return eppdata;
     }
-    err = qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
+    err = qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
     ret = le32_to_cpu(eppdata);
 
     if (err) {
@@ -512,7 +512,7 @@ static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
     int base;
     uint8_t dummy;
 
-    if (!s->chr.chr) {
+    if (!qemu_chr_fe_get_driver(&s->chr)) {
         error_setg(errp, "Can't create parallel device, empty char device");
         return;
     }
@@ -534,7 +534,7 @@ static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
     isa_init_irq(isadev, &s->irq, isa->isairq);
     qemu_register_reset(parallel_reset, s);
 
-    if (qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) {
+    if (qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) {
         s->hw_driver = 1;
         s->status = dummy;
     }
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
index 29fb725..52ec866 100644
--- a/hw/char/pl011.c
+++ b/hw/char/pl011.c
@@ -88,7 +88,7 @@ static uint64_t pl011_read(void *opaque, hwaddr offset,
         s->rsr = c >> 8;
         pl011_update(s);
         if (s->chr.chr) {
-            qemu_chr_fe_accept_input(s->chr.chr);
+            qemu_chr_fe_accept_input(&s->chr);
         }
         r = c;
         break;
@@ -171,7 +171,7 @@ static void pl011_write(void *opaque, hwaddr offset,
         if (s->chr.chr) {
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
+            qemu_chr_fe_write_all(&s->chr, &ch, 1);
         }
         s->int_level |= PL011_INT_TX;
         pl011_update(s);
@@ -333,8 +333,8 @@ static void pl011_realize(DeviceState *dev, Error **errp)
     PL011State *s = PL011(dev);
 
     if (s->chr.chr) {
-        qemu_chr_add_handlers(s->chr.chr, pl011_can_receive, pl011_receive,
-                              pl011_event, s);
+        qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
+                                 pl011_event, s, NULL);
     }
 }
 
diff --git a/hw/char/sclpconsole-lm.c b/hw/char/sclpconsole-lm.c
index 3ef1517..0660cbc 100644
--- a/hw/char/sclpconsole-lm.c
+++ b/hw/char/sclpconsole-lm.c
@@ -91,7 +91,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
     if (scon->echo) {
         /* XXX this blocks entire thread. Rewrite to use
          * qemu_chr_fe_write and background I/O callbacks */
-        qemu_chr_fe_write_all(scon->chr.chr, buf, size);
+        qemu_chr_fe_write_all(&scon->chr, buf, size);
     }
 }
 
@@ -195,14 +195,14 @@ static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len)
 {
     SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
 
-    if (!scon->chr.chr) {
+    if (!qemu_chr_fe_get_driver(&scon->chr)) {
         /* If there's no backend, we can just say we consumed all data. */
         return len;
     }
 
     /* XXX this blocks entire thread. Rewrite to use
      * qemu_chr_fe_write and background I/O callbacks */
-    return qemu_chr_fe_write_all(scon->chr.chr, buf, len);
+    return qemu_chr_fe_write_all(&scon->chr, buf, len);
 }
 
 static int process_mdb(SCLPEvent *event, MDBO *mdbo)
@@ -313,8 +313,8 @@ static int console_init(SCLPEvent *event)
     console_available = true;
 
     if (scon->chr.chr) {
-        qemu_chr_add_handlers(scon->chr.chr, chr_can_read,
-                              chr_read, NULL, scon);
+        qemu_chr_fe_set_handlers(&scon->chr, chr_can_read,
+                                 chr_read, NULL, scon, NULL);
     }
 
     return 0;
diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c
index bb51a2c..0559208 100644
--- a/hw/char/sclpconsole.c
+++ b/hw/char/sclpconsole.c
@@ -163,14 +163,14 @@ static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf,
 {
     SCLPConsole *scon = SCLP_CONSOLE(event);
 
-    if (!scon->chr.chr) {
+    if (!qemu_chr_fe_get_driver(&scon->chr)) {
         /* If there's no backend, we can just say we consumed all data. */
         return len;
     }
 
     /* XXX this blocks entire thread. Rewrite to use
      * qemu_chr_fe_write and background I/O callbacks */
-    return qemu_chr_fe_write_all(scon->chr.chr, buf, len);
+    return qemu_chr_fe_write_all(&scon->chr, buf, len);
 }
 
 static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr)
@@ -228,8 +228,8 @@ static int console_init(SCLPEvent *event)
     }
     console_available = true;
     if (scon->chr.chr) {
-        qemu_chr_add_handlers(scon->chr.chr, chr_can_read,
-                              chr_read, NULL, scon);
+        qemu_chr_fe_set_handlers(&scon->chr, chr_can_read,
+                                 chr_read, NULL, scon, NULL);
     }
 
     return 0;
diff --git a/hw/char/serial.c b/hw/char/serial.c
index 4489bf1..509bc25 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -182,7 +182,7 @@ static void serial_update_parameters(SerialState *s)
     ssp.data_bits = data_bits;
     ssp.stop_bits = stop_bits;
     s->char_transmit_time =  (NANOSECONDS_PER_SECOND / speed) * frame_size;
-    qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+    qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
 
     DPRINTF("speed=%d parity=%c data=%d stop=%d\n",
            speed, parity, data_bits, stop_bits);
@@ -195,7 +195,7 @@ static void serial_update_msl(SerialState *s)
 
     timer_del(s->modem_status_poll);
 
-    if (qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_SERIAL_GET_TIOCM,
+    if (qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_GET_TIOCM,
                           &flags) == -ENOTSUP) {
         s->poll_msl = -1;
         return;
@@ -261,11 +261,11 @@ static void serial_xmit(SerialState *s)
         if (s->mcr & UART_MCR_LOOP) {
             /* in loopback mode, say that we just received a char */
             serial_receive1(s, &s->tsr, 1);
-        } else if (qemu_chr_fe_write(s->chr.chr, &s->tsr, 1) != 1 &&
+        } else if (qemu_chr_fe_write(&s->chr, &s->tsr, 1) != 1 &&
                    s->tsr_retry < MAX_XMIT_RETRY) {
             assert(s->watch_tag == 0);
             s->watch_tag =
-                qemu_chr_fe_add_watch(s->chr.chr, G_IO_OUT | G_IO_HUP,
+                qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
                                       serial_watch_cb, s);
             if (s->watch_tag > 0) {
                 s->tsr_retry++;
@@ -419,8 +419,8 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
             break_enable = (val >> 6) & 1;
             if (break_enable != s->last_break_enable) {
                 s->last_break_enable = break_enable;
-                qemu_chr_fe_ioctl(s->chr.chr, CHR_IOCTL_SERIAL_SET_BREAK,
-                               &break_enable);
+                qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
+                                  &break_enable);
             }
         }
         break;
@@ -434,8 +434,7 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
 
             if (s->poll_msl >= 0 && old_mcr != s->mcr) {
 
-                qemu_chr_fe_ioctl(s->chr.chr,
-                                  CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
+                qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
 
                 flags &= ~(CHR_TIOCM_RTS | CHR_TIOCM_DTR);
 
@@ -444,8 +443,7 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
                 if (val & UART_MCR_DTR)
                     flags |= CHR_TIOCM_DTR;
 
-                qemu_chr_fe_ioctl(s->chr.chr,
-                                  CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
+                qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
                 /* Update the modem status after a one-character-send wait-time, since there may be a response
                    from the device/computer at the other end of the serial line */
                 timer_mod(s->modem_status_poll, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time);
@@ -490,7 +488,7 @@ static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size)
             serial_update_irq(s);
             if (!(s->mcr & UART_MCR_LOOP)) {
                 /* in loopback mode, don't receive any data */
-                qemu_chr_fe_accept_input(s->chr.chr);
+                qemu_chr_fe_accept_input(&s->chr);
             }
         }
         break;
@@ -663,7 +661,7 @@ static int serial_post_load(void *opaque, int version_id)
         }
 
         assert(s->watch_tag == 0);
-        s->watch_tag = qemu_chr_fe_add_watch(s->chr.chr, G_IO_OUT | G_IO_HUP,
+        s->watch_tag = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
                                              serial_watch_cb, s);
     } else {
         /* tsr_retry == 0 implies LSR.TEMT = 1 (transmitter empty).  */
@@ -888,7 +886,7 @@ static void serial_reset(void *opaque)
 
 void serial_realize_core(SerialState *s, Error **errp)
 {
-    if (!s->chr.chr) {
+    if (!qemu_chr_fe_get_driver(&s->chr)) {
         error_setg(errp, "Can't create serial device, empty char device");
         return;
     }
@@ -898,8 +896,8 @@ void serial_realize_core(SerialState *s, Error **errp)
     s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) fifo_timeout_int, s);
     qemu_register_reset(serial_reset, s);
 
-    qemu_chr_add_handlers(s->chr.chr, serial_can_receive1, serial_receive1,
-                          serial_event, s);
+    qemu_chr_fe_set_handlers(&s->chr, serial_can_receive1, serial_receive1,
+                             serial_event, s, NULL);
     fifo8_create(&s->recv_fifo, UART_FIFO_LENGTH);
     fifo8_create(&s->xmit_fifo, UART_FIFO_LENGTH);
     serial_reset(s);
@@ -907,7 +905,7 @@ void serial_realize_core(SerialState *s, Error **errp)
 
 void serial_exit_core(SerialState *s)
 {
-    qemu_chr_add_handlers(s->chr.chr, NULL, NULL, NULL, NULL);
+    qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, NULL, NULL);
     qemu_unregister_reset(serial_reset, s);
 }
 
diff --git a/hw/char/sh_serial.c b/hw/char/sh_serial.c
index c8b91bb..8d82986 100644
--- a/hw/char/sh_serial.c
+++ b/hw/char/sh_serial.c
@@ -110,11 +110,11 @@ static void sh_serial_write(void *opaque, hwaddr offs,
         }
         return;
     case 0x0c: /* FTDR / TDR */
-        if (s->chr.chr) {
+        if (qemu_chr_fe_get_driver(&s->chr)) {
             ch = val;
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
+            qemu_chr_fe_write_all(&s->chr, &ch, 1);
 	}
 	s->dr = val;
 	s->flags &= ~SH_SERIAL_FLAG_TDE;
@@ -399,8 +399,9 @@ void sh_serial_init(MemoryRegion *sysmem,
     if (chr) {
         qemu_chr_fe_claim_no_fail(chr);
         qemu_chr_fe_init(&s->chr, chr, &error_abort);
-        qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
-			      sh_serial_event, s);
+        qemu_chr_fe_set_handlers(&s->chr, sh_serial_can_receive1,
+                                 sh_serial_receive1,
+                                 sh_serial_event, s, NULL);
     }
 
     s->eri = eri_source;
diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c
index 7afc6a5..8d39d40 100644
--- a/hw/char/spapr_vty.c
+++ b/hw/char/spapr_vty.c
@@ -51,7 +51,7 @@ static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
         buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
     }
 
-    qemu_chr_fe_accept_input(dev->chardev.chr);
+    qemu_chr_fe_accept_input(&dev->chardev);
 
     return n;
 }
@@ -62,20 +62,20 @@ void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len)
 
     /* XXX this blocks entire thread. Rewrite to use
      * qemu_chr_fe_write and background I/O callbacks */
-    qemu_chr_fe_write_all(dev->chardev.chr, buf, len);
+    qemu_chr_fe_write_all(&dev->chardev, buf, len);
 }
 
 static void spapr_vty_realize(VIOsPAPRDevice *sdev, Error **errp)
 {
     VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev);
 
-    if (!dev->chardev.chr) {
+    if (!qemu_chr_fe_get_driver(&dev->chardev)) {
         error_setg(errp, "chardev property not set");
         return;
     }
 
-    qemu_chr_add_handlers(dev->chardev.chr, vty_can_receive,
-                          vty_receive, NULL, dev);
+    qemu_chr_fe_set_handlers(&dev->chardev, vty_can_receive,
+                             vty_receive, NULL, dev, NULL);
 }
 
 /* Forward declaration */
diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c
index 8619d10..03ccc52 100644
--- a/hw/char/stm32f2xx_usart.c
+++ b/hw/char/stm32f2xx_usart.c
@@ -98,7 +98,7 @@ static uint64_t stm32f2xx_usart_read(void *opaque, hwaddr addr,
         retvalue = s->usart_sr;
         s->usart_sr &= ~USART_SR_TC;
         if (s->chr.chr) {
-            qemu_chr_fe_accept_input(s->chr.chr);
+            qemu_chr_fe_accept_input(&s->chr);
         }
         return retvalue;
     case USART_DR:
@@ -106,7 +106,7 @@ static uint64_t stm32f2xx_usart_read(void *opaque, hwaddr addr,
         s->usart_sr |= USART_SR_TXE;
         s->usart_sr &= ~USART_SR_RXNE;
         if (s->chr.chr) {
-            qemu_chr_fe_accept_input(s->chr.chr);
+            qemu_chr_fe_accept_input(&s->chr);
         }
         qemu_set_irq(s->irq, 0);
         return s->usart_dr & 0x3FF;
@@ -155,7 +155,7 @@ static void stm32f2xx_usart_write(void *opaque, hwaddr addr,
             if (s->chr.chr) {
                 /* XXX this blocks entire thread. Rewrite to use
                  * qemu_chr_fe_write and background I/O callbacks */
-                qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
+                qemu_chr_fe_write_all(&s->chr, &ch, 1);
             }
             s->usart_sr |= USART_SR_TC;
             s->usart_sr &= ~USART_SR_TXE;
@@ -213,8 +213,8 @@ static void stm32f2xx_usart_realize(DeviceState *dev, Error **errp)
     STM32F2XXUsartState *s = STM32F2XX_USART(dev);
 
     if (s->chr.chr) {
-        qemu_chr_add_handlers(s->chr.chr, stm32f2xx_usart_can_receive,
-                              stm32f2xx_usart_receive, NULL, s);
+        qemu_chr_fe_set_handlers(&s->chr, stm32f2xx_usart_can_receive,
+                                 stm32f2xx_usart_receive, NULL, s, NULL);
     }
 }
 
diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c
index 93acbec..135f589 100644
--- a/hw/char/virtio-console.c
+++ b/hw/char/virtio-console.c
@@ -49,12 +49,12 @@ static ssize_t flush_buf(VirtIOSerialPort *port,
     VirtConsole *vcon = VIRTIO_CONSOLE(port);
     ssize_t ret;
 
-    if (!vcon->chr.chr) {
+    if (!qemu_chr_fe_get_driver(&vcon->chr)) {
         /* If there's no backend, we can just say we consumed all data. */
         return len;
     }
 
-    ret = qemu_chr_fe_write(vcon->chr.chr, buf, len);
+    ret = qemu_chr_fe_write(&vcon->chr, buf, len);
     trace_virtio_console_flush_buf(port->id, len, ret);
 
     if (ret < len) {
@@ -92,8 +92,8 @@ static ssize_t flush_buf(VirtIOSerialPort *port,
         if (!k->is_console) {
             virtio_serial_throttle_port(port, true);
             if (!vcon->watch) {
-                vcon->watch = qemu_chr_fe_add_watch(vcon->chr.chr,
-                                                    G_IO_OUT | G_IO_HUP,
+                vcon->watch = qemu_chr_fe_add_watch(&vcon->chr,
+                                                    G_IO_OUT|G_IO_HUP,
                                                     chr_write_unblocked, vcon);
             }
         }
@@ -109,7 +109,7 @@ static void set_guest_connected(VirtIOSerialPort *port, int guest_connected)
     VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
 
     if (vcon->chr.chr && !k->is_console) {
-        qemu_chr_fe_set_open(vcon->chr.chr, guest_connected);
+        qemu_chr_fe_set_open(&vcon->chr, guest_connected);
     }
 
     if (dev->id) {
@@ -123,7 +123,7 @@ static void guest_writable(VirtIOSerialPort *port)
     VirtConsole *vcon = VIRTIO_CONSOLE(port);
 
     if (vcon->chr.chr) {
-        qemu_chr_fe_accept_input(vcon->chr.chr);
+        qemu_chr_fe_accept_input(&vcon->chr);
     }
 }
 
@@ -170,6 +170,7 @@ static void virtconsole_realize(DeviceState *dev, Error **errp)
     VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
     VirtConsole *vcon = VIRTIO_CONSOLE(dev);
     VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(dev);
+    CharDriverState *chr = qemu_chr_fe_get_driver(&vcon->chr);
 
     if (port->id == 0 && !k->is_console) {
         error_setg(errp, "Port number 0 on virtio-serial devices reserved "
@@ -177,7 +178,7 @@ static void virtconsole_realize(DeviceState *dev, Error **errp)
         return;
     }
 
-    if (vcon->chr.chr) {
+    if (chr) {
         /*
          * For consoles we don't block guest data transfer just
          * because nothing is connected - we'll just let it go
@@ -188,14 +189,14 @@ static void virtconsole_realize(DeviceState *dev, Error **errp)
          * trigger open/close of the device
          */
         if (k->is_console) {
-            vcon->chr.chr->explicit_fe_open = 0;
-            qemu_chr_add_handlers(vcon->chr.chr, chr_can_read, chr_read,
-                                  NULL, vcon);
+            chr->explicit_fe_open = 0;
+            qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read,
+                                     NULL, vcon, NULL);
             virtio_serial_open(port);
         } else {
-            vcon->chr.chr->explicit_fe_open = 1;
-            qemu_chr_add_handlers(vcon->chr.chr, chr_can_read, chr_read,
-                                  chr_event, vcon);
+            chr->explicit_fe_open = 1;
+            qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read,
+                                     chr_event, vcon, NULL);
         }
     }
 }
diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c
index c1d36dc..5e5aca1 100644
--- a/hw/char/xen_console.c
+++ b/hw/char/xen_console.c
@@ -23,6 +23,7 @@
 #include <sys/select.h>
 #include <termios.h>
 
+#include "qapi/error.h"
 #include "hw/hw.h"
 #include "sysemu/char.h"
 #include "hw/xen/xen_backend.h"
@@ -149,8 +150,8 @@ static void xencons_send(struct XenConsole *con)
     ssize_t len, size;
 
     size = con->buffer.size - con->buffer.consumed;
-    if (con->chr.chr) {
-        len = qemu_chr_fe_write(con->chr.chr,
+    if (qemu_chr_fe_get_driver(&con->chr)) {
+        len = qemu_chr_fe_write(&con->chr,
                                 con->buffer.data + con->buffer.consumed,
                                 size);
     } else {
@@ -209,7 +210,8 @@ static int con_init(struct XenDevice *xendev)
                          qemu_chr_new(label, output), &error_abort);
     }
 
-    xenstore_store_pv_console_info(con->xendev.dev, con->chr.chr);
+    xenstore_store_pv_console_info(con->xendev.dev,
+                                   qemu_chr_fe_get_driver(&con->chr));
 
 out:
     g_free(type);
@@ -244,8 +246,8 @@ static int con_initialise(struct XenDevice *xendev)
     xen_be_bind_evtchn(&con->xendev);
     if (con->chr.chr) {
         if (qemu_chr_fe_claim(con->chr.chr) == 0) {
-            qemu_chr_add_handlers(con->chr.chr, xencons_can_receive,
-                                  xencons_receive, NULL, con);
+            qemu_chr_fe_set_handlers(&con->chr, xencons_can_receive,
+                                     xencons_receive, NULL, con, NULL);
         } else {
             xen_be_printf(xendev, 0,
                           "xen_console_init error chardev %s already used\n",
@@ -267,7 +269,7 @@ static void con_disconnect(struct XenDevice *xendev)
     struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
 
     if (con->chr.chr) {
-        qemu_chr_add_handlers(con->chr.chr, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_set_handlers(&con->chr, NULL, NULL, NULL, NULL, NULL);
         qemu_chr_fe_release(con->chr.chr);
     }
     xen_be_unbind_evtchn(&con->xendev);
diff --git a/hw/char/xilinx_uartlite.c b/hw/char/xilinx_uartlite.c
index 185c63b..d6df643 100644
--- a/hw/char/xilinx_uartlite.c
+++ b/hw/char/xilinx_uartlite.c
@@ -107,7 +107,7 @@ uart_read(void *opaque, hwaddr addr, unsigned int size)
                 s->rx_fifo_len--;
             uart_update_status(s);
             uart_update_irq(s);
-            qemu_chr_fe_accept_input(s->chr.chr);
+            qemu_chr_fe_accept_input(&s->chr);
             break;
 
         default:
@@ -146,7 +146,7 @@ uart_write(void *opaque, hwaddr addr,
             if (s->chr.chr) {
                 /* XXX this blocks entire thread. Rewrite to use
                  * qemu_chr_fe_write and background I/O callbacks */
-                qemu_chr_fe_write_all(s->chr.chr, &ch, 1);
+                qemu_chr_fe_write_all(&s->chr, &ch, 1);
             }
             s->regs[addr] = value;
 
@@ -214,7 +214,8 @@ static void xilinx_uartlite_realize(DeviceState *dev, Error **errp)
     XilinxUARTLite *s = XILINX_UARTLITE(dev);
 
     if (s->chr.chr) {
-        qemu_chr_add_handlers(s->chr.chr, uart_can_rx, uart_rx, uart_event, s);
+        qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
+                                 uart_event, s, NULL);
     }
 }
 
diff --git a/hw/ipmi/ipmi_bmc_extern.c b/hw/ipmi/ipmi_bmc_extern.c
index af9b6f3..5530870 100644
--- a/hw/ipmi/ipmi_bmc_extern.c
+++ b/hw/ipmi/ipmi_bmc_extern.c
@@ -105,7 +105,7 @@ static void continue_send(IPMIBmcExtern *ibe)
         goto check_reset;
     }
  send:
-    ret = qemu_chr_fe_write(ibe->chr.chr, ibe->outbuf + ibe->outpos,
+    ret = qemu_chr_fe_write(&ibe->chr, ibe->outbuf + ibe->outpos,
                             ibe->outlen - ibe->outpos);
     if (ret > 0) {
         ibe->outpos += ret;
@@ -442,12 +442,13 @@ static void ipmi_bmc_extern_realize(DeviceState *dev, Error **errp)
 {
     IPMIBmcExtern *ibe = IPMI_BMC_EXTERN(dev);
 
-    if (!ibe->chr.chr) {
+    if (!qemu_chr_fe_get_driver(&ibe->chr)) {
         error_setg(errp, "IPMI external bmc requires chardev attribute");
         return;
     }
 
-    qemu_chr_add_handlers(ibe->chr.chr, can_receive, receive, chr_event, ibe);
+    qemu_chr_fe_set_handlers(&ibe->chr, can_receive, receive,
+                             chr_event, ibe, NULL);
 }
 
 static int ipmi_bmc_extern_post_migrate(void *opaque, int version_id)
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index d5601b1..273ec6d 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -125,9 +125,9 @@ static void malta_fpga_update_display(void *opaque)
     }
     leds_text[8] = '\0';
 
-    qemu_chr_fe_printf(s->display.chr, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n",
+    qemu_chr_fe_printf(&s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n",
                        leds_text);
-    qemu_chr_fe_printf(s->display.chr, "\n\n\n\n|\e[31m%-8.8s\e[00m|",
+    qemu_chr_fe_printf(&s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|",
                        s->display_text);
 }
 
@@ -538,15 +538,15 @@ static void malta_fgpa_display_event(void *opaque, int event)
     MaltaFPGAState *s = opaque;
 
     if (event == CHR_EVENT_OPENED && !s->display_inited) {
-        qemu_chr_fe_printf(s->display.chr, "\e[HMalta LEDBAR\r\n");
-        qemu_chr_fe_printf(s->display.chr, "+--------+\r\n");
-        qemu_chr_fe_printf(s->display.chr, "+        +\r\n");
-        qemu_chr_fe_printf(s->display.chr, "+--------+\r\n");
-        qemu_chr_fe_printf(s->display.chr, "\n");
-        qemu_chr_fe_printf(s->display.chr, "Malta ASCII\r\n");
-        qemu_chr_fe_printf(s->display.chr, "+--------+\r\n");
-        qemu_chr_fe_printf(s->display.chr, "+        +\r\n");
-        qemu_chr_fe_printf(s->display.chr, "+--------+\r\n");
+        qemu_chr_fe_printf(&s->display, "\e[HMalta LEDBAR\r\n");
+        qemu_chr_fe_printf(&s->display, "+--------+\r\n");
+        qemu_chr_fe_printf(&s->display, "+        +\r\n");
+        qemu_chr_fe_printf(&s->display, "+--------+\r\n");
+        qemu_chr_fe_printf(&s->display, "\n");
+        qemu_chr_fe_printf(&s->display, "Malta ASCII\r\n");
+        qemu_chr_fe_printf(&s->display, "+--------+\r\n");
+        qemu_chr_fe_printf(&s->display, "+        +\r\n");
+        qemu_chr_fe_printf(&s->display, "+--------+\r\n");
         s->display_inited = true;
     }
 }
@@ -570,9 +570,9 @@ static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
     memory_region_add_subregion(address_space, base + 0xa00, &s->iomem_hi);
 
     chr = qemu_chr_new("fpga", "vc:320x200");
-    qemu_chr_fe_init(&s->display, chr, &error_abort);
-    qemu_chr_add_handlers(s->display.chr, NULL, NULL,
-                          malta_fgpa_display_event, s);
+    qemu_chr_fe_init(&s->display, chr, NULL);
+    qemu_chr_fe_set_handlers(&s->display, NULL, NULL,
+                             malta_fgpa_display_event, s, NULL);
 
     s->uart = serial_mm_init(address_space, base + 0x900, 3, uart_irq,
                              230400, uart_chr, DEVICE_NATIVE_ENDIAN);
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index efca8b0..bb70704 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -627,7 +627,7 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
     msg = le64_to_cpu(s->msg_buf);
     s->msg_buffered_bytes = 0;
 
-    fd = qemu_chr_fe_get_msgfd(s->server_chr.chr);
+    fd = qemu_chr_fe_get_msgfd(&s->server_chr);
 
     process_msg(s, msg, fd, &err);
     if (err) {
@@ -642,8 +642,8 @@ static int64_t ivshmem_recv_msg(IVShmemState *s, int *pfd, Error **errp)
 
     n = 0;
     do {
-        ret = qemu_chr_fe_read_all(s->server_chr.chr, (uint8_t *)&msg + n,
-                                 sizeof(msg) - n);
+        ret = qemu_chr_fe_read_all(&s->server_chr, (uint8_t *)&msg + n,
+                                   sizeof(msg) - n);
         if (ret < 0 && ret != -EINTR) {
             error_setg_errno(errp, -ret, "read from server failed");
             return INT64_MIN;
@@ -651,7 +651,7 @@ static int64_t ivshmem_recv_msg(IVShmemState *s, int *pfd, Error **errp)
         n += ret;
     } while (n < sizeof(msg));
 
-    *pfd = qemu_chr_fe_get_msgfd(s->server_chr.chr);
+    *pfd = qemu_chr_fe_get_msgfd(&s->server_chr);
     return msg;
 }
 
@@ -868,10 +868,11 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
         s->ivshmem_bar2 = host_memory_backend_get_memory(s->hostmem,
                                                          &error_abort);
     } else {
-        assert(s->server_chr.chr);
+        CharDriverState *chr = qemu_chr_fe_get_driver(&s->server_chr);
+        assert(chr);
 
         IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
-                        s->server_chr.chr->filename);
+                        chr->filename);
 
         /* we allocate enough space for 16 peers and grow as needed */
         resize_peers(s, 16);
@@ -893,8 +894,8 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
             return;
         }
 
-        qemu_chr_add_handlers(s->server_chr.chr, ivshmem_can_receive,
-                              ivshmem_read, NULL, s);
+        qemu_chr_fe_set_handlers(&s->server_chr, ivshmem_can_receive,
+                                 ivshmem_read, NULL, s, NULL);
 
         if (ivshmem_setup_interrupts(s) < 0) {
             error_setg(errp, "failed to initialize interrupts");
@@ -1121,7 +1122,7 @@ static void ivshmem_doorbell_realize(PCIDevice *dev, Error **errp)
 {
     IVShmemState *s = IVSHMEM_COMMON(dev);
 
-    if (!s->server_chr.chr) {
+    if (!qemu_chr_fe_get_driver(&s->server_chr)) {
         error_setg(errp, "You must specify a 'chardev'");
         return;
     }
@@ -1250,7 +1251,7 @@ static void ivshmem_realize(PCIDevice *dev, Error **errp)
                      " or ivshmem-doorbell instead");
     }
 
-    if (!!s->server_chr.chr + !!s->shmobj != 1) {
+    if (!!qemu_chr_fe_get_driver(&s->server_chr) + !!s->shmobj != 1) {
         error_setg(errp, "You must specify either 'shm' or 'chardev'");
         return;
     }
diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c
index ebe3942..a8c8684 100644
--- a/hw/usb/ccid-card-passthru.c
+++ b/hw/usb/ccid-card-passthru.c
@@ -77,9 +77,9 @@ static void ccid_card_vscard_send_msg(PassthruState *s,
     scr_msg_header.length = htonl(length);
     /* XXX this blocks entire thread. Rewrite to use
      * qemu_chr_fe_write and background I/O callbacks */
-    qemu_chr_fe_write_all(s->cs.chr, (uint8_t *)&scr_msg_header,
+    qemu_chr_fe_write_all(&s->cs, (uint8_t *)&scr_msg_header,
                           sizeof(VSCMsgHeader));
-    qemu_chr_fe_write_all(s->cs.chr, payload, length);
+    qemu_chr_fe_write_all(&s->cs, payload, length);
 }
 
 static void ccid_card_vscard_send_apdu(PassthruState *s,
@@ -264,7 +264,9 @@ static void ccid_card_vscard_handle_message(PassthruState *card,
 
 static void ccid_card_vscard_drop_connection(PassthruState *card)
 {
-    qemu_chr_delete(card->cs.chr);
+    CharDriverState *chr = qemu_chr_fe_get_driver(&card->cs);
+
+    qemu_chr_delete(chr);
     card->vscard_in_pos = card->vscard_in_hdr = 0;
 }
 
@@ -324,7 +326,7 @@ static void passthru_apdu_from_guest(
 {
     PassthruState *card = PASSTHRU_CCID_CARD(base);
 
-    if (!card->cs.chr) {
+    if (!qemu_chr_fe_get_driver(&card->cs)) {
         printf("ccid-passthru: no chardev, discarding apdu length %d\n", len);
         return;
     }
@@ -345,12 +347,12 @@ static int passthru_initfn(CCIDCardState *base)
 
     card->vscard_in_pos = 0;
     card->vscard_in_hdr = 0;
-    if (card->cs.chr) {
+    if (qemu_chr_fe_get_driver(&card->cs)) {
         DPRINTF(card, D_INFO, "initing chardev\n");
-        qemu_chr_add_handlers(card->cs.chr,
+        qemu_chr_fe_set_handlers(&card->cs,
             ccid_card_vscard_can_read,
             ccid_card_vscard_read,
-            ccid_card_vscard_event, card);
+            ccid_card_vscard_event, card, NULL);
         ccid_card_vscard_send_init(card);
     } else {
         error_report("missing chardev");
diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c
index b8774b4..a69b9a3 100644
--- a/hw/usb/dev-serial.c
+++ b/hw/usb/dev-serial.c
@@ -209,7 +209,7 @@ static uint8_t usb_get_modem_lines(USBSerialState *s)
     int flags;
     uint8_t ret;
 
-    if (qemu_chr_fe_ioctl(s->cs.chr,
+    if (qemu_chr_fe_ioctl(&s->cs,
                           CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) {
         return FTDI_CTS|FTDI_DSR|FTDI_RLSD;
     }
@@ -262,7 +262,7 @@ static void usb_serial_handle_control(USBDevice *dev, USBPacket *p,
     case DeviceOutVendor | FTDI_SET_MDM_CTRL:
     {
         static int flags;
-        qemu_chr_fe_ioctl(s->cs.chr, CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
+        qemu_chr_fe_ioctl(&s->cs, CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
         if (value & FTDI_SET_RTS) {
             if (value & FTDI_RTS)
                 flags |= CHR_TIOCM_RTS;
@@ -275,7 +275,7 @@ static void usb_serial_handle_control(USBDevice *dev, USBPacket *p,
             else
                 flags &= ~CHR_TIOCM_DTR;
         }
-        qemu_chr_fe_ioctl(s->cs.chr, CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
+        qemu_chr_fe_ioctl(&s->cs, CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
         break;
     }
     case DeviceOutVendor | FTDI_SET_FLOW_CTRL:
@@ -294,7 +294,7 @@ static void usb_serial_handle_control(USBDevice *dev, USBPacket *p,
             divisor = 1;
 
         s->params.speed = (48000000 / 2) / (8 * divisor + subdivisor8);
-        qemu_chr_fe_ioctl(s->cs.chr, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
+        qemu_chr_fe_ioctl(&s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
         break;
     }
     case DeviceOutVendor | FTDI_SET_DATA:
@@ -323,7 +323,7 @@ static void usb_serial_handle_control(USBDevice *dev, USBPacket *p,
                 DPRINTF("unsupported stop bits %d\n", value & FTDI_STOP);
                 goto fail;
         }
-        qemu_chr_fe_ioctl(s->cs.chr, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
+        qemu_chr_fe_ioctl(&s->cs, CHR_IOCTL_SERIAL_SET_PARAMS, &s->params);
         /* TODO: TX ON/OFF */
         break;
     case DeviceInVendor | FTDI_GET_MDM_ST:
@@ -370,7 +370,7 @@ static void usb_serial_handle_data(USBDevice *dev, USBPacket *p)
             iov = p->iov.iov + i;
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(s->cs.chr, iov->iov_base, iov->iov_len);
+            qemu_chr_fe_write_all(&s->cs, iov->iov_base, iov->iov_len);
         }
         p->actual_length = p->iov.size;
         break;
@@ -485,12 +485,13 @@ static void usb_serial_realize(USBDevice *dev, Error **errp)
 {
     USBSerialState *s = USB_SERIAL_DEV(dev);
     Error *local_err = NULL;
+    CharDriverState *chr = qemu_chr_fe_get_driver(&s->cs);
 
     usb_desc_create_serial(dev);
     usb_desc_init(dev);
     dev->auto_attach = 0;
 
-    if (!s->cs.chr) {
+    if (!chr) {
         error_setg(errp, "Property chardev is required");
         return;
     }
@@ -501,11 +502,11 @@ static void usb_serial_realize(USBDevice *dev, Error **errp)
         return;
     }
 
-    qemu_chr_add_handlers(s->cs.chr, usb_serial_can_read, usb_serial_read,
-                          usb_serial_event, s);
+    qemu_chr_fe_set_handlers(&s->cs, usb_serial_can_read, usb_serial_read,
+                             usb_serial_event, s, NULL);
     usb_serial_handle_reset(dev);
 
-    if (s->cs.chr->be_open && !dev->attached) {
+    if (chr->be_open && !dev->attached) {
         usb_device_attach(dev, &error_abort);
     }
 }
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 0b21804..0fb2e9a 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -283,9 +283,10 @@ static gboolean usbredir_write_unblocked(GIOChannel *chan, GIOCondition cond,
 static int usbredir_write(void *priv, uint8_t *data, int count)
 {
     USBRedirDevice *dev = priv;
+    CharDriverState *chr = qemu_chr_fe_get_driver(&dev->cs);
     int r;
 
-    if (!dev->cs.chr->be_open) {
+    if (!chr->be_open) {
         return 0;
     }
 
@@ -294,10 +295,10 @@ static int usbredir_write(void *priv, uint8_t *data, int count)
         return 0;
     }
 
-    r = qemu_chr_fe_write(dev->cs.chr, data, count);
+    r = qemu_chr_fe_write(&dev->cs, data, count);
     if (r < count) {
         if (!dev->watch) {
-            dev->watch = qemu_chr_fe_add_watch(dev->cs.chr, G_IO_OUT | G_IO_HUP,
+            dev->watch = qemu_chr_fe_add_watch(&dev->cs, G_IO_OUT | G_IO_HUP,
                                                usbredir_write_unblocked, dev);
         }
         if (r < 0) {
@@ -1375,7 +1376,7 @@ static void usbredir_realize(USBDevice *udev, Error **errp)
     USBRedirDevice *dev = USB_REDIRECT(udev);
     int i;
 
-    if (dev->cs.chr == NULL) {
+    if (!qemu_chr_fe_get_driver(&dev->cs)) {
         error_setg(errp, QERR_MISSING_PARAMETER, "chardev");
         return;
     }
@@ -1406,8 +1407,9 @@ static void usbredir_realize(USBDevice *udev, Error **errp)
     dev->compatible_speedmask = USB_SPEED_MASK_FULL | USB_SPEED_MASK_HIGH;
 
     /* Let the backend know we are ready */
-    qemu_chr_add_handlers(dev->cs.chr, usbredir_chardev_can_read,
-                          usbredir_chardev_read, usbredir_chardev_event, dev);
+    qemu_chr_fe_set_handlers(&dev->cs, usbredir_chardev_can_read,
+                             usbredir_chardev_read, usbredir_chardev_event,
+                             dev, NULL);
 
     qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev);
 }
@@ -1426,8 +1428,10 @@ static void usbredir_cleanup_device_queues(USBRedirDevice *dev)
 static void usbredir_handle_destroy(USBDevice *udev)
 {
     USBRedirDevice *dev = USB_REDIRECT(udev);
+    CharDriverState *chr = qemu_chr_fe_get_driver(&dev->cs);
+
+    qemu_chr_delete(chr);
 
-    qemu_chr_delete(dev->cs.chr);
     dev->cs.chr = NULL;
     /* Note must be done after qemu_chr_close, as that causes a close event */
     qemu_bh_delete(dev->chardev_close_bh);
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index b57454a..7ee92b3 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -116,7 +116,7 @@ static bool ioeventfd_enabled(void)
 
 static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
 {
-    CharDriverState *chr = dev->opaque;
+    CharBackend *chr = dev->opaque;
     uint8_t *p = (uint8_t *) msg;
     int r, size = VHOST_USER_HDR_SIZE;
 
@@ -196,7 +196,7 @@ static bool vhost_user_one_time_request(VhostUserRequest request)
 static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg,
                             int *fds, int fd_num)
 {
-    CharDriverState *chr = dev->opaque;
+    CharBackend *chr = dev->opaque;
     int ret, size = VHOST_USER_HDR_SIZE + msg->size;
 
     /*
diff --git a/include/hw/char/serial.h b/include/hw/char/serial.h
index c3312fb..c928d7d 100644
--- a/include/hw/char/serial.h
+++ b/include/hw/char/serial.h
@@ -28,6 +28,7 @@
 
 #include "hw/hw.h"
 #include "sysemu/sysemu.h"
+#include "sysemu/char.h"
 #include "exec/memory.h"
 #include "qemu/fifo8.h"
 #include "sysemu/char.h"
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 5881094..816c536 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -169,7 +169,7 @@ CharDriverState *qemu_chr_new(const char *label, const char *filename);
  *
  * Close a fd accpeted by character backend.
  */
-void qemu_chr_fe_disconnect(CharDriverState *chr);
+void qemu_chr_fe_disconnect(CharBackend *be);
 
 /**
  * @qemu_chr_cleanup:
@@ -179,11 +179,11 @@ void qemu_chr_fe_disconnect(CharDriverState *chr);
 void qemu_chr_cleanup(void);
 
 /**
- * @qemu_chr_wait_connected:
+ * @qemu_chr_fe_wait_connected:
  *
  * Wait for characted backend to be connected.
  */
-int qemu_chr_wait_connected(CharDriverState *chr, Error **errp);
+int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp);
 
 /**
  * @qemu_chr_new_noreplay:
@@ -223,7 +223,7 @@ void qemu_chr_free(CharDriverState *chr);
  *
  * @echo true to enable echo, false to disable echo
  */
-void qemu_chr_fe_set_echo(struct CharDriverState *chr, bool echo);
+void qemu_chr_fe_set_echo(CharBackend *be, bool echo);
 
 /**
  * @qemu_chr_fe_set_open:
@@ -231,7 +231,7 @@ void qemu_chr_fe_set_echo(struct CharDriverState *chr, bool echo);
  * Set character frontend open status.  This is an indication that the
  * front end is ready (or not) to begin doing I/O.
  */
-void qemu_chr_fe_set_open(struct CharDriverState *chr, int fe_open);
+void qemu_chr_fe_set_open(CharBackend *be, int fe_open);
 
 /**
  * @qemu_chr_fe_event:
@@ -240,7 +240,7 @@ void qemu_chr_fe_set_open(struct CharDriverState *chr, int fe_open);
  *
  * @event the event to send
  */
-void qemu_chr_fe_event(CharDriverState *s, int event);
+void qemu_chr_fe_event(CharBackend *be, int event);
 
 /**
  * @qemu_chr_fe_printf:
@@ -250,7 +250,7 @@ void qemu_chr_fe_event(CharDriverState *s, int event);
  *
  * @fmt see #printf
  */
-void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...)
+void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
     GCC_FMT_ATTR(2, 3);
 
 /**
@@ -265,7 +265,7 @@ void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...)
  * @func the function to call when the condition happens
  * @user_data the opaque pointer to pass to @func
  */
-guint qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond,
+guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
                             GIOFunc func, void *user_data);
 
 /**
@@ -280,7 +280,7 @@ guint qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond,
  *
  * Returns: the number of bytes consumed
  */
-int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len);
+int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len);
 
 /**
  * @qemu_chr_fe_write_all:
@@ -295,7 +295,7 @@ int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len);
  *
  * Returns: the number of bytes consumed
  */
-int qemu_chr_fe_write_all(CharDriverState *s, const uint8_t *buf, int len);
+int qemu_chr_fe_write_all(CharBackend *be, const uint8_t *buf, int len);
 
 /**
  * @qemu_chr_fe_read_all:
@@ -307,7 +307,7 @@ int qemu_chr_fe_write_all(CharDriverState *s, const uint8_t *buf, int len);
  *
  * Returns: the number of bytes read
  */
-int qemu_chr_fe_read_all(CharDriverState *s, uint8_t *buf, int len);
+int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len);
 
 /**
  * @qemu_chr_fe_ioctl:
@@ -320,7 +320,7 @@ int qemu_chr_fe_read_all(CharDriverState *s, uint8_t *buf, int len);
  * Returns: if @cmd is not supported by the backend, -ENOTSUP, otherwise the
  *          return value depends on the semantics of @cmd
  */
-int qemu_chr_fe_ioctl(CharDriverState *s, int cmd, void *arg);
+int qemu_chr_fe_ioctl(CharBackend *be, int cmd, void *arg);
 
 /**
  * @qemu_chr_fe_get_msgfd:
@@ -333,7 +333,7 @@ int qemu_chr_fe_ioctl(CharDriverState *s, int cmd, void *arg);
  *          this function will return -1 until a client sends a new file
  *          descriptor.
  */
-int qemu_chr_fe_get_msgfd(CharDriverState *s);
+int qemu_chr_fe_get_msgfd(CharBackend *be);
 
 /**
  * @qemu_chr_fe_get_msgfds:
@@ -346,7 +346,7 @@ int qemu_chr_fe_get_msgfd(CharDriverState *s);
  *          this function will return -1 until a client sends a new set of file
  *          descriptors.
  */
-int qemu_chr_fe_get_msgfds(CharDriverState *s, int *fds, int num);
+int qemu_chr_fe_get_msgfds(CharBackend *be, int *fds, int num);
 
 /**
  * @qemu_chr_fe_set_msgfds:
@@ -359,13 +359,13 @@ int qemu_chr_fe_get_msgfds(CharDriverState *s, int *fds, int num);
  *
  * Returns: -1 if fd passing isn't supported.
  */
-int qemu_chr_fe_set_msgfds(CharDriverState *s, int *fds, int num);
+int qemu_chr_fe_set_msgfds(CharBackend *be, int *fds, int num);
 
 /**
  * @qemu_chr_fe_claim:
  *
  * Claim a backend before using it, should be called before calling
- * qemu_chr_add_handlers(). 
+ * qemu_chr_fe_set_handlers().
  *
  * Returns: -1 if the backend is already in use by another frontend, 0 on
  *          success.
@@ -436,7 +436,8 @@ void qemu_chr_be_event(CharDriverState *s, int event);
 /**
  * @qemu_chr_fe_init:
  *
- * Initializes a front end for the given CharBackend and CharDriver.
+ * Initializes a front end for the given CharBackend and
+ * CharDriver.
  *
  * Returns: false on error.
  */
@@ -475,22 +476,8 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
  */
 void qemu_chr_fe_take_focus(CharBackend *b);
 
-void qemu_chr_add_handlers(CharDriverState *s,
-                           IOCanReadHandler *fd_can_read,
-                           IOReadHandler *fd_read,
-                           IOEventHandler *fd_event,
-                           void *opaque);
-
-/* This API can make handler run in the context what you pass to. */
-void qemu_chr_add_handlers_full(CharDriverState *s,
-                                IOCanReadHandler *fd_can_read,
-                                IOReadHandler *fd_read,
-                                IOEventHandler *fd_event,
-                                void *opaque,
-                                GMainContext *context);
-
 void qemu_chr_be_generic_open(CharDriverState *s);
-void qemu_chr_fe_accept_input(CharDriverState *s);
+void qemu_chr_fe_accept_input(CharBackend *be);
 int qemu_chr_add_client(CharDriverState *s, int fd);
 CharDriverState *qemu_chr_find(const char *name);
 bool chr_is_ringbuf(const CharDriverState *chr);
diff --git a/monitor.c b/monitor.c
index 40712f7..1c6f28f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -297,7 +297,7 @@ static void monitor_flush_locked(Monitor *mon)
     len = qstring_get_length(mon->outbuf);
 
     if (len && !mon->mux_out) {
-        rc = qemu_chr_fe_write(mon->chr.chr, (const uint8_t *) buf, len);
+        rc = qemu_chr_fe_write(&mon->chr, (const uint8_t *) buf, len);
         if ((rc < 0 && errno != EAGAIN) || (rc == len)) {
             /* all flushed or error */
             QDECREF(mon->outbuf);
@@ -312,7 +312,7 @@ static void monitor_flush_locked(Monitor *mon)
         }
         if (mon->out_watch == 0) {
             mon->out_watch =
-                qemu_chr_fe_add_watch(mon->chr.chr, G_IO_OUT | G_IO_HUP,
+                qemu_chr_fe_add_watch(&mon->chr, G_IO_OUT | G_IO_HUP,
                                       monitor_unblocked, mon);
         }
     }
@@ -583,7 +583,7 @@ static void monitor_data_init(Monitor *mon)
 static void monitor_data_destroy(Monitor *mon)
 {
     if (mon->chr.chr) {
-        qemu_chr_add_handlers(mon->chr.chr, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_set_handlers(&mon->chr, NULL, NULL, NULL, NULL, NULL);
     }
     if (monitor_is_qmp(mon)) {
         json_message_parser_destroy(&mon->qmp.parser);
@@ -1746,7 +1746,7 @@ void qmp_getfd(const char *fdname, Error **errp)
     mon_fd_t *monfd;
     int fd;
 
-    fd = qemu_chr_fe_get_msgfd(cur_mon->chr.chr);
+    fd = qemu_chr_fe_get_msgfd(&cur_mon->chr);
     if (fd == -1) {
         error_setg(errp, QERR_FD_NOT_SUPPLIED);
         return;
@@ -1871,7 +1871,7 @@ AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id, bool has_opaque,
     Monitor *mon = cur_mon;
     AddfdInfo *fdinfo;
 
-    fd = qemu_chr_fe_get_msgfd(mon->chr.chr);
+    fd = qemu_chr_fe_get_msgfd(&mon->chr);
     if (fd == -1) {
         error_setg(errp, QERR_FD_NOT_SUPPLIED);
         goto error;
@@ -3989,13 +3989,13 @@ void monitor_init(CharDriverState *chr, int flags)
     }
 
     if (monitor_is_qmp(mon)) {
-        qemu_chr_add_handlers(chr, monitor_can_read, monitor_qmp_read,
-                              monitor_qmp_event, mon);
-        qemu_chr_fe_set_echo(chr, true);
+        qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_qmp_read,
+                                 monitor_qmp_event, mon, NULL);
+        qemu_chr_fe_set_echo(&mon->chr, true);
         json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
     } else {
-        qemu_chr_add_handlers(chr, monitor_can_read, monitor_read,
-                              monitor_event, mon);
+        qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_read,
+                                 monitor_event, mon, NULL);
     }
 
     qemu_mutex_lock(&monitor_lock);
diff --git a/net/colo-compare.c b/net/colo-compare.c
index b115465..63d92cb 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -101,7 +101,7 @@ enum {
     SECONDARY_IN,
 };
 
-static int compare_chr_send(CharDriverState *out,
+static int compare_chr_send(CharBackend *out,
                             const uint8_t *buf,
                             uint32_t size);
 
@@ -385,7 +385,7 @@ static void colo_compare_connection(void *opaque, void *user_data)
         }
 
         if (result) {
-            ret = compare_chr_send(s->chr_out.chr, pkt->data, pkt->size);
+            ret = compare_chr_send(&s->chr_out, pkt->data, pkt->size);
             if (ret < 0) {
                 error_report("colo_send_primary_packet failed");
             }
@@ -408,7 +408,7 @@ static void colo_compare_connection(void *opaque, void *user_data)
     }
 }
 
-static int compare_chr_send(CharDriverState *out,
+static int compare_chr_send(CharBackend *out,
                             const uint8_t *buf,
                             uint32_t size)
 {
@@ -451,7 +451,7 @@ static void compare_pri_chr_in(void *opaque, const uint8_t *buf, int size)
 
     ret = net_fill_rstate(&s->pri_rs, buf, size);
     if (ret == -1) {
-        qemu_chr_add_handlers(s->chr_pri_in.chr, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_set_handlers(&s->chr_pri_in, NULL, NULL, NULL, NULL, NULL);
         error_report("colo-compare primary_in error");
     }
 }
@@ -467,7 +467,7 @@ static void compare_sec_chr_in(void *opaque, const uint8_t *buf, int size)
 
     ret = net_fill_rstate(&s->sec_rs, buf, size);
     if (ret == -1) {
-        qemu_chr_add_handlers(s->chr_sec_in.chr, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_set_handlers(&s->chr_sec_in, NULL, NULL, NULL, NULL, NULL);
         error_report("colo-compare secondary_in error");
     }
 }
@@ -480,10 +480,10 @@ static void *colo_compare_thread(void *opaque)
 
     worker_context = g_main_context_new();
 
-    qemu_chr_add_handlers_full(s->chr_pri_in.chr, compare_chr_can_read,
-                          compare_pri_chr_in, NULL, s, worker_context);
-    qemu_chr_add_handlers_full(s->chr_sec_in.chr, compare_chr_can_read,
-                          compare_sec_chr_in, NULL, s, worker_context);
+    qemu_chr_fe_set_handlers(&s->chr_pri_in, compare_chr_can_read,
+                             compare_pri_chr_in, NULL, s, worker_context);
+    qemu_chr_fe_set_handlers(&s->chr_sec_in, compare_chr_can_read,
+                             compare_sec_chr_in, NULL, s, worker_context);
 
     compare_loop = g_main_loop_new(worker_context, FALSE);
 
@@ -545,7 +545,7 @@ static void compare_pri_rs_finalize(SocketReadState *pri_rs)
 
     if (packet_enqueue(s, PRIMARY_IN)) {
         trace_colo_compare_main("primary: unsupported packet in");
-        compare_chr_send(s->chr_out.chr, pri_rs->buf, pri_rs->packet_len);
+        compare_chr_send(&s->chr_out, pri_rs->buf, pri_rs->packet_len);
     } else {
         /* compare connection */
         g_queue_foreach(&s->conn_list, colo_compare_connection, s);
@@ -626,6 +626,7 @@ static void check_old_packet_regular(void *opaque)
 static void colo_compare_complete(UserCreatable *uc, Error **errp)
 {
     CompareState *s = COLO_COMPARE(uc);
+    CharDriverState *chr;
     char thread_name[64];
     static int compare_id;
 
@@ -641,15 +642,18 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
         return;
     }
 
-    if (find_and_check_chardev(&s->chr_pri_in.chr, s->pri_indev, errp)) {
+    if (find_and_check_chardev(&chr, s->pri_indev, errp) ||
+        !qemu_chr_fe_init(&s->chr_pri_in, chr, errp)) {
         return;
     }
 
-    if (find_and_check_chardev(&s->chr_sec_in.chr, s->sec_indev, errp)) {
+    if (find_and_check_chardev(&chr, s->sec_indev, errp) ||
+        !qemu_chr_fe_init(&s->chr_sec_in, chr, errp)) {
         return;
     }
 
-    if (find_and_check_chardev(&s->chr_out.chr, s->outdev, errp)) {
+    if (find_and_check_chardev(&chr, s->outdev, errp) ||
+        !qemu_chr_fe_init(&s->chr_out, chr, errp)) {
         return;
     }
 
@@ -704,11 +708,11 @@ static void colo_compare_finalize(Object *obj)
     CompareState *s = COLO_COMPARE(obj);
 
     if (s->chr_pri_in.chr) {
-        qemu_chr_add_handlers(s->chr_pri_in.chr, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_set_handlers(&s->chr_pri_in, NULL, NULL, NULL, NULL, NULL);
         qemu_chr_fe_release(s->chr_pri_in.chr);
     }
     if (s->chr_sec_in.chr) {
-        qemu_chr_add_handlers(s->chr_sec_in.chr, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_set_handlers(&s->chr_sec_in, NULL, NULL, NULL, NULL, NULL);
         qemu_chr_fe_release(s->chr_sec_in.chr);
     }
     if (s->chr_out.chr) {
diff --git a/net/filter-mirror.c b/net/filter-mirror.c
index 425e146..12d79cd 100644
--- a/net/filter-mirror.c
+++ b/net/filter-mirror.c
@@ -43,7 +43,7 @@ typedef struct MirrorState {
     SocketReadState rs;
 } MirrorState;
 
-static int filter_mirror_send(CharDriverState *chr_out,
+static int filter_mirror_send(CharBackend *chr_out,
                               const struct iovec *iov,
                               int iovcnt)
 {
@@ -110,7 +110,7 @@ static void redirector_chr_read(void *opaque, const uint8_t *buf, int size)
     ret = net_fill_rstate(&s->rs, buf, size);
 
     if (ret == -1) {
-        qemu_chr_add_handlers(s->chr_in.chr, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_set_handlers(&s->chr_in, NULL, NULL, NULL, NULL, NULL);
     }
 }
 
@@ -121,7 +121,7 @@ static void redirector_chr_event(void *opaque, int event)
 
     switch (event) {
     case CHR_EVENT_CLOSED:
-        qemu_chr_add_handlers(s->chr_in.chr, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_set_handlers(&s->chr_in, NULL, NULL, NULL, NULL, NULL);
         break;
     default:
         break;
@@ -138,7 +138,7 @@ static ssize_t filter_mirror_receive_iov(NetFilterState *nf,
     MirrorState *s = FILTER_MIRROR(nf);
     int ret;
 
-    ret = filter_mirror_send(s->chr_out.chr, iov, iovcnt);
+    ret = filter_mirror_send(&s->chr_out, iov, iovcnt);
     if (ret) {
         error_report("filter_mirror_send failed(%s)", strerror(-ret));
     }
@@ -160,8 +160,8 @@ static ssize_t filter_redirector_receive_iov(NetFilterState *nf,
     MirrorState *s = FILTER_REDIRECTOR(nf);
     int ret;
 
-    if (s->chr_out.chr) {
-        ret = filter_mirror_send(s->chr_out.chr, iov, iovcnt);
+    if (qemu_chr_fe_get_driver(&s->chr_out)) {
+        ret = filter_mirror_send(&s->chr_out, iov, iovcnt);
         if (ret) {
             error_report("filter_mirror_send failed(%s)", strerror(-ret));
         }
@@ -185,7 +185,7 @@ static void filter_redirector_cleanup(NetFilterState *nf)
     MirrorState *s = FILTER_REDIRECTOR(nf);
 
     if (s->chr_in.chr) {
-        qemu_chr_add_handlers(s->chr_in.chr, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_set_handlers(&s->chr_in, NULL, NULL, NULL, NULL, NULL);
         qemu_chr_fe_release(s->chr_in.chr);
     }
     if (s->chr_out.chr) {
@@ -258,8 +258,10 @@ static void filter_redirector_setup(NetFilterState *nf, Error **errp)
         if (!qemu_chr_fe_init(&s->chr_in, chr, errp)) {
             return;
         }
-        qemu_chr_add_handlers(s->chr_in.chr, redirector_chr_can_read,
-                              redirector_chr_read, redirector_chr_event, nf);
+
+        qemu_chr_fe_set_handlers(&s->chr_in, redirector_chr_can_read,
+                                 redirector_chr_read, redirector_chr_event,
+                                 nf, NULL);
     }
 
     if (s->outdev) {
diff --git a/net/slirp.c b/net/slirp.c
index 407e8aa..f9f6fc6 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -763,7 +763,8 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str,
             return -1;
         }
 
-        if (slirp_add_exec(s->slirp, 3, fwd->hd.chr, &server, port) < 0) {
+        if (slirp_add_exec(s->slirp, 3, qemu_chr_fe_get_driver(&fwd->hd),
+                           &server, port) < 0) {
             error_report("conflicting/invalid host:port in guest forwarding "
                          "rule '%s'", config_str);
             g_free(fwd);
@@ -774,8 +775,8 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str,
         fwd->slirp = s->slirp;
 
         qemu_chr_fe_claim_no_fail(fwd->hd.chr);
-        qemu_chr_add_handlers(fwd->hd.chr, guestfwd_can_read, guestfwd_read,
-                              NULL, fwd);
+        qemu_chr_fe_set_handlers(&fwd->hd, guestfwd_can_read, guestfwd_read,
+                                 NULL, fwd, NULL);
     }
     return 0;
 
diff --git a/net/vhost-user.c b/net/vhost-user.c
index 4578247..8b7e98d 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -78,7 +78,7 @@ static int vhost_user_start(int queues, NetClientState *ncs[])
         s = DO_UPCAST(VhostUserState, nc, ncs[i]);
 
         options.net_backend = ncs[i];
-        options.opaque      = s->chr.chr;
+        options.opaque      = &s->chr;
         options.busyloop_timeout = 0;
         net = vhost_net_init(&options);
         if (!net) {
@@ -151,7 +151,7 @@ static void vhost_user_cleanup(NetClientState *nc)
         s->vhost_net = NULL;
     }
     if (s->chr.chr) {
-        qemu_chr_add_handlers(s->chr.chr, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, NULL, NULL);
         qemu_chr_fe_release(s->chr.chr);
         s->chr.chr = NULL;
     }
@@ -187,7 +187,7 @@ static gboolean net_vhost_user_watch(GIOChannel *chan, GIOCondition cond,
 {
     VhostUserState *s = opaque;
 
-    qemu_chr_fe_disconnect(s->chr.chr);
+    qemu_chr_fe_disconnect(&s->chr);
 
     return FALSE;
 }
@@ -197,6 +197,7 @@ static void net_vhost_user_event(void *opaque, int event)
     const char *name = opaque;
     NetClientState *ncs[MAX_QUEUE_NUM];
     VhostUserState *s;
+    CharDriverState *chr;
     Error *err = NULL;
     int queues;
 
@@ -206,13 +207,14 @@ static void net_vhost_user_event(void *opaque, int event)
     assert(queues < MAX_QUEUE_NUM);
 
     s = DO_UPCAST(VhostUserState, nc, ncs[0]);
-    trace_vhost_user_event(s->chr.chr->label, event);
+    chr = qemu_chr_fe_get_driver(&s->chr);
+    trace_vhost_user_event(chr->label, event);
     switch (event) {
     case CHR_EVENT_OPENED:
-        s->watch = qemu_chr_fe_add_watch(s->chr.chr, G_IO_HUP,
+        s->watch = qemu_chr_fe_add_watch(&s->chr, G_IO_HUP,
                                          net_vhost_user_watch, s);
         if (vhost_user_start(queues, ncs) < 0) {
-            qemu_chr_fe_disconnect(s->chr.chr);
+            qemu_chr_fe_disconnect(&s->chr);
             return;
         }
         qmp_set_link(name, true, &err);
@@ -255,6 +257,7 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
         nc->queue_index = i;
 
         s = DO_UPCAST(VhostUserState, nc, nc);
+
         if (!qemu_chr_fe_init(&s->chr, chr, &err)) {
             error_report_err(err);
             return -1;
@@ -263,12 +266,12 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
 
     s = DO_UPCAST(VhostUserState, nc, nc0);
     do {
-        if (qemu_chr_wait_connected(chr, &err) < 0) {
+        if (qemu_chr_fe_wait_connected(&s->chr, &err) < 0) {
             error_report_err(err);
             return -1;
         }
-        qemu_chr_add_handlers(chr, NULL, NULL,
-                              net_vhost_user_event, nc0->name);
+        qemu_chr_fe_set_handlers(&s->chr, NULL, NULL,
+                                 net_vhost_user_event, nc0->name, NULL);
     } while (!s->started);
 
     assert(s->vhost_net);
diff --git a/qemu-char.c b/qemu-char.c
index 2c26839..dce86ca 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -268,8 +268,9 @@ static int qemu_chr_fe_write_buffer(CharDriverState *s, const uint8_t *buf, int
     return res;
 }
 
-int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len)
+int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len)
 {
+    CharDriverState *s = be->chr;
     int ret;
 
     if (s->replay && replay_mode == REPLAY_MODE_PLAY) {
@@ -296,7 +297,7 @@ int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len)
     return ret;
 }
 
-int qemu_chr_fe_write_all(CharDriverState *s, const uint8_t *buf, int len)
+static int qemu_chr_write_all(CharDriverState *s, const uint8_t *buf, int len)
 {
     int offset;
     int res;
@@ -320,8 +321,16 @@ int qemu_chr_fe_write_all(CharDriverState *s, const uint8_t *buf, int len)
     return offset;
 }
 
-int qemu_chr_fe_read_all(CharDriverState *s, uint8_t *buf, int len)
+int qemu_chr_fe_write_all(CharBackend *be, const uint8_t *buf, int len)
 {
+    CharDriverState *s = be->chr;
+
+    return qemu_chr_write_all(s, buf, len);
+}
+
+int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len)
+{
+    CharDriverState *s = be->chr;
     int offset = 0, counter = 10;
     int res;
 
@@ -365,8 +374,9 @@ int qemu_chr_fe_read_all(CharDriverState *s, uint8_t *buf, int len)
     return offset;
 }
 
-int qemu_chr_fe_ioctl(CharDriverState *s, int cmd, void *arg)
+int qemu_chr_fe_ioctl(CharBackend *be, int cmd, void *arg)
 {
+    CharDriverState *s = be->chr;
     int res;
     if (!s->chr_ioctl || s->replay) {
         res = -ENOTSUP;
@@ -403,10 +413,11 @@ void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len)
     }
 }
 
-int qemu_chr_fe_get_msgfd(CharDriverState *s)
+int qemu_chr_fe_get_msgfd(CharBackend *be)
 {
+    CharDriverState *s = be->chr;
     int fd;
-    int res = (qemu_chr_fe_get_msgfds(s, &fd, 1) == 1) ? fd : -1;
+    int res = (qemu_chr_fe_get_msgfds(be, &fd, 1) == 1) ? fd : -1;
     if (s->replay) {
         fprintf(stderr,
                 "Replay: get msgfd is not supported for serial devices yet\n");
@@ -415,13 +426,17 @@ int qemu_chr_fe_get_msgfd(CharDriverState *s)
     return res;
 }
 
-int qemu_chr_fe_get_msgfds(CharDriverState *s, int *fds, int len)
+int qemu_chr_fe_get_msgfds(CharBackend *be, int *fds, int len)
 {
+    CharDriverState *s = be->chr;
+
     return s->get_msgfds ? s->get_msgfds(s, fds, len) : -1;
 }
 
-int qemu_chr_fe_set_msgfds(CharDriverState *s, int *fds, int num)
+int qemu_chr_fe_set_msgfds(CharBackend *be, int *fds, int num)
 {
+    CharDriverState *s = be->chr;
+
     return s->set_msgfds ? s->set_msgfds(s, fds, num) : -1;
 }
 
@@ -430,14 +445,16 @@ int qemu_chr_add_client(CharDriverState *s, int fd)
     return s->chr_add_client ? s->chr_add_client(s, fd) : -1;
 }
 
-void qemu_chr_fe_accept_input(CharDriverState *s)
+void qemu_chr_fe_accept_input(CharBackend *be)
 {
+    CharDriverState *s = be->chr;
+
     if (s->chr_accept_input)
         s->chr_accept_input(s);
     qemu_notify_event();
 }
 
-void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...)
+void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
 {
     char buf[READ_BUF_LEN];
     va_list ap;
@@ -445,21 +462,21 @@ void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...)
     vsnprintf(buf, sizeof(buf), fmt, ap);
     /* XXX this blocks entire thread. Rewrite to use
      * qemu_chr_fe_write and background I/O callbacks */
-    qemu_chr_fe_write_all(s, (uint8_t *)buf, strlen(buf));
+    qemu_chr_fe_write_all(be, (uint8_t *)buf, strlen(buf));
     va_end(ap);
 }
 
 static void remove_fd_in_watch(CharDriverState *chr);
 
 static void
-qemu_chr_set_handlers(CharDriverState *s,
+qemu_chr_set_handlers(CharBackend *be,
                       IOCanReadHandler *fd_can_read,
                       IOReadHandler *fd_read,
                       IOEventHandler *fd_event,
                       void *opaque,
-                      GMainContext *context,
-                      int tag)
+                      GMainContext *context)
 {
+    CharDriverState *s = be->chr;
     int fe_open;
 
     if (!opaque && !fd_can_read && !fd_read && !fd_event) {
@@ -473,17 +490,20 @@ qemu_chr_set_handlers(CharDriverState *s,
     s->chr_event = fd_event;
     s->handler_opaque = opaque;
     if (s->chr_update_read_handler) {
-        s->chr_update_read_handler(s, context, tag);
+        s->chr_update_read_handler(s, context, be->tag);
     }
 
     if (!s->explicit_fe_open) {
-        qemu_chr_fe_set_open(s, fe_open);
+        qemu_chr_fe_set_open(be, fe_open);
     }
 
     /* We're connecting to an already opened device, so let's make sure we
        also get the open event */
-    if (fe_open && s->be_open) {
-        qemu_chr_be_generic_open(s);
+    if (fe_open) {
+        qemu_chr_fe_take_focus(be);
+        if (s->be_open) {
+            qemu_chr_be_generic_open(s);
+        }
     }
 }
 
@@ -491,38 +511,6 @@ static int mux_chr_new_handler_tag(CharDriverState *chr, Error **errp);
 static void mux_chr_set_handlers(CharDriverState *chr, GMainContext *context);
 static void mux_set_focus(MuxDriver *d, int focus);
 
-void qemu_chr_add_handlers_full(CharDriverState *s,
-                                IOCanReadHandler *fd_can_read,
-                                IOReadHandler *fd_read,
-                                IOEventHandler *fd_event,
-                                void *opaque,
-                                GMainContext *context)
-{
-    int tag = 0;
-
-    if (s->is_mux) {
-        tag = mux_chr_new_handler_tag(s, &error_abort);
-        mux_chr_set_handlers(s, context);
-    }
-
-    qemu_chr_set_handlers(s, fd_can_read, fd_read,
-                          fd_event, opaque, context, tag);
-
-    if (s->is_mux) {
-        mux_set_focus(s->opaque, tag);
-    }
-}
-
-void qemu_chr_add_handlers(CharDriverState *s,
-                           IOCanReadHandler *fd_can_read,
-                           IOReadHandler *fd_read,
-                           IOEventHandler *fd_event,
-                           void *opaque)
-{
-    qemu_chr_add_handlers_full(s, fd_can_read, fd_read,
-                               fd_event, opaque, NULL);
-}
-
 static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
     return len;
@@ -554,7 +542,6 @@ struct MuxDriver {
     IOReadHandler *chr_read[MAX_MUX];
     IOEventHandler *chr_event[MAX_MUX];
     void *ext_opaque[MAX_MUX];
-    CharDriverState *drv;
     CharBackend chr;
     int focus;
     int mux_cnt;
@@ -579,7 +566,7 @@ static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
     MuxDriver *d = chr->opaque;
     int ret;
     if (!d->timestamps) {
-        ret = qemu_chr_fe_write(d->drv, buf, len);
+        ret = qemu_chr_fe_write(&d->chr, buf, len);
     } else {
         int i;
 
@@ -603,10 +590,11 @@ static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
                          (int)(ti % 1000));
                 /* XXX this blocks entire thread. Rewrite to use
                  * qemu_chr_fe_write and background I/O callbacks */
-                qemu_chr_fe_write_all(d->drv, (uint8_t *)buf1, strlen(buf1));
+                qemu_chr_fe_write_all(&d->chr,
+                                      (uint8_t *)buf1, strlen(buf1));
                 d->linestart = 0;
             }
-            ret += qemu_chr_fe_write(d->drv, buf+i, 1);
+            ret += qemu_chr_fe_write(&d->chr, buf + i, 1);
             if (buf[i] == '\n') {
                 d->linestart = 1;
             }
@@ -643,13 +631,13 @@ static void mux_print_help(CharDriverState *chr)
     }
     /* XXX this blocks entire thread. Rewrite to use
      * qemu_chr_fe_write and background I/O callbacks */
-    qemu_chr_fe_write_all(chr, (uint8_t *)cbuf, strlen(cbuf));
+    qemu_chr_write_all(chr, (uint8_t *)cbuf, strlen(cbuf));
     for (i = 0; mux_help[i] != NULL; i++) {
         for (j=0; mux_help[i][j] != '\0'; j++) {
             if (mux_help[i][j] == '%')
-                qemu_chr_fe_write_all(chr, (uint8_t *)ebuf, strlen(ebuf));
+                qemu_chr_write_all(chr, (uint8_t *)ebuf, strlen(ebuf));
             else
-                qemu_chr_fe_write_all(chr, (uint8_t *)&mux_help[i][j], 1);
+                qemu_chr_write_all(chr, (uint8_t *)&mux_help[i][j], 1);
         }
     }
 }
@@ -674,7 +662,7 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
         case 'x':
             {
                  const char *term =  "QEMU: Terminated\n\r";
-                 qemu_chr_fe_write_all(chr, (uint8_t *)term, strlen(term));
+                 qemu_chr_write_all(chr, (uint8_t *)term, strlen(term));
                  exit(0);
                  break;
             }
@@ -819,7 +807,9 @@ static Notifier muxes_realize_notify = {
 static GSource *mux_chr_add_watch(CharDriverState *s, GIOCondition cond)
 {
     MuxDriver *d = s->opaque;
-    return d->drv->chr_add_watch(d->drv, cond);
+    CharDriverState *chr = qemu_chr_fe_get_driver(&d->chr);
+
+    return chr->chr_add_watch(chr, cond);
 }
 
 static void mux_chr_close(struct CharDriverState *chr)
@@ -889,7 +879,6 @@ static CharDriverState *qemu_chr_open_mux(const char *id,
     d = g_new0(MuxDriver, 1);
 
     chr->opaque = d;
-    d->drv = drv;
     d->focus = -1;
     chr->chr_close = mux_chr_close;
     chr->chr_write = mux_chr_write;
@@ -905,7 +894,7 @@ static CharDriverState *qemu_chr_open_mux(const char *id,
      */
     chr->explicit_be_open = muxes_realized ? 0 : 1;
     chr->is_mux = 1;
-    if (!qemu_chr_fe_init(&d->chr, d->drv, errp)) {
+    if (!qemu_chr_fe_init(&d->chr, drv, errp)) {
         qemu_chr_free(chr);
         return NULL;
     }
@@ -946,8 +935,8 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
         return;
     }
 
-    qemu_chr_set_handlers(b->chr, fd_can_read, fd_read,
-                          fd_event, opaque, context, b->tag);
+    qemu_chr_set_handlers(b, fd_can_read, fd_read,
+                          fd_event, opaque, context);
 
     if (b->chr->is_mux) {
         mux_chr_set_handlers(b->chr, context);
@@ -1364,7 +1353,7 @@ static CharDriverState *qemu_chr_open_stdio(const char *id,
     if (opts->has_signal) {
         stdio_allow_signal = opts->signal;
     }
-    qemu_chr_fe_set_echo(chr, false);
+    qemu_chr_set_echo_stdio(chr, false);
 
     return chr;
 }
@@ -2612,7 +2601,7 @@ static CharDriverState *qemu_chr_open_stdio(const char *id,
     SetConsoleMode(stdio->hStdIn, dwMode);
 
     chr->chr_set_echo = qemu_chr_set_echo_win_stdio;
-    qemu_chr_fe_set_echo(chr, false);
+    qemu_chr_set_echo_win_stdio(chr, false);
 
     return chr;
 
@@ -2627,7 +2616,6 @@ err1:
 }
 #endif /* !_WIN32 */
 
-
 /***********************************************************/
 /* UDP Net console */
 
@@ -3348,7 +3336,7 @@ static int tcp_chr_wait_connected(CharDriverState *chr, Error **errp)
     return 0;
 }
 
-int qemu_chr_wait_connected(CharDriverState *chr, Error **errp)
+static int qemu_chr_wait_connected(CharDriverState *chr, Error **errp)
 {
     if (chr->chr_wait_connected) {
         return chr->chr_wait_connected(chr, errp);
@@ -3357,6 +3345,11 @@ int qemu_chr_wait_connected(CharDriverState *chr, Error **errp)
     return 0;
 }
 
+int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp)
+{
+    return qemu_chr_wait_connected(be->chr, errp);
+}
+
 static void tcp_chr_close(CharDriverState *chr)
 {
     TCPCharDriver *s = chr->opaque;
@@ -4155,15 +4148,19 @@ CharDriverState *qemu_chr_new(const char *label, const char *filename)
     return chr;
 }
 
-void qemu_chr_fe_set_echo(struct CharDriverState *chr, bool echo)
+void qemu_chr_fe_set_echo(CharBackend *be, bool echo)
 {
+    CharDriverState *chr = be->chr;
+
     if (chr->chr_set_echo) {
         chr->chr_set_echo(chr, echo);
     }
 }
 
-void qemu_chr_fe_set_open(struct CharDriverState *chr, int fe_open)
+void qemu_chr_fe_set_open(CharBackend *be, int fe_open)
 {
+    CharDriverState *chr = be->chr;
+
     if (chr->fe_open == fe_open) {
         return;
     }
@@ -4173,16 +4170,19 @@ void qemu_chr_fe_set_open(struct CharDriverState *chr, int fe_open)
     }
 }
 
-void qemu_chr_fe_event(struct CharDriverState *chr, int event)
+void qemu_chr_fe_event(CharBackend *be, int event)
 {
+    CharDriverState *chr = be->chr;
+
     if (chr->chr_fe_event) {
         chr->chr_fe_event(chr, event);
     }
 }
 
-guint qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond,
+guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
                             GIOFunc func, void *user_data)
 {
+    CharDriverState *s = be->chr;
     GSource *src;
     guint tag;
 
@@ -4225,8 +4225,10 @@ void qemu_chr_fe_release(CharDriverState *s)
     s->avail_connections++;
 }
 
-void qemu_chr_fe_disconnect(CharDriverState *chr)
+void qemu_chr_fe_disconnect(CharBackend *be)
 {
+    CharDriverState *chr = be->chr;
+
     if (chr->chr_disconnect) {
         chr->chr_disconnect(chr);
     }
diff --git a/qtest.c b/qtest.c
index 3fb3c11..1a6c8b1 100644
--- a/qtest.c
+++ b/qtest.c
@@ -190,7 +190,7 @@ static void qtest_get_time(qemu_timeval *tv)
     }
 }
 
-static void qtest_send_prefix(CharDriverState *chr)
+static void qtest_send_prefix(CharBackend *chr)
 {
     qemu_timeval tv;
 
@@ -218,7 +218,7 @@ static void GCC_FMT_ATTR(1, 2) qtest_log_send(const char *fmt, ...)
     va_end(ap);
 }
 
-static void do_qtest_send(CharDriverState *chr, const char *str, size_t len)
+static void do_qtest_send(CharBackend *chr, const char *str, size_t len)
 {
     qemu_chr_fe_write_all(chr, (uint8_t *)str, len);
     if (qtest_log_fp && qtest_opened) {
@@ -226,12 +226,12 @@ static void do_qtest_send(CharDriverState *chr, const char *str, size_t len)
     }
 }
 
-static void qtest_send(CharDriverState *chr, const char *str)
+static void qtest_send(CharBackend *chr, const char *str)
 {
     do_qtest_send(chr, str, strlen(str));
 }
 
-static void GCC_FMT_ATTR(2, 3) qtest_sendf(CharDriverState *chr,
+static void GCC_FMT_ATTR(2, 3) qtest_sendf(CharBackend *chr,
                                            const char *fmt, ...)
 {
     va_list ap;
@@ -249,7 +249,7 @@ static void qtest_irq_handler(void *opaque, int n, int level)
     qemu_set_irq(old_irq, level);
 
     if (irq_levels[n] != level) {
-        CharDriverState *chr = qtest_chr.chr;
+        CharBackend *chr = &qtest_chr;
         irq_levels[n] = level;
         qtest_send_prefix(chr);
         qtest_sendf(chr, "IRQ %s %d\n",
@@ -257,7 +257,7 @@ static void qtest_irq_handler(void *opaque, int n, int level)
     }
 }
 
-static void qtest_process_command(CharDriverState *chr, gchar **words)
+static void qtest_process_command(CharBackend *chr, gchar **words)
 {
     const gchar *command;
 
@@ -585,7 +585,7 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
     }
 }
 
-static void qtest_process_inbuf(CharDriverState *chr, GString *inbuf)
+static void qtest_process_inbuf(CharBackend *chr, GString *inbuf)
 {
     char *end;
 
@@ -609,7 +609,7 @@ static void qtest_process_inbuf(CharDriverState *chr, GString *inbuf)
 
 static void qtest_read(void *opaque, const uint8_t *buf, int size)
 {
-    CharDriverState *chr = opaque;
+    CharBackend *chr = opaque;
 
     g_string_append_len(inbuf, (const gchar *)buf, size);
     qtest_process_inbuf(chr, inbuf);
@@ -686,11 +686,12 @@ void qtest_init(const char *qtest_chrdev, const char *qtest_log, Error **errp)
         qtest_log_fp = stderr;
     }
 
-    qemu_chr_add_handlers(chr, qtest_can_read, qtest_read, qtest_event, chr);
-    qemu_chr_fe_set_echo(chr, true);
+    qemu_chr_fe_init(&qtest_chr, chr, errp);
+    qemu_chr_fe_set_handlers(&qtest_chr, qtest_can_read, qtest_read,
+                             qtest_event, &qtest_chr, NULL);
+    qemu_chr_fe_set_echo(&qtest_chr, true);
 
     inbuf = g_string_new("");
-    qemu_chr_fe_init(&qtest_chr, chr, errp);
 }
 
 bool qtest_driver(void)
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index 6e5383d..2d86de1 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -11,6 +11,7 @@
 #include "qemu/osdep.h"
 
 #include "libqtest.h"
+#include "qapi/error.h"
 #include "qemu/option.h"
 #include "qemu/range.h"
 #include "qemu/sockets.h"
@@ -268,7 +269,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
     int fd;
 
     if (s->test_fail) {
-        qemu_chr_fe_disconnect(chr->chr);
+        qemu_chr_fe_disconnect(chr);
         /* now switch to non-failure */
         s->test_fail = false;
     }
@@ -283,7 +284,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
 
     if (msg.size) {
         p += VHOST_USER_HDR_SIZE;
-        size = qemu_chr_fe_read_all(chr->chr, p, msg.size);
+        size = qemu_chr_fe_read_all(chr, p, msg.size);
         if (size != msg.size) {
             g_test_message("Wrong message size received %d != %d\n",
                            size, msg.size);
@@ -306,14 +307,14 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
             s->test_flags = TEST_FLAGS_END;
         }
         p = (uint8_t *) &msg;
-        qemu_chr_fe_write_all(chr->chr, p, VHOST_USER_HDR_SIZE + msg.size);
+        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
         break;
 
     case VHOST_USER_SET_FEATURES:
 	g_assert_cmpint(msg.payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES),
 			!=, 0ULL);
         if (s->test_flags == TEST_FLAGS_DISCONNECT) {
-            qemu_chr_fe_disconnect(chr->chr);
+            qemu_chr_fe_disconnect(chr);
             s->test_flags = TEST_FLAGS_BAD;
         }
         break;
@@ -327,7 +328,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
             msg.payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_MQ;
         }
         p = (uint8_t *) &msg;
-        qemu_chr_fe_write_all(chr->chr, p, VHOST_USER_HDR_SIZE + msg.size);
+        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
         break;
 
     case VHOST_USER_GET_VRING_BASE:
@@ -336,7 +337,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
         msg.size = sizeof(m.payload.state);
         msg.payload.state.num = 0;
         p = (uint8_t *) &msg;
-        qemu_chr_fe_write_all(chr->chr, p, VHOST_USER_HDR_SIZE + msg.size);
+        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
 
         assert(msg.payload.state.index < s->queues * 2);
         s->rings &= ~(0x1ULL << msg.payload.state.index);
@@ -345,7 +346,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
     case VHOST_USER_SET_MEM_TABLE:
         /* received the mem table */
         memcpy(&s->memory, &msg.payload.memory, sizeof(msg.payload.memory));
-        s->fds_num = qemu_chr_fe_get_msgfds(chr->chr, s->fds,
+        s->fds_num = qemu_chr_fe_get_msgfds(chr, s->fds,
                                             G_N_ELEMENTS(s->fds));
 
         /* signal the test that it can continue */
@@ -355,7 +356,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
     case VHOST_USER_SET_VRING_KICK:
     case VHOST_USER_SET_VRING_CALL:
         /* consume the fd */
-        qemu_chr_fe_get_msgfds(chr->chr, &fd, 1);
+        qemu_chr_fe_get_msgfds(chr, &fd, 1);
         /*
          * This is a non-blocking eventfd.
          * The receive function forces it to be blocking,
@@ -369,11 +370,11 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
             close(s->log_fd);
             s->log_fd = -1;
         }
-        qemu_chr_fe_get_msgfds(chr->chr, &s->log_fd, 1);
+        qemu_chr_fe_get_msgfds(chr, &s->log_fd, 1);
         msg.flags |= VHOST_USER_REPLY_MASK;
         msg.size = 0;
         p = (uint8_t *) &msg;
-        qemu_chr_fe_write_all(chr->chr, p, VHOST_USER_HDR_SIZE);
+        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE);
 
         g_cond_signal(&s->data_cond);
         break;
@@ -388,7 +389,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
         msg.size = sizeof(m.payload.u64);
         msg.payload.u64 = s->queues;
         p = (uint8_t *) &msg;
-        qemu_chr_fe_write_all(chr->chr, p, VHOST_USER_HDR_SIZE + msg.size);
+        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
         break;
 
     default:
@@ -456,13 +457,14 @@ static void test_server_create_chr(TestServer *server, const gchar *opt)
 {
     gchar *chr_path;
     CharDriverState *chr;
+
     chr_path = g_strdup_printf("unix:%s%s", server->socket_path, opt);
     chr = qemu_chr_new(server->chr_name, chr_path);
-    qemu_chr_fe_init(&server->chr, chr, &error_abort);
     g_free(chr_path);
 
-    qemu_chr_add_handlers(server->chr.chr, chr_can_read, chr_read,
-                          chr_event, server);
+    qemu_chr_fe_init(&server->chr, chr, &error_abort);
+    qemu_chr_fe_set_handlers(&server->chr, chr_can_read, chr_read,
+                             chr_event, server, NULL);
 }
 
 static void test_server_listen(TestServer *server)
@@ -486,8 +488,9 @@ static inline void test_server_connect(TestServer *server)
 static gboolean _test_server_free(TestServer *server)
 {
     int i;
+    CharDriverState *chr = qemu_chr_fe_get_driver(&server->chr);
 
-    qemu_chr_delete(server->chr.chr);
+    qemu_chr_delete(chr);
 
     for (i = 0; i < server->fds_num; i++) {
         close(server->fds[i]);
@@ -724,7 +727,7 @@ reconnect_cb(gpointer user_data)
 {
     TestServer *s = user_data;
 
-    qemu_chr_fe_disconnect(s->chr.chr);
+    qemu_chr_fe_disconnect(&s->chr);
 
     return FALSE;
 }
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 35/50] char: fold qemu_chr_set_handlers in qemu_chr_fe_set_handlers
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (33 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 34/50] char: use qemu_chr_fe* functions with CharBackend argument Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 36/50] vhost-user: only initialize queue 0 CharBackend Paolo Bonzini
                   ` (15 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

qemu_chr_add_handlers*() have been removed in previous change, so the
common qemu_chr_set_handlers() is no longer needed.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-17-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/sysemu/char.h |  3 +-
 qemu-char.c           | 78 ++++++++++++++++++++++-----------------------------
 2 files changed, 35 insertions(+), 46 deletions(-)

diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 816c536..f2b3999 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -460,7 +460,8 @@ CharDriverState *qemu_chr_fe_get_driver(CharBackend *be);
  * @opaque: an opaque pointer for the callbacks
  * @context: a main loop context or NULL for the default
  *
- * Set the front end char handlers.
+ * Set the front end char handlers. The front end takes the focus if
+ * any of the handler is non-NULL.
  */
 void qemu_chr_fe_set_handlers(CharBackend *b,
                               IOCanReadHandler *fd_can_read,
diff --git a/qemu-char.c b/qemu-char.c
index dce86ca..115909f 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -467,46 +467,6 @@ void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
 }
 
 static void remove_fd_in_watch(CharDriverState *chr);
-
-static void
-qemu_chr_set_handlers(CharBackend *be,
-                      IOCanReadHandler *fd_can_read,
-                      IOReadHandler *fd_read,
-                      IOEventHandler *fd_event,
-                      void *opaque,
-                      GMainContext *context)
-{
-    CharDriverState *s = be->chr;
-    int fe_open;
-
-    if (!opaque && !fd_can_read && !fd_read && !fd_event) {
-        fe_open = 0;
-        remove_fd_in_watch(s);
-    } else {
-        fe_open = 1;
-    }
-    s->chr_can_read = fd_can_read;
-    s->chr_read = fd_read;
-    s->chr_event = fd_event;
-    s->handler_opaque = opaque;
-    if (s->chr_update_read_handler) {
-        s->chr_update_read_handler(s, context, be->tag);
-    }
-
-    if (!s->explicit_fe_open) {
-        qemu_chr_fe_set_open(be, fe_open);
-    }
-
-    /* We're connecting to an already opened device, so let's make sure we
-       also get the open event */
-    if (fe_open) {
-        qemu_chr_fe_take_focus(be);
-        if (s->be_open) {
-            qemu_chr_be_generic_open(s);
-        }
-    }
-}
-
 static int mux_chr_new_handler_tag(CharDriverState *chr, Error **errp);
 static void mux_chr_set_handlers(CharDriverState *chr, GMainContext *context);
 static void mux_set_focus(MuxDriver *d, int focus);
@@ -931,15 +891,43 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
                               void *opaque,
                               GMainContext *context)
 {
-    if (!b->chr) {
+    CharDriverState *s;
+    int fe_open;
+
+    s = b->chr;
+    if (!s) {
         return;
     }
 
-    qemu_chr_set_handlers(b, fd_can_read, fd_read,
-                          fd_event, opaque, context);
+    if (!opaque && !fd_can_read && !fd_read && !fd_event) {
+        fe_open = 0;
+        remove_fd_in_watch(s);
+    } else {
+        fe_open = 1;
+    }
+    s->chr_can_read = fd_can_read;
+    s->chr_read = fd_read;
+    s->chr_event = fd_event;
+    s->handler_opaque = opaque;
+    if (s->chr_update_read_handler) {
+        s->chr_update_read_handler(s, context, b->tag);
+    }
+
+    if (!s->explicit_fe_open) {
+        qemu_chr_fe_set_open(b, fe_open);
+    }
 
-    if (b->chr->is_mux) {
-        mux_chr_set_handlers(b->chr, context);
+    if (fe_open) {
+        qemu_chr_fe_take_focus(b);
+        /* We're connecting to an already opened device, so let's make sure we
+           also get the open event */
+        if (s->be_open) {
+            qemu_chr_be_generic_open(s);
+        }
+    }
+
+    if (s->is_mux) {
+        mux_chr_set_handlers(s, context);
     }
 }
 
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 36/50] vhost-user: only initialize queue 0 CharBackend
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (34 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 35/50] char: fold qemu_chr_set_handlers in qemu_chr_fe_set_handlers Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 37/50] char: replace qemu_chr_claim/release with qemu_chr_fe_init/deinit Paolo Bonzini
                   ` (14 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

All the queues share the same chardev. Initialize only the first queue
CharBackend, and pass it to other queues. This will allow to claim the
chardev only once in a later change.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-18-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 net/vhost-user.c | 29 +++++++++++++----------------
 1 file changed, 13 insertions(+), 16 deletions(-)

diff --git a/net/vhost-user.c b/net/vhost-user.c
index 8b7e98d..357b500 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -20,7 +20,7 @@
 
 typedef struct VhostUserState {
     NetClientState nc;
-    CharBackend chr;
+    CharBackend chr; /* only queue index 0 */
     VHostNetState *vhost_net;
     guint watch;
     uint64_t acked_features;
@@ -62,7 +62,7 @@ static void vhost_user_stop(int queues, NetClientState *ncs[])
     }
 }
 
-static int vhost_user_start(int queues, NetClientState *ncs[])
+static int vhost_user_start(int queues, NetClientState *ncs[], CharBackend *be)
 {
     VhostNetOptions options;
     struct vhost_net *net = NULL;
@@ -78,7 +78,7 @@ static int vhost_user_start(int queues, NetClientState *ncs[])
         s = DO_UPCAST(VhostUserState, nc, ncs[i]);
 
         options.net_backend = ncs[i];
-        options.opaque      = &s->chr;
+        options.opaque      = be;
         options.busyloop_timeout = 0;
         net = vhost_net_init(&options);
         if (!net) {
@@ -150,7 +150,7 @@ static void vhost_user_cleanup(NetClientState *nc)
         g_free(s->vhost_net);
         s->vhost_net = NULL;
     }
-    if (s->chr.chr) {
+    if (nc->queue_index == 0 && s->chr.chr) {
         qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, NULL, NULL);
         qemu_chr_fe_release(s->chr.chr);
         s->chr.chr = NULL;
@@ -213,7 +213,7 @@ static void net_vhost_user_event(void *opaque, int event)
     case CHR_EVENT_OPENED:
         s->watch = qemu_chr_fe_add_watch(&s->chr, G_IO_HUP,
                                          net_vhost_user_watch, s);
-        if (vhost_user_start(queues, ncs) < 0) {
+        if (vhost_user_start(queues, ncs, &s->chr) < 0) {
             qemu_chr_fe_disconnect(&s->chr);
             return;
         }
@@ -247,21 +247,18 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
 
     for (i = 0; i < queues; i++) {
         nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name);
-        if (!nc0) {
-            nc0 = nc;
-        }
-
         snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user%d to %s",
                  i, chr->label);
-
         nc->queue_index = i;
-
-        s = DO_UPCAST(VhostUserState, nc, nc);
-
-        if (!qemu_chr_fe_init(&s->chr, chr, &err)) {
-            error_report_err(err);
-            return -1;
+        if (!nc0) {
+            nc0 = nc;
+            s = DO_UPCAST(VhostUserState, nc, nc);
+            if (!qemu_chr_fe_init(&s->chr, chr, &err)) {
+                error_report_err(err);
+                return -1;
+            }
         }
+
     }
 
     s = DO_UPCAST(VhostUserState, nc, nc0);
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 37/50] char: replace qemu_chr_claim/release with qemu_chr_fe_init/deinit
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (35 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 36/50] vhost-user: only initialize queue 0 CharBackend Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 38/50] char: make some qemu_chr_fe skip if no driver Paolo Bonzini
                   ` (13 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Now that all front end use qemu_chr_fe_init(), we can move chardev
claiming in init(), and add a function deinit() to release the chardev
and cleanup handlers.

The qemu_chr_fe_claim_no_fail() for property are gone, since the
property will raise an error instead. In other cases, where there is
already an error path, an error is raised instead. Finally, other cases
are handled by &error_abort in qemu_chr_fe_init().

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-19-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 backends/rng-egd.c               | 10 +---------
 gdbstub.c                        |  3 +--
 hw/arm/pxa2xx.c                  |  1 -
 hw/char/mcf_uart.c               |  1 -
 hw/char/serial.c                 |  2 +-
 hw/char/sh_serial.c              |  1 -
 hw/char/xen_console.c            | 16 +++-------------
 hw/core/qdev-properties-system.c | 14 +++++---------
 hw/usb/ccid-card-passthru.c      |  1 +
 hw/usb/redirect.c                |  2 +-
 include/sysemu/char.h            | 39 +++++++++------------------------------
 monitor.c                        |  4 +---
 net/colo-compare.c               | 20 +++-----------------
 net/filter-mirror.c              | 20 +++-----------------
 net/slirp.c                      |  1 -
 net/vhost-user.c                 |  8 ++------
 qemu-char.c                      | 36 ++++++++++++------------------------
 tests/vhost-user-test.c          |  1 +
 vl.c                             |  1 -
 19 files changed, 44 insertions(+), 137 deletions(-)

diff --git a/backends/rng-egd.c b/backends/rng-egd.c
index d9e50bb..433f583 100644
--- a/backends/rng-egd.c
+++ b/backends/rng-egd.c
@@ -100,10 +100,6 @@ static void rng_egd_opened(RngBackend *b, Error **errp)
                   "Device '%s' not found", s->chr_name);
         return;
     }
-    if (qemu_chr_fe_claim(chr) != 0) {
-        error_setg(errp, QERR_DEVICE_IN_USE, s->chr_name);
-        return;
-    }
     if (!qemu_chr_fe_init(&s->chr, chr, errp)) {
         return;
     }
@@ -149,11 +145,7 @@ static void rng_egd_finalize(Object *obj)
 {
     RngEgd *s = RNG_EGD(obj);
 
-    if (s->chr.chr) {
-        qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, NULL, NULL);
-        qemu_chr_fe_release(s->chr.chr);
-    }
-
+    qemu_chr_fe_deinit(&s->chr);
     g_free(s->chr_name);
 }
 
diff --git a/gdbstub.c b/gdbstub.c
index 33b056e..5944494 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1494,6 +1494,7 @@ void gdb_exit(CPUArchState *env, int code)
   put_packet(s, buf);
 
 #ifndef CONFIG_USER_ONLY
+  qemu_chr_fe_deinit(&s->chr);
   qemu_chr_delete(chr);
 #endif
 }
@@ -1752,8 +1753,6 @@ int gdbserver_start(const char *device)
         chr = qemu_chr_new_noreplay("gdb", device);
         if (!chr)
             return -1;
-
-        qemu_chr_fe_claim_no_fail(chr);
     }
 
     s = gdbserver_state;
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index 798c05b..cd98379 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -1976,7 +1976,6 @@ static void pxa2xx_fir_realize(DeviceState *dev, Error **errp)
     PXA2xxFIrState *s = PXA2XX_FIR(dev);
 
     if (s->chr.chr) {
-        qemu_chr_fe_claim_no_fail(s->chr.chr);
         qemu_chr_fe_set_handlers(&s->chr, pxa2xx_fir_is_empty,
                                  pxa2xx_fir_rx, pxa2xx_fir_event, s, NULL);
     }
diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c
index cc3db13..b505343 100644
--- a/hw/char/mcf_uart.c
+++ b/hw/char/mcf_uart.c
@@ -285,7 +285,6 @@ void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
     s->irq = irq;
     if (chr) {
         qemu_chr_fe_init(&s->chr, chr, &error_abort);
-        qemu_chr_fe_claim_no_fail(chr);
         qemu_chr_fe_set_handlers(&s->chr, mcf_uart_can_receive,
                                  mcf_uart_receive, mcf_uart_event, s, NULL);
     }
diff --git a/hw/char/serial.c b/hw/char/serial.c
index 509bc25..54f80c6 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -905,7 +905,7 @@ void serial_realize_core(SerialState *s, Error **errp)
 
 void serial_exit_core(SerialState *s)
 {
-    qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, NULL, NULL);
+    qemu_chr_fe_deinit(&s->chr);
     qemu_unregister_reset(serial_reset, s);
 }
 
diff --git a/hw/char/sh_serial.c b/hw/char/sh_serial.c
index 8d82986..8bb45db 100644
--- a/hw/char/sh_serial.c
+++ b/hw/char/sh_serial.c
@@ -397,7 +397,6 @@ void sh_serial_init(MemoryRegion *sysmem,
     memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7);
 
     if (chr) {
-        qemu_chr_fe_claim_no_fail(chr);
         qemu_chr_fe_init(&s->chr, chr, &error_abort);
         qemu_chr_fe_set_handlers(&s->chr, sh_serial_can_receive1,
                                  sh_serial_receive1,
diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c
index 5e5aca1..f664366 100644
--- a/hw/char/xen_console.c
+++ b/hw/char/xen_console.c
@@ -245,15 +245,8 @@ static int con_initialise(struct XenDevice *xendev)
 
     xen_be_bind_evtchn(&con->xendev);
     if (con->chr.chr) {
-        if (qemu_chr_fe_claim(con->chr.chr) == 0) {
-            qemu_chr_fe_set_handlers(&con->chr, xencons_can_receive,
-                                     xencons_receive, NULL, con, NULL);
-        } else {
-            xen_be_printf(xendev, 0,
-                          "xen_console_init error chardev %s already used\n",
-                          con->chr.chr->label);
-            con->chr.chr = NULL;
-        }
+        qemu_chr_fe_set_handlers(&con->chr, xencons_can_receive,
+                                 xencons_receive, NULL, con, NULL);
     }
 
     xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n",
@@ -268,10 +261,7 @@ static void con_disconnect(struct XenDevice *xendev)
 {
     struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
 
-    if (con->chr.chr) {
-        qemu_chr_fe_set_handlers(&con->chr, NULL, NULL, NULL, NULL, NULL);
-        qemu_chr_fe_release(con->chr.chr);
-    }
+    qemu_chr_fe_deinit(&con->chr);
     xen_be_unbind_evtchn(&con->xendev);
 
     if (con->sring) {
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index 6d45d32..c35f0f5 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -206,13 +206,12 @@ static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
                    object_get_typename(obj), prop->name, str);
         return;
     }
-    if (qemu_chr_fe_claim(s) != 0) {
-        error_setg(errp, "Property '%s.%s' can't take value '%s', it's in use",
-                  object_get_typename(obj), prop->name, str);
+
+    if (!qemu_chr_fe_init(be, s, errp)) {
+        error_prepend(errp, "Property '%s.%s' can't take value '%s': ",
+                      object_get_typename(obj), prop->name, str);
         return;
     }
-
-    qemu_chr_fe_init(be, s, errp);
 }
 
 static void release_chr(Object *obj, const char *name, void *opaque)
@@ -221,10 +220,7 @@ static void release_chr(Object *obj, const char *name, void *opaque)
     Property *prop = opaque;
     CharBackend *be = qdev_get_prop_ptr(dev, prop);
 
-    if (be->chr) {
-        qemu_chr_fe_set_handlers(be, NULL, NULL, NULL, NULL, NULL);
-        qemu_chr_fe_release(be->chr);
-    }
+    qemu_chr_fe_deinit(be);
 }
 
 PropertyInfo qdev_prop_chr = {
diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c
index a8c8684..369a8f1 100644
--- a/hw/usb/ccid-card-passthru.c
+++ b/hw/usb/ccid-card-passthru.c
@@ -266,6 +266,7 @@ static void ccid_card_vscard_drop_connection(PassthruState *card)
 {
     CharDriverState *chr = qemu_chr_fe_get_driver(&card->cs);
 
+    qemu_chr_fe_deinit(&card->cs);
     qemu_chr_delete(chr);
     card->vscard_in_pos = card->vscard_in_hdr = 0;
 }
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 0fb2e9a..6f5ad20 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -1430,9 +1430,9 @@ static void usbredir_handle_destroy(USBDevice *udev)
     USBRedirDevice *dev = USB_REDIRECT(udev);
     CharDriverState *chr = qemu_chr_fe_get_driver(&dev->cs);
 
+    qemu_chr_fe_deinit(&dev->cs);
     qemu_chr_delete(chr);
 
-    dev->cs.chr = NULL;
     /* Note must be done after qemu_chr_close, as that causes a close event */
     qemu_bh_delete(dev->chardev_close_bh);
     qemu_bh_delete(dev->device_reject_bh);
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index f2b3999..b81dbcc 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -362,35 +362,6 @@ int qemu_chr_fe_get_msgfds(CharBackend *be, int *fds, int num);
 int qemu_chr_fe_set_msgfds(CharBackend *be, int *fds, int num);
 
 /**
- * @qemu_chr_fe_claim:
- *
- * Claim a backend before using it, should be called before calling
- * qemu_chr_fe_set_handlers().
- *
- * Returns: -1 if the backend is already in use by another frontend, 0 on
- *          success.
- */
-int qemu_chr_fe_claim(CharDriverState *s);
-
-/**
- * @qemu_chr_fe_claim_no_fail:
- *
- * Like qemu_chr_fe_claim, but will exit qemu with an error when the
- * backend is already in use.
- */
-void qemu_chr_fe_claim_no_fail(CharDriverState *s);
-
-/**
- * @qemu_chr_fe_release:
- *
- * Release a backend for use by another frontend.
- *
- * Returns: -1 if the backend is already in use by another frontend, 0 on
- *          success.
- */
-void qemu_chr_fe_release(CharDriverState *s);
-
-/**
  * @qemu_chr_be_can_write:
  *
  * Determine how much data the front end can currently accept.  This function
@@ -437,7 +408,8 @@ void qemu_chr_be_event(CharDriverState *s, int event);
  * @qemu_chr_fe_init:
  *
  * Initializes a front end for the given CharBackend and
- * CharDriver.
+ * CharDriver. Call qemu_chr_fe_deinit() to remove the association and
+ * release the driver.
  *
  * Returns: false on error.
  */
@@ -451,6 +423,13 @@ bool qemu_chr_fe_init(CharBackend *b, CharDriverState *s, Error **errp);
 CharDriverState *qemu_chr_fe_get_driver(CharBackend *be);
 
 /**
+ * @qemu_chr_fe_deinit:
+ *
+ * Dissociate the CharBackend from the CharDriver.
+ */
+void qemu_chr_fe_deinit(CharBackend *b);
+
+/**
  * @qemu_chr_fe_set_handlers:
  * @b: a CharBackend
  * @fd_can_read: callback to get the amount of data the frontend may
diff --git a/monitor.c b/monitor.c
index 1c6f28f..5c349c5 100644
--- a/monitor.c
+++ b/monitor.c
@@ -582,9 +582,7 @@ static void monitor_data_init(Monitor *mon)
 
 static void monitor_data_destroy(Monitor *mon)
 {
-    if (mon->chr.chr) {
-        qemu_chr_fe_set_handlers(&mon->chr, NULL, NULL, NULL, NULL, NULL);
-    }
+    qemu_chr_fe_deinit(&mon->chr);
     if (monitor_is_qmp(mon)) {
         json_message_parser_destroy(&mon->qmp.parser);
     }
diff --git a/net/colo-compare.c b/net/colo-compare.c
index 63d92cb..3083681 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -590,12 +590,6 @@ static int find_and_check_chardev(CharDriverState **chr,
         return 1;
     }
 
-    if (qemu_chr_fe_claim(*chr) < 0) {
-        error_setg(errp, "chardev \"%s\" cannot be claimed",
-                   chr_name);
-        return 1;
-    }
-
     return 0;
 }
 
@@ -707,17 +701,9 @@ static void colo_compare_finalize(Object *obj)
 {
     CompareState *s = COLO_COMPARE(obj);
 
-    if (s->chr_pri_in.chr) {
-        qemu_chr_fe_set_handlers(&s->chr_pri_in, NULL, NULL, NULL, NULL, NULL);
-        qemu_chr_fe_release(s->chr_pri_in.chr);
-    }
-    if (s->chr_sec_in.chr) {
-        qemu_chr_fe_set_handlers(&s->chr_sec_in, NULL, NULL, NULL, NULL, NULL);
-        qemu_chr_fe_release(s->chr_sec_in.chr);
-    }
-    if (s->chr_out.chr) {
-        qemu_chr_fe_release(s->chr_out.chr);
-    }
+    qemu_chr_fe_deinit(&s->chr_pri_in);
+    qemu_chr_fe_deinit(&s->chr_sec_in);
+    qemu_chr_fe_deinit(&s->chr_out);
 
     g_queue_free(&s->conn_list);
 
diff --git a/net/filter-mirror.c b/net/filter-mirror.c
index 12d79cd..1864c81 100644
--- a/net/filter-mirror.c
+++ b/net/filter-mirror.c
@@ -175,22 +175,15 @@ static void filter_mirror_cleanup(NetFilterState *nf)
 {
     MirrorState *s = FILTER_MIRROR(nf);
 
-    if (s->chr_out.chr) {
-        qemu_chr_fe_release(s->chr_out.chr);
-    }
+    qemu_chr_fe_deinit(&s->chr_out);
 }
 
 static void filter_redirector_cleanup(NetFilterState *nf)
 {
     MirrorState *s = FILTER_REDIRECTOR(nf);
 
-    if (s->chr_in.chr) {
-        qemu_chr_fe_set_handlers(&s->chr_in, NULL, NULL, NULL, NULL, NULL);
-        qemu_chr_fe_release(s->chr_in.chr);
-    }
-    if (s->chr_out.chr) {
-        qemu_chr_fe_release(s->chr_out.chr);
-    }
+    qemu_chr_fe_deinit(&s->chr_in);
+    qemu_chr_fe_deinit(&s->chr_out);
 }
 
 static void filter_mirror_setup(NetFilterState *nf, Error **errp)
@@ -211,11 +204,6 @@ static void filter_mirror_setup(NetFilterState *nf, Error **errp)
         return;
     }
 
-    if (qemu_chr_fe_claim(chr) != 0) {
-        error_setg(errp, QERR_DEVICE_IN_USE, s->outdev);
-        return;
-    }
-
     qemu_chr_fe_init(&s->chr_out, chr, errp);
 }
 
@@ -254,7 +242,6 @@ static void filter_redirector_setup(NetFilterState *nf, Error **errp)
             return;
         }
 
-        qemu_chr_fe_claim_no_fail(chr);
         if (!qemu_chr_fe_init(&s->chr_in, chr, errp)) {
             return;
         }
@@ -271,7 +258,6 @@ static void filter_redirector_setup(NetFilterState *nf, Error **errp)
                       "OUT Device '%s' not found", s->outdev);
             return;
         }
-        qemu_chr_fe_claim_no_fail(chr);
         if (!qemu_chr_fe_init(&s->chr_out, chr, errp)) {
             return;
         }
diff --git a/net/slirp.c b/net/slirp.c
index f9f6fc6..0e67535 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -774,7 +774,6 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str,
         fwd->port = port;
         fwd->slirp = s->slirp;
 
-        qemu_chr_fe_claim_no_fail(fwd->hd.chr);
         qemu_chr_fe_set_handlers(&fwd->hd, guestfwd_can_read, guestfwd_read,
                                  NULL, fwd, NULL);
     }
diff --git a/net/vhost-user.c b/net/vhost-user.c
index 357b500..140a4e0 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -150,10 +150,8 @@ static void vhost_user_cleanup(NetClientState *nc)
         g_free(s->vhost_net);
         s->vhost_net = NULL;
     }
-    if (nc->queue_index == 0 && s->chr.chr) {
-        qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, NULL, NULL);
-        qemu_chr_fe_release(s->chr.chr);
-        s->chr.chr = NULL;
+    if (nc->queue_index == 0) {
+        qemu_chr_fe_deinit(&s->chr);
     }
 
     qemu_purge_queued_packets(nc);
@@ -297,8 +295,6 @@ static CharDriverState *net_vhost_claim_chardev(
         return NULL;
     }
 
-    qemu_chr_fe_claim_no_fail(chr);
-
     return chr;
 }
 
diff --git a/qemu-char.c b/qemu-char.c
index 115909f..e5e8038 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -776,6 +776,7 @@ static void mux_chr_close(struct CharDriverState *chr)
 {
     MuxDriver *d = chr->opaque;
 
+    qemu_chr_fe_deinit(&d->chr);
     g_free(d);
 }
 
@@ -884,6 +885,17 @@ bool qemu_chr_fe_init(CharBackend *b, CharDriverState *s, Error **errp)
     return true;
 }
 
+void qemu_chr_fe_deinit(CharBackend *b)
+{
+    assert(b);
+
+    if (b->chr) {
+        qemu_chr_fe_set_handlers(b, NULL, NULL, NULL, NULL, NULL);
+        b->chr->avail_connections++;
+        b->chr = NULL;
+    }
+}
+
 void qemu_chr_fe_set_handlers(CharBackend *b,
                               IOCanReadHandler *fd_can_read,
                               IOReadHandler *fd_read,
@@ -4114,7 +4126,6 @@ CharDriverState *qemu_chr_new_noreplay(const char *label, const char *filename)
         error_report_err(err);
     }
     if (chr && qemu_opt_get_bool(opts, "mux", 0)) {
-        qemu_chr_fe_claim_no_fail(chr);
         monitor_init(chr, MONITOR_USE_READLINE);
     }
     qemu_opts_del(opts);
@@ -4190,29 +4201,6 @@ guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
     return tag;
 }
 
-int qemu_chr_fe_claim(CharDriverState *s)
-{
-    if (s->avail_connections < 1) {
-        return -1;
-    }
-    s->avail_connections--;
-    return 0;
-}
-
-void qemu_chr_fe_claim_no_fail(CharDriverState *s)
-{
-    if (qemu_chr_fe_claim(s) != 0) {
-        fprintf(stderr, "%s: error chardev \"%s\" already used\n",
-                __func__, s->label);
-        exit(1);
-    }
-}
-
-void qemu_chr_fe_release(CharDriverState *s)
-{
-    s->avail_connections++;
-}
-
 void qemu_chr_fe_disconnect(CharBackend *be)
 {
     CharDriverState *chr = be->chr;
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index 2d86de1..24c2323 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -490,6 +490,7 @@ static gboolean _test_server_free(TestServer *server)
     int i;
     CharDriverState *chr = qemu_chr_fe_get_driver(&server->chr);
 
+    qemu_chr_fe_deinit(&server->chr);
     qemu_chr_delete(chr);
 
     for (i = 0; i < server->fds_num; i++) {
diff --git a/vl.c b/vl.c
index e4c534c..44e08b4 100644
--- a/vl.c
+++ b/vl.c
@@ -2417,7 +2417,6 @@ static int mon_init_func(void *opaque, QemuOpts *opts, Error **errp)
         exit(1);
     }
 
-    qemu_chr_fe_claim_no_fail(chr);
     monitor_init(chr, flags);
     return 0;
 }
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 38/50] char: make some qemu_chr_fe skip if no driver
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (36 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 37/50] char: replace qemu_chr_claim/release with qemu_chr_fe_init/deinit Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 39/50] tests: start chardev unit tests Paolo Bonzini
                   ` (12 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

In most cases, front ends do not care about the side effect of
CharBackend, so we can simply skip the checks and call the qemu_chr_fe
functions even without associated CharDriver.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-20-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/arm/pxa2xx.c           |  8 +++-----
 hw/arm/strongarm.c        | 16 ++++++---------
 hw/char/bcm2835_aux.c     | 18 ++++++-----------
 hw/char/cadence_uart.c    | 24 +++++++----------------
 hw/char/digic-uart.c      | 14 +++++--------
 hw/char/escc.c            |  4 +---
 hw/char/etraxfs_ser.c     |  8 +++-----
 hw/char/imx_serial.c      | 26 +++++++++---------------
 hw/char/ipoctal232.c      | 14 +++++--------
 hw/char/lm32_juart.c      | 14 +++++--------
 hw/char/lm32_uart.c       | 14 +++++--------
 hw/char/mcf_uart.c        |  8 +++-----
 hw/char/milkymist-uart.c  | 10 +++-------
 hw/char/pl011.c           | 18 ++++++-----------
 hw/char/sclpconsole-lm.c  |  6 ++----
 hw/char/sclpconsole.c     |  6 ++----
 hw/char/stm32f2xx_usart.c | 22 +++++++--------------
 hw/char/virtio-console.c  |  6 ++----
 hw/char/xen_console.c     |  6 ++----
 hw/char/xilinx_uartlite.c | 14 +++++--------
 include/sysemu/char.h     | 40 +++++++++++++++++++++++++------------
 qemu-char.c               | 50 +++++++++++++++++++++++++++++++++++++++--------
 22 files changed, 156 insertions(+), 190 deletions(-)

diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index cd98379..c9f4503 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -1903,7 +1903,7 @@ static void pxa2xx_fir_write(void *opaque, hwaddr addr,
         } else {
             ch = ~value;
         }
-        if (s->chr.chr && s->enable && (s->control[0] & (1 << 3))) { /* TXE */
+        if (s->enable && (s->control[0] & (1 << 3))) { /* TXE */
             /* XXX this blocks entire thread. Rewrite to use
              * qemu_chr_fe_write and background I/O callbacks */
             qemu_chr_fe_write_all(&s->chr, &ch, 1);
@@ -1975,10 +1975,8 @@ static void pxa2xx_fir_realize(DeviceState *dev, Error **errp)
 {
     PXA2xxFIrState *s = PXA2XX_FIR(dev);
 
-    if (s->chr.chr) {
-        qemu_chr_fe_set_handlers(&s->chr, pxa2xx_fir_is_empty,
-                                 pxa2xx_fir_rx, pxa2xx_fir_event, s, NULL);
-    }
+    qemu_chr_fe_set_handlers(&s->chr, pxa2xx_fir_is_empty,
+                             pxa2xx_fir_rx, pxa2xx_fir_event, s, NULL);
 }
 
 static bool pxa2xx_fir_vmstate_validate(void *opaque, int version_id)
diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c
index fd13a39..370198a 100644
--- a/hw/arm/strongarm.c
+++ b/hw/arm/strongarm.c
@@ -1020,9 +1020,7 @@ static void strongarm_uart_update_parameters(StrongARMUARTState *s)
     ssp.data_bits = data_bits;
     ssp.stop_bits = stop_bits;
     s->char_transmit_time =  (NANOSECONDS_PER_SECOND / speed) * frame_size;
-    if (s->chr.chr) {
-        qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
-    }
+    qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
 
     DPRINTF(stderr, "%s speed=%d parity=%c data=%d stop=%d\n", s->chr->label,
             speed, parity, data_bits, stop_bits);
@@ -1239,13 +1237,11 @@ static void strongarm_uart_init(Object *obj)
     s->rx_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_rx_to, s);
     s->tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_tx, s);
 
-    if (s->chr.chr) {
-        qemu_chr_fe_set_handlers(&s->chr,
-                                 strongarm_uart_can_receive,
-                                 strongarm_uart_receive,
-                                 strongarm_uart_event,
-                                 s, NULL);
-    }
+    qemu_chr_fe_set_handlers(&s->chr,
+                             strongarm_uart_can_receive,
+                             strongarm_uart_receive,
+                             strongarm_uart_event,
+                             s, NULL);
 }
 
 static void strongarm_uart_reset(DeviceState *dev)
diff --git a/hw/char/bcm2835_aux.c b/hw/char/bcm2835_aux.c
index c49ec8c..af329aa 100644
--- a/hw/char/bcm2835_aux.c
+++ b/hw/char/bcm2835_aux.c
@@ -79,9 +79,7 @@ static uint64_t bcm2835_aux_read(void *opaque, hwaddr offset, unsigned size)
                 s->read_pos = 0;
             }
         }
-        if (s->chr.chr) {
-            qemu_chr_fe_accept_input(&s->chr);
-        }
+        qemu_chr_fe_accept_input(&s->chr);
         bcm2835_aux_update(s);
         return c;
 
@@ -168,11 +166,9 @@ static void bcm2835_aux_write(void *opaque, hwaddr offset, uint64_t value,
     case AUX_MU_IO_REG:
         /* "DLAB bit set means access baudrate register" is NYI */
         ch = value;
-        if (s->chr.chr) {
-            /* XXX this blocks entire thread. Rewrite to use
-             * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(&s->chr, &ch, 1);
-        }
+        /* XXX this blocks entire thread. Rewrite to use
+         * qemu_chr_fe_write and background I/O callbacks */
+        qemu_chr_fe_write_all(&s->chr, &ch, 1);
         break;
 
     case AUX_MU_IER_REG:
@@ -282,10 +278,8 @@ static void bcm2835_aux_realize(DeviceState *dev, Error **errp)
 {
     BCM2835AuxState *s = BCM2835_AUX(dev);
 
-    if (s->chr.chr) {
-        qemu_chr_fe_set_handlers(&s->chr, bcm2835_aux_can_receive,
-                                 bcm2835_aux_receive, NULL, s, NULL);
-    }
+    qemu_chr_fe_set_handlers(&s->chr, bcm2835_aux_can_receive,
+                             bcm2835_aux_receive, NULL, s, NULL);
 }
 
 static Property bcm2835_aux_props[] = {
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
index 4459b2d..291818e 100644
--- a/hw/char/cadence_uart.c
+++ b/hw/char/cadence_uart.c
@@ -142,9 +142,7 @@ static void uart_rx_reset(CadenceUARTState *s)
 {
     s->rx_wpos = 0;
     s->rx_count = 0;
-    if (s->chr.chr) {
-        qemu_chr_fe_accept_input(&s->chr);
-    }
+    qemu_chr_fe_accept_input(&s->chr);
 }
 
 static void uart_tx_reset(CadenceUARTState *s)
@@ -156,10 +154,8 @@ static void uart_send_breaks(CadenceUARTState *s)
 {
     int break_enabled = 1;
 
-    if (s->chr.chr) {
-        qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
-                          &break_enabled);
-    }
+    qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
+                      &break_enabled);
 }
 
 static void uart_parameters_setup(CadenceUARTState *s)
@@ -210,9 +206,7 @@ static void uart_parameters_setup(CadenceUARTState *s)
 
     packet_size += ssp.data_bits + ssp.stop_bits;
     s->char_tx_time = (NANOSECONDS_PER_SECOND / ssp.speed) * packet_size;
-    if (s->chr.chr) {
-        qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
-    }
+    qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
 }
 
 static int uart_can_receive(void *opaque)
@@ -368,9 +362,7 @@ static void uart_read_rx_fifo(CadenceUARTState *s, uint32_t *c)
         *c = s->rx_fifo[rx_rpos];
         s->rx_count--;
 
-        if (s->chr.chr) {
-            qemu_chr_fe_accept_input(&s->chr);
-        }
+        qemu_chr_fe_accept_input(&s->chr);
     } else {
         *c = 0;
     }
@@ -474,10 +466,8 @@ static void cadence_uart_realize(DeviceState *dev, Error **errp)
     s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
                                           fifo_trigger_update, s);
 
-    if (s->chr.chr) {
-        qemu_chr_fe_set_handlers(&s->chr, uart_can_receive, uart_receive,
-                                 uart_event, s, NULL);
-    }
+    qemu_chr_fe_set_handlers(&s->chr, uart_can_receive, uart_receive,
+                             uart_event, s, NULL);
 }
 
 static void cadence_uart_init(Object *obj)
diff --git a/hw/char/digic-uart.c b/hw/char/digic-uart.c
index c7b3db6..2955e19 100644
--- a/hw/char/digic-uart.c
+++ b/hw/char/digic-uart.c
@@ -76,11 +76,9 @@ static void digic_uart_write(void *opaque, hwaddr addr, uint64_t value,
 
     switch (addr) {
     case R_TX:
-        if (s->chr.chr) {
-            /* XXX this blocks entire thread. Rewrite to use
-             * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(&s->chr, &ch, 1);
-        }
+        /* XXX this blocks entire thread. Rewrite to use
+         * qemu_chr_fe_write and background I/O callbacks */
+        qemu_chr_fe_write_all(&s->chr, &ch, 1);
         break;
 
     case R_ST:
@@ -147,10 +145,8 @@ static void digic_uart_realize(DeviceState *dev, Error **errp)
 {
     DigicUartState *s = DIGIC_UART(dev);
 
-    if (s->chr.chr) {
-        qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
-                                 uart_event, s, NULL);
-    }
+    qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
+                             uart_event, s, NULL);
 }
 
 static void digic_uart_init(Object *obj)
diff --git a/hw/char/escc.c b/hw/char/escc.c
index 4578a46..c71b0a8 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -599,9 +599,7 @@ static uint64_t escc_mem_read(void *opaque, hwaddr addr,
         else
             ret = s->rx;
         trace_escc_mem_readb_data(CHN_C(s), ret);
-        if (s->chr.chr) {
-            qemu_chr_fe_accept_input(&s->chr);
-        }
+        qemu_chr_fe_accept_input(&s->chr);
         return ret;
     default:
         break;
diff --git a/hw/char/etraxfs_ser.c b/hw/char/etraxfs_ser.c
index d812954..18c374b 100644
--- a/hw/char/etraxfs_ser.c
+++ b/hw/char/etraxfs_ser.c
@@ -231,11 +231,9 @@ static void etraxfs_ser_realize(DeviceState *dev, Error **errp)
 {
     ETRAXSerial *s = ETRAX_SERIAL(dev);
 
-    if (s->chr.chr) {
-        qemu_chr_fe_set_handlers(&s->chr,
-                                 serial_can_receive, serial_receive,
-                                 serial_event, s, NULL);
-    }
+    qemu_chr_fe_set_handlers(&s->chr,
+                             serial_can_receive, serial_receive,
+                             serial_event, s, NULL);
 }
 
 static void etraxfs_ser_class_init(ObjectClass *klass, void *data)
diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c
index d9a0a25..8dbb7b2 100644
--- a/hw/char/imx_serial.c
+++ b/hw/char/imx_serial.c
@@ -121,9 +121,7 @@ static uint64_t imx_serial_read(void *opaque, hwaddr offset,
             s->usr2 &= ~USR2_RDR;
             s->uts1 |= UTS1_RXEMPTY;
             imx_update(s);
-            if (s->chr.chr) {
-                qemu_chr_fe_accept_input(&s->chr);
-            }
+            qemu_chr_fe_accept_input(&s->chr);
         }
         return c;
 
@@ -182,11 +180,9 @@ static void imx_serial_write(void *opaque, hwaddr offset,
     case 0x10: /* UTXD */
         ch = value;
         if (s->ucr2 & UCR2_TXEN) {
-            if (s->chr.chr) {
-                /* XXX this blocks entire thread. Rewrite to use
-                 * qemu_chr_fe_write and background I/O callbacks */
-                qemu_chr_fe_write_all(&s->chr, &ch, 1);
-            }
+            /* XXX this blocks entire thread. Rewrite to use
+             * qemu_chr_fe_write and background I/O callbacks */
+            qemu_chr_fe_write_all(&s->chr, &ch, 1);
             s->usr1 &= ~USR1_TRDY;
             imx_update(s);
             s->usr1 |= USR1_TRDY;
@@ -215,9 +211,7 @@ static void imx_serial_write(void *opaque, hwaddr offset,
         }
         if (value & UCR2_RXEN) {
             if (!(s->ucr2 & UCR2_RXEN)) {
-                if (s->chr.chr) {
-                    qemu_chr_fe_accept_input(&s->chr);
-                }
+                qemu_chr_fe_accept_input(&s->chr);
             }
         }
         s->ucr2 = value & 0xffff;
@@ -319,12 +313,10 @@ static void imx_serial_realize(DeviceState *dev, Error **errp)
 {
     IMXSerialState *s = IMX_SERIAL(dev);
 
-    if (s->chr.chr) {
-        qemu_chr_fe_set_handlers(&s->chr, imx_can_receive, imx_receive,
-                                 imx_event, s, NULL);
-    } else {
-        DPRINTF("No char dev for uart\n");
-    }
+    DPRINTF("char dev for uart: %p\n", qemu_chr_fe_get_driver(&s->chr));
+
+    qemu_chr_fe_set_handlers(&s->chr, imx_can_receive, imx_receive,
+                             imx_event, s, NULL);
 }
 
 static void imx_serial_init(Object *obj)
diff --git a/hw/char/ipoctal232.c b/hw/char/ipoctal232.c
index d504721..6f150e0 100644
--- a/hw/char/ipoctal232.c
+++ b/hw/char/ipoctal232.c
@@ -288,9 +288,7 @@ static uint16_t io_read(IPackDevice *ip, uint8_t addr)
             if (ch->rx_pending == 0) {
                 ch->sr &= ~SR_RXRDY;
                 blk->isr &= ~ISR_RXRDY(channel);
-                if (ch->dev.chr) {
-                    qemu_chr_fe_accept_input(&ch->dev);
-                }
+                qemu_chr_fe_accept_input(&ch->dev);
             } else {
                 ch->rhr_idx = (ch->rhr_idx + 1) % RX_FIFO_SIZE;
             }
@@ -357,13 +355,11 @@ static void io_write(IPackDevice *ip, uint8_t addr, uint16_t val)
     case REG_THRa:
     case REG_THRb:
         if (ch->sr & SR_TXRDY) {
+            uint8_t thr = reg;
             DPRINTF("Write THR%c (0x%x)\n", channel + 'a', reg);
-            if (ch->dev.chr) {
-                uint8_t thr = reg;
-                /* XXX this blocks entire thread. Rewrite to use
-                 * qemu_chr_fe_write and background I/O callbacks */
-                qemu_chr_fe_write_all(&ch->dev, &thr, 1);
-            }
+            /* XXX this blocks entire thread. Rewrite to use
+             * qemu_chr_fe_write and background I/O callbacks */
+            qemu_chr_fe_write_all(&ch->dev, &thr, 1);
         } else {
             DPRINTF("Write THR%c (0x%x), Tx disabled\n", channel + 'a', reg);
         }
diff --git a/hw/char/lm32_juart.c b/hw/char/lm32_juart.c
index 9629e9e..febb412 100644
--- a/hw/char/lm32_juart.c
+++ b/hw/char/lm32_juart.c
@@ -75,11 +75,9 @@ void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx)
     trace_lm32_juart_set_jtx(s->jtx);
 
     s->jtx = jtx;
-    if (s->chr.chr) {
-        /* XXX this blocks entire thread. Rewrite to use
-         * qemu_chr_fe_write and background I/O callbacks */
-        qemu_chr_fe_write_all(&s->chr, &ch, 1);
-    }
+    /* XXX this blocks entire thread. Rewrite to use
+     * qemu_chr_fe_write and background I/O callbacks */
+    qemu_chr_fe_write_all(&s->chr, &ch, 1);
 }
 
 void lm32_juart_set_jrx(DeviceState *d, uint32_t jtx)
@@ -120,10 +118,8 @@ static void lm32_juart_realize(DeviceState *dev, Error **errp)
 {
     LM32JuartState *s = LM32_JUART(dev);
 
-    if (s->chr.chr) {
-        qemu_chr_fe_set_handlers(&s->chr, juart_can_rx, juart_rx,
-                                 juart_event, s, NULL);
-    }
+    qemu_chr_fe_set_handlers(&s->chr, juart_can_rx, juart_rx,
+                             juart_event, s, NULL);
 }
 
 static const VMStateDescription vmstate_lm32_juart = {
diff --git a/hw/char/lm32_uart.c b/hw/char/lm32_uart.c
index e325b91..1b2746f 100644
--- a/hw/char/lm32_uart.c
+++ b/hw/char/lm32_uart.c
@@ -177,11 +177,9 @@ static void uart_write(void *opaque, hwaddr addr,
     addr >>= 2;
     switch (addr) {
     case R_RXTX:
-        if (s->chr.chr) {
-            /* XXX this blocks entire thread. Rewrite to use
-             * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(&s->chr, &ch, 1);
-        }
+        /* XXX this blocks entire thread. Rewrite to use
+         * qemu_chr_fe_write and background I/O callbacks */
+        qemu_chr_fe_write_all(&s->chr, &ch, 1);
         break;
     case R_IER:
     case R_LCR:
@@ -267,10 +265,8 @@ static void lm32_uart_realize(DeviceState *dev, Error **errp)
 {
     LM32UartState *s = LM32_UART(dev);
 
-    if (s->chr.chr) {
-        qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
-                                 uart_event, s, NULL);
-    }
+    qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
+                             uart_event, s, NULL);
 }
 
 static const VMStateDescription vmstate_lm32_uart = {
diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c
index b505343..456591a 100644
--- a/hw/char/mcf_uart.c
+++ b/hw/char/mcf_uart.c
@@ -114,11 +114,9 @@ uint64_t mcf_uart_read(void *opaque, hwaddr addr,
 static void mcf_uart_do_tx(mcf_uart_state *s)
 {
     if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
-        if (s->chr.chr) {
-            /* XXX this blocks entire thread. Rewrite to use
-             * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(&s->chr, (unsigned char *)&s->tb, 1);
-        }
+        /* XXX this blocks entire thread. Rewrite to use
+         * qemu_chr_fe_write and background I/O callbacks */
+        qemu_chr_fe_write_all(&s->chr, (unsigned char *)&s->tb, 1);
         s->sr |= MCF_UART_TxEMP;
     }
     if (s->tx_enabled) {
diff --git a/hw/char/milkymist-uart.c b/hw/char/milkymist-uart.c
index 0a4c617..dec0a8c 100644
--- a/hw/char/milkymist-uart.c
+++ b/hw/char/milkymist-uart.c
@@ -124,9 +124,7 @@ static void uart_write(void *opaque, hwaddr addr, uint64_t value,
     addr >>= 2;
     switch (addr) {
     case R_RXTX:
-        if (s->chr.chr) {
-            qemu_chr_fe_write_all(&s->chr, &ch, 1);
-        }
+        qemu_chr_fe_write_all(&s->chr, &ch, 1);
         s->regs[R_STAT] |= STAT_TX_EVT;
         break;
     case R_DIV:
@@ -200,10 +198,8 @@ static void milkymist_uart_realize(DeviceState *dev, Error **errp)
 {
     MilkymistUartState *s = MILKYMIST_UART(dev);
 
-    if (s->chr.chr) {
-        qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
-                                 uart_event, s, NULL);
-    }
+    qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
+                             uart_event, s, NULL);
 }
 
 static void milkymist_uart_init(Object *obj)
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
index 52ec866..900ee5d 100644
--- a/hw/char/pl011.c
+++ b/hw/char/pl011.c
@@ -87,9 +87,7 @@ static uint64_t pl011_read(void *opaque, hwaddr offset,
         trace_pl011_read_fifo(s->read_count);
         s->rsr = c >> 8;
         pl011_update(s);
-        if (s->chr.chr) {
-            qemu_chr_fe_accept_input(&s->chr);
-        }
+        qemu_chr_fe_accept_input(&s->chr);
         r = c;
         break;
     case 1: /* UARTRSR */
@@ -168,11 +166,9 @@ static void pl011_write(void *opaque, hwaddr offset,
     case 0: /* UARTDR */
         /* ??? Check if transmitter is enabled.  */
         ch = value;
-        if (s->chr.chr) {
-            /* XXX this blocks entire thread. Rewrite to use
-             * qemu_chr_fe_write and background I/O callbacks */
-            qemu_chr_fe_write_all(&s->chr, &ch, 1);
-        }
+        /* XXX this blocks entire thread. Rewrite to use
+         * qemu_chr_fe_write and background I/O callbacks */
+        qemu_chr_fe_write_all(&s->chr, &ch, 1);
         s->int_level |= PL011_INT_TX;
         pl011_update(s);
         break;
@@ -332,10 +328,8 @@ static void pl011_realize(DeviceState *dev, Error **errp)
 {
     PL011State *s = PL011(dev);
 
-    if (s->chr.chr) {
-        qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
-                                 pl011_event, s, NULL);
-    }
+    qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
+                             pl011_event, s, NULL);
 }
 
 static void pl011_class_init(ObjectClass *oc, void *data)
diff --git a/hw/char/sclpconsole-lm.c b/hw/char/sclpconsole-lm.c
index 0660cbc..7191717 100644
--- a/hw/char/sclpconsole-lm.c
+++ b/hw/char/sclpconsole-lm.c
@@ -312,10 +312,8 @@ static int console_init(SCLPEvent *event)
     }
     console_available = true;
 
-    if (scon->chr.chr) {
-        qemu_chr_fe_set_handlers(&scon->chr, chr_can_read,
-                                 chr_read, NULL, scon, NULL);
-    }
+    qemu_chr_fe_set_handlers(&scon->chr, chr_can_read,
+                             chr_read, NULL, scon, NULL);
 
     return 0;
 }
diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c
index 0559208..27a6034 100644
--- a/hw/char/sclpconsole.c
+++ b/hw/char/sclpconsole.c
@@ -227,10 +227,8 @@ static int console_init(SCLPEvent *event)
         return -1;
     }
     console_available = true;
-    if (scon->chr.chr) {
-        qemu_chr_fe_set_handlers(&scon->chr, chr_can_read,
-                                 chr_read, NULL, scon, NULL);
-    }
+    qemu_chr_fe_set_handlers(&scon->chr, chr_can_read,
+                             chr_read, NULL, scon, NULL);
 
     return 0;
 }
diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c
index 03ccc52..8e9852b 100644
--- a/hw/char/stm32f2xx_usart.c
+++ b/hw/char/stm32f2xx_usart.c
@@ -97,17 +97,13 @@ static uint64_t stm32f2xx_usart_read(void *opaque, hwaddr addr,
     case USART_SR:
         retvalue = s->usart_sr;
         s->usart_sr &= ~USART_SR_TC;
-        if (s->chr.chr) {
-            qemu_chr_fe_accept_input(&s->chr);
-        }
+        qemu_chr_fe_accept_input(&s->chr);
         return retvalue;
     case USART_DR:
         DB_PRINT("Value: 0x%" PRIx32 ", %c\n", s->usart_dr, (char) s->usart_dr);
         s->usart_sr |= USART_SR_TXE;
         s->usart_sr &= ~USART_SR_RXNE;
-        if (s->chr.chr) {
-            qemu_chr_fe_accept_input(&s->chr);
-        }
+        qemu_chr_fe_accept_input(&s->chr);
         qemu_set_irq(s->irq, 0);
         return s->usart_dr & 0x3FF;
     case USART_BRR:
@@ -152,11 +148,9 @@ static void stm32f2xx_usart_write(void *opaque, hwaddr addr,
     case USART_DR:
         if (value < 0xF000) {
             ch = value;
-            if (s->chr.chr) {
-                /* XXX this blocks entire thread. Rewrite to use
-                 * qemu_chr_fe_write and background I/O callbacks */
-                qemu_chr_fe_write_all(&s->chr, &ch, 1);
-            }
+            /* XXX this blocks entire thread. Rewrite to use
+             * qemu_chr_fe_write and background I/O callbacks */
+            qemu_chr_fe_write_all(&s->chr, &ch, 1);
             s->usart_sr |= USART_SR_TC;
             s->usart_sr &= ~USART_SR_TXE;
         }
@@ -212,10 +206,8 @@ static void stm32f2xx_usart_realize(DeviceState *dev, Error **errp)
 {
     STM32F2XXUsartState *s = STM32F2XX_USART(dev);
 
-    if (s->chr.chr) {
-        qemu_chr_fe_set_handlers(&s->chr, stm32f2xx_usart_can_receive,
-                                 stm32f2xx_usart_receive, NULL, s, NULL);
-    }
+    qemu_chr_fe_set_handlers(&s->chr, stm32f2xx_usart_can_receive,
+                             stm32f2xx_usart_receive, NULL, s, NULL);
 }
 
 static void stm32f2xx_usart_class_init(ObjectClass *klass, void *data)
diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c
index 135f589..378c1c1 100644
--- a/hw/char/virtio-console.c
+++ b/hw/char/virtio-console.c
@@ -108,7 +108,7 @@ static void set_guest_connected(VirtIOSerialPort *port, int guest_connected)
     DeviceState *dev = DEVICE(port);
     VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
 
-    if (vcon->chr.chr && !k->is_console) {
+    if (!k->is_console) {
         qemu_chr_fe_set_open(&vcon->chr, guest_connected);
     }
 
@@ -122,9 +122,7 @@ static void guest_writable(VirtIOSerialPort *port)
 {
     VirtConsole *vcon = VIRTIO_CONSOLE(port);
 
-    if (vcon->chr.chr) {
-        qemu_chr_fe_accept_input(&vcon->chr);
-    }
+    qemu_chr_fe_accept_input(&vcon->chr);
 }
 
 /* Readiness of the guest to accept data on a port */
diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c
index f664366..785bf86 100644
--- a/hw/char/xen_console.c
+++ b/hw/char/xen_console.c
@@ -244,10 +244,8 @@ static int con_initialise(struct XenDevice *xendev)
 	return -1;
 
     xen_be_bind_evtchn(&con->xendev);
-    if (con->chr.chr) {
-        qemu_chr_fe_set_handlers(&con->chr, xencons_can_receive,
-                                 xencons_receive, NULL, con, NULL);
-    }
+    qemu_chr_fe_set_handlers(&con->chr, xencons_can_receive,
+                             xencons_receive, NULL, con, NULL);
 
     xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n",
 		  con->ring_ref,
diff --git a/hw/char/xilinx_uartlite.c b/hw/char/xilinx_uartlite.c
index d6df643..c7888f7 100644
--- a/hw/char/xilinx_uartlite.c
+++ b/hw/char/xilinx_uartlite.c
@@ -143,11 +143,9 @@ uart_write(void *opaque, hwaddr addr,
             break;
 
         case R_TX:
-            if (s->chr.chr) {
-                /* XXX this blocks entire thread. Rewrite to use
-                 * qemu_chr_fe_write and background I/O callbacks */
-                qemu_chr_fe_write_all(&s->chr, &ch, 1);
-            }
+            /* XXX this blocks entire thread. Rewrite to use
+             * qemu_chr_fe_write and background I/O callbacks */
+            qemu_chr_fe_write_all(&s->chr, &ch, 1);
             s->regs[addr] = value;
 
             /* hax.  */
@@ -213,10 +211,8 @@ static void xilinx_uartlite_realize(DeviceState *dev, Error **errp)
 {
     XilinxUARTLite *s = XILINX_UARTLITE(dev);
 
-    if (s->chr.chr) {
-        qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
-                                 uart_event, s, NULL);
-    }
+    qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
+                             uart_event, s, NULL);
 }
 
 static void xilinx_uartlite_init(Object *obj)
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index b81dbcc..2f60a10 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -168,6 +168,7 @@ CharDriverState *qemu_chr_new(const char *label, const char *filename);
  * @qemu_chr_fe_disconnect:
  *
  * Close a fd accpeted by character backend.
+ * Without associated CharDriver, do nothing.
  */
 void qemu_chr_fe_disconnect(CharBackend *be);
 
@@ -181,7 +182,8 @@ void qemu_chr_cleanup(void);
 /**
  * @qemu_chr_fe_wait_connected:
  *
- * Wait for characted backend to be connected.
+ * Wait for characted backend to be connected, return < 0 on error or
+ * if no assicated CharDriver.
  */
 int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp);
 
@@ -220,6 +222,7 @@ void qemu_chr_free(CharDriverState *chr);
  * Ask the backend to override its normal echo setting.  This only really
  * applies to the stdio backend and is used by the QMP server such that you
  * can see what you type if you try to type QMP commands.
+ * Without associated CharDriver, do nothing.
  *
  * @echo true to enable echo, false to disable echo
  */
@@ -230,13 +233,15 @@ void qemu_chr_fe_set_echo(CharBackend *be, bool echo);
  *
  * Set character frontend open status.  This is an indication that the
  * front end is ready (or not) to begin doing I/O.
+ * Without associated CharDriver, do nothing.
  */
 void qemu_chr_fe_set_open(CharBackend *be, int fe_open);
 
 /**
  * @qemu_chr_fe_event:
  *
- * Send an event from the front end to the back end.
+ * Send an event from the front end to the back end. It does nothing
+ * without associated CharDriver.
  *
  * @event the event to send
  */
@@ -245,8 +250,9 @@ void qemu_chr_fe_event(CharBackend *be, int event);
 /**
  * @qemu_chr_fe_printf:
  *
- * Write to a character backend using a printf style interface.
- * This function is thread-safe.
+ * Write to a character backend using a printf style interface.  This
+ * function is thread-safe. It does nothing without associated
+ * CharDriver.
  *
  * @fmt see #printf
  */
@@ -259,7 +265,7 @@ void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
  * If the backend is connected, create and add a #GSource that fires
  * when the given condition (typically G_IO_OUT|G_IO_HUP or G_IO_HUP)
  * is active; return the #GSource's tag.  If it is disconnected,
- * return 0.
+ * or without associated CharDriver, return 0.
  *
  * @cond the condition to poll for
  * @func the function to call when the condition happens
@@ -278,7 +284,7 @@ guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
  * @buf the data
  * @len the number of bytes to send
  *
- * Returns: the number of bytes consumed
+ * Returns: the number of bytes consumed (0 if no assicated CharDriver)
  */
 int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len);
 
@@ -293,7 +299,7 @@ int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len);
  * @buf the data
  * @len the number of bytes to send
  *
- * Returns: the number of bytes consumed
+ * Returns: the number of bytes consumed (0 if no assicated CharDriver)
  */
 int qemu_chr_fe_write_all(CharBackend *be, const uint8_t *buf, int len);
 
@@ -305,7 +311,7 @@ int qemu_chr_fe_write_all(CharBackend *be, const uint8_t *buf, int len);
  * @buf the data buffer
  * @len the number of bytes to read
  *
- * Returns: the number of bytes read
+ * Returns: the number of bytes read (0 if no assicated CharDriver)
  */
 int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len);
 
@@ -317,8 +323,9 @@ int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len);
  * @cmd see CHR_IOCTL_*
  * @arg the data associated with @cmd
  *
- * Returns: if @cmd is not supported by the backend, -ENOTSUP, otherwise the
- *          return value depends on the semantics of @cmd
+ * Returns: if @cmd is not supported by the backend or there is no
+ *          associated CharDriver, -ENOTSUP, otherwise the return
+ *          value depends on the semantics of @cmd
  */
 int qemu_chr_fe_ioctl(CharBackend *be, int cmd, void *arg);
 
@@ -357,7 +364,7 @@ int qemu_chr_fe_get_msgfds(CharBackend *be, int *fds, int num);
  * result in overwriting the fd array with the new value without being send.
  * Upon writing the message the fd array is freed.
  *
- * Returns: -1 if fd passing isn't supported.
+ * Returns: -1 if fd passing isn't supported or no associated CharDriver.
  */
 int qemu_chr_fe_set_msgfds(CharBackend *be, int *fds, int num);
 
@@ -418,7 +425,8 @@ bool qemu_chr_fe_init(CharBackend *b, CharDriverState *s, Error **errp);
 /**
  * @qemu_chr_fe_get_driver:
  *
- * Returns the driver associated with a CharBackend or NULL.
+ * Returns the driver associated with a CharBackend or NULL if no
+ * associated CharDriver.
  */
 CharDriverState *qemu_chr_fe_get_driver(CharBackend *be);
 
@@ -426,6 +434,8 @@ CharDriverState *qemu_chr_fe_get_driver(CharBackend *be);
  * @qemu_chr_fe_deinit:
  *
  * Dissociate the CharBackend from the CharDriver.
+ *
+ * Safe to call without associated CharDriver.
  */
 void qemu_chr_fe_deinit(CharBackend *b);
 
@@ -441,6 +451,8 @@ void qemu_chr_fe_deinit(CharBackend *b);
  *
  * Set the front end char handlers. The front end takes the focus if
  * any of the handler is non-NULL.
+ *
+ * Without associated CharDriver, nothing is changed.
  */
 void qemu_chr_fe_set_handlers(CharBackend *b,
                               IOCanReadHandler *fd_can_read,
@@ -452,7 +464,9 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
 /**
  * @qemu_chr_fe_take_focus:
  *
- * Take the focus (if the front end is muxed)
+ * Take the focus (if the front end is muxed).
+ *
+ * Without associated CharDriver, nothing is changed.
  */
 void qemu_chr_fe_take_focus(CharBackend *b);
 
diff --git a/qemu-char.c b/qemu-char.c
index e5e8038..3bfde82 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -273,6 +273,10 @@ int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len)
     CharDriverState *s = be->chr;
     int ret;
 
+    if (!s) {
+        return 0;
+    }
+
     if (s->replay && replay_mode == REPLAY_MODE_PLAY) {
         int offset;
         replay_char_write_event_load(&ret, &offset);
@@ -325,6 +329,10 @@ int qemu_chr_fe_write_all(CharBackend *be, const uint8_t *buf, int len)
 {
     CharDriverState *s = be->chr;
 
+    if (!s) {
+        return 0;
+    }
+
     return qemu_chr_write_all(s, buf, len);
 }
 
@@ -334,10 +342,10 @@ int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len)
     int offset = 0, counter = 10;
     int res;
 
-    if (!s->chr_sync_read) {
+    if (!s || !s->chr_sync_read) {
         return 0;
     }
-    
+
     if (s->replay && replay_mode == REPLAY_MODE_PLAY) {
         return replay_char_read_all_load(buf);
     }
@@ -378,7 +386,8 @@ int qemu_chr_fe_ioctl(CharBackend *be, int cmd, void *arg)
 {
     CharDriverState *s = be->chr;
     int res;
-    if (!s->chr_ioctl || s->replay) {
+
+    if (!s || !s->chr_ioctl || s->replay) {
         res = -ENOTSUP;
     } else {
         res = s->chr_ioctl(s, cmd, arg);
@@ -418,7 +427,7 @@ int qemu_chr_fe_get_msgfd(CharBackend *be)
     CharDriverState *s = be->chr;
     int fd;
     int res = (qemu_chr_fe_get_msgfds(be, &fd, 1) == 1) ? fd : -1;
-    if (s->replay) {
+    if (s && s->replay) {
         fprintf(stderr,
                 "Replay: get msgfd is not supported for serial devices yet\n");
         exit(1);
@@ -430,6 +439,10 @@ int qemu_chr_fe_get_msgfds(CharBackend *be, int *fds, int len)
 {
     CharDriverState *s = be->chr;
 
+    if (!s) {
+        return -1;
+    }
+
     return s->get_msgfds ? s->get_msgfds(s, fds, len) : -1;
 }
 
@@ -437,6 +450,10 @@ int qemu_chr_fe_set_msgfds(CharBackend *be, int *fds, int num)
 {
     CharDriverState *s = be->chr;
 
+    if (!s) {
+        return -1;
+    }
+
     return s->set_msgfds ? s->set_msgfds(s, fds, num) : -1;
 }
 
@@ -449,6 +466,10 @@ void qemu_chr_fe_accept_input(CharBackend *be)
 {
     CharDriverState *s = be->chr;
 
+    if (!s) {
+        return;
+    }
+
     if (s->chr_accept_input)
         s->chr_accept_input(s);
     qemu_notify_event();
@@ -945,6 +966,10 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
 
 void qemu_chr_fe_take_focus(CharBackend *b)
 {
+    if (!b->chr) {
+        return;
+    }
+
     if (b->chr->is_mux) {
         mux_set_focus(b->chr->opaque, b->tag);
     }
@@ -3347,6 +3372,11 @@ static int qemu_chr_wait_connected(CharDriverState *chr, Error **errp)
 
 int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp)
 {
+    if (!be->chr) {
+        error_setg(errp, "missing associated backend");
+        return -1;
+    }
+
     return qemu_chr_wait_connected(be->chr, errp);
 }
 
@@ -4151,7 +4181,7 @@ void qemu_chr_fe_set_echo(CharBackend *be, bool echo)
 {
     CharDriverState *chr = be->chr;
 
-    if (chr->chr_set_echo) {
+    if (chr && chr->chr_set_echo) {
         chr->chr_set_echo(chr, echo);
     }
 }
@@ -4160,6 +4190,10 @@ void qemu_chr_fe_set_open(CharBackend *be, int fe_open)
 {
     CharDriverState *chr = be->chr;
 
+    if (!chr) {
+        return;
+    }
+
     if (chr->fe_open == fe_open) {
         return;
     }
@@ -4173,7 +4207,7 @@ void qemu_chr_fe_event(CharBackend *be, int event)
 {
     CharDriverState *chr = be->chr;
 
-    if (chr->chr_fe_event) {
+    if (chr && chr->chr_fe_event) {
         chr->chr_fe_event(chr, event);
     }
 }
@@ -4185,7 +4219,7 @@ guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
     GSource *src;
     guint tag;
 
-    if (s->chr_add_watch == NULL) {
+    if (!s || s->chr_add_watch == NULL) {
         return 0;
     }
 
@@ -4205,7 +4239,7 @@ void qemu_chr_fe_disconnect(CharBackend *be)
 {
     CharDriverState *chr = be->chr;
 
-    if (chr->chr_disconnect) {
+    if (chr && chr->chr_disconnect) {
         chr->chr_disconnect(chr);
     }
 }
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 39/50] tests: start chardev unit tests
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (37 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 38/50] char: make some qemu_chr_fe skip if no driver Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 40/50] char: move front end handlers in CharBackend Paolo Bonzini
                   ` (11 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-21-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile.include |   4 +
 tests/test-char.c      | 253 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 257 insertions(+)
 create mode 100644 tests/test-char.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index cbe38ad..e65e9f7 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -8,6 +8,8 @@ SYSEMU_TARGET_LIST := $(subst -softmmu.mak,,$(notdir \
 
 check-unit-y = tests/check-qdict$(EXESUF)
 gcov-files-check-qdict-y = qobject/qdict.c
+check-unit-y = tests/test-char$(EXESUF)
+gcov-files-check-qdict-y = qemu-char.c
 check-unit-y += tests/check-qfloat$(EXESUF)
 gcov-files-check-qfloat-y = qobject/qfloat.c
 check-unit-y += tests/check-qint$(EXESUF)
@@ -481,6 +483,8 @@ tests/check-qnull$(EXESUF): tests/check-qnull.o $(test-util-obj-y)
 tests/check-qjson$(EXESUF): tests/check-qjson.o $(test-util-obj-y)
 tests/check-qom-interface$(EXESUF): tests/check-qom-interface.o $(test-qom-obj-y)
 tests/check-qom-proplist$(EXESUF): tests/check-qom-proplist.o $(test-qom-obj-y)
+
+tests/test-char$(EXESUF): tests/test-char.o qemu-char.o qemu-timer.o $(test-util-obj-y) $(qtest-obj-y) $(test-io-obj-y)
 tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(test-block-obj-y)
 tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y)
 tests/test-rfifolock$(EXESUF): tests/test-rfifolock.o $(test-util-obj-y)
diff --git a/tests/test-char.c b/tests/test-char.c
new file mode 100644
index 0000000..13c55b8
--- /dev/null
+++ b/tests/test-char.c
@@ -0,0 +1,253 @@
+#include "qemu/osdep.h"
+
+#include "qemu-common.h"
+#include "qemu/config-file.h"
+#include "sysemu/char.h"
+#include "sysemu/sysemu.h"
+#include "qapi/error.h"
+#include "qmp-commands.h"
+
+typedef struct FeHandler {
+    int read_count;
+    int last_event;
+    char read_buf[128];
+} FeHandler;
+
+static int fe_can_read(void *opaque)
+{
+    FeHandler *h = opaque;
+
+    return sizeof(h->read_buf) - h->read_count;
+}
+
+static void fe_read(void *opaque, const uint8_t *buf, int size)
+{
+    FeHandler *h = opaque;
+
+    g_assert_cmpint(size, <=, fe_can_read(opaque));
+
+    memcpy(h->read_buf + h->read_count, buf, size);
+    h->read_count += size;
+}
+
+static void fe_event(void *opaque, int event)
+{
+    FeHandler *h = opaque;
+
+    h->last_event = event;
+}
+
+#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
+static void char_stdio_test_subprocess(void)
+{
+    CharDriverState *chr;
+    CharBackend be;
+    int ret;
+
+    chr = qemu_chr_new("label", "stdio");
+    g_assert_nonnull(chr);
+
+    qemu_chr_fe_init(&be, chr, &error_abort);
+    qemu_chr_fe_set_open(&be, true);
+    ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
+    g_assert_cmpint(ret, ==, 4);
+
+    qemu_chr_fe_deinit(&be);
+    qemu_chr_delete(chr);
+}
+
+static void char_stdio_test(void)
+{
+    g_test_trap_subprocess("/char/stdio/subprocess", 0, 0);
+    g_test_trap_assert_passed();
+    g_test_trap_assert_stdout("buf");
+}
+#endif
+
+
+static void char_ringbuf_test(void)
+{
+    QemuOpts *opts;
+    CharDriverState *chr;
+    CharBackend be;
+    char *data;
+    int ret;
+
+    opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
+                            1, &error_abort);
+    qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
+
+    qemu_opt_set(opts, "size", "5", &error_abort);
+    chr = qemu_chr_new_from_opts(opts, NULL);
+    g_assert_null(chr);
+    qemu_opts_del(opts);
+
+    opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
+                            1, &error_abort);
+    qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
+    qemu_opt_set(opts, "size", "2", &error_abort);
+    chr = qemu_chr_new_from_opts(opts, &error_abort);
+    g_assert_nonnull(chr);
+    qemu_opts_del(opts);
+
+    qemu_chr_fe_init(&be, chr, &error_abort);
+    ret = qemu_chr_fe_write(&be, (void *)"buff", 4);
+    g_assert_cmpint(ret, ==, 4);
+
+    data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
+    g_assert_cmpstr(data, ==, "ff");
+    g_free(data);
+
+    data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
+    g_assert_cmpstr(data, ==, "");
+    g_free(data);
+
+    qemu_chr_fe_deinit(&be);
+    qemu_chr_delete(chr);
+}
+
+static void char_mux_test(void)
+{
+    QemuOpts *opts;
+    CharDriverState *chr, *base;
+    char *data;
+    FeHandler h1 = { 0, }, h2 = { 0, };
+    CharBackend chr_be1, chr_be2;
+
+    opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label",
+                            1, &error_abort);
+    qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
+    qemu_opt_set(opts, "size", "128", &error_abort);
+    qemu_opt_set(opts, "mux", "on", &error_abort);
+    chr = qemu_chr_new_from_opts(opts, &error_abort);
+    g_assert_nonnull(chr);
+    qemu_opts_del(opts);
+
+    qemu_chr_fe_init(&chr_be1, chr, &error_abort);
+    qemu_chr_fe_set_handlers(&chr_be1,
+                             fe_can_read,
+                             fe_read,
+                             fe_event,
+                             &h1,
+                             NULL);
+
+    qemu_chr_fe_init(&chr_be2, chr, &error_abort);
+    qemu_chr_fe_set_handlers(&chr_be2,
+                             fe_can_read,
+                             fe_read,
+                             fe_event,
+                             &h2,
+                             NULL);
+    qemu_chr_fe_take_focus(&chr_be2);
+
+    base = qemu_chr_find("mux-label-base");
+    g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0);
+
+    qemu_chr_be_write(base, (void *)"hello", 6);
+    g_assert_cmpint(h1.read_count, ==, 0);
+    g_assert_cmpint(h2.read_count, ==, 6);
+    g_assert_cmpstr(h2.read_buf, ==, "hello");
+    h2.read_count = 0;
+
+    /* switch focus */
+    qemu_chr_be_write(base, (void *)"\1c", 2);
+
+    qemu_chr_be_write(base, (void *)"hello", 6);
+    g_assert_cmpint(h2.read_count, ==, 0);
+    g_assert_cmpint(h1.read_count, ==, 6);
+    g_assert_cmpstr(h1.read_buf, ==, "hello");
+    h1.read_count = 0;
+
+    /* remove first handler */
+    qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL, NULL);
+    qemu_chr_be_write(base, (void *)"hello", 6);
+    g_assert_cmpint(h1.read_count, ==, 0);
+    g_assert_cmpint(h2.read_count, ==, 0);
+
+    qemu_chr_be_write(base, (void *)"\1c", 2);
+    qemu_chr_be_write(base, (void *)"hello", 6);
+    g_assert_cmpint(h1.read_count, ==, 0);
+    g_assert_cmpint(h2.read_count, ==, 6);
+    g_assert_cmpstr(h2.read_buf, ==, "hello");
+    h2.read_count = 0;
+
+    /* print help */
+    qemu_chr_be_write(base, (void *)"\1?", 2);
+    data = qmp_ringbuf_read("mux-label-base", 128, false, 0, &error_abort);
+    g_assert_cmpint(strlen(data), !=, 0);
+    g_free(data);
+
+    qemu_chr_fe_deinit(&chr_be1);
+    qemu_chr_fe_deinit(&chr_be2);
+    qemu_chr_delete(chr);
+}
+
+static void char_null_test(void)
+{
+    Error *err = NULL;
+    CharDriverState *chr;
+    CharBackend be;
+    int ret;
+
+    chr = qemu_chr_find("label-null");
+    g_assert_null(chr);
+
+    chr = qemu_chr_new("label-null", "null");
+    chr = qemu_chr_find("label-null");
+    g_assert_nonnull(chr);
+
+    g_assert(qemu_chr_has_feature(chr,
+                 QEMU_CHAR_FEATURE_FD_PASS) == false);
+    g_assert(qemu_chr_has_feature(chr,
+                 QEMU_CHAR_FEATURE_RECONNECTABLE) == false);
+
+    /* check max avail */
+    qemu_chr_fe_init(&be, chr, &error_abort);
+    qemu_chr_fe_init(&be, chr, &err);
+    error_free_or_abort(&err);
+
+    /* deinit & reinit */
+    qemu_chr_fe_deinit(&be);
+    qemu_chr_fe_init(&be, chr, &error_abort);
+
+    qemu_chr_fe_set_open(&be, true);
+
+    qemu_chr_fe_set_handlers(&be,
+                             fe_can_read,
+                             fe_read,
+                             fe_event,
+                             NULL, NULL);
+
+    ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
+    g_assert_cmpint(ret, ==, 4);
+
+    qemu_chr_fe_deinit(&be);
+    qemu_chr_delete(chr);
+}
+
+static void char_invalid_test(void)
+{
+    CharDriverState *chr;
+
+    chr = qemu_chr_new("label-invalid", "invalid");
+    g_assert_null(chr);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    module_call_init(MODULE_INIT_QOM);
+    qemu_add_opts(&qemu_chardev_opts);
+
+    g_test_add_func("/char/null", char_null_test);
+    g_test_add_func("/char/invalid", char_invalid_test);
+    g_test_add_func("/char/ringbuf", char_ringbuf_test);
+    g_test_add_func("/char/mux", char_mux_test);
+#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
+    g_test_add_func("/char/stdio/subprocess", char_stdio_test_subprocess);
+    g_test_add_func("/char/stdio", char_stdio_test);
+#endif
+
+    return g_test_run();
+}
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 40/50] char: move front end handlers in CharBackend
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (38 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 39/50] tests: start chardev unit tests Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 41/50] char: rename chr_close/chr_free Paolo Bonzini
                   ` (10 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Since the hanlders are associated with a CharBackend, rather than the
CharDriverState, it is more appropriate to store in CharBackend. This
avoids the handler copy dance in qemu_chr_fe_set_handlers() then
mux_chr_update_read_handler(), by storing the CharBackend pointer
directly.

Also a mux CharDriver should go through mux->backends[focused], since
chr->be will stay NULL. Before that, it was possible to call
chr->handler by mistake with surprising results, for ex through
qemu_chr_be_can_write(), which would result in calling the last set
handler front end, not the one with focus.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-22-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/bt/hci-csr.c       |  12 +++--
 include/sysemu/char.h |  11 ++--
 qemu-char.c           | 141 +++++++++++++++++++++++++++++---------------------
 ui/console.c          |   4 +-
 4 files changed, 98 insertions(+), 70 deletions(-)

diff --git a/hw/bt/hci-csr.c b/hw/bt/hci-csr.c
index b77c036..cdf52a9 100644
--- a/hw/bt/hci-csr.c
+++ b/hw/bt/hci-csr.c
@@ -78,15 +78,17 @@ enum {
 
 static inline void csrhci_fifo_wake(struct csrhci_s *s)
 {
+    CharBackend *be = s->chr.be;
+
     if (!s->enable || !s->out_len)
         return;
 
     /* XXX: Should wait for s->modem_state & CHR_TIOCM_RTS? */
-    if (s->chr.chr_can_read && s->chr.chr_can_read(s->chr.handler_opaque) &&
-                    s->chr.chr_read) {
-        s->chr.chr_read(s->chr.handler_opaque,
-                        s->outfifo + s->out_start ++, 1);
-        s->out_len --;
+    if (be && be->chr_can_read && be->chr_can_read(be->opaque) &&
+        be->chr_read) {
+        be->chr_read(be->opaque,
+                     s->outfifo + s->out_start++, 1);
+        s->out_len--;
         if (s->out_start >= s->out_size) {
             s->out_start = 0;
             s->out_size = FIFO_LEN;
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 2f60a10..7187c3e 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -76,6 +76,10 @@ typedef enum {
  * CharDriverState */
 typedef struct CharBackend {
     CharDriverState *chr;
+    IOEventHandler *chr_event;
+    IOCanReadHandler *chr_can_read;
+    IOReadHandler *chr_read;
+    void *opaque;
     int tag;
 } CharBackend;
 
@@ -86,22 +90,19 @@ struct CharDriverState {
                          const uint8_t *buf, int len);
     GSource *(*chr_add_watch)(struct CharDriverState *s, GIOCondition cond);
     void (*chr_update_read_handler)(struct CharDriverState *s,
-                                    GMainContext *context, int tag);
+                                    GMainContext *context);
     int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg);
     int (*get_msgfds)(struct CharDriverState *s, int* fds, int num);
     int (*set_msgfds)(struct CharDriverState *s, int *fds, int num);
     int (*chr_add_client)(struct CharDriverState *chr, int fd);
     int (*chr_wait_connected)(struct CharDriverState *chr, Error **errp);
-    IOEventHandler *chr_event;
-    IOCanReadHandler *chr_can_read;
-    IOReadHandler *chr_read;
-    void *handler_opaque;
     void (*chr_close)(struct CharDriverState *chr);
     void (*chr_disconnect)(struct CharDriverState *chr);
     void (*chr_accept_input)(struct CharDriverState *chr);
     void (*chr_set_echo)(struct CharDriverState *chr, bool echo);
     void (*chr_set_fe_open)(struct CharDriverState *chr, int fe_open);
     void (*chr_fe_event)(struct CharDriverState *chr, int event);
+    CharBackend *be;
     void *opaque;
     char *label;
     char *filename;
diff --git a/qemu-char.c b/qemu-char.c
index 3bfde82..9d106d1 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -192,6 +192,8 @@ CharDriverState *qemu_chr_alloc(ChardevCommon *backend, Error **errp)
 
 void qemu_chr_be_event(CharDriverState *s, int event)
 {
+    CharBackend *be = s->be;
+
     /* Keep track if the char device is open */
     switch (event) {
         case CHR_EVENT_OPENED:
@@ -202,9 +204,11 @@ void qemu_chr_be_event(CharDriverState *s, int event)
             break;
     }
 
-    if (!s->chr_event)
+    if (!be || !be->chr_event) {
         return;
-    s->chr_event(s->handler_opaque, event);
+    }
+
+    be->chr_event(be->opaque, event);
 }
 
 void qemu_chr_be_generic_open(CharDriverState *s)
@@ -398,15 +402,21 @@ int qemu_chr_fe_ioctl(CharBackend *be, int cmd, void *arg)
 
 int qemu_chr_be_can_write(CharDriverState *s)
 {
-    if (!s->chr_can_read)
+    CharBackend *be = s->be;
+
+    if (!be || !be->chr_can_read) {
         return 0;
-    return s->chr_can_read(s->handler_opaque);
+    }
+
+    return be->chr_can_read(be->opaque);
 }
 
 void qemu_chr_be_write_impl(CharDriverState *s, uint8_t *buf, int len)
 {
-    if (s->chr_read) {
-        s->chr_read(s->handler_opaque, buf, len);
+    CharBackend *be = s->be;
+
+    if (be && be->chr_read) {
+        be->chr_read(be->opaque, buf, len);
     }
 }
 
@@ -488,7 +498,6 @@ void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
 }
 
 static void remove_fd_in_watch(CharDriverState *chr);
-static int mux_chr_new_handler_tag(CharDriverState *chr, Error **errp);
 static void mux_chr_set_handlers(CharDriverState *chr, GMainContext *context);
 static void mux_set_focus(MuxDriver *d, int focus);
 
@@ -519,10 +528,7 @@ static CharDriverState *qemu_chr_open_null(const char *id,
 #define MUX_BUFFER_SIZE 32	/* Must be a power of 2.  */
 #define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1)
 struct MuxDriver {
-    IOCanReadHandler *chr_can_read[MAX_MUX];
-    IOReadHandler *chr_read[MAX_MUX];
-    IOEventHandler *chr_event[MAX_MUX];
-    void *ext_opaque[MAX_MUX];
+    CharBackend *backends[MAX_MUX];
     CharBackend chr;
     int focus;
     int mux_cnt;
@@ -625,8 +631,11 @@ static void mux_print_help(CharDriverState *chr)
 
 static void mux_chr_send_event(MuxDriver *d, int mux_nr, int event)
 {
-    if (d->chr_event[mux_nr])
-        d->chr_event[mux_nr](d->ext_opaque[mux_nr], event);
+    CharBackend *be = d->backends[mux_nr];
+
+    if (be && be->chr_event) {
+        be->chr_event(be->opaque, event);
+    }
 }
 
 static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
@@ -677,12 +686,12 @@ static void mux_chr_accept_input(CharDriverState *chr)
 {
     MuxDriver *d = chr->opaque;
     int m = d->focus;
+    CharBackend *be = d->backends[m];
 
-    while (d->prod[m] != d->cons[m] &&
-           d->chr_can_read[m] &&
-           d->chr_can_read[m](d->ext_opaque[m])) {
-        d->chr_read[m](d->ext_opaque[m],
-                       &d->buffer[m][d->cons[m]++ & MUX_BUFFER_MASK], 1);
+    while (be && d->prod[m] != d->cons[m] &&
+           be->chr_can_read && be->chr_can_read(be->opaque)) {
+        be->chr_read(be->opaque,
+                     &d->buffer[m][d->cons[m]++ & MUX_BUFFER_MASK], 1);
     }
 }
 
@@ -691,11 +700,16 @@ static int mux_chr_can_read(void *opaque)
     CharDriverState *chr = opaque;
     MuxDriver *d = chr->opaque;
     int m = d->focus;
+    CharBackend *be = d->backends[m];
 
-    if ((d->prod[m] - d->cons[m]) < MUX_BUFFER_SIZE)
+    if ((d->prod[m] - d->cons[m]) < MUX_BUFFER_SIZE) {
         return 1;
-    if (d->chr_can_read[m])
-        return d->chr_can_read[m](d->ext_opaque[m]);
+    }
+
+    if (be && be->chr_can_read) {
+        return be->chr_can_read(be->opaque);
+    }
+
     return 0;
 }
 
@@ -704,16 +718,17 @@ static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
     CharDriverState *chr = opaque;
     MuxDriver *d = chr->opaque;
     int m = d->focus;
+    CharBackend *be = d->backends[m];
     int i;
 
-    mux_chr_accept_input (opaque);
+    mux_chr_accept_input(opaque);
 
-    for(i = 0; i < size; i++)
+    for (i = 0; i < size; i++)
         if (mux_proc_byte(chr, d, buf[i])) {
             if (d->prod[m] == d->cons[m] &&
-                d->chr_can_read[m] &&
-                d->chr_can_read[m](d->ext_opaque[m]))
-                d->chr_read[m](d->ext_opaque[m], &buf[i], 1);
+                be && be->chr_can_read &&
+                be->chr_can_read(be->opaque))
+                be->chr_read(be->opaque, &buf[i], 1);
             else
                 d->buffer[m][d->prod[m]++ & MUX_BUFFER_MASK] = buf[i];
         }
@@ -730,21 +745,6 @@ static void mux_chr_event(void *opaque, int event)
         mux_chr_send_event(d, i, event);
 }
 
-static void mux_chr_update_read_handler(CharDriverState *chr,
-                                        GMainContext *context,
-                                        int tag)
-{
-    MuxDriver *d = chr->opaque;
-
-    assert(tag >= 0);
-    assert(tag < d->mux_cnt);
-
-    d->ext_opaque[tag] = chr->handler_opaque;
-    d->chr_can_read[tag] = chr->chr_can_read;
-    d->chr_read[tag] = chr->chr_read;
-    d->chr_event[tag] = chr->chr_event;
-}
-
 static bool muxes_realized;
 
 /**
@@ -796,12 +796,19 @@ static GSource *mux_chr_add_watch(CharDriverState *s, GIOCondition cond)
 static void mux_chr_close(struct CharDriverState *chr)
 {
     MuxDriver *d = chr->opaque;
+    int i;
 
+    for (i = 0; i < d->mux_cnt; i++) {
+        CharBackend *be = d->backends[i];
+        if (be) {
+            be->chr = NULL;
+        }
+    }
     qemu_chr_fe_deinit(&d->chr);
     g_free(d);
 }
 
-static int mux_chr_new_handler_tag(CharDriverState *chr, Error **errp)
+static int mux_chr_new_fe(CharDriverState *chr, CharBackend *be, Error **errp)
 {
     MuxDriver *d = chr->opaque;
 
@@ -810,6 +817,8 @@ static int mux_chr_new_handler_tag(CharDriverState *chr, Error **errp)
         return -1;
     }
 
+    d->backends[d->mux_cnt] = be;
+
     return d->mux_cnt++;
 }
 
@@ -864,7 +873,6 @@ static CharDriverState *qemu_chr_open_mux(const char *id,
     d->focus = -1;
     chr->chr_close = mux_chr_close;
     chr->chr_write = mux_chr_write;
-    chr->chr_update_read_handler = mux_chr_update_read_handler;
     chr->chr_accept_input = mux_chr_accept_input;
     /* Frontend guest-open / -close notification is not support with muxes */
     chr->chr_set_fe_open = NULL;
@@ -894,10 +902,12 @@ bool qemu_chr_fe_init(CharBackend *b, CharDriverState *s, Error **errp)
     int tag = 0;
 
     if (s->is_mux) {
-        tag = mux_chr_new_handler_tag(s, errp);
+        tag = mux_chr_new_fe(s, b, errp);
         if (tag < 0) {
             return false;
         }
+    } else {
+        s->be = b;
     }
 
     b->tag = tag;
@@ -906,6 +916,16 @@ bool qemu_chr_fe_init(CharBackend *b, CharDriverState *s, Error **errp)
     return true;
 }
 
+static bool qemu_chr_is_busy(CharDriverState *s)
+{
+    if (s->is_mux) {
+        MuxDriver *d = s->opaque;
+        return d->mux_cnt >= 0;
+    } else {
+        return s->be != NULL;
+    }
+}
+
 void qemu_chr_fe_deinit(CharBackend *b)
 {
     assert(b);
@@ -913,6 +933,11 @@ void qemu_chr_fe_deinit(CharBackend *b)
     if (b->chr) {
         qemu_chr_fe_set_handlers(b, NULL, NULL, NULL, NULL, NULL);
         b->chr->avail_connections++;
+        b->chr->be = NULL;
+        if (b->chr->is_mux) {
+            MuxDriver *d = b->chr->opaque;
+            d->backends[b->tag] = NULL;
+        }
         b->chr = NULL;
     }
 }
@@ -938,12 +963,12 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
     } else {
         fe_open = 1;
     }
-    s->chr_can_read = fd_can_read;
-    s->chr_read = fd_read;
-    s->chr_event = fd_event;
-    s->handler_opaque = opaque;
+    b->chr_can_read = fd_can_read;
+    b->chr_read = fd_read;
+    b->chr_event = fd_event;
+    b->opaque = opaque;
     if (s->chr_update_read_handler) {
-        s->chr_update_read_handler(s, context, b->tag);
+        s->chr_update_read_handler(s, context);
     }
 
     if (!s->explicit_fe_open) {
@@ -1202,8 +1227,7 @@ static GSource *fd_chr_add_watch(CharDriverState *chr, GIOCondition cond)
 }
 
 static void fd_chr_update_read_handler(CharDriverState *chr,
-                                       GMainContext *context,
-                                       int tag)
+                                       GMainContext *context)
 {
     FDCharDriver *s = chr->opaque;
 
@@ -1460,8 +1484,7 @@ static void pty_chr_update_read_handler_locked(CharDriverState *chr)
 }
 
 static void pty_chr_update_read_handler(CharDriverState *chr,
-                                        GMainContext *context,
-                                        int tag)
+                                        GMainContext *context)
 {
     qemu_mutex_lock(&chr->chr_write_lock);
     pty_chr_update_read_handler_locked(chr);
@@ -2707,8 +2730,7 @@ static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
 }
 
 static void udp_chr_update_read_handler(CharDriverState *chr,
-                                        GMainContext *context,
-                                        int tag)
+                                        GMainContext *context)
 {
     NetCharDriver *s = chr->opaque;
 
@@ -3127,8 +3149,7 @@ static void tcp_chr_connect(void *opaque)
 }
 
 static void tcp_chr_update_read_handler(CharDriverState *chr,
-                                        GMainContext *context,
-                                        int tag)
+                                        GMainContext *context)
 {
     TCPCharDriver *s = chr->opaque;
 
@@ -4246,6 +4267,9 @@ void qemu_chr_fe_disconnect(CharBackend *be)
 
 static void qemu_chr_free_common(CharDriverState *chr)
 {
+    if (chr->be) {
+        chr->be->chr = NULL;
+    }
     g_free(chr->filename);
     g_free(chr->label);
     if (chr->logfd != -1) {
@@ -4790,8 +4814,7 @@ void qmp_chardev_remove(const char *id, Error **errp)
         error_setg(errp, "Chardev '%s' not found", id);
         return;
     }
-    if (chr->chr_can_read || chr->chr_read ||
-        chr->chr_event || chr->handler_opaque) {
+    if (qemu_chr_is_busy(chr)) {
         error_setg(errp, "Chardev '%s' is busy", id);
         return;
     }
diff --git a/ui/console.c b/ui/console.c
index 19adac7..f490346 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1083,6 +1083,7 @@ static void kbd_send_chars(void *opaque)
 void kbd_put_keysym_console(QemuConsole *s, int keysym)
 {
     uint8_t buf[16], *q;
+    CharBackend *be;
     int c;
 
     if (!s || (s->console_type == GRAPHIC_CONSOLE))
@@ -1125,7 +1126,8 @@ void kbd_put_keysym_console(QemuConsole *s, int keysym)
         if (s->echo) {
             console_puts(s->chr, buf, q - buf);
         }
-        if (s->chr->chr_read) {
+        be = s->chr->be;
+        if (be && be->chr_read) {
             qemu_fifo_write(&s->out_fifo, buf, q - buf);
             kbd_send_chars(s);
         }
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 41/50] char: rename chr_close/chr_free
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (39 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 40/50] char: move front end handlers in CharBackend Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 42/50] char: remove explicit_fe_open, use a set_handlers argument Paolo Bonzini
                   ` (9 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

The function is used to free the backend opaque pointer, let's name it
accordingly.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-23-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 backends/baum.c       |  4 ++--
 backends/msmouse.c    |  4 ++--
 backends/testdev.c    |  4 ++--
 include/sysemu/char.h |  2 +-
 qemu-char.c           | 58 +++++++++++++++++++++++++--------------------------
 spice-qemu-char.c     |  4 ++--
 6 files changed, 38 insertions(+), 38 deletions(-)

diff --git a/backends/baum.c b/backends/baum.c
index c537141..a516434 100644
--- a/backends/baum.c
+++ b/backends/baum.c
@@ -551,7 +551,7 @@ static void baum_chr_read(void *opaque)
     }
 }
 
-static void baum_close(struct CharDriverState *chr)
+static void baum_free(struct CharDriverState *chr)
 {
     BaumDriverState *baum = chr->opaque;
 
@@ -589,7 +589,7 @@ static CharDriverState *chr_baum_init(const char *id,
     chr->opaque = baum;
     chr->chr_write = baum_write;
     chr->chr_accept_input = baum_accept_input;
-    chr->chr_close = baum_close;
+    chr->chr_free = baum_free;
 
     handle = g_malloc0(brlapi_getHandleSize());
     baum->brlapi = handle;
diff --git a/backends/msmouse.c b/backends/msmouse.c
index 85d08f7..448369f 100644
--- a/backends/msmouse.c
+++ b/backends/msmouse.c
@@ -133,7 +133,7 @@ static int msmouse_chr_write (struct CharDriverState *s, const uint8_t *buf, int
     return len;
 }
 
-static void msmouse_chr_close (struct CharDriverState *chr)
+static void msmouse_chr_free(struct CharDriverState *chr)
 {
     MouseState *mouse = chr->opaque;
 
@@ -162,7 +162,7 @@ static CharDriverState *qemu_chr_open_msmouse(const char *id,
         return NULL;
     }
     chr->chr_write = msmouse_chr_write;
-    chr->chr_close = msmouse_chr_close;
+    chr->chr_free = msmouse_chr_free;
     chr->chr_accept_input = msmouse_chr_accept_input;
     chr->explicit_be_open = true;
 
diff --git a/backends/testdev.c b/backends/testdev.c
index 3ab1c90..1ba8bf2 100644
--- a/backends/testdev.c
+++ b/backends/testdev.c
@@ -102,7 +102,7 @@ static int testdev_write(CharDriverState *chr, const uint8_t *buf, int len)
     return orig_len;
 }
 
-static void testdev_close(struct CharDriverState *chr)
+static void testdev_free(struct CharDriverState *chr)
 {
     TestdevCharState *testdev = chr->opaque;
 
@@ -122,7 +122,7 @@ static CharDriverState *chr_testdev_init(const char *id,
 
     chr->opaque = testdev;
     chr->chr_write = testdev_write;
-    chr->chr_close = testdev_close;
+    chr->chr_free = testdev_free;
 
     return chr;
 }
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 7187c3e..d029d54 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -96,7 +96,7 @@ struct CharDriverState {
     int (*set_msgfds)(struct CharDriverState *s, int *fds, int num);
     int (*chr_add_client)(struct CharDriverState *chr, int fd);
     int (*chr_wait_connected)(struct CharDriverState *chr, Error **errp);
-    void (*chr_close)(struct CharDriverState *chr);
+    void (*chr_free)(struct CharDriverState *chr);
     void (*chr_disconnect)(struct CharDriverState *chr);
     void (*chr_accept_input)(struct CharDriverState *chr);
     void (*chr_set_echo)(struct CharDriverState *chr, bool echo);
diff --git a/qemu-char.c b/qemu-char.c
index 9d106d1..af060ce 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -793,7 +793,7 @@ static GSource *mux_chr_add_watch(CharDriverState *s, GIOCondition cond)
     return chr->chr_add_watch(chr, cond);
 }
 
-static void mux_chr_close(struct CharDriverState *chr)
+static void mux_chr_free(struct CharDriverState *chr)
 {
     MuxDriver *d = chr->opaque;
     int i;
@@ -871,7 +871,7 @@ static CharDriverState *qemu_chr_open_mux(const char *id,
 
     chr->opaque = d;
     d->focus = -1;
-    chr->chr_close = mux_chr_close;
+    chr->chr_free = mux_chr_free;
     chr->chr_write = mux_chr_write;
     chr->chr_accept_input = mux_chr_accept_input;
     /* Frontend guest-open / -close notification is not support with muxes */
@@ -1240,7 +1240,7 @@ static void fd_chr_update_read_handler(CharDriverState *chr,
     }
 }
 
-static void fd_chr_close(struct CharDriverState *chr)
+static void fd_chr_free(struct CharDriverState *chr)
 {
     FDCharDriver *s = chr->opaque;
 
@@ -1276,7 +1276,7 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out,
     chr->chr_add_watch = fd_chr_add_watch;
     chr->chr_write = fd_chr_write;
     chr->chr_update_read_handler = fd_chr_update_read_handler;
-    chr->chr_close = fd_chr_close;
+    chr->chr_free = fd_chr_free;
 
     return chr;
 }
@@ -1357,10 +1357,10 @@ static void qemu_chr_set_echo_stdio(CharDriverState *chr, bool echo)
     tcsetattr (0, TCSANOW, &tty);
 }
 
-static void qemu_chr_close_stdio(struct CharDriverState *chr)
+static void qemu_chr_free_stdio(struct CharDriverState *chr)
 {
     term_exit();
-    fd_chr_close(chr);
+    fd_chr_free(chr);
 }
 
 static CharDriverState *qemu_chr_open_stdio(const char *id,
@@ -1397,7 +1397,7 @@ static CharDriverState *qemu_chr_open_stdio(const char *id,
     if (!chr) {
         return NULL;
     }
-    chr->chr_close = qemu_chr_close_stdio;
+    chr->chr_free = qemu_chr_free_stdio;
     chr->chr_set_echo = qemu_chr_set_echo_stdio;
     if (opts->has_signal) {
         stdio_allow_signal = opts->signal;
@@ -1594,7 +1594,7 @@ static void pty_chr_state(CharDriverState *chr, int connected)
     }
 }
 
-static void pty_chr_close(struct CharDriverState *chr)
+static void pty_chr_free(struct CharDriverState *chr)
 {
     PtyCharDriver *s = chr->opaque;
 
@@ -1647,7 +1647,7 @@ static CharDriverState *qemu_chr_open_pty(const char *id,
     chr->opaque = s;
     chr->chr_write = pty_chr_write;
     chr->chr_update_read_handler = pty_chr_update_read_handler;
-    chr->chr_close = pty_chr_close;
+    chr->chr_free = pty_chr_free;
     chr->chr_add_watch = pty_chr_add_watch;
     chr->explicit_be_open = true;
 
@@ -1842,9 +1842,9 @@ static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
     return 0;
 }
 
-static void qemu_chr_close_tty(CharDriverState *chr)
+static void qemu_chr_free_tty(CharDriverState *chr)
 {
-    fd_chr_close(chr);
+    fd_chr_free(chr);
 }
 
 static CharDriverState *qemu_chr_open_tty_fd(int fd,
@@ -1859,7 +1859,7 @@ static CharDriverState *qemu_chr_open_tty_fd(int fd,
         return NULL;
     }
     chr->chr_ioctl = tty_serial_ioctl;
-    chr->chr_close = qemu_chr_close_tty;
+    chr->chr_free = qemu_chr_free_tty;
     return chr;
 }
 #endif /* __linux__ || __sun__ */
@@ -1965,7 +1965,7 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
     return 0;
 }
 
-static void pp_close(CharDriverState *chr)
+static void pp_free(CharDriverState *chr)
 {
     ParallelCharDriver *drv = chr->opaque;
     int fd = drv->fd;
@@ -1999,7 +1999,7 @@ static CharDriverState *qemu_chr_open_pp_fd(int fd,
     chr->opaque = drv;
     chr->chr_write = null_chr_write;
     chr->chr_ioctl = pp_ioctl;
-    chr->chr_close = pp_close;
+    chr->chr_free = pp_free;
 
     drv->fd = fd;
     drv->mode = IEEE1284_MODE_COMPAT;
@@ -2098,7 +2098,7 @@ typedef struct {
 static int win_chr_poll(void *opaque);
 static int win_chr_pipe_poll(void *opaque);
 
-static void win_chr_close(CharDriverState *chr)
+static void win_chr_free(CharDriverState *chr)
 {
     WinCharState *s = chr->opaque;
 
@@ -2185,7 +2185,7 @@ static int win_chr_init(CharDriverState *chr, const char *filename, Error **errp
     return 0;
 
  fail:
-    win_chr_close(chr);
+    win_chr_free(chr);
     return -1;
 }
 
@@ -2297,7 +2297,7 @@ static CharDriverState *qemu_chr_open_win_path(const char *filename,
     s = g_new0(WinCharState, 1);
     chr->opaque = s;
     chr->chr_write = win_chr_write;
-    chr->chr_close = win_chr_close;
+    chr->chr_free = win_chr_free;
 
     if (win_chr_init(chr, filename, errp) < 0) {
         g_free(s);
@@ -2383,7 +2383,7 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename,
     return 0;
 
  fail:
-    win_chr_close(chr);
+    win_chr_free(chr);
     return -1;
 }
 
@@ -2406,7 +2406,7 @@ static CharDriverState *qemu_chr_open_pipe(const char *id,
     s = g_new0(WinCharState, 1);
     chr->opaque = s;
     chr->chr_write = win_chr_write;
-    chr->chr_close = win_chr_close;
+    chr->chr_free = win_chr_free;
 
     if (win_chr_pipe_init(chr, filename, errp) < 0) {
         g_free(s);
@@ -2562,7 +2562,7 @@ static void qemu_chr_set_echo_win_stdio(CharDriverState *chr, bool echo)
     }
 }
 
-static void win_stdio_close(CharDriverState *chr)
+static void win_stdio_free(CharDriverState *chr)
 {
     WinStdioCharState *stdio = chr->opaque;
 
@@ -2606,7 +2606,7 @@ static CharDriverState *qemu_chr_open_stdio(const char *id,
 
     chr->opaque    = stdio;
     chr->chr_write = win_stdio_write;
-    chr->chr_close = win_stdio_close;
+    chr->chr_free = win_stdio_free;
 
     if (is_console) {
         if (qemu_add_wait_object(stdio->hStdIn,
@@ -2743,7 +2743,7 @@ static void udp_chr_update_read_handler(CharDriverState *chr,
     }
 }
 
-static void udp_chr_close(CharDriverState *chr)
+static void udp_chr_free(CharDriverState *chr)
 {
     NetCharDriver *s = chr->opaque;
 
@@ -2774,7 +2774,7 @@ static CharDriverState *qemu_chr_open_udp(QIOChannelSocket *sioc,
     chr->opaque = s;
     chr->chr_write = udp_chr_write;
     chr->chr_update_read_handler = udp_chr_update_read_handler;
-    chr->chr_close = udp_chr_close;
+    chr->chr_free = udp_chr_free;
     /* be isn't opened until we get a connection */
     chr->explicit_be_open = true;
     return chr;
@@ -3401,7 +3401,7 @@ int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp)
     return qemu_chr_wait_connected(be->chr, errp);
 }
 
-static void tcp_chr_close(CharDriverState *chr)
+static void tcp_chr_free(CharDriverState *chr)
 {
     TCPCharDriver *s = chr->opaque;
 
@@ -3496,7 +3496,7 @@ static int ringbuf_chr_read(CharDriverState *chr, uint8_t *buf, int len)
     return i;
 }
 
-static void ringbuf_chr_close(struct CharDriverState *chr)
+static void ringbuf_chr_free(struct CharDriverState *chr)
 {
     RingBufCharDriver *d = chr->opaque;
 
@@ -3535,7 +3535,7 @@ static CharDriverState *qemu_chr_open_ringbuf(const char *id,
 
     chr->opaque = d;
     chr->chr_write = ringbuf_chr_write;
-    chr->chr_close = ringbuf_chr_close;
+    chr->chr_free = ringbuf_chr_free;
 
     return chr;
 
@@ -4281,8 +4281,8 @@ static void qemu_chr_free_common(CharDriverState *chr)
 
 void qemu_chr_free(CharDriverState *chr)
 {
-    if (chr->chr_close) {
-        chr->chr_close(chr);
+    if (chr->chr_free) {
+        chr->chr_free(chr);
     }
     qemu_chr_free_common(chr);
 }
@@ -4661,7 +4661,7 @@ static CharDriverState *qmp_chardev_open_socket(const char *id,
     chr->chr_wait_connected = tcp_chr_wait_connected;
     chr->chr_write = tcp_chr_write;
     chr->chr_sync_read = tcp_chr_sync_read;
-    chr->chr_close = tcp_chr_close;
+    chr->chr_free = tcp_chr_free;
     chr->chr_disconnect = tcp_chr_disconnect;
     chr->get_msgfds = tcp_get_msgfds;
     chr->set_msgfds = tcp_set_msgfds;
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index 351fcaa..930b8c5 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -199,7 +199,7 @@ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
     return read_bytes;
 }
 
-static void spice_chr_close(struct CharDriverState *chr)
+static void spice_chr_free(struct CharDriverState *chr)
 {
     SpiceCharDriver *s = chr->opaque;
 
@@ -289,7 +289,7 @@ static CharDriverState *chr_open(const char *subtype,
     chr->opaque = s;
     chr->chr_write = spice_chr_write;
     chr->chr_add_watch = spice_chr_add_watch;
-    chr->chr_close = spice_chr_close;
+    chr->chr_free = spice_chr_free;
     chr->chr_set_fe_open = set_fe_open;
     chr->explicit_be_open = true;
     chr->chr_fe_event = spice_chr_fe_event;
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 42/50] char: remove explicit_fe_open, use a set_handlers argument
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (40 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 41/50] char: rename chr_close/chr_free Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 43/50] char: move fe_open in CharBackend Paolo Bonzini
                   ` (8 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

No need to keep explicit_fe_open around if it affects only a
qemu_chr_fe_set_handlers(). Use an additional argument instead.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022095318.17775-24-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 backends/rng-egd.c          |  2 +-
 gdbstub.c                   |  2 +-
 hw/arm/pxa2xx.c             |  2 +-
 hw/arm/strongarm.c          |  2 +-
 hw/char/bcm2835_aux.c       |  2 +-
 hw/char/cadence_uart.c      |  2 +-
 hw/char/debugcon.c          |  2 +-
 hw/char/digic-uart.c        |  2 +-
 hw/char/escc.c              |  2 +-
 hw/char/etraxfs_ser.c       |  2 +-
 hw/char/exynos4210_uart.c   |  2 +-
 hw/char/grlib_apbuart.c     |  2 +-
 hw/char/imx_serial.c        |  2 +-
 hw/char/ipoctal232.c        |  3 ++-
 hw/char/lm32_juart.c        |  2 +-
 hw/char/lm32_uart.c         |  2 +-
 hw/char/mcf_uart.c          |  3 ++-
 hw/char/milkymist-uart.c    |  2 +-
 hw/char/pl011.c             |  2 +-
 hw/char/sclpconsole-lm.c    |  2 +-
 hw/char/sclpconsole.c       |  2 +-
 hw/char/serial.c            |  2 +-
 hw/char/sh_serial.c         |  2 +-
 hw/char/spapr_vty.c         |  2 +-
 hw/char/stm32f2xx_usart.c   |  2 +-
 hw/char/virtio-console.c    |  6 ++----
 hw/char/xen_console.c       |  2 +-
 hw/char/xilinx_uartlite.c   |  2 +-
 hw/ipmi/ipmi_bmc_extern.c   |  2 +-
 hw/mips/mips_malta.c        |  2 +-
 hw/misc/ivshmem.c           |  2 +-
 hw/usb/ccid-card-passthru.c |  2 +-
 hw/usb/dev-serial.c         |  2 +-
 hw/usb/redirect.c           |  2 +-
 include/sysemu/char.h       |  6 ++++--
 monitor.c                   |  4 ++--
 net/colo-compare.c          | 10 ++++++----
 net/filter-mirror.c         |  8 +++++---
 net/slirp.c                 |  2 +-
 net/vhost-user.c            |  2 +-
 qemu-char.c                 |  9 +++++----
 qtest.c                     |  2 +-
 tests/test-char.c           |  8 ++++----
 tests/vhost-user-test.c     |  2 +-
 44 files changed, 67 insertions(+), 60 deletions(-)

diff --git a/backends/rng-egd.c b/backends/rng-egd.c
index 433f583..69c04b1 100644
--- a/backends/rng-egd.c
+++ b/backends/rng-egd.c
@@ -106,7 +106,7 @@ static void rng_egd_opened(RngBackend *b, Error **errp)
 
     /* FIXME we should resubmit pending requests when the CDS reconnects. */
     qemu_chr_fe_set_handlers(&s->chr, rng_egd_chr_can_read,
-                             rng_egd_chr_read, NULL, s, NULL);
+                             rng_egd_chr_read, NULL, s, NULL, true);
 }
 
 static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)
diff --git a/gdbstub.c b/gdbstub.c
index 5944494..b2e1b79 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1779,7 +1779,7 @@ int gdbserver_start(const char *device)
     if (chr) {
         qemu_chr_fe_init(&s->chr, chr, &error_abort);
         qemu_chr_fe_set_handlers(&s->chr, gdb_chr_can_receive, gdb_chr_receive,
-                                 gdb_chr_event, NULL, NULL);
+                                 gdb_chr_event, NULL, NULL, true);
     }
     s->state = chr ? RS_IDLE : RS_INACTIVE;
     s->mon_chr = mon_chr;
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index c9f4503..42cdde0 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -1976,7 +1976,7 @@ static void pxa2xx_fir_realize(DeviceState *dev, Error **errp)
     PXA2xxFIrState *s = PXA2XX_FIR(dev);
 
     qemu_chr_fe_set_handlers(&s->chr, pxa2xx_fir_is_empty,
-                             pxa2xx_fir_rx, pxa2xx_fir_event, s, NULL);
+                             pxa2xx_fir_rx, pxa2xx_fir_event, s, NULL, true);
 }
 
 static bool pxa2xx_fir_vmstate_validate(void *opaque, int version_id)
diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c
index 370198a..85db1e2 100644
--- a/hw/arm/strongarm.c
+++ b/hw/arm/strongarm.c
@@ -1241,7 +1241,7 @@ static void strongarm_uart_init(Object *obj)
                              strongarm_uart_can_receive,
                              strongarm_uart_receive,
                              strongarm_uart_event,
-                             s, NULL);
+                             s, NULL, true);
 }
 
 static void strongarm_uart_reset(DeviceState *dev)
diff --git a/hw/char/bcm2835_aux.c b/hw/char/bcm2835_aux.c
index af329aa..4d46ad6 100644
--- a/hw/char/bcm2835_aux.c
+++ b/hw/char/bcm2835_aux.c
@@ -279,7 +279,7 @@ static void bcm2835_aux_realize(DeviceState *dev, Error **errp)
     BCM2835AuxState *s = BCM2835_AUX(dev);
 
     qemu_chr_fe_set_handlers(&s->chr, bcm2835_aux_can_receive,
-                             bcm2835_aux_receive, NULL, s, NULL);
+                             bcm2835_aux_receive, NULL, s, NULL, true);
 }
 
 static Property bcm2835_aux_props[] = {
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
index 291818e..c2b9154 100644
--- a/hw/char/cadence_uart.c
+++ b/hw/char/cadence_uart.c
@@ -467,7 +467,7 @@ static void cadence_uart_realize(DeviceState *dev, Error **errp)
                                           fifo_trigger_update, s);
 
     qemu_chr_fe_set_handlers(&s->chr, uart_can_receive, uart_receive,
-                             uart_event, s, NULL);
+                             uart_event, s, NULL, true);
 }
 
 static void cadence_uart_init(Object *obj)
diff --git a/hw/char/debugcon.c b/hw/char/debugcon.c
index 2009c3e..80dce07 100644
--- a/hw/char/debugcon.c
+++ b/hw/char/debugcon.c
@@ -92,7 +92,7 @@ static void debugcon_realize_core(DebugconState *s, Error **errp)
         return;
     }
 
-    qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, s, NULL);
+    qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, s, NULL, true);
 }
 
 static void debugcon_isa_realizefn(DeviceState *dev, Error **errp)
diff --git a/hw/char/digic-uart.c b/hw/char/digic-uart.c
index 2955e19..029f5bb 100644
--- a/hw/char/digic-uart.c
+++ b/hw/char/digic-uart.c
@@ -146,7 +146,7 @@ static void digic_uart_realize(DeviceState *dev, Error **errp)
     DigicUartState *s = DIGIC_UART(dev);
 
     qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
-                             uart_event, s, NULL);
+                             uart_event, s, NULL, true);
 }
 
 static void digic_uart_init(Object *obj)
diff --git a/hw/char/escc.c b/hw/char/escc.c
index c71b0a8..d6662dc 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -1016,7 +1016,7 @@ static void escc_realize(DeviceState *dev, Error **errp)
             s->chn[i].clock = s->frequency / 2;
             qemu_chr_fe_set_handlers(&s->chn[i].chr, serial_can_receive,
                                      serial_receive1, serial_event,
-                                     &s->chn[i], NULL);
+                                     &s->chn[i], NULL, true);
         }
     }
 
diff --git a/hw/char/etraxfs_ser.c b/hw/char/etraxfs_ser.c
index 18c374b..5438387 100644
--- a/hw/char/etraxfs_ser.c
+++ b/hw/char/etraxfs_ser.c
@@ -233,7 +233,7 @@ static void etraxfs_ser_realize(DeviceState *dev, Error **errp)
 
     qemu_chr_fe_set_handlers(&s->chr,
                              serial_can_receive, serial_receive,
-                             serial_event, s, NULL);
+                             serial_event, s, NULL, true);
 }
 
 static void etraxfs_ser_class_init(ObjectClass *klass, void *data)
diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
index 48216b1..571c324 100644
--- a/hw/char/exynos4210_uart.c
+++ b/hw/char/exynos4210_uart.c
@@ -642,7 +642,7 @@ static int exynos4210_uart_init(SysBusDevice *dev)
 
     qemu_chr_fe_set_handlers(&s->chr, exynos4210_uart_can_receive,
                              exynos4210_uart_receive, exynos4210_uart_event,
-                             s, NULL);
+                             s, NULL, true);
 
     return 0;
 }
diff --git a/hw/char/grlib_apbuart.c b/hw/char/grlib_apbuart.c
index e50d65b..db686e6 100644
--- a/hw/char/grlib_apbuart.c
+++ b/hw/char/grlib_apbuart.c
@@ -247,7 +247,7 @@ static int grlib_apbuart_init(SysBusDevice *dev)
                              grlib_apbuart_can_receive,
                              grlib_apbuart_receive,
                              grlib_apbuart_event,
-                             uart, NULL);
+                             uart, NULL, true);
 
     sysbus_init_irq(dev, &uart->irq);
 
diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c
index 8dbb7b2..99545fc 100644
--- a/hw/char/imx_serial.c
+++ b/hw/char/imx_serial.c
@@ -316,7 +316,7 @@ static void imx_serial_realize(DeviceState *dev, Error **errp)
     DPRINTF("char dev for uart: %p\n", qemu_chr_fe_get_driver(&s->chr));
 
     qemu_chr_fe_set_handlers(&s->chr, imx_can_receive, imx_receive,
-                             imx_event, s, NULL);
+                             imx_event, s, NULL, true);
 }
 
 static void imx_serial_init(Object *obj)
diff --git a/hw/char/ipoctal232.c b/hw/char/ipoctal232.c
index 6f150e0..93929c2 100644
--- a/hw/char/ipoctal232.c
+++ b/hw/char/ipoctal232.c
@@ -544,7 +544,8 @@ static void ipoctal_realize(DeviceState *dev, Error **errp)
         /* Redirect IP-Octal channels to host character devices */
         if (qemu_chr_fe_get_driver(&ch->dev)) {
             qemu_chr_fe_set_handlers(&ch->dev, hostdev_can_receive,
-                                     hostdev_receive, hostdev_event, ch, NULL);
+                                     hostdev_receive, hostdev_event,
+                                     ch, NULL, true);
             DPRINTF("Redirecting channel %u to %s\n", i, ch->dev->label);
         } else {
             DPRINTF("Could not redirect channel %u, no chardev set\n", i);
diff --git a/hw/char/lm32_juart.c b/hw/char/lm32_juart.c
index febb412..f8c1e0d 100644
--- a/hw/char/lm32_juart.c
+++ b/hw/char/lm32_juart.c
@@ -119,7 +119,7 @@ static void lm32_juart_realize(DeviceState *dev, Error **errp)
     LM32JuartState *s = LM32_JUART(dev);
 
     qemu_chr_fe_set_handlers(&s->chr, juart_can_rx, juart_rx,
-                             juart_event, s, NULL);
+                             juart_event, s, NULL, true);
 }
 
 static const VMStateDescription vmstate_lm32_juart = {
diff --git a/hw/char/lm32_uart.c b/hw/char/lm32_uart.c
index 1b2746f..7f3597c 100644
--- a/hw/char/lm32_uart.c
+++ b/hw/char/lm32_uart.c
@@ -266,7 +266,7 @@ static void lm32_uart_realize(DeviceState *dev, Error **errp)
     LM32UartState *s = LM32_UART(dev);
 
     qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
-                             uart_event, s, NULL);
+                             uart_event, s, NULL, true);
 }
 
 static const VMStateDescription vmstate_lm32_uart = {
diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c
index 456591a..ecaa091 100644
--- a/hw/char/mcf_uart.c
+++ b/hw/char/mcf_uart.c
@@ -284,7 +284,8 @@ void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
     if (chr) {
         qemu_chr_fe_init(&s->chr, chr, &error_abort);
         qemu_chr_fe_set_handlers(&s->chr, mcf_uart_can_receive,
-                                 mcf_uart_receive, mcf_uart_event, s, NULL);
+                                 mcf_uart_receive, mcf_uart_event,
+                                 s, NULL, true);
     }
     mcf_uart_reset(s);
     return s;
diff --git a/hw/char/milkymist-uart.c b/hw/char/milkymist-uart.c
index dec0a8c..ae8e2f3 100644
--- a/hw/char/milkymist-uart.c
+++ b/hw/char/milkymist-uart.c
@@ -199,7 +199,7 @@ static void milkymist_uart_realize(DeviceState *dev, Error **errp)
     MilkymistUartState *s = MILKYMIST_UART(dev);
 
     qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
-                             uart_event, s, NULL);
+                             uart_event, s, NULL, true);
 }
 
 static void milkymist_uart_init(Object *obj)
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
index 900ee5d..24ea973 100644
--- a/hw/char/pl011.c
+++ b/hw/char/pl011.c
@@ -329,7 +329,7 @@ static void pl011_realize(DeviceState *dev, Error **errp)
     PL011State *s = PL011(dev);
 
     qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
-                             pl011_event, s, NULL);
+                             pl011_event, s, NULL, true);
 }
 
 static void pl011_class_init(ObjectClass *oc, void *data)
diff --git a/hw/char/sclpconsole-lm.c b/hw/char/sclpconsole-lm.c
index 7191717..07d6ebd 100644
--- a/hw/char/sclpconsole-lm.c
+++ b/hw/char/sclpconsole-lm.c
@@ -313,7 +313,7 @@ static int console_init(SCLPEvent *event)
     console_available = true;
 
     qemu_chr_fe_set_handlers(&scon->chr, chr_can_read,
-                             chr_read, NULL, scon, NULL);
+                             chr_read, NULL, scon, NULL, true);
 
     return 0;
 }
diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c
index 27a6034..b78f240 100644
--- a/hw/char/sclpconsole.c
+++ b/hw/char/sclpconsole.c
@@ -228,7 +228,7 @@ static int console_init(SCLPEvent *event)
     }
     console_available = true;
     qemu_chr_fe_set_handlers(&scon->chr, chr_can_read,
-                             chr_read, NULL, scon, NULL);
+                             chr_read, NULL, scon, NULL, true);
 
     return 0;
 }
diff --git a/hw/char/serial.c b/hw/char/serial.c
index 54f80c6..ffbacd8 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -897,7 +897,7 @@ void serial_realize_core(SerialState *s, Error **errp)
     qemu_register_reset(serial_reset, s);
 
     qemu_chr_fe_set_handlers(&s->chr, serial_can_receive1, serial_receive1,
-                             serial_event, s, NULL);
+                             serial_event, s, NULL, true);
     fifo8_create(&s->recv_fifo, UART_FIFO_LENGTH);
     fifo8_create(&s->xmit_fifo, UART_FIFO_LENGTH);
     serial_reset(s);
diff --git a/hw/char/sh_serial.c b/hw/char/sh_serial.c
index 8bb45db..9d35564 100644
--- a/hw/char/sh_serial.c
+++ b/hw/char/sh_serial.c
@@ -400,7 +400,7 @@ void sh_serial_init(MemoryRegion *sysmem,
         qemu_chr_fe_init(&s->chr, chr, &error_abort);
         qemu_chr_fe_set_handlers(&s->chr, sh_serial_can_receive1,
                                  sh_serial_receive1,
-                                 sh_serial_event, s, NULL);
+                                 sh_serial_event, s, NULL, true);
     }
 
     s->eri = eri_source;
diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c
index 8d39d40..31822fe 100644
--- a/hw/char/spapr_vty.c
+++ b/hw/char/spapr_vty.c
@@ -75,7 +75,7 @@ static void spapr_vty_realize(VIOsPAPRDevice *sdev, Error **errp)
     }
 
     qemu_chr_fe_set_handlers(&dev->chardev, vty_can_receive,
-                             vty_receive, NULL, dev, NULL);
+                             vty_receive, NULL, dev, NULL, true);
 }
 
 /* Forward declaration */
diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c
index 8e9852b..59872e6 100644
--- a/hw/char/stm32f2xx_usart.c
+++ b/hw/char/stm32f2xx_usart.c
@@ -207,7 +207,7 @@ static void stm32f2xx_usart_realize(DeviceState *dev, Error **errp)
     STM32F2XXUsartState *s = STM32F2XX_USART(dev);
 
     qemu_chr_fe_set_handlers(&s->chr, stm32f2xx_usart_can_receive,
-                             stm32f2xx_usart_receive, NULL, s, NULL);
+                             stm32f2xx_usart_receive, NULL, s, NULL, true);
 }
 
 static void stm32f2xx_usart_class_init(ObjectClass *klass, void *data)
diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c
index 378c1c1..776205b 100644
--- a/hw/char/virtio-console.c
+++ b/hw/char/virtio-console.c
@@ -187,14 +187,12 @@ static void virtconsole_realize(DeviceState *dev, Error **errp)
          * trigger open/close of the device
          */
         if (k->is_console) {
-            chr->explicit_fe_open = 0;
             qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read,
-                                     NULL, vcon, NULL);
+                                     NULL, vcon, NULL, true);
             virtio_serial_open(port);
         } else {
-            chr->explicit_fe_open = 1;
             qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read,
-                                     chr_event, vcon, NULL);
+                                     chr_event, vcon, NULL, false);
         }
     }
 }
diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c
index 785bf86..86cdc52 100644
--- a/hw/char/xen_console.c
+++ b/hw/char/xen_console.c
@@ -245,7 +245,7 @@ static int con_initialise(struct XenDevice *xendev)
 
     xen_be_bind_evtchn(&con->xendev);
     qemu_chr_fe_set_handlers(&con->chr, xencons_can_receive,
-                             xencons_receive, NULL, con, NULL);
+                             xencons_receive, NULL, con, NULL, true);
 
     xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n",
 		  con->ring_ref,
diff --git a/hw/char/xilinx_uartlite.c b/hw/char/xilinx_uartlite.c
index c7888f7..37d313b 100644
--- a/hw/char/xilinx_uartlite.c
+++ b/hw/char/xilinx_uartlite.c
@@ -212,7 +212,7 @@ static void xilinx_uartlite_realize(DeviceState *dev, Error **errp)
     XilinxUARTLite *s = XILINX_UARTLITE(dev);
 
     qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
-                             uart_event, s, NULL);
+                             uart_event, s, NULL, true);
 }
 
 static void xilinx_uartlite_init(Object *obj)
diff --git a/hw/ipmi/ipmi_bmc_extern.c b/hw/ipmi/ipmi_bmc_extern.c
index 5530870..4b310e5 100644
--- a/hw/ipmi/ipmi_bmc_extern.c
+++ b/hw/ipmi/ipmi_bmc_extern.c
@@ -448,7 +448,7 @@ static void ipmi_bmc_extern_realize(DeviceState *dev, Error **errp)
     }
 
     qemu_chr_fe_set_handlers(&ibe->chr, can_receive, receive,
-                             chr_event, ibe, NULL);
+                             chr_event, ibe, NULL, true);
 }
 
 static int ipmi_bmc_extern_post_migrate(void *opaque, int version_id)
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index 273ec6d..cf9bd3e 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -572,7 +572,7 @@ static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
     chr = qemu_chr_new("fpga", "vc:320x200");
     qemu_chr_fe_init(&s->display, chr, NULL);
     qemu_chr_fe_set_handlers(&s->display, NULL, NULL,
-                             malta_fgpa_display_event, s, NULL);
+                             malta_fgpa_display_event, s, NULL, true);
 
     s->uart = serial_mm_init(address_space, base + 0x900, 3, uart_irq,
                              230400, uart_chr, DEVICE_NATIVE_ENDIAN);
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index bb70704..230e51b 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -895,7 +895,7 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
         }
 
         qemu_chr_fe_set_handlers(&s->server_chr, ivshmem_can_receive,
-                                 ivshmem_read, NULL, s, NULL);
+                                 ivshmem_read, NULL, s, NULL, true);
 
         if (ivshmem_setup_interrupts(s) < 0) {
             error_setg(errp, "failed to initialize interrupts");
diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c
index 369a8f1..1faef0e 100644
--- a/hw/usb/ccid-card-passthru.c
+++ b/hw/usb/ccid-card-passthru.c
@@ -353,7 +353,7 @@ static int passthru_initfn(CCIDCardState *base)
         qemu_chr_fe_set_handlers(&card->cs,
             ccid_card_vscard_can_read,
             ccid_card_vscard_read,
-            ccid_card_vscard_event, card, NULL);
+            ccid_card_vscard_event, card, NULL, true);
         ccid_card_vscard_send_init(card);
     } else {
         error_report("missing chardev");
diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c
index a69b9a3..ef1e1ad 100644
--- a/hw/usb/dev-serial.c
+++ b/hw/usb/dev-serial.c
@@ -503,7 +503,7 @@ static void usb_serial_realize(USBDevice *dev, Error **errp)
     }
 
     qemu_chr_fe_set_handlers(&s->cs, usb_serial_can_read, usb_serial_read,
-                             usb_serial_event, s, NULL);
+                             usb_serial_event, s, NULL, true);
     usb_serial_handle_reset(dev);
 
     if (chr->be_open && !dev->attached) {
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 6f5ad20..528081e 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -1409,7 +1409,7 @@ static void usbredir_realize(USBDevice *udev, Error **errp)
     /* Let the backend know we are ready */
     qemu_chr_fe_set_handlers(&dev->cs, usbredir_chardev_can_read,
                              usbredir_chardev_read, usbredir_chardev_event,
-                             dev, NULL);
+                             dev, NULL, true);
 
     qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev);
 }
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index d029d54..ae32e1c 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -109,7 +109,6 @@ struct CharDriverState {
     int logfd;
     int be_open;
     int fe_open;
-    int explicit_fe_open;
     int explicit_be_open;
     int avail_connections;
     int is_mux;
@@ -449,6 +448,8 @@ void qemu_chr_fe_deinit(CharBackend *b);
  * @fd_event: event callback
  * @opaque: an opaque pointer for the callbacks
  * @context: a main loop context or NULL for the default
+ * @set_open: whether to call qemu_chr_fe_set_open() implicitely when
+ * any of the handler is non-NULL
  *
  * Set the front end char handlers. The front end takes the focus if
  * any of the handler is non-NULL.
@@ -460,7 +461,8 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
                               IOReadHandler *fd_read,
                               IOEventHandler *fd_event,
                               void *opaque,
-                              GMainContext *context);
+                              GMainContext *context,
+                              bool set_open);
 
 /**
  * @qemu_chr_fe_take_focus:
diff --git a/monitor.c b/monitor.c
index 5c349c5..b73a999 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3988,12 +3988,12 @@ void monitor_init(CharDriverState *chr, int flags)
 
     if (monitor_is_qmp(mon)) {
         qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_qmp_read,
-                                 monitor_qmp_event, mon, NULL);
+                                 monitor_qmp_event, mon, NULL, true);
         qemu_chr_fe_set_echo(&mon->chr, true);
         json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
     } else {
         qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_read,
-                                 monitor_event, mon, NULL);
+                                 monitor_event, mon, NULL, true);
     }
 
     qemu_mutex_lock(&monitor_lock);
diff --git a/net/colo-compare.c b/net/colo-compare.c
index 3083681..109990f 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -451,7 +451,8 @@ static void compare_pri_chr_in(void *opaque, const uint8_t *buf, int size)
 
     ret = net_fill_rstate(&s->pri_rs, buf, size);
     if (ret == -1) {
-        qemu_chr_fe_set_handlers(&s->chr_pri_in, NULL, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_set_handlers(&s->chr_pri_in, NULL, NULL, NULL,
+                                 NULL, NULL, true);
         error_report("colo-compare primary_in error");
     }
 }
@@ -467,7 +468,8 @@ static void compare_sec_chr_in(void *opaque, const uint8_t *buf, int size)
 
     ret = net_fill_rstate(&s->sec_rs, buf, size);
     if (ret == -1) {
-        qemu_chr_fe_set_handlers(&s->chr_sec_in, NULL, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_set_handlers(&s->chr_sec_in, NULL, NULL, NULL,
+                                 NULL, NULL, true);
         error_report("colo-compare secondary_in error");
     }
 }
@@ -481,9 +483,9 @@ static void *colo_compare_thread(void *opaque)
     worker_context = g_main_context_new();
 
     qemu_chr_fe_set_handlers(&s->chr_pri_in, compare_chr_can_read,
-                             compare_pri_chr_in, NULL, s, worker_context);
+                             compare_pri_chr_in, NULL, s, worker_context, true);
     qemu_chr_fe_set_handlers(&s->chr_sec_in, compare_chr_can_read,
-                             compare_sec_chr_in, NULL, s, worker_context);
+                             compare_sec_chr_in, NULL, s, worker_context, true);
 
     compare_loop = g_main_loop_new(worker_context, FALSE);
 
diff --git a/net/filter-mirror.c b/net/filter-mirror.c
index 1864c81..b7d6456 100644
--- a/net/filter-mirror.c
+++ b/net/filter-mirror.c
@@ -110,7 +110,8 @@ static void redirector_chr_read(void *opaque, const uint8_t *buf, int size)
     ret = net_fill_rstate(&s->rs, buf, size);
 
     if (ret == -1) {
-        qemu_chr_fe_set_handlers(&s->chr_in, NULL, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_set_handlers(&s->chr_in, NULL, NULL, NULL,
+                                 NULL, NULL, true);
     }
 }
 
@@ -121,7 +122,8 @@ static void redirector_chr_event(void *opaque, int event)
 
     switch (event) {
     case CHR_EVENT_CLOSED:
-        qemu_chr_fe_set_handlers(&s->chr_in, NULL, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_set_handlers(&s->chr_in, NULL, NULL, NULL,
+                                 NULL, NULL, true);
         break;
     default:
         break;
@@ -248,7 +250,7 @@ static void filter_redirector_setup(NetFilterState *nf, Error **errp)
 
         qemu_chr_fe_set_handlers(&s->chr_in, redirector_chr_can_read,
                                  redirector_chr_read, redirector_chr_event,
-                                 nf, NULL);
+                                 nf, NULL, true);
     }
 
     if (s->outdev) {
diff --git a/net/slirp.c b/net/slirp.c
index 0e67535..64dd325 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -775,7 +775,7 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str,
         fwd->slirp = s->slirp;
 
         qemu_chr_fe_set_handlers(&fwd->hd, guestfwd_can_read, guestfwd_read,
-                                 NULL, fwd, NULL);
+                                 NULL, fwd, NULL, true);
     }
     return 0;
 
diff --git a/net/vhost-user.c b/net/vhost-user.c
index 140a4e0..7aff77e 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -266,7 +266,7 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
             return -1;
         }
         qemu_chr_fe_set_handlers(&s->chr, NULL, NULL,
-                                 net_vhost_user_event, nc0->name, NULL);
+                                 net_vhost_user_event, nc0->name, NULL, true);
     } while (!s->started);
 
     assert(s->vhost_net);
diff --git a/qemu-char.c b/qemu-char.c
index af060ce..a1517a4 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -832,7 +832,7 @@ static void mux_chr_set_handlers(CharDriverState *chr, GMainContext *context)
                              mux_chr_read,
                              mux_chr_event,
                              chr,
-                             context);
+                             context, true);
 }
 
 static void mux_set_focus(MuxDriver *d, int focus)
@@ -931,7 +931,7 @@ void qemu_chr_fe_deinit(CharBackend *b)
     assert(b);
 
     if (b->chr) {
-        qemu_chr_fe_set_handlers(b, NULL, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_set_handlers(b, NULL, NULL, NULL, NULL, NULL, true);
         b->chr->avail_connections++;
         b->chr->be = NULL;
         if (b->chr->is_mux) {
@@ -947,7 +947,8 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
                               IOReadHandler *fd_read,
                               IOEventHandler *fd_event,
                               void *opaque,
-                              GMainContext *context)
+                              GMainContext *context,
+                              bool set_open)
 {
     CharDriverState *s;
     int fe_open;
@@ -971,7 +972,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
         s->chr_update_read_handler(s, context);
     }
 
-    if (!s->explicit_fe_open) {
+    if (set_open) {
         qemu_chr_fe_set_open(b, fe_open);
     }
 
diff --git a/qtest.c b/qtest.c
index 1a6c8b1..46b99ae 100644
--- a/qtest.c
+++ b/qtest.c
@@ -688,7 +688,7 @@ void qtest_init(const char *qtest_chrdev, const char *qtest_log, Error **errp)
 
     qemu_chr_fe_init(&qtest_chr, chr, errp);
     qemu_chr_fe_set_handlers(&qtest_chr, qtest_can_read, qtest_read,
-                             qtest_event, &qtest_chr, NULL);
+                             qtest_event, &qtest_chr, NULL, true);
     qemu_chr_fe_set_echo(&qtest_chr, true);
 
     inbuf = g_string_new("");
diff --git a/tests/test-char.c b/tests/test-char.c
index 13c55b8..241685a 100644
--- a/tests/test-char.c
+++ b/tests/test-char.c
@@ -129,7 +129,7 @@ static void char_mux_test(void)
                              fe_read,
                              fe_event,
                              &h1,
-                             NULL);
+                             NULL, true);
 
     qemu_chr_fe_init(&chr_be2, chr, &error_abort);
     qemu_chr_fe_set_handlers(&chr_be2,
@@ -137,7 +137,7 @@ static void char_mux_test(void)
                              fe_read,
                              fe_event,
                              &h2,
-                             NULL);
+                             NULL, true);
     qemu_chr_fe_take_focus(&chr_be2);
 
     base = qemu_chr_find("mux-label-base");
@@ -159,7 +159,7 @@ static void char_mux_test(void)
     h1.read_count = 0;
 
     /* remove first handler */
-    qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL, NULL);
+    qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL, NULL, true);
     qemu_chr_be_write(base, (void *)"hello", 6);
     g_assert_cmpint(h1.read_count, ==, 0);
     g_assert_cmpint(h2.read_count, ==, 0);
@@ -216,7 +216,7 @@ static void char_null_test(void)
                              fe_can_read,
                              fe_read,
                              fe_event,
-                             NULL, NULL);
+                             NULL, NULL, true);
 
     ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
     g_assert_cmpint(ret, ==, 4);
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index 24c2323..a7f0629 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -464,7 +464,7 @@ static void test_server_create_chr(TestServer *server, const gchar *opt)
 
     qemu_chr_fe_init(&server->chr, chr, &error_abort);
     qemu_chr_fe_set_handlers(&server->chr, chr_can_read, chr_read,
-                             chr_event, server, NULL);
+                             chr_event, server, NULL, true);
 }
 
 static void test_server_listen(TestServer *server)
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 43/50] char: move fe_open in CharBackend
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (41 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 42/50] char: remove explicit_fe_open, use a set_handlers argument Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 44/50] char: remove unused CHR_EVENT_FOCUS Paolo Bonzini
                   ` (7 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

The fe_open state belongs to front end.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022100951.19562-1-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/sysemu/char.h | 2 +-
 qemu-char.c           | 7 ++++---
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index ae32e1c..2c3060c 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -81,6 +81,7 @@ typedef struct CharBackend {
     IOReadHandler *chr_read;
     void *opaque;
     int tag;
+    int fe_open;
 } CharBackend;
 
 struct CharDriverState {
@@ -108,7 +109,6 @@ struct CharDriverState {
     char *filename;
     int logfd;
     int be_open;
-    int fe_open;
     int explicit_be_open;
     int avail_connections;
     int is_mux;
diff --git a/qemu-char.c b/qemu-char.c
index a1517a4..3b98acf 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -910,6 +910,7 @@ bool qemu_chr_fe_init(CharBackend *b, CharDriverState *s, Error **errp)
         s->be = b;
     }
 
+    b->fe_open = false;
     b->tag = tag;
     b->chr = s;
 
@@ -4216,10 +4217,10 @@ void qemu_chr_fe_set_open(CharBackend *be, int fe_open)
         return;
     }
 
-    if (chr->fe_open == fe_open) {
+    if (be->fe_open == fe_open) {
         return;
     }
-    chr->fe_open = fe_open;
+    be->fe_open = fe_open;
     if (chr->chr_set_fe_open) {
         chr->chr_set_fe_open(chr, fe_open);
     }
@@ -4304,7 +4305,7 @@ ChardevInfoList *qmp_query_chardev(Error **errp)
         info->value = g_malloc0(sizeof(*info->value));
         info->value->label = g_strdup(chr->label);
         info->value->filename = g_strdup(chr->filename);
-        info->value->frontend_open = chr->fe_open;
+        info->value->frontend_open = chr->be && chr->be->fe_open;
 
         info->next = chr_list;
         chr_list = info;
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 44/50] char: remove unused CHR_EVENT_FOCUS
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (42 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 43/50] char: move fe_open in CharBackend Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 45/50] char: use an enum for CHR_EVENT Paolo Bonzini
                   ` (6 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Usage has long been removed, since commit f220174de8d9.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022100951.19562-2-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/usb/ccid-card-passthru.c | 2 --
 hw/usb/dev-serial.c         | 2 --
 include/sysemu/char.h       | 1 -
 3 files changed, 5 deletions(-)

diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c
index 1faef0e..325129a 100644
--- a/hw/usb/ccid-card-passthru.c
+++ b/hw/usb/ccid-card-passthru.c
@@ -312,8 +312,6 @@ static void ccid_card_vscard_event(void *opaque, int event)
     case CHR_EVENT_BREAK:
         card->vscard_in_pos = card->vscard_in_hdr = 0;
         break;
-    case CHR_EVENT_FOCUS:
-        break;
     case CHR_EVENT_OPENED:
         DPRINTF(card, D_INFO, "%s: CHR_EVENT_OPENED\n", __func__);
         break;
diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c
index ef1e1ad..6066d9b 100644
--- a/hw/usb/dev-serial.c
+++ b/hw/usb/dev-serial.c
@@ -466,8 +466,6 @@ static void usb_serial_event(void *opaque, int event)
         case CHR_EVENT_BREAK:
             s->event_trigger |= FTDI_BI;
             break;
-        case CHR_EVENT_FOCUS:
-            break;
         case CHR_EVENT_OPENED:
             if (!s->dev.attached) {
                 usb_device_attach(&s->dev, &error_abort);
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 2c3060c..43da4ac 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -14,7 +14,6 @@
 /* character device */
 
 #define CHR_EVENT_BREAK   0 /* serial break char */
-#define CHR_EVENT_FOCUS   1 /* focus to this terminal (modal input needed) */
 #define CHR_EVENT_OPENED  2 /* new connection established */
 #define CHR_EVENT_MUX_IN  3 /* mux-focus was set to this terminal */
 #define CHR_EVENT_MUX_OUT 4 /* mux-focus will move on */
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 45/50] char: use an enum for CHR_EVENT
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (43 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 44/50] char: remove unused CHR_EVENT_FOCUS Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 46/50] char: remove unused qemu_chr_fe_event Paolo Bonzini
                   ` (5 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

This may help to catch unhandled cases, and avoid having to maintain
numbering.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022100951.19562-3-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/sysemu/char.h | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 43da4ac..de0d99b 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -13,11 +13,13 @@
 
 /* character device */
 
-#define CHR_EVENT_BREAK   0 /* serial break char */
-#define CHR_EVENT_OPENED  2 /* new connection established */
-#define CHR_EVENT_MUX_IN  3 /* mux-focus was set to this terminal */
-#define CHR_EVENT_MUX_OUT 4 /* mux-focus will move on */
-#define CHR_EVENT_CLOSED  5 /* connection closed */
+typedef enum {
+    CHR_EVENT_BREAK, /* serial break char */
+    CHR_EVENT_OPENED, /* new connection established */
+    CHR_EVENT_MUX_IN, /* mux-focus was set to this terminal */
+    CHR_EVENT_MUX_OUT, /* mux-focus will move on */
+    CHR_EVENT_CLOSED /* connection closed */
+} QEMUChrEvent;
 
 
 #define CHR_IOCTL_SERIAL_SET_PARAMS   1
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 46/50] char: remove unused qemu_chr_fe_event
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (44 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 45/50] char: use an enum for CHR_EVENT Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 47/50] char: replace avail_connections Paolo Bonzini
                   ` (4 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

I introduced this function in d61b0c9a2f7f, but it isn't
used. Furthermore, it was incomplete, as it would need to translate QEMU
chr events to Spice port events.

(presumably it was used in the follow-up NBD-spice series that was not
completed: http://lists.gnu.org/archive/html/qemu-devel/2013-11/msg02024.html)

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022100951.19562-4-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/sysemu/char.h | 11 -----------
 qemu-char.c           |  9 ---------
 spice-qemu-char.c     | 10 ----------
 3 files changed, 30 deletions(-)

diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index de0d99b..6bad856 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -103,7 +103,6 @@ struct CharDriverState {
     void (*chr_accept_input)(struct CharDriverState *chr);
     void (*chr_set_echo)(struct CharDriverState *chr, bool echo);
     void (*chr_set_fe_open)(struct CharDriverState *chr, int fe_open);
-    void (*chr_fe_event)(struct CharDriverState *chr, int event);
     CharBackend *be;
     void *opaque;
     char *label;
@@ -239,16 +238,6 @@ void qemu_chr_fe_set_echo(CharBackend *be, bool echo);
 void qemu_chr_fe_set_open(CharBackend *be, int fe_open);
 
 /**
- * @qemu_chr_fe_event:
- *
- * Send an event from the front end to the back end. It does nothing
- * without associated CharDriver.
- *
- * @event the event to send
- */
-void qemu_chr_fe_event(CharBackend *be, int event);
-
-/**
  * @qemu_chr_fe_printf:
  *
  * Write to a character backend using a printf style interface.  This
diff --git a/qemu-char.c b/qemu-char.c
index 3b98acf..9bd2e65 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -4226,15 +4226,6 @@ void qemu_chr_fe_set_open(CharBackend *be, int fe_open)
     }
 }
 
-void qemu_chr_fe_event(CharBackend *be, int event)
-{
-    CharDriverState *chr = be->chr;
-
-    if (chr && chr->chr_fe_event) {
-        chr->chr_fe_event(chr, event);
-    }
-}
-
 guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
                             GIOFunc func, void *user_data)
 {
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index 930b8c5..89fae6d 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -236,15 +236,6 @@ static void spice_port_set_fe_open(struct CharDriverState *chr, int fe_open)
 #endif
 }
 
-static void spice_chr_fe_event(struct CharDriverState *chr, int event)
-{
-#if SPICE_SERVER_VERSION >= 0x000c02
-    SpiceCharDriver *s = chr->opaque;
-
-    spice_server_port_event(&s->sin, event);
-#endif
-}
-
 static void print_allowed_subtypes(void)
 {
     const char** psubtype;
@@ -292,7 +283,6 @@ static CharDriverState *chr_open(const char *subtype,
     chr->chr_free = spice_chr_free;
     chr->chr_set_fe_open = set_fe_open;
     chr->explicit_be_open = true;
-    chr->chr_fe_event = spice_chr_fe_event;
     chr->chr_accept_input = spice_chr_accept_input;
 
     QLIST_INSERT_HEAD(&spice_chars, s, next);
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 47/50] char: replace avail_connections
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (45 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 46/50] char: remove unused qemu_chr_fe_event Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 48/50] char: use common error path in qmp_chardev_add Paolo Bonzini
                   ` (3 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

No need to count the users of a CharDriverState, it can rely on the fact
of whether there is a CharBackend associated or if there is enough space
in the muxer.

Simplify and fold chr_mux_new_fe() in qemu_chr_fe_init() since there is
a single user now. Also switch from fprintf to raising error instead.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022100951.19562-5-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/bt/hci-csr.c       |  1 -
 include/sysemu/char.h |  1 -
 qemu-char.c           | 34 +++++++++++++---------------------
 3 files changed, 13 insertions(+), 23 deletions(-)

diff --git a/hw/bt/hci-csr.c b/hw/bt/hci-csr.c
index cdf52a9..fbb3109 100644
--- a/hw/bt/hci-csr.c
+++ b/hw/bt/hci-csr.c
@@ -468,7 +468,6 @@ CharDriverState *uart_hci_init(void)
     s->chr.opaque = s;
     s->chr.chr_write = csrhci_write;
     s->chr.chr_ioctl = csrhci_ioctl;
-    s->chr.avail_connections = 1;
 
     s->hci = qemu_next_hci();
     s->hci->opaque = s;
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 6bad856..0628b14 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -110,7 +110,6 @@ struct CharDriverState {
     int logfd;
     int be_open;
     int explicit_be_open;
-    int avail_connections;
     int is_mux;
     guint fd_in_tag;
     bool replay;
diff --git a/qemu-char.c b/qemu-char.c
index 9bd2e65..02adea4 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -808,20 +808,6 @@ static void mux_chr_free(struct CharDriverState *chr)
     g_free(d);
 }
 
-static int mux_chr_new_fe(CharDriverState *chr, CharBackend *be, Error **errp)
-{
-    MuxDriver *d = chr->opaque;
-
-    if (d->mux_cnt >= MAX_MUX) {
-        fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n");
-        return -1;
-    }
-
-    d->backends[d->mux_cnt] = be;
-
-    return d->mux_cnt++;
-}
-
 static void mux_chr_set_handlers(CharDriverState *chr, GMainContext *context)
 {
     MuxDriver *d = chr->opaque;
@@ -902,10 +888,16 @@ bool qemu_chr_fe_init(CharBackend *b, CharDriverState *s, Error **errp)
     int tag = 0;
 
     if (s->is_mux) {
-        tag = mux_chr_new_fe(s, b, errp);
-        if (tag < 0) {
-            return false;
+        MuxDriver *d = s->opaque;
+
+        if (d->mux_cnt >= MAX_MUX) {
+            goto unavailable;
         }
+
+        d->backends[d->mux_cnt] = b;
+        tag = d->mux_cnt++;
+    } else if (s->be) {
+        goto unavailable;
     } else {
         s->be = b;
     }
@@ -913,8 +905,11 @@ bool qemu_chr_fe_init(CharBackend *b, CharDriverState *s, Error **errp)
     b->fe_open = false;
     b->tag = tag;
     b->chr = s;
-
     return true;
+
+unavailable:
+    error_setg(errp, QERR_DEVICE_IN_USE, s->label);
+    return false;
 }
 
 static bool qemu_chr_is_busy(CharDriverState *s)
@@ -933,7 +928,6 @@ void qemu_chr_fe_deinit(CharBackend *b)
 
     if (b->chr) {
         qemu_chr_fe_set_handlers(b, NULL, NULL, NULL, NULL, NULL, true);
-        b->chr->avail_connections++;
         b->chr->be = NULL;
         if (b->chr->is_mux) {
             MuxDriver *d = b->chr->opaque;
@@ -4782,8 +4776,6 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
     }
 
     chr->label = g_strdup(id);
-    chr->avail_connections =
-        (backend->type == CHARDEV_BACKEND_KIND_MUX) ? MAX_MUX : 1;
     if (!chr->filename) {
         chr->filename = g_strdup(ChardevBackendKind_lookup[backend->type]);
     }
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 48/50] char: use common error path in qmp_chardev_add
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (46 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 47/50] char: replace avail_connections Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 49/50] char: remove explicit_be_open from CharDriverState Paolo Bonzini
                   ` (2 subsequent siblings)
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022100951.19562-6-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 qemu-char.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index 02adea4..5e9684d 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -4752,8 +4752,7 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
     chr = qemu_chr_find(id);
     if (chr) {
         error_setg(errp, "Chardev '%s' already exists", id);
-        g_free(ret);
-        return NULL;
+        goto out_error;
     }
 
     for (i = backends; i; i = i->next) {
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 49/50] char: remove explicit_be_open from CharDriverState
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (47 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 48/50] char: use common error path in qmp_chardev_add Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 13:47 ` [Qemu-devel] [PULL 50/50] exec.c: workaround regression caused by alignment change in d2f39ad Paolo Bonzini
  2016-10-24 15:11 ` [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Peter Maydell
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Marc-André Lureau

From: Marc-André Lureau <marcandre.lureau@redhat.com>

It's only used in qmp_chardev_add(), so use a create() argument instead.

Also switched to typedef functions for CharDriverParse/CharDriverCreate.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20161022100951.19562-7-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 backends/baum.c       |  1 +
 backends/msmouse.c    |  3 ++-
 backends/testdev.c    |  1 +
 include/sysemu/char.h | 12 +++++++----
 qemu-char.c           | 55 ++++++++++++++++++++++++++++++++++-----------------
 spice-qemu-char.c     |  5 ++++-
 ui/console.c          | 11 ++++++-----
 ui/gtk.c              |  3 ---
 8 files changed, 59 insertions(+), 32 deletions(-)

diff --git a/backends/baum.c b/backends/baum.c
index a516434..919844e 100644
--- a/backends/baum.c
+++ b/backends/baum.c
@@ -566,6 +566,7 @@ static void baum_free(struct CharDriverState *chr)
 static CharDriverState *chr_baum_init(const char *id,
                                       ChardevBackend *backend,
                                       ChardevReturn *ret,
+                                      bool *be_opened,
                                       Error **errp)
 {
     ChardevCommon *common = backend->u.braille.data;
diff --git a/backends/msmouse.c b/backends/msmouse.c
index 448369f..733ca80 100644
--- a/backends/msmouse.c
+++ b/backends/msmouse.c
@@ -151,6 +151,7 @@ static QemuInputHandler msmouse_handler = {
 static CharDriverState *qemu_chr_open_msmouse(const char *id,
                                               ChardevBackend *backend,
                                               ChardevReturn *ret,
+                                              bool *be_opened,
                                               Error **errp)
 {
     ChardevCommon *common = backend->u.msmouse.data;
@@ -164,7 +165,7 @@ static CharDriverState *qemu_chr_open_msmouse(const char *id,
     chr->chr_write = msmouse_chr_write;
     chr->chr_free = msmouse_chr_free;
     chr->chr_accept_input = msmouse_chr_accept_input;
-    chr->explicit_be_open = true;
+    *be_opened = false;
 
     mouse = g_new0(MouseState, 1);
     mouse->hs = qemu_input_handler_register((DeviceState *)mouse,
diff --git a/backends/testdev.c b/backends/testdev.c
index 1ba8bf2..60156e3 100644
--- a/backends/testdev.c
+++ b/backends/testdev.c
@@ -112,6 +112,7 @@ static void testdev_free(struct CharDriverState *chr)
 static CharDriverState *chr_testdev_init(const char *id,
                                          ChardevBackend *backend,
                                          ChardevReturn *ret,
+                                         bool *be_opened,
                                          Error **errp)
 {
     TestdevCharState *testdev;
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 0628b14..0a14942 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -109,7 +109,6 @@ struct CharDriverState {
     char *filename;
     int logfd;
     int be_open;
-    int explicit_be_open;
     int is_mux;
     guint fd_in_tag;
     bool replay;
@@ -474,10 +473,15 @@ void qemu_chr_set_feature(CharDriverState *chr,
                           CharDriverFeature feature);
 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
 
+typedef void CharDriverParse(QemuOpts *opts, ChardevBackend *backend,
+                             Error **errp);
+typedef CharDriverState *CharDriverCreate(const char *id,
+                                          ChardevBackend *backend,
+                                          ChardevReturn *ret, bool *be_opened,
+                                          Error **errp);
+
 void register_char_driver(const char *name, ChardevBackendKind kind,
-        void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp),
-        CharDriverState *(*create)(const char *id, ChardevBackend *backend,
-                                   ChardevReturn *ret, Error **errp));
+                          CharDriverParse *parse, CharDriverCreate *create);
 
 extern int term_escape_char;
 
diff --git a/qemu-char.c b/qemu-char.c
index 5e9684d..6dd779f 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -509,6 +509,7 @@ static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 static CharDriverState *qemu_chr_open_null(const char *id,
                                            ChardevBackend *backend,
                                            ChardevReturn *ret,
+                                           bool *be_opened,
                                            Error **errp)
 {
     CharDriverState *chr;
@@ -519,7 +520,7 @@ static CharDriverState *qemu_chr_open_null(const char *id,
         return NULL;
     }
     chr->chr_write = null_chr_write;
-    chr->explicit_be_open = true;
+    *be_opened = false;
     return chr;
 }
 
@@ -836,7 +837,9 @@ static void mux_set_focus(MuxDriver *d, int focus)
 
 static CharDriverState *qemu_chr_open_mux(const char *id,
                                           ChardevBackend *backend,
-                                          ChardevReturn *ret, Error **errp)
+                                          ChardevReturn *ret,
+                                          bool *be_opened,
+                                          Error **errp)
 {
     ChardevMux *mux = backend->u.mux.data;
     CharDriverState *chr, *drv;
@@ -868,7 +871,7 @@ static CharDriverState *qemu_chr_open_mux(const char *id,
     /* only default to opened state if we've realized the initial
      * set of muxes
      */
-    chr->explicit_be_open = muxes_realized ? 0 : 1;
+    *be_opened = muxes_realized;
     chr->is_mux = 1;
     if (!qemu_chr_fe_init(&d->chr, drv, errp)) {
         qemu_chr_free(chr);
@@ -1280,6 +1283,7 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out,
 static CharDriverState *qemu_chr_open_pipe(const char *id,
                                            ChardevBackend *backend,
                                            ChardevReturn *ret,
+                                           bool *be_opened,
                                            Error **errp)
 {
     ChardevHostdev *opts = backend->u.pipe.data;
@@ -1362,6 +1366,7 @@ static void qemu_chr_free_stdio(struct CharDriverState *chr)
 static CharDriverState *qemu_chr_open_stdio(const char *id,
                                             ChardevBackend *backend,
                                             ChardevReturn *ret,
+                                            bool *be_opened,
                                             Error **errp)
 {
     ChardevStdio *opts = backend->u.stdio.data;
@@ -1609,6 +1614,7 @@ static void pty_chr_free(struct CharDriverState *chr)
 static CharDriverState *qemu_chr_open_pty(const char *id,
                                           ChardevBackend *backend,
                                           ChardevReturn *ret,
+                                          bool *be_opened,
                                           Error **errp)
 {
     CharDriverState *chr;
@@ -1645,7 +1651,7 @@ static CharDriverState *qemu_chr_open_pty(const char *id,
     chr->chr_update_read_handler = pty_chr_update_read_handler;
     chr->chr_free = pty_chr_free;
     chr->chr_add_watch = pty_chr_add_watch;
-    chr->explicit_be_open = true;
+    *be_opened = false;
 
     s->ioc = QIO_CHANNEL(qio_channel_file_new_fd(master_fd));
     s->timer_tag = 0;
@@ -1845,6 +1851,7 @@ static void qemu_chr_free_tty(CharDriverState *chr)
 
 static CharDriverState *qemu_chr_open_tty_fd(int fd,
                                              ChardevCommon *backend,
+                                             bool *be_opened,
                                              Error **errp)
 {
     CharDriverState *chr;
@@ -1975,6 +1982,7 @@ static void pp_free(CharDriverState *chr)
 
 static CharDriverState *qemu_chr_open_pp_fd(int fd,
                                             ChardevCommon *backend,
+                                            bool *be_opened,
                                             Error **errp)
 {
     CharDriverState *chr;
@@ -2047,6 +2055,7 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
 
 static CharDriverState *qemu_chr_open_pp_fd(int fd,
                                             ChardevCommon *backend,
+                                            bool *be_opened,
                                             Error **errp)
 {
     CharDriverState *chr;
@@ -2058,7 +2067,7 @@ static CharDriverState *qemu_chr_open_pp_fd(int fd,
     chr->opaque = (void *)(intptr_t)fd;
     chr->chr_write = null_chr_write;
     chr->chr_ioctl = pp_ioctl;
-    chr->explicit_be_open = true;
+    *be_opened = false;
     return chr;
 }
 #endif
@@ -2387,6 +2396,7 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename,
 static CharDriverState *qemu_chr_open_pipe(const char *id,
                                            ChardevBackend *backend,
                                            ChardevReturn *ret,
+                                           bool *be_opened,
                                            Error **errp)
 {
     ChardevHostdev *opts = backend->u.pipe.data;
@@ -2433,6 +2443,7 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out,
 static CharDriverState *qemu_chr_open_win_con(const char *id,
                                               ChardevBackend *backend,
                                               ChardevReturn *ret,
+                                              bool *be_opened,
                                               Error **errp)
 {
     ChardevCommon *common = backend->u.console.data;
@@ -2578,6 +2589,7 @@ static void win_stdio_free(CharDriverState *chr)
 static CharDriverState *qemu_chr_open_stdio(const char *id,
                                             ChardevBackend *backend,
                                             ChardevReturn *ret,
+                                            bool *be_opened,
                                             Error **errp)
 {
     CharDriverState   *chr;
@@ -2753,6 +2765,7 @@ static void udp_chr_free(CharDriverState *chr)
 
 static CharDriverState *qemu_chr_open_udp(QIOChannelSocket *sioc,
                                           ChardevCommon *backend,
+                                          bool *be_opened,
                                           Error **errp)
 {
     CharDriverState *chr = NULL;
@@ -2772,7 +2785,7 @@ static CharDriverState *qemu_chr_open_udp(QIOChannelSocket *sioc,
     chr->chr_update_read_handler = udp_chr_update_read_handler;
     chr->chr_free = udp_chr_free;
     /* be isn't opened until we get a connection */
-    chr->explicit_be_open = true;
+    *be_opened = false;
     return chr;
 }
 
@@ -3504,6 +3517,7 @@ static void ringbuf_chr_free(struct CharDriverState *chr)
 static CharDriverState *qemu_chr_open_ringbuf(const char *id,
                                               ChardevBackend *backend,
                                               ChardevReturn *ret,
+                                              bool *be_opened,
                                               Error **errp)
 {
     ChardevRingbuf *opts = backend->u.ringbuf.data;
@@ -4032,17 +4046,14 @@ static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend,
 typedef struct CharDriver {
     const char *name;
     ChardevBackendKind kind;
-    void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp);
-    CharDriverState *(*create)(const char *id, ChardevBackend *backend,
-                               ChardevReturn *ret, Error **errp);
+    CharDriverParse *parse;
+    CharDriverCreate *create;
 } CharDriver;
 
 static GSList *backends;
 
 void register_char_driver(const char *name, ChardevBackendKind kind,
-        void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp),
-        CharDriverState *(*create)(const char *id, ChardevBackend *backend,
-                                   ChardevReturn *ret, Error **errp))
+                          CharDriverParse *parse, CharDriverCreate *create)
 {
     CharDriver *s;
 
@@ -4429,6 +4440,7 @@ QemuOptsList qemu_chardev_opts = {
 static CharDriverState *qmp_chardev_open_file(const char *id,
                                               ChardevBackend *backend,
                                               ChardevReturn *ret,
+                                              bool *be_opened,
                                               Error **errp)
 {
     ChardevFile *file = backend->u.file.data;
@@ -4464,6 +4476,7 @@ static CharDriverState *qmp_chardev_open_file(const char *id,
 static CharDriverState *qmp_chardev_open_serial(const char *id,
                                                 ChardevBackend *backend,
                                                 ChardevReturn *ret,
+                                                bool *be_opened,
                                                 Error **errp)
 {
     ChardevHostdev *serial = backend->u.serial.data;
@@ -4488,6 +4501,7 @@ static int qmp_chardev_open_file_source(char *src, int flags,
 static CharDriverState *qmp_chardev_open_file(const char *id,
                                               ChardevBackend *backend,
                                               ChardevReturn *ret,
+                                              bool *be_opened,
                                               Error **errp)
 {
     ChardevFile *file = backend->u.file.data;
@@ -4522,6 +4536,7 @@ static CharDriverState *qmp_chardev_open_file(const char *id,
 static CharDriverState *qmp_chardev_open_serial(const char *id,
                                                 ChardevBackend *backend,
                                                 ChardevReturn *ret,
+                                                bool *be_opened,
                                                 Error **errp)
 {
     ChardevHostdev *serial = backend->u.serial.data;
@@ -4533,7 +4548,7 @@ static CharDriverState *qmp_chardev_open_serial(const char *id,
         return NULL;
     }
     qemu_set_nonblock(fd);
-    return qemu_chr_open_tty_fd(fd, common, errp);
+    return qemu_chr_open_tty_fd(fd, common, be_opened, errp);
 }
 #endif
 
@@ -4541,6 +4556,7 @@ static CharDriverState *qmp_chardev_open_serial(const char *id,
 static CharDriverState *qmp_chardev_open_parallel(const char *id,
                                                   ChardevBackend *backend,
                                                   ChardevReturn *ret,
+                                                  bool *be_opened,
                                                   Error **errp)
 {
     ChardevHostdev *parallel = backend->u.parallel.data;
@@ -4551,7 +4567,7 @@ static CharDriverState *qmp_chardev_open_parallel(const char *id,
     if (fd < 0) {
         return NULL;
     }
-    return qemu_chr_open_pp_fd(fd, common, errp);
+    return qemu_chr_open_pp_fd(fd, common, be_opened, errp);
 }
 #endif
 
@@ -4580,6 +4596,7 @@ static gboolean socket_reconnect_timeout(gpointer opaque)
 static CharDriverState *qmp_chardev_open_socket(const char *id,
                                                 ChardevBackend *backend,
                                                 ChardevReturn *ret,
+                                                bool *be_opened,
                                                 Error **errp)
 {
     CharDriverState *chr;
@@ -4656,7 +4673,7 @@ static CharDriverState *qmp_chardev_open_socket(const char *id,
     chr->chr_add_watch = tcp_chr_add_watch;
     chr->chr_update_read_handler = tcp_chr_update_read_handler;
     /* be isn't opened until we get a connection */
-    chr->explicit_be_open = true;
+    *be_opened = false;
 
     chr->filename = SocketAddress_to_str("disconnected:",
                                          addr, is_listen, is_telnet);
@@ -4712,6 +4729,7 @@ static CharDriverState *qmp_chardev_open_socket(const char *id,
 static CharDriverState *qmp_chardev_open_udp(const char *id,
                                              ChardevBackend *backend,
                                              ChardevReturn *ret,
+                                             bool *be_opened,
                                              Error **errp)
 {
     ChardevUdp *udp = backend->u.udp.data;
@@ -4724,7 +4742,7 @@ static CharDriverState *qmp_chardev_open_udp(const char *id,
         object_unref(OBJECT(sioc));
         return NULL;
     }
-    return qemu_chr_open_udp(sioc, common, errp);
+    return qemu_chr_open_udp(sioc, common, be_opened, errp);
 }
 
 
@@ -4748,6 +4766,7 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
     Error *local_err = NULL;
     GSList *i;
     CharDriver *cd;
+    bool be_opened = true;
 
     chr = qemu_chr_find(id);
     if (chr) {
@@ -4759,7 +4778,7 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
         cd = i->data;
 
         if (cd->kind == backend->type) {
-            chr = cd->create(id, backend, ret, &local_err);
+            chr = cd->create(id, backend, ret, &be_opened, &local_err);
             if (local_err) {
                 error_propagate(errp, local_err);
                 goto out_error;
@@ -4778,7 +4797,7 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
     if (!chr->filename) {
         chr->filename = g_strdup(ChardevBackendKind_lookup[backend->type]);
     }
-    if (!chr->explicit_be_open) {
+    if (be_opened) {
         qemu_chr_be_event(chr, CHR_EVENT_OPENED);
     }
     QTAILQ_INSERT_TAIL(&chardevs, chr, next);
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index 89fae6d..276c4ae 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -282,7 +282,6 @@ static CharDriverState *chr_open(const char *subtype,
     chr->chr_add_watch = spice_chr_add_watch;
     chr->chr_free = spice_chr_free;
     chr->chr_set_fe_open = set_fe_open;
-    chr->explicit_be_open = true;
     chr->chr_accept_input = spice_chr_accept_input;
 
     QLIST_INSERT_HEAD(&spice_chars, s, next);
@@ -293,6 +292,7 @@ static CharDriverState *chr_open(const char *subtype,
 static CharDriverState *qemu_chr_open_spice_vmc(const char *id,
                                                 ChardevBackend *backend,
                                                 ChardevReturn *ret,
+                                                bool *be_opened,
                                                 Error **errp)
 {
     ChardevSpiceChannel *spicevmc = backend->u.spicevmc.data;
@@ -311,6 +311,7 @@ static CharDriverState *qemu_chr_open_spice_vmc(const char *id,
         return NULL;
     }
 
+    *be_opened = false;
     return chr_open(type, spice_vmc_set_fe_open, common, errp);
 }
 
@@ -318,6 +319,7 @@ static CharDriverState *qemu_chr_open_spice_vmc(const char *id,
 static CharDriverState *qemu_chr_open_spice_port(const char *id,
                                                  ChardevBackend *backend,
                                                  ChardevReturn *ret,
+                                                 bool *be_opened,
                                                  Error **errp)
 {
     ChardevSpicePort *spiceport = backend->u.spiceport.data;
@@ -335,6 +337,7 @@ static CharDriverState *qemu_chr_open_spice_port(const char *id,
     if (!chr) {
         return NULL;
     }
+    *be_opened = false;
     s = chr->opaque;
     s->sin.portname = g_strdup(name);
 
diff --git a/ui/console.c b/ui/console.c
index f490346..ed888e5 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -2079,10 +2079,6 @@ static CharDriverState *text_console_init(ChardevVC *vc, Error **errp)
     s->chr = chr;
     chr->opaque = s;
     chr->chr_set_echo = text_console_set_echo;
-    /* console/chardev init sometimes completes elsewhere in a 2nd
-     * stage, so defer OPENED events until they are fully initialized
-     */
-    chr->explicit_be_open = true;
 
     if (display_state) {
         text_console_do_init(chr, display_state);
@@ -2093,8 +2089,13 @@ static CharDriverState *text_console_init(ChardevVC *vc, Error **errp)
 static VcHandler *vc_handler = text_console_init;
 
 static CharDriverState *vc_init(const char *id, ChardevBackend *backend,
-                                ChardevReturn *ret, Error **errp)
+                                ChardevReturn *ret, bool *be_opened,
+                                Error **errp)
 {
+    /* console/chardev init sometimes completes elsewhere in a 2nd
+     * stage, so defer OPENED events until they are fully initialized
+     */
+    *be_opened = false;
     return vc_handler(backend->u.vc.data, errp);
 }
 
diff --git a/ui/gtk.c b/ui/gtk.c
index 83984f6..25e6d99 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1685,9 +1685,6 @@ static CharDriverState *gd_vc_handler(ChardevVC *vc, Error **errp)
     /* Temporary, until gd_vc_vte_init runs.  */
     chr->opaque = g_new0(VirtualConsole, 1);
 
-    /* defer OPENED events until our vc is fully initialized */
-    chr->explicit_be_open = true;
-
     vcs[nb_vcs++] = chr;
 
     return chr;
-- 
1.8.3.1

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

* [Qemu-devel] [PULL 50/50] exec.c: workaround regression caused by alignment change in d2f39ad
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (48 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 49/50] char: remove explicit_be_open from CharDriverState Paolo Bonzini
@ 2016-10-24 13:47 ` Paolo Bonzini
  2016-10-24 15:11 ` [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Peter Maydell
  50 siblings, 0 replies; 52+ messages in thread
From: Paolo Bonzini @ 2016-10-24 13:47 UTC (permalink / raw)
  To: qemu-devel; +Cc: Haozhong Zhang

From: Haozhong Zhang <haozhong.zhang@intel.com>

Commit d2f39ad "exec.c: Ensure right alignment also for file backed ram"
added an additional alignment requirement on the size of backend file
besides the previous page size. On x86, the alignment is changed from
4KB in QEMU 2.6 to 2MB in QEMU 2.7.

This change breaks certain usages in QEMU 2.7 on x86, e.g.
    -object memory-backend-file,id=mem1,mem-path=/tmp/,size=$SZ
    -device pc-dimm,id=dimm1,memdev=mem1
where $SZ is multiple of 4KB but not 2MB (e.g. 1023M). QEMU 2.7
reports the following error message and aborts:
qemu-system-x86_64: -device pc-dimm,memdev=mem1,id=nv1: backend memory size must be multiple of 0x200000

The same regression may also happen in other platforms as indicated by
Igor Mammedov. This change is however necessary for s390 according to
the commit message of d2f39ad, so we workaround the regression by taking
the change only on s390.

Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
Reported-by: "Xu, Anthony" <anthony.xu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 exec.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/exec.c b/exec.c
index e63c5a1..6d7f600 100644
--- a/exec.c
+++ b/exec.c
@@ -1254,7 +1254,12 @@ static void *file_ram_alloc(RAMBlock *block,
     }
 
     block->page_size = qemu_fd_getpagesize(fd);
-    block->mr->align = MAX(block->page_size, QEMU_VMALLOC_ALIGN);
+    block->mr->align = block->page_size;
+#if defined(__s390x__)
+    if (kvm_enabled()) {
+        block->mr->align = MAX(block->mr->align, QEMU_VMALLOC_ALIGN);
+    }
+#endif
 
     if (memory < block->page_size) {
         error_setg(errp, "memory size 0x" RAM_ADDR_FMT " must be equal to "
-- 
1.8.3.1

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

* Re: [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24
  2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
                   ` (49 preceding siblings ...)
  2016-10-24 13:47 ` [Qemu-devel] [PULL 50/50] exec.c: workaround regression caused by alignment change in d2f39ad Paolo Bonzini
@ 2016-10-24 15:11 ` Peter Maydell
  50 siblings, 0 replies; 52+ messages in thread
From: Peter Maydell @ 2016-10-24 15:11 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: QEMU Developers

On 24 October 2016 at 14:46, Paolo Bonzini <pbonzini@redhat.com> wrote:
> The following changes since commit b49e452fe994f8fbcd22bf5a87b79a2355481318:
>
>   Merge remote-tracking branch 'remotes/riku/tags/pull-linux-user-20160921' into staging (2016-10-21 13:49:58 +0100)
>
> are available in the git repository at:
>
>
>   git://github.com/bonzini/qemu.git tags/for-upstream
>
> for you to fetch changes up to 8360668e6988736bf621d8f3a3bae5d9f1a30bc5:
>
>   exec.c: workaround regression caused by alignment change in d2f39ad (2016-10-24 15:46:11 +0200)
>
> ----------------------------------------------------------------
> * KVM run_on_cpu fix (Alex)
> * atomic usage fixes (Emilio, me)
> * hugetlbfs alignment fix (Haozhong)
> * CharBackend refactoring (Marc-André)
> * test-i386 fixes (me)
> * MemoryListener optimizations (me)
> * Miscellaneous bugfixes (me)
> * iSER support (Roy)
> * --version formatting (Thomas)
>
> ----------------------------------------------------------------

Applied, thanks.

-- PMM

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

end of thread, other threads:[~2016-10-24 15:11 UTC | newest]

Thread overview: 52+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-24 13:46 [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Paolo Bonzini
2016-10-24 13:46 ` [Qemu-devel] [PULL 01/50] kvm-all: don't use stale dbg_data->cpu Paolo Bonzini
2016-10-24 13:46 ` [Qemu-devel] [PULL 02/50] rbd: shift byte count as a 64-bit value Paolo Bonzini
2016-10-24 13:46 ` [Qemu-devel] [PULL 03/50] block/iscsi: Introducing new zero-copy API Paolo Bonzini
2016-10-24 13:46 ` [Qemu-devel] [PULL 04/50] block/iscsi: Adding new iSER transport layer option Paolo Bonzini
2016-10-24 13:46 ` [Qemu-devel] [PULL 05/50] Put the copyright information on a separate line Paolo Bonzini
2016-10-24 13:46 ` [Qemu-devel] [PULL 06/50] atomic: introduce smp_mb_acquire and smp_mb_release Paolo Bonzini
2016-10-24 13:46 ` [Qemu-devel] [PULL 07/50] qemu-thread: use acquire/release to clarify semantics of QemuEvent Paolo Bonzini
2016-10-24 13:46 ` [Qemu-devel] [PULL 08/50] rcu: simplify memory barriers Paolo Bonzini
2016-10-24 13:46 ` [Qemu-devel] [PULL 09/50] atomic: base mb_read/mb_set on load-acquire and store-release Paolo Bonzini
2016-10-24 13:46 ` [Qemu-devel] [PULL 10/50] qht-bench: relax test_start/stop atomic accesses Paolo Bonzini
2016-10-24 13:46 ` [Qemu-devel] [PULL 11/50] test-i386: fix bitrot for 64-bit Paolo Bonzini
2016-10-24 13:46 ` [Qemu-devel] [PULL 12/50] target-i386: fix 32-bit addresses in LEA Paolo Bonzini
2016-10-24 13:46 ` [Qemu-devel] [PULL 13/50] tcg: try sti when moving a constant into a dead memory temp Paolo Bonzini
2016-10-24 13:46 ` [Qemu-devel] [PULL 14/50] memory: eliminate global MemoryListeners Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 15/50] memory: add a per-AddressSpace list of listeners Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 16/50] memory: optimize memory_global_dirty_log_sync Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 17/50] memory: optimize memory_region_sync_dirty_bitmap Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 18/50] char: serial: check divider value against baud base Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 19/50] char.h: misc doc fix Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 20/50] rng: remove unused included header Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 21/50] char: remove use-after-free on win-stdio Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 22/50] ringbuf: fix chr_write return value Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 23/50] sun4uv: fix serial initialization regression Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 24/50] malta: replace chr init by CHR_EVENT_OPENED handler Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 25/50] char: remove init callback Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 26/50] xilinx: fix buffer overflow on realize Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 27/50] mux: split mux_chr_update_read_handler() Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 28/50] char: introduce CharBackend Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 29/50] char: start converting mux driver to use CharBackend Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 30/50] char: replace PROP_CHR with CharBackend Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 31/50] char: remaining switch to CharBackend in frontend Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 32/50] char: rename some frontend functions Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 33/50] colo: claim in find_and_check_chardev Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 34/50] char: use qemu_chr_fe* functions with CharBackend argument Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 35/50] char: fold qemu_chr_set_handlers in qemu_chr_fe_set_handlers Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 36/50] vhost-user: only initialize queue 0 CharBackend Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 37/50] char: replace qemu_chr_claim/release with qemu_chr_fe_init/deinit Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 38/50] char: make some qemu_chr_fe skip if no driver Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 39/50] tests: start chardev unit tests Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 40/50] char: move front end handlers in CharBackend Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 41/50] char: rename chr_close/chr_free Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 42/50] char: remove explicit_fe_open, use a set_handlers argument Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 43/50] char: move fe_open in CharBackend Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 44/50] char: remove unused CHR_EVENT_FOCUS Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 45/50] char: use an enum for CHR_EVENT Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 46/50] char: remove unused qemu_chr_fe_event Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 47/50] char: replace avail_connections Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 48/50] char: use common error path in qmp_chardev_add Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 49/50] char: remove explicit_be_open from CharDriverState Paolo Bonzini
2016-10-24 13:47 ` [Qemu-devel] [PULL 50/50] exec.c: workaround regression caused by alignment change in d2f39ad Paolo Bonzini
2016-10-24 15:11 ` [Qemu-devel] [PULL 00/50] Miscellaneous patches for 2016-10-24 Peter Maydell

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.